springBoot集成myBatis 自动生成Model并支持分页

上一节用springBoot集成的jpa并实现了jpa的增删改查操作,这一节讲解在原来项目的基础上集成mybatis,并和jpa配合使用,取长补短,mybatis相对于jpa操作查询语句更加灵活,但jpa相对于mybatis更符合java面向对象编程,但不可避免的项目中总会出现比如统计,多表联合查询的需求,这种情况使用jpa就会很繁琐,这时候如果项目中嵌入了mybatis就可以很方便的处理了,比如调用一些数据库特有的函数也是很方便的。

mybatis比jpa的学习门槛低也更简单,更加容易很好的操作sql语句。

本节顺便也集成了mybatis的自动生成插件和实体类注释生成插件,默认的mybatis自动生成插件是不支持注释生成,也集成了mybatis的翻页插件,实现翻页处理。

1、加入mybatis依赖,自动生成依赖和mybatis分页插件依赖

<!-- mybatis 集成 -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.0.1</version>
        </dependency>
        <!-- mybatis自动生成插件 -->
        <dependency>
            <groupId>org.mybatis.generator</groupId>
            <artifactId>mybatis-generator-core</artifactId>
            <version>1.3.5</version>
        </dependency>
        <!-- mybatis自动分页插件 -->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.2.10</version>
        </dependency>
mybatis依赖

2、在spring配置文件中添加mybatis配置和分页配置

......
mybatis:
  type-aliases-package: com.apgblogs.firstspringboot.entity
  mapper-locations: classpath:mapper/*.xml

pagehelper:
  helperDialect: mysql
  reasonable: true
  supportMethodsArguments: true
  params: count=countSql
  returnPageInfo: check

3、 在config目录下编写自定义生成注释类和mybatis自动生成插件启动类

  • CommentGenerator 注释生成 会获取到mysql数据库字段注释
  • MyBatisGeneratorRun 自动生成插件启动类
config目录
package com.apgblogs.firstspringboot.config;

import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.dom.java.Field;
import org.mybatis.generator.api.dom.java.InnerClass;
import org.mybatis.generator.api.dom.java.Method;
import org.mybatis.generator.internal.DefaultCommentGenerator;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Properties;

/**
 * @author xiaomianyang
 * @description mybatis 注释生成
 * @date 2019-04-28 上午 10:58
 */
public class CommentGenerator extends DefaultCommentGenerator {
    private Properties properties;
    private Properties systemPro;
    private boolean suppressDate;
    private boolean suppressAllComments;
    private String currentDateStr;

    public CommentGenerator() {
        super();
        properties = new Properties();
        systemPro = System.getProperties();
        suppressDate = false;
        suppressAllComments = false;
        currentDateStr = (new SimpleDateFormat("yyyy-MM-dd")).format(new Date());
    }


    public void addFieldComment(Field field, IntrospectedTable introspectedTable,
                                IntrospectedColumn introspectedColumn) {
        if (suppressAllComments) {
            return;
        }
        StringBuilder sb = new StringBuilder();
        field.addJavaDocLine("/**");
        sb.append(" * ");
        sb.append(introspectedColumn.getRemarks());
        field.addJavaDocLine(sb.toString().replace("\n", " "));
        field.addJavaDocLine(" */");
    }

    public void addFieldComment(Field field, IntrospectedTable introspectedTable) {

    }

    public void addGeneralMethodComment(Method method, IntrospectedTable introspectedTable) {

    }

    public void addGetterComment(Method method, IntrospectedTable introspectedTable,
                                 IntrospectedColumn introspectedColumn) {

    }

    public void addSetterComment(Method method, IntrospectedTable introspectedTable,
                                 IntrospectedColumn introspectedColumn) {

    }

    public void addClassComment(InnerClass innerClass, IntrospectedTable introspectedTable, boolean markAsDoNotDelete) {

    }

