所需jar包:Spring所需包、MyBatis所需包、mybatis-spring-1.x.x.jar(Spring与Mybatis整合包,需额外下载)
配置流程(个人觉得把逻辑顺序理清后需要记忆性的方面并不会太多):
以下是位于WEB-INF下的applicationContext.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:c="http://www.springframework.org/schema/c"
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
<context:annotation-config></context:annotation-config>
<!-- 只扫描Repository和Service注解的类 -->
<context:component-scan base-package="pers"
use-default-filters="false">
<context:include-filter type="annotation"
expression="org.springframework.stereotype.Repository" />
<context:include-filter type="annotation"
expression="org.springframework.stereotype.Service" />
</context:component-scan>
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean"
p:jndiName="java:comp/env/jdbc/mysql"></bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="dataSource"></bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"
p:dataSource-ref="dataSource" p:configLocation="classpath:mybatis-config.xml"></bean>
<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate"
c:_-ref="sqlSessionFactory"></bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"
p:basePackage="pers.dao" p:sqlSessionFactoryBeanName="sqlSessionFactory"
p:sqlSessionTemplateBeanName="sqlSessionTemplate">
</bean>
<tx:annotation-driven />
</beans>
①由于使用的是JNDI数据源所以还需在tomcat的context.xml文件中添加如下配置
本以为配置数据源应该都该在spring-jdbc-xxx的jar下包找的(Eclipse ALT+SHIFT+T可以快捷查询具体类在哪个jar包下),但可能由于jndi的数据源配置需在服务器中配置(这里是Tomcat服务器中的context.xml负责配置),所以把它放到spring-context-xxx.jar包中了
②SqlSessionFactoryBean:负责生成SqlSessionFactory,位于整合的mybatis-spring整合包中(由于该整合包是由MyBatis开发所以以mybatis为前缀,因Spring3发布时Mybatis3尚未完成,所以MyBatis社区自己进行整合)
个人比较喜欢看着左侧的属性栏进行Spring的属性装配,因为觉得能找到就没必要去记那么多没必要的属性。看到该类的属性相信大家都发现了mybatis的配置文件中的所有标签这里都有,也就是说mybatis配置文件的所有标签属性都可以通过该类配置,但个人不推荐所以只说个人喜欢的方式。我配置时看到哪个属性是我在配置文件中已经配置好的就直接填充,如dataSource。
configLocation:mybatis配置文件的所在位置,配置该属性后会根据位置解析文件然后为相应的标签属性赋值,具体方法为该类中的buildSqlSessionFactory()方法,有兴趣的可以去看看。
谈一下FactoryBean:Spring中的xxxFactoryBean都继承了Spring的FactoryBean,生成的bean一般为实现时的泛型,如上图中泛型为SqlSessionFactory,固配置该SqlSessionFactoryBean的实际bean是SqlSessionFactory实例,所以配置SqlSessionTemplate中的sqlSessionFactory属性时将用bean id="sqlSessionFactory"将用该SqlSessionFactory实例填充,上面JndiObjectFactoryBean亦然。看一下源码注解:
粗略讲一下第一段大意:实现该接口的对象将会作为一个为了对象而公开的工厂,而不是直接作为一个bean实例进行公开(如配置class为SqlSessionFactoryBean后生成(公开)的bean为SqlSessionFactory而不是SqlSessionFactoryBean),返回bean的方法是getObject(),即getObject返回的bean是什么则工厂bean生成的bean就是什么,一般设定为泛型的实例
③SqlSessionTemplate:一个模板类,通过调用SqlSession来完成工作,SqlSession由SqlSessionFactory负责生成,在Mybatis-Spring项目中它是一个核心类,主要的2个属性:
sqlSessionFactory:该类没有无参构造函数,即代表该属性必须作为构造器参数配置
executeorType:执行器,取值范围为SIMPLE、REUSE、BATCH,等同于mybatis配置文件中的setting的defaultExecutorType,可作为构造函数的第二个参数,但个人建议还是在mybatis配置文件中配置
该类具体构造方法如下图:
④MapperScannerConfigurer(数目少的话可以用MapperFactoryBean,这里不做介绍):采用自动扫描形式配置映射器,主要属性:
basePackage:指定让Spring自动扫描什么包,它会逐层深入扫描
annotationClass:表示如果该类被这个注解标识的时候才进行扫描(我例子中设置的是Repository,该注解一般用于标识DAO层)
sqlSessionFactoryBeanName:指定在Spring中定义sqlSessionFactory的bean的名称。如果它被定义,sqlSessionFactory将不起作用。
sqlSessionTemplateBeanName:指定在Spring中定义sqlSessionTemplate的bean的名称。如果它被定义,sqlSessionTemplate将不起作用。
makerInterface:指定实现了什么接口就认为它是Mapper,需提供一个公共接口去标记。
该类中还有sqlSessionFactory与sqlSessionTemplate这两个属性,但个人建议以sqlSessionFactoryBeanName、sqlSessionTemplateBeanName替代,因:
这两个方法都已标识过时,代表着可能过几个版本就会消失掉。
以下是该例子的相关代码,如果只对流程有兴趣的可以直接跳到最底Spring MVC层的简单配置
Role.java
package pers.vo;
import java.io.Serializable;
public class Role implements Serializable{
private static final long serialVersionUID = 1L;
private Integer id;
private String roleName;
private String note;
@Override
public String toString() {
return "Role [id=" + id + ", roleName=" + roleName + ", note=" + note + "]";
}
public Role() {
}
public Role(String roleName, String note) {
super();
this.roleName = roleName;
this.note = note;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
}
RoleDAO.java
package pers.dao;
import java.util.List;
import org.apache.ibatis.session.RowBounds;
import org.springframework.stereotype.Repository;
import pers.vo.Role;
@Repository
public interface RoleDAO {
Role findRoleById(int id);
int insertRole(Role role);
int deleteRoleById(int id);
int updateRole(Role role);
List<Role> findRolesByKeyName(String name);
List<Role> findAllRoles(RowBounds rowBounds);
}
RoleService.java
package pers.service;
import java.util.List;
import pers.vo.Role;
public interface RoleService {
Role findRoleById(int id);
int insertRole(Role role);
int deleteRoleById(int id);
int updateRole(Role role);
List<Role> findRolesByKeyName(String name);
List<Role> findAllRoles(int start,int limit);
}
RoleServiceImpl.java
package pers.service.impl;
import java.util.List;
import org.apache.ibatis.session.RowBounds;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import pers.dao.RoleDAO;
import pers.service.RoleService;
import pers.vo.Role;
@Service
public class RoleServiceImpl implements RoleService {
@Autowired(required=false)
private RoleDAO roleDAO;
@Override
@Transactional(propagation = Propagation.SUPPORTS)
public Role findRoleById(int id) {
return roleDAO.findRoleById(id);
}
@Override
@Transactional(propagation = Propagation.REQUIRED)
public int insertRole(Role role) {
return roleDAO.insertRole(role);
}
@Override
@Transactional(propagation = Propagation.REQUIRED)
public int deleteRoleById(int id) {
return roleDAO.deleteRoleById(id);
}
@Override
@Transactional(propagation = Propagation.REQUIRED)
public int updateRole(Role role) {
return roleDAO.updateRole(role);
}
@Override
@Transactional(propagation = Propagation.SUPPORTS)
public List<Role> findRolesByKeyName(String name) {
return roleDAO.findRolesByKeyName(name);
}
@Override
@Transactional(propagation = Propagation.SUPPORTS)
public List<Role> findAllRoles(int start, int limit) {
return roleDAO.findAllRoles(new RowBounds(start, limit));
}
}
RoleController.java
package pers.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import pers.service.RoleService;
import pers.vo.Role;
@Controller
public class RoleController {
@Autowired
private RoleService roleService;
public void setRoleService(RoleService roleService) {
this.roleService = roleService;
}
public RoleController() {
}
@RequestMapping("/role/getRole")
@ResponseBody
public Role getRole(@RequestParam("id") int id) {
Role role = roleService.findRoleById(id);
System.out.println(role);
return role;
}
}
mybatis-config.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>
<settings>
<setting name="mapUnderscoreToCamelCase" value="true" />
<setting name="aggressiveLazyLoading" value="false" />
<setting name="lazyLoadingEnabled" value="true" />
<setting name="useGeneratedKeys" value="true" />
<setting name="defaultExecutorType" value="REUSE" />
<setting name="defaultStatementTimeout" value="25000" />
</settings>
<typeAliases>
<package name="pers.vo" />
</typeAliases>
<mappers>
<mapper resource="mapper/role.xml" />
</mappers>
</configuration>
Role.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">
<mapper namespace="pers.dao.RoleDAO">
<cache eviction="LRU" flushInterval="100000"></cache>
<select id="findRoleById" resultType="role">
<![CDATA[select id,role_name,note from tb_role where id=#{id}]]>
</select>
<select id="findRolesByKeyName" resultType="role">
<bind name="name_pattern" value="'%'+ name + '%'"/>
<![CDATA[select id,role_name,note from tb_role where role_name like #{name_pattern}]]>
</select>
<select id="findAllRoles" resultType="role">
<![CDATA[select id,role_name,note from tb_role]]>
</select>
<insert id="insertRole" parameterType="role">
<![CDATA[insert into tb_role(role_name,note) values (#{roleName},#{note})]]>
</insert>
<update id="updateRole" parameterType="role">
<![CDATA[select role_name,note from tb_role where id=#{id}]]>
</update>
<delete id="deleteRoleById">
<![CDATA[delete from tb_role where id=#{id}]]>
</delete>
</mapper>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
id="WebApp_ID" version="3.1">
<display-name>SM_Integration</display-name>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>springDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/dispatcher-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
MVC配置文件dispatcher-servlet.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:aop="http://www.springframework.org/schema/aop"
xmlns:c="http://www.springframework.org/schema/c" xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
<mvc:annotation-driven></mvc:annotation-driven>
<context:component-scan base-package="pers.*"></context:component-scan>
<context:annotation-config></context:annotation-config>
<!-- <bean
class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="mappingJacksonHttpMessageConverter" />
</list>
</property>
</bean> -->
<!-- Spring视图拦截器 -->
<bean
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<!-- JSON视图拦截器,读取到@ResponseBody的时候触发 -->
<ref bean="mappingJacksonHttpMessageConverter" />
</list>
</property>
</bean>
<!-- json转换器,可将结果转化 -->
<bean id="mappingJacksonHttpMessageConverter"
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>application/json;charset=UTF-8</value>
</list>
</property>
</bean>
</beans>
我的mybatis入门书中视图拦截器使用的是注释中的 AnnotationMethodHandlerAdapter,但根据注解 AnnotationMethodHandlerAdapter在3.2版本后已过时,现在支持使用RequestMappingHandlerAdapter,下图是两个类的属性图:
图放不下RequestMappingHandlerAdapter所有属性。
可以看出AnnotationMethodHandlerAdapter中的大部分属性RequestMappingHandlerAdapter都有,且增加了不少属性,AnnotationMethodHandlerAdapter继承了WebContentGenerator,而RequestMappingHandlerAdapter继承了AbstractHandlerMethodAdapter,AbstractHandlerMethodAdapter继承了WebContentGenerator,由于我要设置的属性两者都有所以进行了替换,程序依然能正常允许。
index.jsp为空页面,网址后缀添加/role/getRole?id=xx 获取要查询的数据并以json格式下载,图如下:
保存的json文件:
Spring MVC使用json还需添加jackson-databind-x.x.x、jackson-annotations-x.x.x、jackson-core-x.x.x 3个jar包
我的数据库tb_role就只有id,role_name,note 3个属性,便于实践,就不讲太多