上一节用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>
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 自动生成插件启动类
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 通用业务层父类,比如分页查询,一般都会用到分页查询,把分页查询封装到此业务父类,让其他业务类继承,可以减少代码量
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自动生成规则
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文件夹
在项目目录下创建dao包
7、启动mybatis自动生成插件,观察生成文件
查看mapper目录,可以看到UserDao.xml文件已经生成
查看entity目录,看看实体类
查看dao目录,在继承参数中加入实体类名,并删除生成的增删改查方法,对于这种生成不完美的有条件的可以自定义生成策略,这样也就不用在手工修改了
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()); } }
查询所有用户就可以看到控制台输出了,没有报错的话那就正确集成了,也具有了翻页的功能
9、文章源码地址
码云: https://gitee.com/apgblogs/springBootStudy
至此springboot集成mybatis就完成了,而且还可以和jpa配合使用,有以下几点需要注意
- mybatis生成的实体类和jpa的实体类是重复的,实际上用mybatis生成后在加入jpa的注解就可以了,这样jpa和mybatis都可以共用一个实体类
- mybatis自动生成每次启动时注意配置文件中的表映射要注释掉,不然会对其覆盖,也可以自定义生成规则,编写自己的生成方法,比如每次都分页查询的sql语句就可以用这种方式实现
- 也有maven的mybatis生成插件,我也用过但总是会报错就是说找不到那个自动生成注释的类,也不知道是啥原因就放弃了,还是自己弄一个main方法启动更加方便一点