    public void addClassComment(InnerClass innerClass, IntrospectedTable introspectedTable) {
    }

}
package com.apgblogs.firstspringboot.config;

import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.internal.DefaultShellCallback;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * @author xiaomianyang
 * @description mybatis 自动生成
 * @date 2019-04-28 上午 11:29
 */
public class MyBatisGeneratorRun {

    public static void main(String[] args) throws Exception{
        MyBatisGeneratorRun app = new MyBatisGeneratorRun();

        System.out.println(app.getClass().getResource("/").getPath());
        app.generator();
        System.out.println(System.getProperty("user.dir"));
    }

    public void generator() throws Exception{

        List<String> warnings = new ArrayList<String>();
        boolean overwrite = true;
        InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("generatorConfig.xml");
        ConfigurationParser cp = new ConfigurationParser(warnings);
        Configuration config = cp.parseConfiguration(resourceAsStream);
        DefaultShellCallback callback = new DefaultShellCallback(overwrite);
        MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
        myBatisGenerator.generate(null);

        for(String warning:warnings){
            System.out.println(warning);
        }
    }
}

4、在项目目录下创建base包

  • BaseDao 通用增删改查父类,这样生成dao就不用在写增晒改查借口了
  • BaseModel 通用实体父类,比如创建日期,创建人,id,等字段就可以放到这个包中,自动生成的实体类就不用创建重复的字段了
  • BaseService 通用业务层父类,比如分页查询,一般都会用到分页查询,把分页查询封装到此业务父类,让其他业务类继承,可以减少代码量
base目录
package com.apgblogs.firstspringboot.base;

import com.github.pagehelper.Page;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * @author xiaomianyang
 * @description 增删改查基础类
 * @date 2019-04-28 上午 11:56
 */
public interface BaseDao<T extends BaseModel> {

    int deleteByPrimaryKey(String id);

    int insertSelective(T record);

    T selectByPrimaryKey(String id);

    int updateByPrimaryKeySelective(T record);

    int updateByPrimaryKey(T record);

    List<T> selectAll(@Param("record") T record, @Param("page") Page page);
}
package com.apgblogs.firstspringboot.base;

import java.io.Serializable;
import java.util.Date;

/**
 * @author xiaomianyang
 * @description 模型基础类
 * @date 2019-04-28 下午 12:02
 */
public class BaseModel implements Serializable {


    private String id;
    /**
     * 由谁创建
     */
    private String createBy;
    /**
     * 创建时间
     */
    private Date createDate;
    /**
     * 最后修改者
     */
    private String updateBy;
    /**
     * 最后修改时间
     */
    private Date updateDate;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getCreateBy() {
        return createBy;
    }

    public void setCreateBy(String createBy) {
        this.createBy = createBy;
    }

    public Date getCreateDate() {
        return createDate;
    }

    public void setCreateDate(Date createDate) {
        this.createDate = createDate;
    }

    public String getUpdateBy() {
        return updateBy;
    }

    public void setUpdateBy(String updateBy) {
        this.updateBy = updateBy;
    }

    public Date getUpdateDate() {
        return updateDate;
    }

    public void setUpdateDate(Date updateDate) {
        this.updateDate = updateDate;
    }
}
package com.apgblogs.firstspringboot.base;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * @author xiaomianyang
 * @description
 * @date 2019-04-28 下午 12:33
 */
public class BaseService<D extends BaseDao,M extends BaseModel> {

    @Autowired
    protected D dao;

    /**
     * @description 查询全部
     * @author sunjinping
     * @date 2019-04-28 下午 01:03
     * @param [m, page]
     * @return java.util.List<M>
     */
    public PageInfo selectAll(M m, Page page){
        page=PageHelper.startPage(page.getPageNum(),page.getPageSize());
        dao.selectAll(m,page);
        PageInfo pageInfo=new PageInfo<>(page.getResult());
        return pageInfo;
    }
}

