2018/1/1
根据上一篇文档(Spring(13):新增功能:超市订单的供应商表查询 and 根据供应商名称查询供应商信息--功能实现(上)),还有更加简洁的手法吗?
答:有的,Mybatis-Spring 提供了MapperFactoryBean, 能够以配置的方式生成映射器实现并注入给业务组件。前提是:仅仅使用SqlsessionTemplate执行基本的数据访问操作,不包含其它非Mybatis的工作,可以不必手工编码SqlsessionTemplate或者SqlSessionDaoSupport 来实现此类DAO。
【0】文件结构
图1
【1】在上一个案例基础上,删除ProviderMapperImpl.java,保留接口和SQL映射文件,然后在applicationContext-mybatis.xml 配置DAO,完整内容如下:
<?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:tx="http://www.springframework.org/schema/tx"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">
<!-- 数据源配置 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url">
<value><![CDATA[jdbc:mysql://127.0.0.1:3306/test?
useUnicode=true&characterEncoding=utf-8]]></value>
</property>
<property name="username" value="root"></property>
<property name="password" value=""></property>
</bean>
<!-- SqlSessionFactoryBean 配置 -->
<bean id="sqlSessionFactory"
class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 引用数据源组件 -->
<property name="dataSource" ref="dataSource"></property>
<!-- 引用Mybatis配置文件的配置 -->
<property name="configLocation" value="classpath:mybatis-config.xml"></property>
</bean>
<!-- 配置DAO -->
<bean id="providerMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="com.smbms.dao.ProviderMapper"></property>
<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean>
<!-- 配置业务Bean ,构造器注入,一定要有带参构造函数-->
<bean id="providerService" class="com.smbms.service.ProviderServiceImpl">
<constructor-arg name="providerMapper" ref="providerMapper" ></constructor-arg>
</bean>
</beans>
解释:(1)配置DAO组件,class属性不是某个实现类,而是
MapperFactoryBean;
(2)通过mapperInterface 属性指定了映射器(SQL映射接口文件),只能是接口类型,不能是某个实现类;
(3)MapperFactoryBean 是 SqlSessionDaoSupport 的子类,需要通过setSqlSessionFactory() 方法注入 SqlSessionFactory 实例,以创建SqlSessionTemplate。
【2】新建业务类接口 ProviderService.java 和实例 ProviderServiceImpl.java,注意 ProviderServiceImpl.java 直接将providerMapper属性调用了:
ProviderService.java :
package com.smbms.service;
import java.util.List;
import com.smbms.entities.Provider;
public interface ProviderService {
public List<Provider> findUsersWithConditions();
public List<Provider> findUsersWithConditionsByAddress(String address);
}
ProviderServiceImpl.java:
package com.smbms.service;
import java.util.List;
import com.smbms.dao.ProviderMapper;
import com.smbms.entities.Provider;
public class ProviderServiceImpl implements ProviderService{
private ProviderMapper providerMapper;
public ProviderServiceImpl() {}
public ProviderServiceImpl(ProviderMapper providerMapper) {
this.providerMapper = providerMapper;
}
@Override
public List<Provider> findUsersWithConditions() {
return providerMapper.providershow();
}
@Override
public List<Provider> findUsersWithConditionsByAddress(String address) {
return providerMapper.providershowbyAddress(address);
}
}
【3】编写单元测试 ProviderServiceImplTest.java:
package com.smbms.service;
import java.util.List;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.smbms.entities.Provider;
public class ProviderServiceImplTest {
@Test
public void test() {
System.out.println("start..");
System.out.println("----------------1----------------");
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext-mybatis.xml");
ProviderService providerService = (ProviderService) ctx.getBean("providerService");
List<Provider> providers = providerService.findUsersWithConditions();
for(Provider p: providers){
p.toString();
}
System.out.println("---------------2----------------");
String address = "Maoming";
System.out.println("------------显示供应商地点为茂名的结果------------");
providers = providerService.findUsersWithConditionsByAddress(address);
for(Provider p: providers){
p.toString();
}
}
}
【4】输出结果:
DEBUG 01-01 21:43:30,475 JDBC Connection [jdbc:mysql://127.0.0.1:3306/test?
useUnicode=true&characterEncoding=utf-8, UserName=root@localhost, MySQL Connector Java] will not be managed by Spring (JakartaCommonsLoggingImpl.java:54)
DEBUG 01-01 21:43:30,483 ==> Preparing: select * from smbms_provider (JakartaCommonsLoggingImpl.java:54)
DEBUG 01-01 21:43:30,532 ==> Parameters: (JakartaCommonsLoggingImpl.java:54)
DEBUG 01-01 21:43:31,998 <== Columns: id, proAddress, proFax, createdBy, creatiomDate, modifyBy, modifyDate (JakartaCommonsLoggingImpl.java:59)
DEBUG 01-01 21:43:31,999 <== Row: 1, Maoming, 0213-11, 110, 2017-12-31 00:00:00.0, null, null (JakartaCommonsLoggingImpl.java:59)
DEBUG 01-01 21:43:33,482 <== Row: 2, Gaozhou, 0213-12, 110, 2017-12-31 18:32:43.0, null, null (JakartaCommonsLoggingImpl.java:59)
DEBUG 01-01 21:43:33,484 <== Total: 2 (JakartaCommonsLoggingImpl.java:54)
DEBUG 01-01 21:43:33,544 Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@36bc55de] (JakartaCommonsLoggingImpl.java:54)
DEBUG 01-01 21:43:33,545 Returning JDBC Connection to DataSource (DataSourceUtils.java:327)
---------------2----------------
------------显示供应商地点为茂名的结果------------
DEBUG 01-01 21:43:33,546 Creating a new SqlSession (JakartaCommonsLoggingImpl.java:54)
DEBUG 01-01 21:43:33,546 SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@757277dc] was not registered for synchronization because synchronization is not active (JakartaCommonsLoggingImpl.java:54)
DEBUG 01-01 21:43:33,546 Fetching JDBC Connection from DataSource (DataSourceUtils.java:110)
DEBUG 01-01 21:43:33,547 JDBC Connection [jdbc:mysql://127.0.0.1:3306/test?
useUnicode=true&characterEncoding=utf-8, UserName=root@localhost, MySQL Connector Java] will not be managed by Spring (JakartaCommonsLoggingImpl.java:54)
DEBUG 01-01 21:43:33,548 ==> Preparing: select * from smbms_provider where proAddress like CONCAT('%',?,'%') (JakartaCommonsLoggingImpl.java:54)
DEBUG 01-01 21:43:33,548 ==> Parameters: Maoming(String) (JakartaCommonsLoggingImpl.java:54)
DEBUG 01-01 21:43:33,746 <== Columns: id, proAddress, proFax, createdBy, creatiomDate, modifyBy, modifyDate (JakartaCommonsLoggingImpl.java:59)
DEBUG 01-01 21:43:33,747 <== Row: 1, Maoming, 0213-11, 110, 2017-12-31 00:00:00.0, null, null (JakartaCommonsLoggingImpl.java:59)
DEBUG 01-01 21:43:33,748 <== Total: 1 (JakartaCommonsLoggingImpl.java:54)
DEBUG 01-01 21:43:33,748 Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@757277dc] (JakartaCommonsLoggingImpl.java:54)
DEBUG 01-01 21:43:33,748 Returning JDBC Connection to DataSource (DataSourceUtils.java:327)
同理,可以对User也采取相应的动作,目的去查询User的信息:
【5】在applicationContext-mybatis.xml 配置user-DAO,添加的内容如下:
<!-- 配置DAO-user -->
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="com.smbms.dao.UserMapper"></property>
<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean>
<!-- 配置provider业务Bean ,构造器注入,一定要有带参构造函数-->
<bean id="userService" class="com.smbms.service.UserServiceImpl">
<constructor-arg name="userMapper" ref="userMapper"></constructor-arg>
</bean>
【6】新建业务类接口 UserService.java 和实例 UserServiceImpl.java,注意 UserServiceImpl.java 直接将UserMapper属性调用了:
UserService.java:
package com.smbms.service;
import java.util.List;
import com.smbms.entities.User;
public interface UserService {
public List<User> findUsersWithConditions();
public User findUsersWithConditionsById(Integer id);
}
User ServiceImpl.java:
package com.smbms.service;
import java.util.List;
import com.smbms.dao.UserMapper;
import com.smbms.entities.User;
public class UserServiceImpl implements UserService{
private UserMapper userMapper;
@Override
public List<User> findUsersWithConditions() {
return userMapper.Usershow();
}
@Override
public User findUsersWithConditionsById(Integer id) {
return userMapper.UsershowById(id);
}
public UserServiceImpl() {}
public UserServiceImpl(UserMapper userMapper) {
this.userMapper = userMapper;
}
}
【7】新建单元测试 UserServiceImplTest.java :
package com.smbms.service;
import java.util.List;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.smbms.entities.User;
public class UserServiceImplTest {
@Test
public void test() {
System.out.println("start..");
System.out.println("----------------1----------------");
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext-mybatis.xml");
UserService userService = (UserService) ctx.getBean("userService");
List<User> users = userService.findUsersWithConditions();
for(User u: users){
u.toString();
}
System.out.println("---------------2----------------");
String address = "Maoming";
System.out.println("------------显示用户ID为1的结果------------");
User user = userService.findUsersWithConditionsById(1);
user.toString();
}
}
【8】输出结果:
DEBUG 01-01 22:31:30,662 JDBC Connection [jdbc:mysql://127.0.0.1:3306/test?
useUnicode=true&characterEncoding=utf-8, UserName=root@localhost, MySQL Connector Java] will not be managed by Spring (JakartaCommonsLoggingImpl.java:54)
DEBUG 01-01 22:31:30,678 ==> Preparing: select * from smbms_user (JakartaCommonsLoggingImpl.java:54)
DEBUG 01-01 22:31:30,736 ==> Parameters: (JakartaCommonsLoggingImpl.java:54)
DEBUG 01-01 22:31:30,790 <== Columns: id, userCode, userName, userPassword, gender, birthday, phone, address, userRole, createBy, createDate, modifyBy, modifyDate (JakartaCommonsLoggingImpl.java:59)
DEBUG 01-01 22:31:30,792 <== Row: 1, test01, mmb02, 9876543210, 2, 1991-12-29, 0000, maoming, 110, 1, 2017-12-17 10:50:04.0, null, null (JakartaCommonsLoggingImpl.java:59)
DEBUG 01-01 22:31:30,797 <== Row: 2, test01, mmb02, scua, 2, 1991-12-29, 0000, maoming, 110, 1, 2017-12-17 10:56:48.0, null, null (JakartaCommonsLoggingImpl.java:59)
DEBUG 01-01 22:31:30,799 <== Row: 3, test01, mmb02, scua, 2, 1991-12-29, 0000, maoming, 110, 1, 2017-12-17 10:58:46.0, null, null (JakartaCommonsLoggingImpl.java:59)
DEBUG 01-01 22:31:30,800 <== Row: 4, test01, mmb02, scua, 2, 1991-12-29, 0000, maoming, 110, 1, 2017-12-17 11:01:42.0, null, null (JakartaCommonsLoggingImpl.java:59)
DEBUG 01-01 22:31:30,802 <== Row: 5, test01, mmb02, scua, 2, 1991-12-29, 0000, maoming, 110, 1, 2017-12-17 11:03:05.0, null, null (JakartaCommonsLoggingImpl.java:59)
DEBUG 01-01 22:31:30,803 <== Total: 5 (JakartaCommonsLoggingImpl.java:54)
DEBUG 01-01 22:31:30,806 Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2a65fe7c] (JakartaCommonsLoggingImpl.java:54)
DEBUG 01-01 22:31:30,807 Returning JDBC Connection to DataSource (DataSourceUtils.java:327)
---------------2----------------
------------显示用户ID为1的结果------------
DEBUG 01-01 22:31:30,808 Creating a new SqlSession (JakartaCommonsLoggingImpl.java:54)
DEBUG 01-01 22:31:30,808 SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6236eb5f] was not registered for synchronization because synchronization is not active (JakartaCommonsLoggingImpl.java:54)
DEBUG 01-01 22:31:30,808 Fetching JDBC Connection from DataSource (DataSourceUtils.java:110)
DEBUG 01-01 22:31:30,809 JDBC Connection [jdbc:mysql://127.0.0.1:3306/test?
useUnicode=true&characterEncoding=utf-8, UserName=root@localhost, MySQL Connector Java] will not be managed by Spring (JakartaCommonsLoggingImpl.java:54)
DEBUG 01-01 22:31:30,810 ==> Preparing: select * from smbms_user where id = ? (JakartaCommonsLoggingImpl.java:54)
DEBUG 01-01 22:31:30,810 ==> Parameters: 1(Integer) (JakartaCommonsLoggingImpl.java:54)
DEBUG 01-01 22:31:30,811 <== Columns: id, userCode, userName, userPassword, gender, birthday, phone, address, userRole, createBy, createDate, modifyBy, modifyDate (JakartaCommonsLoggingImpl.java:59)
DEBUG 01-01 22:31:30,812 <== Row: 1, test01, mmb02, 9876543210, 2, 1991-12-29, 0000, maoming, 110, 1, 2017-12-17 10:50:04.0, null, null (JakartaCommonsLoggingImpl.java:59)
DEBUG 01-01 22:31:30,813 <== Total: 1 (JakartaCommonsLoggingImpl.java:54)
DEBUG 01-01 22:31:30,814 Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6236eb5f] (JakartaCommonsLoggingImpl.java:54)
DEBUG 01-01 22:31:30,814 Returning JDBC Connection to DataSource (DataSourceUtils.java:327)
看一下完整的Spring配置文件吧!
<?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:tx="http://www.springframework.org/schema/tx"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">
<!-- 数据源配置 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url">
<value><![CDATA[jdbc:mysql://127.0.0.1:3306/test?
useUnicode=true&characterEncoding=utf-8]]></value>
</property>
<property name="username" value="root"></property>
<property name="password" value=""></property>
</bean>
<!-- SqlSessionFactoryBean 配置 -->
<bean id="sqlSessionFactory"
class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 引用数据源组件 -->
<property name="dataSource" ref="dataSource"></property>
<!-- 引用Mybatis配置文件的配置 -->
<property name="configLocation" value="classpath:mybatis-config.xml"></property>
</bean>
<!-- 配置DAO-provider -->
<bean id="providerMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="com.smbms.dao.ProviderMapper"></property>
<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean>
<!-- 配置DAO-user -->
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="com.smbms.dao.UserMapper"></property>
<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean>
<!-- 配置provider业务Bean ,构造器注入,一定要有带参构造函数-->
<bean id="providerService" class="com.smbms.service.ProviderServiceImpl">
<constructor-arg name="providerMapper" ref="providerMapper" ></constructor-arg>
</bean>
<!-- 配置provider业务Bean ,构造器注入,一定要有带参构造函数-->
<bean id="userService" class="com.smbms.service.UserServiceImpl">
<constructor-arg name="userMapper" ref="userMapper"></constructor-arg>
</bean>
</beans>
解释:provider写了一个mapper,user写了一个mapper,随着业务的增加,在DAO和业务Bean上花费的代码和管理会越来越多,有没有更好的办法简化DAO模块的编码呢?
答案是肯定的,那就是使用MapperScannerConfigurer注入映射器。相关内容在我的下一篇博文:Spring(15):使用MapperScannerConfigurer注入映射器。
【9】工程说明.txt:
(1)这是Mybatis和Spring整合练习的工程;
(2)实际使用有3个包:dao、entities、service;
(3)Mybatis配置文件内容很简洁,Spring完成大部分配置管理;
(4)通过SQLSessionTemplate的实现类对数据库进行操作;
(5)配置DAO组件并进入SqlSessionTemplate实例;
(6)配置业务Bean并注入DAO实例 ;
(7)完成的功能是:查询provider的列表,模糊查询供应商信息;
(8)与smbms05MybatisSpring的区别:去掉了实现类ProviderMapperImpl;仅仅保留ProviderMapper
接口和相关SQL映射文件,通过MapperFactoryBean注入给业务组件。
(9)此外,也新增了一个User查询,照壶画瓢;
以上,是 Spring(14):使用MapperFactoryBean注入映射器 的全部内容。