Mybatis Generator 最佳实践

前言

实际开发之中,虽然有很多 CRUD 工具,但是使用最多的还是 Mybatis,而Mybatis Gerator可以帮助你自动生成基本的单表 CRUD 代码,提高效率

但是生成的代码有些地方已经不符合当前的风格和标准,比如现在很多项目都是使用lombok,而不是在实体类里面添加 get/set 方法,默认生成的注释信息不友好,这个时候我们可以通过一些修改来生成我们想要的结果

本项目为SpringBoot项目,数据为MySQL

使用

引入依赖

后边的 Plugn 是以 Maven 生成的,若以代码形式来生成则无需配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<!--mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis.generator/mybatis-generator-core -->
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.7</version>
</dependency>

<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.7</version>
<configuration>
<!--自定义路径,否则会自动识别GeneratorConfig.xml文件-->
<!-- <configurationFiile>${basedir}/src/main/resources/generatorConfig.xml</configurationFile>-->
<!--是为了运行mvn mybatis-generator:generate -e时显示具体过程-->
<verbose>true</verbose>
<!--为了生成文件时后一次生成的文件覆盖前一次生成的同名文件-->
<overwrite>true</overwrite>
</configuration>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.44</version>
</dependency>
</dependencies>
</plugin>

后边的 Plugn 是以 Maven 生成需要配置的,若以代码形式来生成则无需配置
我的存放目录如下
1.png

添加自定义插件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
package com.bwensun.common.mybatis;

import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;
import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;
import org.mybatis.generator.api.dom.java.Interface;
import org.mybatis.generator.api.dom.java.Method;
import org.mybatis.generator.api.dom.java.TopLevelClass;

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

/**
* lombok插件
*
* @author bwensun
* @date 2019/12/16
*/
public class LombokPlugin extends PluginAdapter {

@Override
public boolean validate(List<String> warnings) {
return true;
}

@Override
public boolean clientGenerated(Interface interfaze, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
SimpleDateFormat dateFormatter = new SimpleDateFormat(properties.getProperty("dateFormat", "yyyy-MM-dd"));
//接口添加注释
interfaze.addJavaDocLine("/**");
interfaze.addJavaDocLine(" * " + introspectedTable.getRemarks());
interfaze.addJavaDocLine(" *");
interfaze.addJavaDocLine(" * @author " + properties.getProperty("author"));
interfaze.addJavaDocLine(" * @date " + dateFormatter.format(new Date()));
interfaze.addJavaDocLine(" */");
//dao添加注解
addAnnotations(interfaze, "org.springframework.stereotype.Repository", "@Repository");


return true;
}

@Override
public boolean modelBaseRecordClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
if (Boolean.parseBoolean(this.properties.getProperty("data"))) {
addAnnotations(topLevelClass, "lombok.Data", "@Data");
} else {
addAnnotations(topLevelClass, "lombok.Getter", "@Getter");
addAnnotations(topLevelClass, "lombok.Setter", "@Setter");
addAnnotations(topLevelClass, "lombok.ToString", "@ToString");
}
if (Boolean.parseBoolean(this.properties.getProperty("builder"))) {
addAnnotations(topLevelClass, "lombok.Builder", "@Builder");
}
return true;
}

/**
* 关闭get方法生成
*/
@Override
public boolean modelGetterMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedColumn introspectedColumn, IntrospectedTable introspectedTable, ModelClassType modelClassType) {
return false;
}

/**
* 关闭set方法生成
*/
@Override
public boolean modelSetterMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedColumn introspectedColumn, IntrospectedTable introspectedTable, ModelClassType modelClassType) {
return false;
}

public void addSwaggerAnnotation(){

}


/**
* 设置类注解
*
* @param importedType 导包类型
* @param annotation 注解
*/
private void addAnnotations(TopLevelClass topLevelClass, String importedType, String annotation) {
topLevelClass.addImportedType(importedType);
topLevelClass.addAnnotation(annotation);
}

/**
* 设置接口注解
*
* @param importedType 导包类型
* @param annotation 注解
*/
private void addAnnotations(Interface interfaze, String importedType, String annotation) {
interfaze.addImportedType(new FullyQualifiedJavaType(importedType));
interfaze.addAnnotation(annotation);
}

private String date2Str(Date date) {
SimpleDateFormat format = new SimpleDateFormat("yyyy/MM/dd");
return format.format(date);
}
}

说明
Mybatis Generator 的配置文件中包含了 plugn 标签,我们就可以通过手写插件来实现我们自己的功能,

