Spring Boot MyBatis 通用Mapper插件集成
來自: http://blog.csdn.net/catoop/article/details/50684676
看本文之前,請確保你已經在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; }
}</pre>
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; }
}</pre>
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; }
}</pre>
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 特別注意,該接口不能被掃描到,否則會出錯 }</pre>
三、屬性配置文件
屬性配置文件中和文章開頭指定的文章一樣配置,沒有什么修改,下面粘貼出來: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);
}</pre>
然后在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方法 }
}</pre>
最后還有一點要說明,使用公共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
}</pre>
其他沒有什么可說的了,請至少要到 https://github.com/abel533/Mapper 把插件的其他說明再看一遍。
</div>