看本文之前,请确保你已经在SpringBoot中集成MyBatis,并能正常使用。
如果没有,那么请先移步 http://blog.csdn.net/catoop/article/details/50553714 做了解后,再按本文步骤操作。
使用MyBatis在我们通过xml集中配置SQL,并通过创建接口Mapper文件来完成持久化DAO层(mybatis内部使用的是动态代理,所以我们不需要自己编写实现类)。
然而在实际开发中,单表操作非常多,如果你也想像JPA、JDBC那样做一个所谓的BaseDao。那么可以实现一个通用Mapper来达到目的。现在有现成的通用Mapper插件,我们无需重新创造轮子(代码是开源的,你也可以自己在其基础上修改)。
通用Mapper插件网址:https://github.com/abel533/Mapper
下面是使用方法(本文直接将分页插件PageHelper也集成了):
一、添加或修改pom依赖
<!-- MyBatis -->
<!-- <dependency> -->
<!-- <groupId>org.mybatis.spring.boot</groupId> -->
<!-- <artifactId>mybatis-spring-boot-starter</artifactId> -->
<!-- <version>1.0.1-SNAPSHOT</version> -->
<!-- </dependency> -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.2.3</version>
</dependency>
<!-- 分页插件 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>4.1.1</version>
</dependency>
<!--通用Mapper插件-->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper</artifactId>
<version>3.3.4</version>
</dependency>
这里说一下,文章开始指定的那篇文章中直接依赖的mybatis的starter。因为本文在集成通用Mapper的时候直接使用出现了错误,所以将mybatis的starter中的Java类(它本身只有2个Java类,非常简单)拷贝到工程中,注释掉了头部的//@ConditionalOnBean(DataSource.class),你不用去找那2个类的源码了,下面会粘贴出来。
二、将下面4个Java类加入到工程中
将文件
MybatisAutoConfiguration.java
MyBatisMapperScannerConfig.java
MybatisProperties.java
MyMapper.java
添加到 org.springboot.sample.config.mybatis 中(包名根据自己工程修改)
最有一个MyMapper.java要特别注意,不要把MyMapper放到同其他Mapper一起,该类不能被当做普通Mapper一样被扫描,否则会出错。
package org.springboot.sample.config.mybatis;
import java.util.Properties;
import javax.annotation.PostConstruct;
import javax.sql.DataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import com.github.pagehelper.PageHelper;
/** * {@link EnableAutoConfiguration Auto-Configuration} for Mybatis. Contributes a * {@link SqlSessionFactory} and a {@link SqlSessionTemplate}. * * If {@link org.mybatis.spring.annotation.MapperScan} is used, or a configuration file is * specified as a property, those will be considered, otherwise this auto-configuration * will attempt to register mappers based on the interface definitions in or under the * root auto-configuration package. * * @author Eddú Meléndez * @author Josh Long */
@Configuration
@ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class })
//@ConditionalOnBean(DataSource.class)
@EnableConfigurationProperties(MybatisProperties.class)
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
public class MybatisAutoConfiguration {
private static Log log = LogFactory.getLog(MybatisAutoConfiguration.class);
@Autowired
private MybatisProperties properties;
@Autowired(required = false)
private Interceptor[] interceptors;
@Autowired
private ResourceLoader resourceLoader = new DefaultResourceLoader();
@PostConstruct
public void checkConfigFileExists() {
if (this.properties.isCheckConfigLocation()) {
Resource resource = this.resourceLoader
.getResource(this.properties.getConfig());
Assert.state(resource.exists(),
"Cannot find config location: " + resource
+ " (please add config file or check your Mybatis "
+ "configuration)");
}
}
@Bean(name = "sqlSessionFactory")
@ConditionalOnMissingBean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
factory.setDataSource(dataSource);
if (StringUtils.hasText(this.properties.getConfig())) {
factory.setConfigLocation(
this.resourceLoader.getResource(this.properties.getConfig()));
} else {
if (this.interceptors != null && this.interceptors.length > 0) {
factory.setPlugins(this.interceptors);
}
factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());
factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());
factory.setMapperLocations(this.properties.getMapperLocations());
}
return factory.getObject();
}
@Bean
@ConditionalOnMissingBean
public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory,
this.properties.getExecutorType());
}
/** * 分页插件 * * @param dataSource * @return * @author SHANHY * @create 2016年2月18日 */
@Bean
public PageHelper pageHelper(DataSource dataSource) {
log.info("注册MyBatis分页插件PageHelper");
PageHelper pageHelper = new PageHelper();
Properties p = new Properties();
p.setProperty("offsetAsPageNum", "true");
p.setProperty("rowBoundsWithCount", "true");
p.setProperty("reasonable", "true");
pageHelper.setProperties(p);
return pageHelper;
}
}
package org.springboot.sample.config.mybatis;
import java.util.Properties;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import tk.mybatis.spring.mapper.MapperScannerConfigurer;
/** * MyBatis扫描接口,使用的tk.mybatis.spring.mapper.MapperScannerConfigurer <br/> * 如果你不使用通用Mapper,可以改为org.xxx... * */
@Configuration
//TODO 注意,由于MapperScannerConfigurer执行的比较早,所以必须有下面的注解
@AutoConfigureAfter(MybatisAutoConfiguration.class)
public class MyBatisMapperScannerConfig {
@Bean
public MapperScannerConfigurer mapperScannerConfigurer() {
MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactory");
mapperScannerConfigurer.setBasePackage("org.springboot.sample.mapper");
Properties properties = new Properties();
// 这里要特别注意,不要把MyMapper放到 basePackage 中,也就是不能同其他Mapper一样被扫描到。
properties.setProperty("mappers", MyMapper.class.getName());
properties.setProperty("notEmpty", "false");
properties.setProperty("IDENTITY", "MYSQL");
mapperScannerConfigurer.setProperties(properties);
return mapperScannerConfigurer;
}
}
package org.springboot.sample.config.mybatis;
import org.apache.ibatis.session.ExecutorType;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.core.io.Resource;
/** * Configuration properties for Mybatis. * * @author Eddú Meléndez */
@ConfigurationProperties(prefix = MybatisProperties.MYBATIS_PREFIX)
public class MybatisProperties {
public static final String MYBATIS_PREFIX = "mybatis";
/** * Config file path. */
private String config;
/** * Location of mybatis mapper files. */
private Resource[] mapperLocations;
/** * Package to scan domain objects. */
private String typeAliasesPackage;
/** * Package to scan handlers. */
private String typeHandlersPackage;
/** * Check the config file exists. */
private boolean checkConfigLocation = false;
/** * Execution mode. */
private ExecutorType executorType = ExecutorType.SIMPLE;
public String getConfig() {
return this.config;
}
public void setConfig(String config) {
this.config = config;
}
public Resource[] getMapperLocations() {
return this.mapperLocations;
}
public void setMapperLocations(Resource[] mapperLocations) {
this.mapperLocations = mapperLocations;
}
public String getTypeHandlersPackage() {
return this.typeHandlersPackage;
}
public void setTypeHandlersPackage(String typeHandlersPackage) {
this.typeHandlersPackage = typeHandlersPackage;
}
public String getTypeAliasesPackage() {
return this.typeAliasesPackage;
}
public void setTypeAliasesPackage(String typeAliasesPackage) {
this.typeAliasesPackage = typeAliasesPackage;
}
public boolean isCheckConfigLocation() {
return this.checkConfigLocation;
}
public void setCheckConfigLocation(boolean checkConfigLocation) {
this.checkConfigLocation = checkConfigLocation;
}
public ExecutorType getExecutorType() {
return this.executorType;
}
public void setExecutorType(ExecutorType executorType) {
this.executorType = executorType;
}
}
package org.springboot.sample.config.mybatis;
import tk.mybatis.mapper.common.Mapper;
import tk.mybatis.mapper.common.MySqlMapper;
/** * 被继承的Mapper,一般业务Mapper继承它 * */
public interface MyMapper<T> extends Mapper<T>, MySqlMapper<T> {
//TODO
//FIXME 特别注意,该接口不能被扫描到,否则会出错
}
三、属性配置文件
属性配置文件中和文章开头指定的文章一样配置,没有什么修改,下面粘贴出来:
mybatis.mapper-locations=classpath*:org/springboot/sample/mapper/sql/mysql/*Mapper.xml
mybatis.type-aliases-package=org.springboot.sample.entity
四、在业务Mapper中继承基础MyMapper接口
public interface StudentMapper extends MyMapper<Student> {
List<Student> likeName(String name);
Student getById(int id);
int add(Student stu);
String getNameById(int id);
}
然后在Service中使用即可,后面就没什么说的了。
@Service
public class StudentService {
@Autowired
private JdbcTemplate jdbcTemplate;
@Autowired
private StudentMapper studentMapper;
@TargetDataSource(name="ds2")
public List<Student> likeName(String name){
return studentMapper.likeName(name);
}
public int testSave(){
Student stu = new Student();
stu.setAge(33);
stu.setName("测试新增");
stu.setSumScore("66");
stu.setAvgScore("22");
return studentMapper.insert(stu);//这里调用的是基础Mapper中的insert方法
}
}
最后还有一点要说明,使用公共Mapper“可能”需要对实体类进行修改。如果你的实体字段和数据库字段不一致(或者实体名称和数据库表名不一致),这样才需要修改,例如:
/** * 学生实体 * * @author 单红宇(365384722) * @myblog http://blog.csdn.net/catoop/ * @create 2016年1月12日 */
public class Student implements Serializable{
@Id
private int id;
private String name;
@Column(name="SCORE_SUM")
private String sumScore;
@Column(name="SCORE_AVG")
private String avgScore;
private int age;
// getter setter
}
其他没有什么可说的了,请至少要到 https://github.com/abel533/Mapper 把插件的其他说明再看一遍。