重写注释部分注释方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
package com.bwensun.common.mybatis;

import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.dom.java.*;

import org.mybatis.generator.internal.DefaultCommentGenerator;
import org.mybatis.generator.internal.util.StringUtility;

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

/**
* 增加 swagger 字段注释支持
*
* @author daiwenzh5
* @date 2019/9/8 18:56
*/
public class CustomCommentGenerator extends DefaultCommentGenerator {

private Properties properties;

public CustomCommentGenerator() {
properties = new Properties();
}

@Override
public void addConfigurationProperties(Properties properties) {
// 获取自定义的 properties
this.properties.putAll(properties);
}

/**
* 添加 swagger 字段注解
*
* @param field 字段
* @param introspectedTable 表
* @param introspectedColumn 列
* @param imports 导入类
*/
@Override
public void addFieldAnnotation(Field field, IntrospectedTable introspectedTable, IntrospectedColumn introspectedColumn, Set<FullyQualifiedJavaType> imports) {
imports.add(new FullyQualifiedJavaType("io.swagger.annotations.ApiModelProperty"));
String remarks = introspectedColumn.getRemarks();
field.addAnnotation(this.getSwaggerAnnotation(field.getName(), remarks));
super.addFieldAnnotation(field, introspectedTable, introspectedColumn, imports);
}

@Override
public void addFieldAnnotation(Field field, IntrospectedTable introspectedTable, Set<FullyQualifiedJavaType> set) {
super.addFieldAnnotation(field, introspectedTable, set);
}

@Override
public void addFieldComment(Field field, IntrospectedTable introspectedTable, IntrospectedColumn introspectedColumn) {
// 获取字段注释
String remarks = introspectedColumn.getRemarks();
field.addJavaDocLine("/**");
field.addJavaDocLine(" * " + remarks);
field.addJavaDocLine(" */");
}

@Override
public void addGeneralMethodComment(Method method, IntrospectedTable introspectedTable) {
/* if (suppressAllComments) {
return;
}*/
String methodDoc = getMethodDoc(method, introspectedTable);
method.addJavaDocLine("/**");
method.addJavaDocLine(" * " + methodDoc);
method.addJavaDocLine(" *");
setMethodParam(method);
setMethodReturn(method, introspectedTable);
method.addJavaDocLine(" */");
}

@Override
public void addClassAnnotation(InnerClass innerClass, IntrospectedTable introspectedTable, Set<FullyQualifiedJavaType> set) {
super.addClassAnnotation(innerClass, introspectedTable, set);
}

@Override
public void addModelClassComment(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
String author = properties.getProperty("author");
String dateFormat = properties.getProperty("dateFormat", "yyyy-MM-dd");
SimpleDateFormat dateFormatter = new SimpleDateFormat(dateFormat);

// 获取表注释
String remarks = introspectedTable.getRemarks();

topLevelClass.addJavaDocLine("/**");
topLevelClass.addJavaDocLine(" * " + remarks);
topLevelClass.addJavaDocLine(" *");
topLevelClass.addJavaDocLine(" * @author " + author);
topLevelClass.addJavaDocLine(" * @date " + dateFormatter.format(new Date()));
topLevelClass.addJavaDocLine(" */");
}

/**
* 获取 swagger 注解信息
*
* @param name 字段名
* @param remarks 注释信息
* @return 返回 swagger 注释字符串
*/
private String getSwaggerAnnotation(String name, String remarks) {
StringBuffer buffer = new StringBuffer("@ApiModelProperty(");
buffer.append("name = \"");
buffer.append(name);
if (StringUtility.stringHasValue(remarks)) {
buffer.append("\", value = \"");
buffer.append(remarks);
}
buffer.append("\")");
return buffer.toString();
}

private String getMethodDoc(Method method, IntrospectedTable introspectedTable) {
String remarks = introspectedTable.getRemarks();
String methodDoc;
switch (method.getName()){
case "deleteByPrimaryKey":
methodDoc = ("根据主键删除" + remarks + "记录");
break;
case "selectByPrimaryKey":
methodDoc = ("根据主键查询" + remarks + "记录");
break;
case "insert":
methodDoc = ("新增记录至" + remarks);
break;
case "selectAll":
methodDoc = ("查询" + remarks + "所有记录");
break;
case "updateByPrimaryKey":
methodDoc = ("根据主键更新" + remarks + "记录");
break;
default:
methodDoc = "description";
break;
}
return methodDoc;
}

/**
* 设置参数注释
*
* @param method 方法
*/
private void setMethodParam(Method method) {
List<Parameter> parameters = method.getParameters();
if (parameters.size() != 0){
parameters.forEach(x ->
method.addJavaDocLine(" * @param " + x.getName() + ("ID".equalsIgnoreCase(x.getName())?" 主键":" 记录") )
);
}
}

/**
* 设置返回值注释
*
* @param method 方法
* @param introspectedTable 表对象
*/
private void setMethodReturn(Method method, IntrospectedTable introspectedTable) {
String methodReturn;
String shortName = method.getReturnType().getShortName();
if ("int".equalsIgnoreCase(shortName)){
methodReturn = "受影响的记录数";
}else if (shortName.startsWith("java.util.List")){
methodReturn = introspectedTable.getRemarks() + "list";
}else {
methodReturn = introspectedTable.getRemarks() + "记录";
}
method.addJavaDocLine(" * @return " + methodReturn);
}

}

