Spring Boot MyBatis 通用Mapper插件集成

vedx8423 8年前

来自: 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;      }    }
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 把插件的其他说明再看一遍。