【化学药品管理平台——spring MVC+Spring+MyBatis实现 0301】SSM框架搭建
前两个系列我们介绍了Servlet+Jsp和SSH框架开发的Cupboard化学药品管理平台,此篇我们介绍以SSM框架(Spring+SpringMVC+Mybatis)对此项目的开发。
Mybatis
MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。
jar包
SqlMapConfig.xml核心配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="db.properties"></properties>
<!-- 配置环境集合属性对象,和spring整合后 environments配置将被移除-->
<environments default="development">
<environment id="development">
<!-- 配置jdbc事务管理-->
<transactionManager type="JDBC" />
<!-- 数据库连接池-->
<!-- <dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/cupboard?characterEncoding=utf-8" />
<property name="username" value="root" />
<property name="password" value="root" />
</dataSource> -->
<!-- 引用属性配置文件db.properties中的配置信息 -->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</dataSource>
</environment>
</environments>
<!-- 映射器,用于加载相关的mapper.xml配置文件 -->
<mappers>
<!-- 原生sql映射文件Users.xml -->
<mapper resource="User.xml"/>
<!--
动态sql映射文件UserMapper.xml
使用class属性引入Mapper接口实现动态代理Dao的规则:
1. 接口的名称和映射文件名称除扩展名外要完全相同
2. 接口和映射文件要放在同一个目录下
-->
<!-- <mapper class="com.rclv.mapper.UserMapper"/> -->
<!--
使用包扫描的方式批量引入Mapper接口的规则:
1. 接口的名称和映射文件名称除扩展名外要完全相同
2. 接口和映射文件要放在同一个目录下
-->
<package name="com.rclv.mapper"/>
</mappers>
</configuration>
properties标签:引入属性配置文件。可将数据库连接参数单独配置在db.properties中,然后再加载到sqlMapConfig.xml配置文件中,这样方便对参数统一管理。
environments标签:配置环境集合属性对象。该标签下可以配置多个环境变量,映射到多种数据源和数据库。
environment标签:环境子属性对象,用来配置不同环境变量。
transactionManager标签:配置事务管理器。
dataSource标签:配置数据库连接池。
mappers标签:映射器,用于加载相关的sql映射配置文件。
mapper:配置sql映射文件。resouce属性:路径为xml映射文件的路径包名+文件名。class属性:路径为Mapper接口的全名。
package标签:包扫描。也可用包扫描的方式引入Mapper接口,name属性值为接口所在包路径。
Xml映射文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace:命名空间,做sql隔离 -->
<mapper namespace="test">
<!--
id:sql语句唯一标识
parameterType:传入参数的类型
resultType:返回结果集类型
#{}以预编译的形式将参数设置到sql语句中,可以有效防止sql注入,起到占位符的作用
-->
<insert id="mybatisRegist" parameterType="com.rclv.pojo.User" >
insert into user (uid, uname, upassword, ugrade) values(#{uid}, #{uname}, #{upassword}, #{ugrade})
</insert>
</mapper>
mapper标签:根节点元素。namespace属性定义命名空间,做sql隔离。
insert标签:映射插入语句。id为sql语句唯一标识,parameterType为传入参数类型,resultType为返回结果集类型,#{}帮助设置sql语句的参数,类似于占位符。
其他映射语句标签:select映射查询语句、update映射更新语句、delete映射删除语句等。在标签内写具体的sql语句即可。
Mybatis测试
我们做一个用户注册的测试,即添加用户数据。
先看一下MybatisTest测试项目的文件结构。
package com.rclv.test;
public class MybatisTest {
@Test
public void mybatisRegist() throws Exception{
String resource = "SqlMapConfig.xml";
// 1.将核心配置文件读取到输入流
InputStream inputStream = Resources.getResourceAsStream(resource);
// 2.通过核心配置文件输入流来创建会话工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
// 3.通过工厂创建会话
SqlSession openSession = factory.openSession();
// 4.创建要添加的对象User
User user = new User();
user.setUid(UUIDUtils.getId());
user.setUname("Mybatis");
user.setUpassword(MD5Utils.md5("m23456"));
user.setUgrade("2018");
// 5.insert()方法执行添加语句。第一个参数为所调用的sql语句,写法为:映射文件namespace属性值.sql语句id属性值
openSession.insert("test.mybatisRegist", user);
// 6.提交事务(mybatis会自动开启事务,但不会自动提交,所以需要手动提交事务)
openSession.commit();
}
}
1. 将核心配置文件读取到输入流
2. 通过核心配置文件输入流来创建会话工厂
3. 通过工厂创建会话
4. 创建要添加的对象User
5. insert()方法执行添加语句。第一个参数为所调用的sql语句,写法为:映射文件namespace属性值.sql语句id属性值
6.添加操作需要提交事务(mybatis会自动开启事务,但不会自动提交,所以需要手动提交事务)
Mybatis原生DAO测试
现在我们把数据操作代码写到dao层,做一个mybatis原生dao的测试。
dao层。
package com.rclv.dao;
public class UserDaoImpl implements UserDao {
private SqlSessionFactory sqlSessionFactory;
// 1.通过构造方法注入sqlSessionFactory
public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {
this.sqlSessionFactory = sqlSessionFactory;
}
@Override
public void mybatisRegist(User user) {
// 2.通过工厂创建会话。sqlSesion是线程不安全的,所以它的最佳使用范围在方法体内。
SqlSession openSession = sqlSessionFactory.openSession();
// 3.insert()方法执行添加语句。
openSession.insert("test.mybatisRegist", user);
// 4.提交事务
openSession.commit();
}
}
1. 通过构造方法注入sqlSessionFactory
2. 通过工厂创建会话。sqlSesion是线程不安全的,所以它的最佳使用范围在方法体内。
3. insert()方法执行添加语句。
4. 提交事务
测试层。
package com.rclv.test;
public class MybatisDaoTest {
private SqlSessionFactory factory;
//@Before:在测试方法前执行此方法
@Before
public void setUp() throws Exception{
String resource = "SqlMapConfig.xml";
// 1.将核心配置文件读取到输入流
InputStream inputStream = Resources.getResourceAsStream(resource);
// 2.通过核心配置文件输入流来创建会话工厂
factory = new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void testMybatisRegist() throws Exception{
// 3.将初始化好的会话工厂注入到实现类中
UserDao userDao = new UserDaoImpl(factory);
// 4.创建要添加的对象User
User user = new User();
user.setUid(UUIDUtils.getId());
user.setUname("Mybatis");
user.setUpassword(MD5Utils.md5("m23456"));
user.setUgrade("2018");
// 5.调用dao层方法,进行数据添加操作
userDao.mybatisRegist(user);
}
}
1. 将核心配置文件读取到输入流
2. 通过核心配置文件输入流来创建会话工厂
3. 将初始化好的会话工厂注入到实现类中
4. 创建要添加的对象User
5. 调用dao层方法,进行数据添加操作
@Before注解表示在测试方法执行前需要执行该注解下的方法。
我们将SqlSessionFactory作为全局变量提取出来,并在@Before注解下初始化,方便注入到dao中,在单个方法中创建线程不安全的sqlSession。
Mapper动态代理方式只需要编写Mapper接口(相当于Dao接口),由Mybatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体即是接口实现类方法。
配置Mapper映射文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<!--
mapper接口代理实现编写规则:
1. 映射文件中namespace要等于接口的全路径名称
2. 映射文件中sql语句id要等于接口的方法名称
3. 映射文件中传入参数类型要等于接口方法的传入参数类型
4. 映射文件中返回结果集类型要等于接口方法的返回值类型
-->
<mapper namespace="com.rclv.mapper.UserMapper">
<insert id="mybatisRegist" parameterType="com.rclv.pojo.User" >
insert into user (uid, uname, upassword, ugrade) values(#{uid}, #{uname}, #{upassword}, #{ugrade})
</insert>
</mapper>
映射文件配置规则:
1. 映射文件中namespace要等于接口的全路径名称
2. 映射文件中sql语句id要等于接口的方法名称
3. 映射文件中传入参数类型要等于接口方法的传入参数类型
4. 映射文件中返回结果集类型要等于接口方法的返回值类型
UserMapper接口
package com.rclv.mapper;
import java.util.List;
import com.rclv.pojo.User;
public interface UserMapper {
public void mybatisRegist(User user);
}
接口的定义和上面映射文件的配置规则相对应。
Mybatis动态代理DAO测试
package com.rclv.test;
public class MybatisMapperTest {
private SqlSessionFactory factory;
//作用:在测试方法前执行这个方法
@Before
public void setUp() throws Exception{
String resource = "SqlMapConfig.xml";
// 1.将核心配置文件读取到输入流
InputStream inputStream = Resources.getResourceAsStream(resource);
// 2.通过核心配置文件输入流来创建会话工厂
factory = new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void testMybatisRegist() throws Exception{
// 3.通过工厂创建会话。sqlSesion是线程不安全的,所以它的最佳使用范围在方法体内。
SqlSession openSession = factory.openSession();
// 4.通过getMapper方法创建代理对象来实例化接口
UserMapper mapper = openSession.getMapper(UserMapper.class);
// 5.创建要添加的对象User
User user = new User();
user.setUid(UUIDUtils.getId());
user.setUname("Mybatis");
user.setUpassword(MD5Utils.md5("m23456"));
user.setUgrade("2018");
// 6.调用UserMapper接口中的方法,动态实现数据添加操作。
mapper.mybatisRegist(user);
// 7.提交事务
openSession.commit();
}
}
1. 将核心配置文件读取到输入流
2. 通过核心配置文件输入流来创建会话工厂
3. 通过工厂创建会话。sqlSesion是线程不安全的,所以它的最佳使用范围在方法体内。
4. 通过getMapper方法创建代理对象来实例化接口
5. 创建要添加的对象User
6. 调用UserMapper接口中的方法,动态实现数据添加操作。
7. 提交事务
SpringMVC
Spring MVC 是一个建立在中央前端控制器servlet(DispatcherServlet)的MVC模式Web框架,它负责发送每个请求到合适的处理程序,使用视图来最终返回响应结果的概念。Spring MVC 是 Spring 产品组合的一部分,它享有 Spring IoC容器紧密结合Spring松耦合等特点,因此它有Spring的所有优点。
jar包
web.xml中配置前端控制器
SpringMVC是一个基于DispatcherServlet前端控制器的MVC框架,每一个请求都先访问DispatcherServlet。DispatcherServlet负责转发每一个Request请求给相应的Handler,Handler处理以后再返回相应的视图(View)和模型(Model)。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<display-name>SpringMVCTest</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<!-- spirngMvc前端控制器 -->
<servlet>
<servlet-name>SpringMVCTest</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 指定springMvc核心配置文件位置 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:SpringMvc.xml</param-value>
</init-param>
<!-- tomcat启动的时候即加载此servlet -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>SpringMVCTest</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
</web-app>
web.xml中,在servlet标签中配置SpringMVC前端控制器DispatcherServlet,对所有的以*.action结尾的访问进行控制,并在初始化中制定springMVC核心配置文件的位置,设置<load-on-startup>为1,在tomcat启动时即加载此servlet。
SpringMvc.xml核心配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!-- @Controller注解扫描。使用注解扫描可以对Bean进行批量注册,而不需要再给每个Bean单独使用xml的方式进行配置 -->
<context:component-scan base-package="com.rclv.controller"></context:component-scan>
<!--
如果没有显示的配置处理器映射器和处理器适配那么springMvc会去默认的dispatcherServlet.properties中查找
对应的处理器映射器和处理器适配器去使用,这样每个请求都要扫描一次他的默认配置文件,效率非常低,会降低访问速度,所以要显示的配置处理器映射器和
处理器适配器
-->
<!-- 注解形式的处理器映射器 -->
<!-- <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"></bean> -->
<!-- 注解形式的处理器适配器 -->
<!-- <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"></bean> -->
<!-- 配置最新版的注解的处理器映射器 -->
<!-- <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"></bean> -->
<!-- 配置最新版的注解的处理器适配器 -->
<!-- <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"></bean> -->
<!-- 注解驱动:自动配置最新版的注解的处理器映射器和处理器适配器 -->
<mvc:annotation-driven></mvc:annotation-driven>
<!-- 配置视图解析器:在controller中指定页面路径时,可以直接写页面去掉扩展名的名称,而不用再写页面的完整路径名称了 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 完整页面路径 = 前缀 + 去掉后缀名的页面名称 + 后缀 -->
<!-- 前缀 -->
<property name="prefix" value="/jsp/"></property>
<!-- 后缀 -->
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
1. 需要配置对@Controller注解的扫描。
2. 配置注解形式的处理器映射器和处理器适配器。可指定配置,也可配置注解驱动,注解驱动将自动配置最新版的处理器映射器和处理器适配器。
3. 配置视图解析器。配置前缀和后缀属性之后,controller类中指定页面返回路径时,可以直接写去掉扩展名的页面名称,而不需要写页面的全路径。
SpringMVC测试
SpringMVCTest测试项目的文件结构。
测试一下跳转到注册页面的/user/registUI.action。
<c:if test="${empty user }">
<li style="position: relative; left:68%"><a href="${pageContext.request.contextPath }/user/loginUI.action">登录</a></li>
<li style="position: relative; left:68%"><a href="${pageContext.request.contextPath }/user/registUI.action">注册</a></li>
</c:if>
package com.rclv.controller;
// 1.@controller用于标记一个类,该类是一个springmvc controller对象
@Controller
@RequestMapping("/user")
public class UserControllerTest {
// 2.指定url到请求方法的映射,url中输入一个地址,就会请求到这个方法.例如:localhost:/SpringMVCTest/user/registUI.action
@RequestMapping("/registUI")
public ModelAndView registUI() {
// 3.模型和视图对象。model模型: 模型对象中存放了返回给页面的数据;view视图: 视图对象中指定了返回的页面的位置
ModelAndView modelAndView = new ModelAndView();
// 4.指定返回的页面位置。若没有在SpringMvc.xml中配置视图解析器的前缀和后缀,则页面返回路径需要写完整
// modelAndView.setViewName("/jsp/register.jsp");
modelAndView.setViewName("register");
return modelAndView;
}
1. @controller注解。用于标记一个类,表示该类是一个springmvc controller对象,即是一个控制器。
2. @RequestMapping注解。用于类或方法标记,用于处理请求地址映射。用于方法上,表示请求路径结尾,用于类上,表示结尾路径的上一层路径。
3. 模型和视图对象。model模型: 模型对象中存放了返回给页面的数据;view视图: 视图对象中指定了返回的页面的位置。
4. 指定返回的页面位置。若没有在SpringMvc.xml中配置视图解析器的前缀和后缀,则页面返回路径需要写完整。
前台页面点击注册按钮,url为localhost:/SpringMVCTest/user/registUI.action,将会访问到UserController中的registUI()方法,registUI()返回一个ModelAndView对象,将跳转到视图对象设置的返回页面register.jsp。这里如果在SpringMvc.xml中没有配置视图解析器的前缀和后缀,则页面返回路径需要写完整,即modelAndView.setViewName("/jsp/register.jsp")。
参数绑定
// 1.绑定User实体类参数,可以直接获取从前台传入的user对象
@RequestMapping("/regist")
public ModelAndView regist(User user){
// 2.设置获取到的user对象的变量值
user.setUid(UUIDUtils.getId());
user.setUpassword(MD5Utils.md5(user.getUpassword()));
// 3.在控制台输出user对象,检测是否可以通过参数绑定获取前台传入的实体类对象
System.out.println(user);
ModelAndView modelAndView = new ModelAndView();
// 4.将要返回给页面的数据放入模型和视图对象中,数据将返回到request域中
modelAndView.addObject("msg", "注册成功");
// 5.指定返回的页面位置
modelAndView.setViewName("msg");
return modelAndView;
}
1. Controller类的方法中可以绑定一些参数,在方法体中可以直接使用。绑定User实体类参数,可以直接获取从前台传入的user对象
2. 设置获取到的user对象的变量值
3. 在控制台输出user对象,检测是否可以通过参数绑定获取前台传入的实体类对象
4. 将要返回给页面的数据放入模型和视图对象中,数据将返回到request域中
5. 指定返回的页面位置
String返回类型
// 1.绑定HttpServletRequest对象。
@RequestMapping("/regist2")
public String regist2(User user, HttpServletRequest request){
// 2.设置获取到的user对象的变量值
user.setUid(UUIDUtils.getId());
user.setUpassword(MD5Utils.md5(user.getUpassword()));
// 3.在控制台输出user对象,检测是否可以通过参数绑定获取前台传入的实体类对象
System.out.println(user);
// 4.设置msg属性值到request域,并返回到msg.jsp页面
request.setAttribute("msg", "注册成功");
return "msg";
}
1. 绑定HttpServletRequest对象。
2. 设置获取到的user对象的变量值
3. 在控制台输出user对象,检测是否可以通过参数绑定获取前台传入的实体类对象
4. 设置msg属性值到request域,并返回到msg.jsp页面
Controller类中的方法返回类型也可为String,这样的话,返回的字符串就代表返回的页面位置,效果同modelAndView.setViewName()。
至此,我们介绍了两个新的框架(Mybatis和SpringMVC)及其配置,下一篇我们将介绍Sping和Mybatis、SpringMVC的整合。