配置文件配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
<?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>
<!-- 数据库驱动:选择你的本地硬盘上面的数据库驱动包-->
<classPathEntry location="D:\ProgramFile\maven\maven_repository\mysql\mysql-connector-java\5.1.44\mysql-connector-java-5.1.44.jar"/>
<context id="CustomGenerator" defaultModelType="hierarchical" targetRuntime="MyBatis3Simple">
<property name="autoDelimitKeywords" value="false"/>

<plugin type="org.mybatis.generator.plugins.SerializablePlugin"/>
<!-- 插件 -->
<plugin type="com.bwensun.common.mybatis.LombokPlugin">
<property name="author" value="bwensun"/>
<property name="builder" value="false"/>
<property name="data" value="false"/>
</plugin>

<commentGenerator type = "com.bwensun.common.mybatis.CustomCommentGenerator">
<property name="javaFileEncoding" value="UTF-8"/>
<property name="suppressDate" value="true" />
<property name="suppressAllComments" value="false" />
<property name="author" value="郑建雄"/>
<property name="dateFormat" value="yyyy/MM/dd"/>
</commentGenerator>
<!--数据库链接URL,用户名、密码 -->
<jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://127.0.0.1:3306/blog?useSSL=true"
userId="root" password="285413">
<property name="useInformationSchema" value="true" />

</jdbcConnection>
<javaTypeResolver>
<property name="forceBigDecimals" value="false"/>
</javaTypeResolver>
<!-- 生成模型的包名和位置-->
<javaModelGenerator targetPackage="com.bwensun.blog.domain" targetProject="BLOG_API/src/main/java">
<!-- 是否允许子包,即targetPackage.schemaName.tableName -->
<property name="enableSubPackages" value="true"/>
<!-- 是否对model添加 构造函数 -->
<property name="constructorBased" value="false"/>
<!-- 是否对类CHAR类型的列的数据进行trim操作 -->
<property name="trimStrings" value="true"/>
<!-- 建立的Model对象是否 不可改变 即生成的Model对象不会有 setter方法,只有构造方法 -->
<!--<property name="immutable" value="false"/>-->
</javaModelGenerator>
<!-- 生成映射文件的包名和位置-->
<sqlMapGenerator targetPackage="mapper" targetProject="BLOG_USER_SERVICE/src/main/resources">
<property name="enableSubPackages" value="false"/>
</sqlMapGenerator>
<!-- 生成DAO的包名和位置-->
<javaClientGenerator type="XMLMAPPER" targetPackage="com.bwensun.repository"
targetProject="BLOG_USER_SERVICE/src/main/java">
<property name="enableSubPackages" value="false"/>
</javaClientGenerator>
<!-->要生成的表 tableName是数据库中的表名或视图名 domainObjectName是实体类名<-->
<table tableName="USER" domainObjectName="User" enableCountByExample="false" enableUpdateByExample="false"
enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false">

</table>
</context>
</generatorConfiguration>

执行生成代码

1
2
3
4
5
6
7
8
9
10
11
/**
* @author bwensun
* @date 2019/12/17
*/
public class MybatisGenerator {
public static void main(String[] args) {
String path = "D:\\ProgramFile\\idea_workspace\\DUBBO_TEST\\BLOG\\BLOG_USER_SERVICE\\src\\main\\resources\\generatorConfig.xml";
args = new String[]{"-configfile", path, "-overwrite"};
ShellRunner.main(args);
}
}
作者

孙博文

发布于

2019-12-18

更新于

2021-07-18

许可协议

评论