5、在resources目录下创建mybatis自动生成配置文件

  • generator.properties 用来存放数据库连接属性
  • generatorConfig.xml 配置mybatis自动生成规则
resources目录

generator.properties文件代码

jdbc.driverLocation=D:/workSpace/mavenRepository/repository/mysql/mysql-connector-java/8.0.15/mysql-connector-java-8.0.15.jar
jdbc.driverClass=com.mysql.cj.jdbc.Driver
jdbc.connectionURL=jdbc:mysql://apg-server:3306/test?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&failOverReadOnly=false&serverTimezone=Asia/Shanghai
jdbc.userId=root
jdbc.password=123456

generatorConfig.xml文件代码

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>
    <!--导入属性配置-->
    <properties resource="generator.properties"></properties>

    <!--指定特定数据库的jdbc驱动jar包的位置-->
    <classPathEntry location="${jdbc.driverLocation}"/>

    <context id="default" targetRuntime="MyBatis3">

        <!-- JavaBean 实现 序列化 接口 -->
        <plugin type="org.mybatis.generator.plugins.SerializablePlugin"/>
        <!-- genenat entity时,生成toString -->
        <plugin type="org.mybatis.generator.plugins.ToStringPlugin" />

        <!-- optional,旨在创建class时,对注释进行控制 -->
        <commentGenerator type="com.apgblogs.firstspringboot.config.CommentGenerator">
        </commentGenerator>

        <!--jdbc的数据库连接 -->
        <jdbcConnection
                driverClass="${jdbc.driverClass}"
                connectionURL="${jdbc.connectionURL}"
                userId="${jdbc.userId}"
                password="${jdbc.password}">
        </jdbcConnection>


        <!-- 非必需,类型处理器,在数据库类型和java类型之间的转换控制-->
        <javaTypeResolver>
            <property name="forceBigDecimals" value="false"/>
        </javaTypeResolver>


        <!-- Model模型生成器,用来生成含有主键key的类,记录类 以及查询Example类
            targetPackage     指定生成的model生成所在的包名
            targetProject     指定在该项目下所在的路径
        -->
        <javaModelGenerator targetPackage="com.apgblogs.firstspringboot.entity"
                            targetProject="src/main/java">

            <!-- 是否允许子包,即targetPackage.schemaName.tableName -->
            <property name="enableSubPackages" value="false"/>
            <!-- 是否对model添加 构造函数 -->
            <property name="constructorBased" value="false"/>
            <!-- 是否对类CHAR类型的列的数据进行trim操作 -->
            <property name="trimStrings" value="true"/>
            <!-- 建立的Model对象是否 不可改变  即生成的Model对象不会有 setter方法,只有构造方法 -->
            <property name="immutable" value="false"/>
            <property name="rootClass" value="com.apgblogs.firstspringboot.base.BaseModel"/>
        </javaModelGenerator>

        <!--Mapper映射文件生成所在的目录 为每一个数据库的表生成对应的SqlMap文件 -->
        <sqlMapGenerator targetPackage="mapper"
                         targetProject="src/main/resources">
            <property name="enableSubPackages" value="false"/>
        </sqlMapGenerator>

        <!-- 客户端代码,生成易于使用的针对Model对象和XML配置文件 的代码
                type="ANNOTATEDMAPPER",生成Java Model 和基于注解的Mapper对象
                type="MIXEDMAPPER",生成基于注解的Java Model 和相应的Mapper对象
                type="XMLMAPPER",生成SQLMap XML文件和独立的Mapper接口
        -->
        <javaClientGenerator targetPackage="com.apgblogs.firstspringboot.dao"
                             targetProject="src/main/java" type="XMLMAPPER">
            <property name="enableSubPackages" value="true"/>
            <property name="rootInterface" value="com.apgblogs.firstspringboot.base.BaseDao"/>
        </javaClientGenerator>
        <table tableName="t_user" mapperName="UserDao"
               enableCountByExample="false"
               enableUpdateByExample="false"
               enableDeleteByExample="false"
               enableSelectByExample="false"
               enableSelectByPrimaryKey="true"
               enableUpdateByPrimaryKey="true"
               enableDeleteByPrimaryKey="true"
               selectByExampleQueryId="false">
        </table>
    </context>
