在springboot工程中如果使用mybatis作为持久层框架,那必须知道如何自动生成 java 实体类、dao 层接口(mapper 接口)及mapper.xml文件,这样可以减少不必要的开发。
生成代码的方式有很多种,比如说利用idea的插件、maven插件,使用代码执行方法去生成
下面分享一下利用代码去生成我们需要的实体类、dao、mapper.xml
打开官网:http://mybatis.org/generator/quickstart.html,官网里面描述的已经很清楚了,下面我们重新解释一下它的配置,这是重点,整个代码的核心就是这个配置
DOCTYPE generatorConfiguration PUBLIC
"-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<context id="simple" targetRuntime="MyBatis3">
<jdbcConnection driverClass="org.hsqldb.jdbcDriver"
connectionURL="jdbc:hsqldb:mem:aname" />
<javaModelGenerator targetPackage="example.model" targetProject="src/main/java"/>
<sqlMapGenerator targetPackage="example.mapper" targetProject="src/main/resources"/>
<javaClientGenerator type="XMLMAPPER" targetPackage="example.mapper" targetProject="src/main/java"/>
<table tableName="FooTable" />
context>
generatorConfiguration>
这是官网给出的一段简单的配置,我们一般会在resources目录下新建一个mybatisGeneratorConfig.xml这样的配置文件。这个配置里面有几个重要的标签,下面我们就解读一下这份配置
它主要是包含三个子元素
属性 | 描述 |
---|---|
properties | 引入配置资源,例如数据库配置信息 |
classPathEntry | 引入类路径,例如引入JDBC的驱动程序 |
context | 用于指定生成一组对象的环境 |
这些子元素的顺序最好按照表格的顺序来配置,properties放在最前面,context放在最后面
这个元素不是必须的,它有两个属性
属性 | 描述 |
---|---|
resource | 相对资源 |
url | 全路径 |
一般情况下我们的mybatisGeneratorConfig.xml配置文件和application.properties项目配置文件都是在resources目录下,因此使用resource属性,可以以下方式:
<properties resource="application.properties"/>
如果使用url,则
<properties url="file:///F:\javaStudy\mybatis-generator\mybatisGenerator\src\main\resources\application.properties"/>
一般情况下我们都是使用resource这个属性,如果使用url,不同开发人员项目所在的目录一般都是不一样的,比如我的项目是放在本机上的F盘,而有些人是E盘
这个元素用于引入某些类的路径,例如JDBC驱动类
属性 | 描述 |
---|---|
location | 相对路径或绝对路径 |
配置如下
<classPathEntry location="E:/apache-maven-3.8.5/repository/mysql/mysql-connector-java/8.0.18/mysql-connector-java-8.0.18.jar"/>
classPathEntry只在下面这两种情况下才有效
- 当加载 JDBC 驱动内省数据库时
- 当加载根类中的 JavaModelGenerator 检查重写的方法时
元素用于指定生成一组对象的环境 ,有以下四个属性
属性 | 描述 |
---|---|
id | context唯一标识,用于追踪错误信息 |
defaultModelType | 如果目标运行时为“MyBatis3Simple”、“MyBatis 3DynamicSql”或“MyBatist3Kotlin”,则忽略此属性,它有下面三个值conditional(默认),flat(推荐),hierarchical |
targetRuntime | 此属性用于指定生成的代码的运行时环境,有四个可选值:MyBatis3DynamicSql 、 MyBatis3Kotlin 、 MyBatis3(默认) 、 MyBatis3Simple |
introspectedColumnImpl | 该参数可以指定扩展org.mybatis.generator.api.IntrospectedColumn 该类的实现类 |
它有以下几个子元素
这些元素需要按照严格的顺序来,后面会对属性逐一讲解
context配置例子
<context id="mysql_tables" targetRuntime="MyBatis3" defaultModelType="flat">
//子元素配置项
context>
使用MyBatis3 生成的mapper内容
long countByExample(StudentExample example);
int insert(Student row);
int insertSelective(Student row);
List<Student> selectByExample(StudentExample example);
Student selectByPrimaryKey(Long id);
int updateByExampleSelective(@Param("row") Student row, @Param("example") StudentExample example);
int updateByExample(@Param("row") Student row, @Param("example") StudentExample example);
int updateByPrimaryKeySelective(Student row);
int updateByPrimaryKey(Student row);
而使用MyBatis3Simple生成的mapper如下
int insert(Student row);
Student selectByPrimaryKey(Long id);
List<Student> selectAll();
int updateByPrimaryKey(Student row);
很显然MyBatis3要比MyBatis3Simple生成的方法要多,正常情况下我们使用MyBatis3会比较多
它有以下几个属性
属性 | 描述 |
---|---|
autoDelimitKeywords | 如果为true,则如果SQL关键字用作表中的列名,则MBG将对其进行分隔,默认值是false |
beginningDelimiter | 要用作需要分隔符的SQL标识符的起始标识符分隔符的值,默认值为双引号(“) |
endingDelimiter | 要用作需要分隔符的SQL标识符的结束标识符分隔符的值,默认值为双引号(“) |
javaFileEncoding | java文件的编码 |
javaFormatter | 使用此属性可以为生成的Java文件指定用户提供的格式化程序的完整类名 |
kotlinFileEncoding | Kotlin文件的编码 |
kotlinFormatter | 使用此属性可以为生成的Kotlin文件指定用户提供的格式化程序的完整类名 |
xmlFormatter | 使用此属性可以为生成的XML文件指定用户提供的格式化程序的完整类名 |
配置例子:
<context id="mysql_tables" targetRuntime="MyBatis3" defaultModelType="flat">
<property name="beginningDelimiter" value=""/>
<property name="endingDelimiter" value=""/>
<property name="javaFileEncode" value="UTF-8"/>
context>
元素用于定义插件,它有一个属性
属性 | 描述 |
---|---|
type | 完整的类名 |
配置例子
<plugin type="org.mybatis.generator.plugins.SerializablePlugin" />
<plugin type="org.mybatis.generator.plugins.EqualsHashCodePlugin">
<property name="useEqualsHashCodeFromRoot" value="true"/>
plugin>
<plugin type="org.mybatis.generator.plugins.ToStringPlugin">
<property name="useToStringFromRoot" value="true"/>
plugin>
<plugin type="org.mybatis.generator.plugins.UnmergeableXmlMappersPlugin" />
生成的实体类会包含下面的几个方法
@Override
public boolean equals(Object that) {
// 代码省略
}
@Override
public int hashCode() {
// 代码省略
}
@Override
public String toString() {
// 代码省略
}
该元素主要用于配置注释,它有一个属性
属性 | 描述 |
---|---|
type | 完整的类名 |
它有一个子元素property,主要包含以下几个属性
属性 | 描述 |
---|---|
suppressAllComments | 不让生成注释,默认值是false,表示生成注释,如果为true,表示不让生成注释 |
suppressDate | 不让生成的注释包含时间戳,默认值是false |
addRemarkComments | 添加 db 表中字段的注释 |
dateFormat | 将日期写入生成的注释时使用的日期格式字符串 |
useLegacyGeneratedAnnotation | 指定是否使用不推荐使用的“javax”命名空间中的注释 |
比较常用的是suppressAllComments、suppressDate、addRemarkComments
配置例子
<commentGenerator type="com.example.mybatisgenerator.CommentGenerator">
<property name="addRemarkComments" value="true"/>
<property name="suppressAllComments" value="true"/>
<property name="suppressDate" value="true"/>
commentGenerator>
不知道大家有没有注意到com.example.mybatisgenerator.CommentGenerator是我自定义的注释实现类,这里为什么要自定义呢?
/**
* Database Column Remarks:
* 自增ID
*
* This field was generated by MyBatis Generator.
* This field corresponds to the database column student.id
*
* @mbg.generated
*/
private Long id;
/**
* Database Column Remarks:
* 名称
*
* This field was generated by MyBatis Generator.
* This field corresponds to the database column student.name
*
* @mbg.generated
*/
private String name;
这是mybatis自带的注释格式,为了简洁一些,一般都会自定义一个注释的实现类
package com.example.mybatisgenerator;
import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.dom.java.Field;
import org.mybatis.generator.internal.DefaultCommentGenerator;
import org.mybatis.generator.internal.util.StringUtility;
import java.util.Properties;
public class CommentGenerator extends DefaultCommentGenerator {
private boolean addRemarkComments = false;
@Override
public void addConfigurationProperties(Properties props){
super.addConfigurationProperties(props);
this.addRemarkComments = StringUtility.isTrue(props.getProperty("addRemarkComments"));
}
@Override
public void addFieldComment(Field field, IntrospectedTable introspectedTable,
IntrospectedColumn introspectedColumn) {
String remarks = introspectedColumn.getRemarks();
if (addRemarkComments && StringUtility.stringHasValue(remarks)){
field.addJavaDocLine("/**");
String[] remarkLines = remarks.split(System.getProperty("line.separator"));
for (String remarkLine : remarkLines) {
field.addJavaDocLine(" * " + remarkLine);
}
field.addJavaDocLine(" */");
}
}
}
最后生成这样的注释
/**
* 自增ID
*/
private Long id;
/**
* 名称
*/
private String name;
/**
* 年龄
*/
private Integer age;
元素用于指定内省表所需的数据库连接的属性
属性 | 描述 |
---|---|
driverClass | 用于访问数据库的JDBC驱动程序的完全限定类名 |
connectionURL | 用于访问数据库的JDBC连接URL |
userId | 数据库账号 |
password | 数据库密码 |
配置例子:
<jdbcConnection
driverClass="${spring.datasource.driver-class-name}"
connectionURL="${spring.datasource.url}"
userId="${spring.datasource.username}"
password="${spring.datasource.password}">
jdbcConnection>
前面介绍了properties元素,主要是引入一些外部配置,我们可以通过${}的方式去访问变量
元素用于定义Java类型解析程序的属性,它有一个属性
属性 | 描述 |
---|---|
type | Java类型解析程序 |
它有一个子元素property,主要包含以下几个属性
属性 | 描述 |
---|---|
forceBigDecimals | 强制转换DECIMAL和NUMERIC字段为java.math.BigDecimal |
useJSR310Types | 强制使用DATE、TIME和TIMESTAMP字段的JSR-310数据类型,而不是使用java.util.DATE |
配置例子
<javaTypeResolver>
<property name="forceBigDecimals" value="true"/>
javaTypeResolver>
这个是生成实体类配置标签,它有两个必选属性
属性 | 描述 |
---|---|
targetPackage | 生成实体类存放的包路径 |
targetProject | 指定目标项目路径,可以是绝对路径或相对路径 |
它还包含了下面几个 property 子元素属性
属性 | 描述 |
---|---|
constructorBased | :该属性只对MyBatis3 有效,如果true 就会使用构造方法入参,如果false 就会使用setter 方式。默认为false |
enableSubPackages | 如果true ,MBG会根据catalog 和schema 来生成子包,默认是false |
immutable | 用来配置实体类属性是否可变,默认是false |
rootClass | 设置所有实体类的基类 |
trimStrings | 是否去掉返回数据的空白符 |
加粗的属性enableSubPackages和trimStrings是比较常用的配置
配置示例如下:
<javaModelGenerator targetPackage="com.example.mybatisgenerator.entity"
targetProject="src\main\java">
<property name="enableSubPackages" value="true" />
<property name="trimStrings" value="true"/>
javaModelGenerator>
元素用于定义SQL映射生成器的属性,它有两个必选属性
属性 | 描述 |
---|---|
targetPackage | xml存放的包路径 |
targetProject | 指定目标项目路径,可以是绝对路径或相对路径 |
property 子元素属性
属性 | 描述 |
---|---|
enableSubPackages | 如果true ,MBG会根据catalog 和schema 来生成子包,默认是false |
配置例子
<sqlMapGenerator
targetPackage="mapper"
targetProject="src\main\resources">
<property name="enableSubPackages" value="true" />
sqlMapGenerator>
元素用于定义Java客户端生成器的属性,其实就说持久层(DAO)接口,它包含三个属性
属性 | 描述 |
---|---|
type | 此属性用于选择预定义的Java客户端生成器之一,或指定用户提供的Java客户端生成程序 |
targetPackage | 生成实体类存放的包路径 |
targetProject | 指定目标项目路径,可以是绝对路径或相对路径 |
property 子元素属性
属性 | 描述 |
---|---|
enableSubPackages | 如果true ,MBG会根据catalog 和schema 来生成子包,默认是false |
dynamicSqlSupportPackage | 此属性仅适用于目标运行时MyBatis3DynamicSql或MyBatis3Kotlin |
配置例子
<javaClientGenerator type="XMLMAPPER"
targetPackage="com.example.mybatisgenerator.mapper"
targetProject="src\main\java">
<property name="enableSubPackages" value="true" />
javaClientGenerator>
元素用于为每个表生成实体类、sql映射文件(xml),持久层接口(DAO),这是非常重要的配置
属性 | 描述 |
---|---|
tableName | 必填属性,数据库表,如果需要,指定的值可以包含SQL通配符 |
schema | 数据库模式-如果数据库不使用模式,或者有默认模式,则不需要数据库模式。如果需要,指定的值可以包含SQL通配符。 |
catalog | 数据库目录-如果数据库不使用目录,或者有默认目录,则不需要该目录 |
alias | 别名,例如 select * from news as n,会为表加上别名。 注意目标运行时为“MyBatis3DynamicSql”或“MyBatis 3Kotlin”,则忽略此属性 |
domainObjectName | 实体类名称。比如表名是news,会生成News、NewsMapper等文件,如果设置该属性为NewsPO,那么会生成NewsPO、NewsPOMapper |
mapperName | Mapper的名称 注意目标运行时为“MyBatis3DynamicSql”或“MyBatis 3Kotlin”,则忽略此属性 |
sqlProviderName | sql映射文件(xml)的名称 注意目标运行时为“MyBatis3DynamicSql”或“MyBatis 3Kotlin”,则忽略此属性 |
enableInsert | 插入方法,默认值为true 注意目标运行时为“MyBatis3DynamicSql”或“MyBatis 3Kotlin”,则忽略此属性 |
enableSelectByPrimaryKey | 根据主键查询方法 ,默认值为true 注意目标运行时为“MyBatis3DynamicSql”或“MyBatis 3Kotlin”,则忽略此属性 |
enableSelectByExample | 根据条件查询方法 ,默认值为true 注意目标运行时为“MyBatis3DynamicSql”或“MyBatis 3Kotlin”,则忽略此属性 |
enableUpdateByPrimaryKey | 根据主键更新方法,默认值为true 注意目标运行时为“MyBatis3DynamicSql”或“MyBatis 3Kotlin”,则忽略此属性 |
enableDeleteByPrimaryKey | 根据主键删除方法,一般情况下都是软删除,因此一般不生成该方法 注意目标运行时为“MyBatis3DynamicSql”或“MyBatis 3Kotlin”,则忽略此属性 |
enableDeleteByExample | 根据条件删除方法,默认值为true 注意目标运行时为“MyBatis3DynamicSql”或“MyBatis 3Kotlin”,则忽略此属性 |
enableCountByExample | 根据条件查询总数方法,默认值为true 注意目标运行时为“MyBatis3DynamicSql”或“MyBatis 3Kotlin”,则忽略此属性 |
enableUpdateByExample | 根据条件更新方法,默认值为true 注意目标运行时为“MyBatis3DynamicSql”或“MyBatis 3Kotlin”,则忽略此属性 |
selectByPrimaryKeyQueryId | 此值将以以下形式添加到select by主键语句的select列表中:“''as QUERYID”。这对于在运行时识别DBA跟踪工具中的查询非常有用。如果您使用这样的值,您应该为MBG生成的每个不同的查询指定一个唯一的id。 注意目标运行时为“MyBatis3DynamicSql”或“MyBatis 3Kotlin”,则忽略此属性 |
selectByExampleQueryId | 此值将以以下形式添加到select by example语句的select列表中:“''as QUERYID”。这对于在运行时识别DBA跟踪工具中的查询非常有用。如果您使用这样的值,您应该为MBG生成的每个不同的查询指定一个唯一的id 注意目标运行时为“MyBatis3DynamicSql”或“MyBatis 3Kotlin”,则忽略此属性 |
modelType | 如果希望为此表覆盖默认模型类型,则使用此属性 |
escapeWildcards | 指示在搜索列时是否应转义架构和tableName中的SQL通配符(“_”和“%”)。如果架构或表名包含SQL通配符,则某些驱动程序需要这样做(例如,如果表名为MY_table,则某些驱动器要求转义下划线).默认值为false。 |
delimitIdentifiers | 指示MBG在搜索表时是否应使用指定的大小写,然后在生成的SQL中对标识符进行定界。默认值为false |
delimitAllColumns | 指示MBG是否应向生成的SQL中的所有列名添加分隔符。默认值为false |
它有下面几个属性
下面对generatedKey和columnOverride进行讲解
generatedKey
主键生成属性,默认情况下都是都是这样配置
<generatedKey column="id" sqlStatement="Mysql" identity="false" />
columnOverride
重新某些字段的值,这个比较有用,比如说数据表的TINYINT型字段默认对应的javaType是Byte,有时候我们需要转成Integer
下面是一个table的配置示例
<table tableName="student"
enableCountByExample="true"
enableUpdateByExample="true"
enableDeleteByExample="false"
enableSelectByExample="true"
selectByExampleQueryId="true"
enableSelectByPrimaryKey="true"
enableUpdateByPrimaryKey="true"
enableDeleteByPrimaryKey="false"
>
<generatedKey column="id" sqlStatement="Mysql" identity="false" />
<columnOverride column="deleted" javaType="Integer" jdbcType="TINYINT"/>
<columnOverride column="create_time" javaType="java.time.LocalDateTime" jdbcType="TIMESTAMP"/>
<columnOverride column="update_time" javaType="java.time.LocalDateTime" jdbcType="TIMESTAMP"/>
table>
1.引入依赖
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.28version>
dependency>
<dependency>
<groupId>com.zaxxergroupId>
<artifactId>HikariCPartifactId>
dependency>
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>2.2.0version>
dependency>
<dependency>
<groupId>org.mybatis.generatorgroupId>
<artifactId>mybatis-generator-coreartifactId>
<version>1.4.1version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
dependencies>
2.配置
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
spring.datasource.url=jdbc:mysql://localhost:3306/demo?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
3.mybatis生成器xml配置
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="application.properties"/>
<classPathEntry location="E:/apache-maven-3.8.5/repository/mysql/mysql-connector-java/8.0.18/mysql-connector-java-8.0.18.jar"/>
<context id="mysql_tables" targetRuntime="MyBatis3" defaultModelType="flat">
<property name="beginningDelimiter" value=""/>
<property name="endingDelimiter" value=""/>
<property name="javaFileEncode" value="UTF-8"/>
<plugin type="org.mybatis.generator.plugins.SerializablePlugin" />
<plugin type="org.mybatis.generator.plugins.EqualsHashCodePlugin">
<property name="useEqualsHashCodeFromRoot" value="true"/>
plugin>
<plugin type="org.mybatis.generator.plugins.ToStringPlugin">
<property name="useToStringFromRoot" value="true"/>
plugin>
<plugin type="org.mybatis.generator.plugins.UnmergeableXmlMappersPlugin" />
<commentGenerator type="com.example.mybatisgenerator.CommentGenerator">
<property name="addRemarkComments" value="true"/>
<property name="suppressAllComments" value="true"/>
<property name="suppressDate" value="true"/>
commentGenerator>
<jdbcConnection
driverClass="${spring.datasource.driver-class-name}"
connectionURL="${spring.datasource.url}"
userId="${spring.datasource.username}"
password="${spring.datasource.password}">
jdbcConnection>
<javaTypeResolver>
<property name="forceBigDecimals" value="true"/>
javaTypeResolver>
<javaModelGenerator targetPackage="com.example.mybatisgenerator.entity"
targetProject="src\main\java">
<property name="enableSubPackages" value="true" />
<property name="trimStrings" value="true"/>
javaModelGenerator>
<sqlMapGenerator
targetPackage="mapper"
targetProject="src\main\resources">
<property name="enableSubPackages" value="true" />
sqlMapGenerator>
<javaClientGenerator type="XMLMAPPER"
targetPackage="com.example.mybatisgenerator.mapper"
targetProject="src\main\java">
<property name="enableSubPackages" value="true" />
javaClientGenerator>
<table tableName="student"
enableCountByExample="true"
enableUpdateByExample="true"
enableDeleteByExample="false"
enableSelectByExample="true"
selectByExampleQueryId="true"
enableSelectByPrimaryKey="true"
enableUpdateByPrimaryKey="true"
enableDeleteByPrimaryKey="false"
>
<generatedKey column="id" sqlStatement="Mysql" identity="false" />
<columnOverride column="deleted" javaType="Integer" jdbcType="TINYINT"/>
<columnOverride column="create_time" javaType="java.time.LocalDateTime" jdbcType="TIMESTAMP"/>
<columnOverride column="update_time" javaType="java.time.LocalDateTime" jdbcType="TIMESTAMP"/>
table>
context>
generatorConfiguration>
com.example.mybatisgenerator.CommentGenerator自定义注释的实现类代码上面有
4.启动
在测试类里面写一个方法
@Test
void generate() throws XMLParserException, IOException, InvalidConfigurationException, SQLException, InterruptedException {
List<String> warnings = new ArrayList<>();
InputStream in = MyBatisGenerator.class.getClassLoader().getResourceAsStream("mybatisGeneratorConfig.xml");
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(in);
assert in != null;
in.close();
// 覆盖 Java 文件
boolean overwrite = true;
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
// 生成文件
myBatisGenerator.generate(null);
// 打印信息
warnings.forEach(System.err::println);
}