</generatorConfiguration>

6、创建一个存放dao目录和mapper目录用来存放mybatis自动生成的文件

  • mapper 用来存放sql xml文件
  • dao mybatis操作数据库的接口

在resources目录下创建mapper文件夹

resources目录

在项目目录下创建dao包

springboot dao

7、启动mybatis自动生成插件,观察生成文件

mybatis自动生成插件

查看mapper目录,可以看到UserDao.xml文件已经生成

sql mapper映射文件

查看entity目录,看看实体类

实体类

查看dao目录,在继承参数中加入实体类名,并删除生成的增删改查方法,对于这种生成不完美的有条件的可以自定义生成策略,这样也就不用在手工修改了

Userdao

8、编写mybatis查询的测试用例

测试用例中也有jpa的方法,jpa和mybatis都可以运行测试

package com.apgblogs.firstspringboot;

import com.apgblogs.firstspringboot.dao.UserDao;
import com.apgblogs.firstspringboot.entity.TUser;
import com.apgblogs.firstspringboot.entity.TUserEntity;
import com.apgblogs.firstspringboot.service.UserServiceImpl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageInfo;
import com.google.gson.Gson;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.List;

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class FirstSpringBootApplicationTests {

    private static Logger logger= LoggerFactory.getLogger(FirstSpringBootApplicationTests.class);

    @Autowired
    private UserServiceImpl userService;

    @Autowired
    private UserDao userDao;

    @Test
    public void getUserList(){
        List<TUserEntity> tUserEntityList=userService.getUserList();
        logger.info("用户列表{}",new Gson().toJson(tUserEntityList));
    }

    @Test
    public void insertUser(){
        TUserEntity tUserEntity=new TUserEntity();
        tUserEntity.setUserName("赵四");
        tUserEntity.setUserPswd("123456");
        tUserEntity.setCreateBy("123");
        tUserEntity.setUpdateBy("123");
        userService.insertUser(tUserEntity);
    }

    @Test
    public void getUser(){
        TUser tUser=userDao.selectByPrimaryKey("4028f1816b4f253b016b4f2541df0000");
        logger.info("用户{}",new Gson().toJson(tUser));
    }

    @Test
    public void getAllUser(){
        Page page=new Page();
        //每页数量
        page.setPageSize(10);
        //页码
        page.setPageNum(0);
        //排序 排序可以放到page中,在查询语句中可以动态支持排序
        page.setOrderBy("");
        PageInfo pageInfo=userService.selectAll(null,page);
        logger.info("分页用户,第{}页,共{}条,{}",pageInfo.getPageNum(),pageInfo.getTotal(),pageInfo.getList());
    }
}

查询所有用户就可以看到控制台输出了,没有报错的话那就正确集成了,也具有了翻页的功能

springboot控制台

9、文章源码地址

码云: https://gitee.com/apgblogs/springBootStudy

至此springboot集成mybatis就完成了,而且还可以和jpa配合使用,有以下几点需要注意

  • mybatis生成的实体类和jpa的实体类是重复的,实际上用mybatis生成后在加入jpa的注解就可以了,这样jpa和mybatis都可以共用一个实体类
  • mybatis自动生成每次启动时注意配置文件中的表映射要注释掉,不然会对其覆盖,也可以自定义生成规则,编写自己的生成方法,比如每次都分页查询的sql语句就可以用这种方式实现
  • 也有maven的mybatis生成插件,我也用过但总是会报错就是说找不到那个自动生成注释的类,也不知道是啥原因就放弃了,还是自己弄一个main方法启动更加方便一点

发表评论