代码演示Mybatis-Generator 扩展自定义生成

Mybatis-Generator 可自动生成Model、Dao、Mapper代码,但其自带生成的代码存在以下问题:

  • 生成的注释不是我们想要的,我们期望的是根据数据库表、字段生成不同的注释;
  • 分页代码生成缺失,每个公司的分页方式不同,尤其是老久项目或已发布API,不能随意变动,那么如何自适应分页代码生成;
  • Mapper.xml没有group by相关代码生成;
  • 重复生成代码时,Mapper.xml并不是覆盖原代码,而是对内容进行了追加;
  • 序列化,mybatis-generator内置了SerializablePlugin,但仅对Model,并没有对 Example序列化,在一些开发中是不够的;
  • 对Service Layer代码没有生成。

实际上,mybatis-generator提供了PluginAdapter供我们来继承,进行个性化的一些扩展(Plugin的相关内容是阅读本文的前置条件)如果不熟悉的同学,请自行补充,本文不对其进行相关介绍)。同时,本文不可能涵盖所有业务所需的扩展点,但是基本样板已有,可参考本文代码继续进行扩展。

一、注释的自定义生成

根据数据库表或字段的COMMENT生成注释。@Date 生成的时间可根据需要自己定义格式。

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
182
183
184
185
186
187
188
189
190
191
192
193
194
复制代码package run.override;
import java.util.Date;
import java.util.Properties;

import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.dom.java.CompilationUnit;
import org.mybatis.generator.api.dom.java.Field;
import org.mybatis.generator.api.dom.java.InnerClass;
import org.mybatis.generator.api.dom.java.InnerEnum;
import org.mybatis.generator.api.dom.java.JavaElement;
import org.mybatis.generator.api.dom.java.Method;
import org.mybatis.generator.api.dom.java.Parameter;
import org.mybatis.generator.api.dom.xml.XmlElement;
import org.mybatis.generator.internal.DefaultCommentGenerator;
import org.mybatis.generator.internal.util.StringUtility;
/**
* Comment Generator
* @ClassName CommentGenerator
* @Description
* @author Marvis
*/
public class CommentGenerator extends DefaultCommentGenerator {
private Properties properties;
private boolean suppressDate;
private boolean suppressAllComments;

public CommentGenerator() {
this.properties = new Properties();
this.suppressDate = false;
this.suppressAllComments = false;
}

public void addJavaFileComment(CompilationUnit compilationUnit) {

compilationUnit.addFileCommentLine("/*** copyright (c) 2019 Marvis ***/");
}
/**
* XML file Comment
*/
public void addComment(XmlElement xmlElement) {
if (this.suppressAllComments) {
return;
}

}

public void addRootComment(XmlElement rootElement) {
}

public void addConfigurationProperties(Properties properties) {
this.properties.putAll(properties);

this.suppressDate = StringUtility.isTrue(properties.getProperty("suppressDate"));

this.suppressAllComments = StringUtility.isTrue(properties.getProperty("suppressAllComments"));
}

protected void addJavadocTag(JavaElement javaElement, boolean markAsDoNotDelete) {
StringBuilder sb = new StringBuilder();
sb.append(" * ");
sb.append("@date");
String s = getDateString();
if (s != null) {
sb.append(' ');
sb.append(s);
}
javaElement.addJavaDocLine(sb.toString());
}

protected String getDateString() {
if (this.suppressDate) {
return null;
}
return new Date().toString();
}
/**
* Comment of Example inner class(GeneratedCriteria ,Criterion)
*/
public void addClassComment(InnerClass innerClass, IntrospectedTable introspectedTable) {
if (this.suppressAllComments) {
return;
}

innerClass.addJavaDocLine("/**");
innerClass.addJavaDocLine(" * " + introspectedTable.getFullyQualifiedTable().getDomainObjectName()+ "<p/>");
innerClass.addJavaDocLine(" * " + introspectedTable.getFullyQualifiedTable().toString());
addJavadocTag(innerClass, false);
innerClass.addJavaDocLine(" */");
}

public void addEnumComment(InnerEnum innerEnum, IntrospectedTable introspectedTable) {
if (this.suppressAllComments) {
return;
}

StringBuilder sb = new StringBuilder();

innerEnum.addJavaDocLine("/**");
innerEnum.addJavaDocLine(" * " + introspectedTable.getFullyQualifiedTable().getAlias()+ "<p/>");
innerEnum.addJavaDocLine(" * " + introspectedTable.getFullyQualifiedTable());
innerEnum.addJavaDocLine(sb.toString());

addJavadocTag(innerEnum, false);

innerEnum.addJavaDocLine(" */");
}
/**
* entity filed Comment
*/
public void addFieldComment(Field field, IntrospectedTable introspectedTable,
IntrospectedColumn introspectedColumn) {
if (this.suppressAllComments) {
return;
}

// if(introspectedColumn.getRemarks() != null && !introspectedColumn.getRemarks().trim().equals(""))

field.addJavaDocLine("/**");
field.addJavaDocLine(" * " + introspectedColumn.getRemarks());
field.addJavaDocLine(" * @author " );
field.addJavaDocLine(" * @date " + getDateString() );
field.addJavaDocLine(" * @return");
field.addJavaDocLine(" */");
}
/**
* Comment of EXample filed
*/
public void addFieldComment(Field field, IntrospectedTable introspectedTable) {
if (this.suppressAllComments) {
return;
}
field.addJavaDocLine("/**");
addJavadocTag(field, false);
field.addJavaDocLine(" */");
}
/**
* Comment of Example method
*/
public void addGeneralMethodComment(Method method, IntrospectedTable introspectedTable) {
if (this.suppressAllComments) {
return;
}
}
/**
*
* entity Getter Comment
*/
public void addGetterComment(Method method, IntrospectedTable introspectedTable,
IntrospectedColumn introspectedColumn) {
if (this.suppressAllComments) {
return;
}
method.addJavaDocLine("/**");


method.addJavaDocLine(" * @return " + introspectedTable.getFullyQualifiedTable().getAlias() + " : " + introspectedColumn.getRemarks());
method.addJavaDocLine(" */");
}

public void addSetterComment(Method method, IntrospectedTable introspectedTable,
IntrospectedColumn introspectedColumn) {
if (this.suppressAllComments) {
return;
}

StringBuilder sb = new StringBuilder();

method.addJavaDocLine("/**");

Parameter parm = (Parameter) method.getParameters().get(0);
sb.append(" * @param ");
sb.append(parm.getName());
sb.append(" : ");
sb.append(introspectedColumn.getRemarks());
method.addJavaDocLine(sb.toString());
method.addJavaDocLine(" */");
}

/**
* Comment of Example inner class(Criteria)
*/
public void addClassComment(InnerClass innerClass, IntrospectedTable introspectedTable, boolean markAsDoNotDelete) {
if (this.suppressAllComments) {
return;
}

innerClass.addJavaDocLine("/**");
innerClass.addJavaDocLine(" * " + introspectedTable.getFullyQualifiedTable().getAlias()+ "<p/>");
innerClass.addJavaDocLine(" * " + introspectedTable.getFullyQualifiedTable().toString());
addJavadocTag(innerClass, markAsDoNotDelete);

innerClass.addJavaDocLine(" */");
}

Model 类注释(表的描述): MySQL。

1)EntityCommentPlugin

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
复制代码package run.override.model;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Date;
import java.util.List;

import org.mybatis.generator.api.FullyQualifiedTable;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;
import org.mybatis.generator.api.dom.java.TopLevelClass;
import org.mybatis.generator.internal.JDBCConnectionFactory;
import org.mybatis.generator.internal.util.StringUtility;

/**
* Comment of Entity,only support MySQL
* @ClassName CommentPlugin
* @Description
* @author Marvis
*/
public class EntityCommentPlugin extends PluginAdapter {

@Override
public boolean modelBaseRecordClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
addModelClassComment(topLevelClass, introspectedTable);
return super.modelBaseRecordClassGenerated(topLevelClass, introspectedTable);
}

@Override
public boolean modelRecordWithBLOBsClassGenerated(TopLevelClass topLevelClass,
IntrospectedTable introspectedTable) {

addModelClassComment(topLevelClass, introspectedTable);
return super.modelRecordWithBLOBsClassGenerated(topLevelClass, introspectedTable);
}

protected void addModelClassComment(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {

FullyQualifiedTable table = introspectedTable.getFullyQualifiedTable();
String tableComment = getTableComment(table);

topLevelClass.addJavaDocLine("/**");
if(StringUtility.stringHasValue(tableComment))
topLevelClass.addJavaDocLine(" * " + tableComment + "<p/>");
topLevelClass.addJavaDocLine(" * " + table.toString() + "<p/>");
topLevelClass.addJavaDocLine(" * @date " + new Date().toString());
topLevelClass.addJavaDocLine(" *");
topLevelClass.addJavaDocLine(" */");
}

/**
* @author Marvis
* @date Jul 13, 2017 4:39:52 PM
* @param table
*/
private String getTableComment(FullyQualifiedTable table) {
String tableComment = "";
Connection connection = null;
Statement statement = null;
ResultSet rs = null;
try {
JDBCConnectionFactory jdbc = new JDBCConnectionFactory(context.getJdbcConnectionConfiguration());
connection = jdbc.getConnection();
statement = connection.createStatement();
rs = statement.executeQuery("SHOW CREATE TABLE " + table.getIntrospectedTableName());

if (rs != null && rs.next()) {
String createDDL = rs.getString(2);
int index = createDDL.indexOf("COMMENT='");
if (index < 0) {
tableComment = "";
} else {
tableComment = createDDL.substring(index + 9);
tableComment = tableComment.substring(0, tableComment.length() - 1);
}
}

} catch (SQLException e) {

} finally {
closeConnection(connection, statement, rs);
}
return tableComment;
}
/**
*
* @author Marvis
* @date Jul 13, 2017 4:45:26 PM
* @param connection
* @param statement
* @param rs
*/
private void closeConnection(Connection connection, Statement statement, ResultSet rs) {
try {
if (null != rs)
rs.close();
} catch (SQLException e) {

e.printStackTrace();
} finally {
try {
if (statement != null)
statement.close();
} catch (Exception e) {
e.printStackTrace();

} finally {

try {
if (connection != null)
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
/**
* This plugin is always valid - no properties are required
*/
@Override
public boolean validate(List<String> warnings) {
return true;
}
}

二、分页和分组代码生成

这里,我对Dao Model进行了通用方法的抽取,建立通用基类。同时,对其进行了一些扩展,增加分页和分组。

先对基类进行介绍。

1)BaseMapper

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
复制代码package cn.xxx.core.base.dao;

import java.util.List;

import org.apache.ibatis.annotations.Param;

public interface BaseMapper<T, Example, ID> {

long countByExample(Example example);

int deleteByExample(Example example);

int deleteByPrimaryKey(ID id);

int insert(T record);

int insertSelective(T record);

List<T> selectByExample(Example example);

T selectByPrimaryKey(ID id);

int updateByExampleSelective(@Param("record") T record, @Param("example") Example example);

int updateByExample(@Param("record") T record, @Param("example") Example example);

int updateByPrimaryKeySelective(T record);

int updateByPrimaryKey(T record);

}

2)BaseExample

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
复制代码package cn.xxx.core.base.model;
/**
* BaseExample 基类
* @ClassName BaseExample
* @Description 增加分页参数
* @author Marvis
* @date Jul 31, 2017 11:26:53 AM
*/
public abstract class BaseExample {

protected PageInfo pageInfo;
protected String groupByClause;

public PageInfo getPageInfo() {
return pageInfo;
}

public void setPageInfo(PageInfo pageInfo) {
this.pageInfo = pageInfo;
}

public String getGroupByClause() {
return groupByClause;
}

public void setGroupByClause(String groupByClause) {
this.groupByClause = groupByClause;
}

}

3)PageInfo

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
复制代码package cn.xxx.core.base.model;

import com.fasterxml.jackson.annotation.JsonIgnore;

/**
* 分页查询参数类
*
* @author
*
*/
public class PageInfo {

public static final int Default_PageSize = 20;

// 当前页码
protected int currentPage = 1;

// 总页数
protected int totalPage;

// 总记录数
protected int totalCount;

// 每页条数
protected int pageSize = Default_PageSize;

// 开始
protected int pageBegin = 0;

// 结束
protected int pageEnd = 20;

/**
* bean起始坐标(不包含)
*/
private Integer pageBeginId = null;

public static final String PageQuery_classname = "pageInfo";

/**
* 将分布参数传入处理,最终计算出当前页码PageQuery_currPage,开始坐标PageQuery_star,
* 结束坐标PageQuery_end,总页数PageQuery_Psize
* <p/>
* 页数从1开始计数
*
* @param totalCount
* 记录总数
* @param pageSize
* 每页显示个数
* @param currentPage
* 当前页码
*/
public void setPageParams(int totalCount, int pageSize, int currentPage) {

this.totalPage = pageSize == 0 ? 1 : (int) Math.ceil((double) totalCount / (double) pageSize);

this.totalCount = totalCount;
this.pageSize = pageSize;
this.currentPage = currentPage;

float Psize_l = totalCount / (float) (this.pageSize);
if (currentPage < 2) {
currentPage = 1;
pageBegin = 0;
} else if (currentPage > Psize_l) {
if (Psize_l == 0) {
currentPage = 1;
} else {
currentPage = (int) Math.ceil(Psize_l);
}

pageBegin = (currentPage - 1) * this.pageSize;
} else {
pageBegin = (currentPage - 1) * this.pageSize;
}
pageSize = (int) Math.ceil(Psize_l);
this.pageEnd = currentPage * this.pageSize;

if (this.currentPage <= 0 || this.currentPage > this.totalPage)
this.pageSize = 0;
}

/**
* 将分布参数传入处理,最终计算出当前页码PageQuery_currPage,开始坐标PageQuery_star,
* 结束坐标PageQuery_end,总页数PageQuery_Psize
*
* @param infoCount
* 记录总数
*/
public void setPageParams(int totalCount) {
this.setPageParams(totalCount, this.pageSize, this.currentPage);
}

@Override
public String toString() {
return "PageInfo [currentPage=" + currentPage + ", totalPage=" + totalPage + ", totalCount=" + totalCount
+ ", pageSize=" + pageSize + ", pageBegin=" + pageBegin + ", pageEnd=" + pageEnd + ", pageBeginId="
+ pageBeginId + "]";
}

public int getCurrentPage() {
return currentPage;
}

public int getTotalPage() {
return totalPage;
}

public int getTotalCount() {
return totalCount;
}

/**
* 每页显示个数
*/
public int getPageSize() {
return pageSize;
}

@JsonIgnore
public int getPageBegin() {
return pageBegin;
}

@JsonIgnore
public int getPageEnd() {
return pageEnd;
}

/**
* bean起始id(不包含)
*/
@JsonIgnore
public Integer getPageBeginId() {
return pageBeginId;
}

/**
* 请求页
*/
public void setCurrentPage(int currentPage) {
this.currentPage = currentPage;
}

/**
* 每页显示个数
*/
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
}

4)PaginationPlugin

分页扩展。并且Example继承BaseExample

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
复制代码package run.override.pagination;

import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;
import org.mybatis.generator.api.dom.java.TopLevelClass;
import org.mybatis.generator.api.dom.xml.Attribute;
import org.mybatis.generator.api.dom.xml.TextElement;
import org.mybatis.generator.api.dom.xml.XmlElement;

import run.override.mapper.SqlMapIsMergeablePlugin;
import run.override.proxyFactory.FullyQualifiedJavaTypeProxyFactory;

public class PaginationPlugin extends SqlMapIsMergeablePlugin {
@Override
public boolean modelExampleClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {

FullyQualifiedJavaType baseExampleType = FullyQualifiedJavaTypeProxyFactory.getBaseExampleInstance();
topLevelClass.setSuperClass(baseExampleType);

topLevelClass.addImportedType(baseExampleType);
return super.modelExampleClassGenerated(topLevelClass, introspectedTable);
}

@Override
public boolean sqlMapSelectByExampleWithBLOBsElementGenerated(XmlElement element,
IntrospectedTable introspectedTable) {

XmlElement isNotNullElement1 = new XmlElement("if");
isNotNullElement1.addAttribute(new Attribute("test", "groupByClause != null"));
isNotNullElement1.addElement(new TextElement("group by ${groupByClause}"));
element.addElement(5, isNotNullElement1);
XmlElement isNotNullElement = new XmlElement("if");
isNotNullElement.addAttribute(new Attribute("test", "pageInfo != null"));
isNotNullElement.addElement(new TextElement("limit #{pageInfo.pageBegin} , #{pageInfo.pageSize}"));
element.addElement(isNotNullElement);

return super.sqlMapUpdateByExampleWithBLOBsElementGenerated(element, introspectedTable);
}

@Override
public boolean sqlMapSelectByExampleWithoutBLOBsElementGenerated(XmlElement element,
IntrospectedTable introspectedTable) {

XmlElement isNotNullElement1 = new XmlElement("if");
isNotNullElement1.addAttribute(new Attribute("test", "groupByClause != null"));
isNotNullElement1.addElement(new TextElement("group by ${groupByClause}"));
element.addElement(5, isNotNullElement1);

XmlElement isNotNullElement = new XmlElement("if");
isNotNullElement.addAttribute(new Attribute("test", "pageInfo != null"));
isNotNullElement.addElement(new TextElement("limit #{pageInfo.pageBegin} , #{pageInfo.pageSize}"));
element.addElement(isNotNullElement);

return super.sqlMapUpdateByExampleWithoutBLOBsElementGenerated(element, introspectedTable);
}

@Override
public boolean sqlMapCountByExampleElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {

XmlElement answer = new XmlElement("select");

String fqjt = introspectedTable.getExampleType();

answer.addAttribute(new Attribute("id", introspectedTable.getCountByExampleStatementId()));
answer.addAttribute(new Attribute("parameterType", fqjt));
answer.addAttribute(new Attribute("resultType", "java.lang.Integer"));

this.context.getCommentGenerator().addComment(answer);

StringBuilder sb = new StringBuilder();
sb.append("select count(1) from ");
sb.append(introspectedTable.getAliasedFullyQualifiedTableNameAtRuntime());

XmlElement ifElement = new XmlElement("if");
ifElement.addAttribute(new Attribute("test", "_parameter != null"));
XmlElement includeElement = new XmlElement("include");
includeElement.addAttribute(new Attribute("refid", introspectedTable.getExampleWhereClauseId()));
ifElement.addElement(includeElement);

element.getElements().clear();
element.getElements().add(new TextElement(sb.toString()));
element.getElements().add(ifElement);
return super.sqlMapUpdateByExampleWithoutBLOBsElementGenerated(element, introspectedTable);
}
}

5)FullyQualifiedJavaTypeProxyFactory

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
复制代码package run.override.proxyFactory;
import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;

public class FullyQualifiedJavaTypeProxyFactory extends FullyQualifiedJavaType{

private static FullyQualifiedJavaType pageInfoInstance = new FullyQualifiedJavaType("cn.xxx.core.base.model.PageInfo");
private static FullyQualifiedJavaType baseExampleInstance = new FullyQualifiedJavaType("cn.xxx.core.base.model.BaseExample");
private static FullyQualifiedJavaType baseMapperInstance = new FullyQualifiedJavaType("cn.xxx.core.base.dao.BaseMapper");
private static FullyQualifiedJavaType baseServiceInstance = new FullyQualifiedJavaType("cn.xxx.core.base.service.BaseService");
private static FullyQualifiedJavaType baseServiceImplInstance = new FullyQualifiedJavaType("cn.xxx.core.base.service.impl.BaseServiceImpl");

public FullyQualifiedJavaTypeProxyFactory(String fullTypeSpecification) {
super(fullTypeSpecification);
}

public static final FullyQualifiedJavaType getPageInfoInstanceInstance() {

return pageInfoInstance;
}
public static final FullyQualifiedJavaType getBaseExampleInstance() {

return baseExampleInstance;
}

public static final FullyQualifiedJavaType getBaseMapperInstance() {

return baseMapperInstance;
}
public static final FullyQualifiedJavaType getBaseServiceInstance() {

return baseServiceInstance;
}
public static final FullyQualifiedJavaType getBaseServiceImplInstance() {

return baseServiceImplInstance;
}
}

三、Dao 生成代码简化

1)ClientDaoPlugin

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
复制代码package run.override.dao;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.JavaTypeResolver;
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 org.mybatis.generator.internal.types.JavaTypeResolverDefaultImpl;

import run.override.model.EntityCommentPlugin;
import run.override.proxyFactory.FullyQualifiedJavaTypeProxyFactory;

/**
* javaClient("XMLMAPPER") extended
*
* @ClassName ClientDaoPlugin
* @Description Mapper.java
* @author Marvis
*/
public class ClientDaoPlugin extends EntityCommentPlugin {

@Override
public boolean clientGenerated(Interface interfaze, TopLevelClass topLevelClass,
IntrospectedTable introspectedTable) {

JavaTypeResolver javaTypeResolver = new JavaTypeResolverDefaultImpl();
FullyQualifiedJavaType calculateJavaType = javaTypeResolver
.calculateJavaType(introspectedTable.getPrimaryKeyColumns().get(0));

FullyQualifiedJavaType superInterfaceType = new FullyQualifiedJavaType(
new StringBuilder("BaseMapper<")
.append(introspectedTable.getBaseRecordType())
.append(",")
.append(introspectedTable.getExampleType())
.append(",")
.append(calculateJavaType.getShortName())
.append(">")
.toString()
);
FullyQualifiedJavaType baseMapperInstance = FullyQualifiedJavaTypeProxyFactory.getBaseMapperInstance();

interfaze.addSuperInterface(superInterfaceType);
interfaze.addImportedType(baseMapperInstance);

List<Method> changeMethods = interfaze.getMethods().stream()
.filter(method -> method.getName().endsWith("WithBLOBs")
|| method.getReturnType().toString().endsWith("WithBLOBs")
|| Arrays.toString(method.getParameters().toArray()).contains("WithBLOBs"))
.collect(Collectors.toList());

interfaze.getMethods().retainAll(changeMethods);

if (changeMethods.isEmpty())
interfaze.getImportedTypes().removeIf(javaType -> javaType.getFullyQualifiedName().equals("java.util.List")
|| javaType.getFullyQualifiedName().equals("org.apache.ibatis.annotations.Param"));

return super.clientGenerated(interfaze, topLevelClass, introspectedTable);
}

}

四、修正

重复生成时Mapper.xml不是覆盖原代码,而是对内容进行了追加。

1)SqlMapIsMergeablePlugin

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
复制代码package run.override.mapper;

import org.mybatis.generator.api.GeneratedXmlFile;
import org.mybatis.generator.api.IntrospectedTable;
import run.override.dao.ClientDaoPlugin;

public class SqlMapIsMergeablePlugin extends ClientDaoPlugin {

@Override
public boolean sqlMapGenerated(GeneratedXmlFile sqlMap, IntrospectedTable introspectedTable) {
//重新生成代码,xml内容覆盖
sqlMap.setMergeable(false);
return super.sqlMapGenerated(sqlMap, introspectedTable);
}
}

五、序列化自定义扩展

增加Example的序列化,并增加@SuppressWarnings("serial")注解。

1)SerializablePlugin

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
复制代码package run.override;

import java.util.List;
import java.util.Properties;

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.TopLevelClass;

public class SerializablePlugin extends PluginAdapter {
private FullyQualifiedJavaType serializable;
private FullyQualifiedJavaType gwtSerializable;
private boolean addGWTInterface;
private boolean suppressJavaInterface;

public SerializablePlugin() {
this.serializable = new FullyQualifiedJavaType("java.io.Serializable");
this.gwtSerializable = new FullyQualifiedJavaType("com.google.gwt.user.client.rpc.IsSerializable");
}

@Override
public void setProperties(Properties properties) {
super.setProperties(properties);
this.addGWTInterface = Boolean.valueOf(properties.getProperty("addGWTInterface")).booleanValue();
this.suppressJavaInterface = Boolean.valueOf(properties.getProperty("suppressJavaInterface")).booleanValue();
}
@Override
public boolean modelBaseRecordClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
makeSerializable(topLevelClass, introspectedTable);
return true;
}
@Override
public boolean modelPrimaryKeyClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
makeSerializable(topLevelClass, introspectedTable);
return true;
}
@Override
public boolean modelRecordWithBLOBsClassGenerated(TopLevelClass topLevelClass,
IntrospectedTable introspectedTable) {
makeSerializable(topLevelClass, introspectedTable);
return true;
}

@Override
public boolean modelExampleClassGenerated(TopLevelClass topLevelClass,IntrospectedTable introspectedTable){
makeSerializable(topLevelClass, introspectedTable);
return true;
}

protected void makeSerializable(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
if (this.addGWTInterface) {
topLevelClass.addImportedType(this.gwtSerializable);
topLevelClass.addSuperInterface(this.gwtSerializable);
}

if (!(this.suppressJavaInterface)) {
topLevelClass.addImportedType(this.serializable);
topLevelClass.addSuperInterface(this.serializable);
topLevelClass.addAnnotation("@SuppressWarnings(\"serial\")");

}
}

/**
* This plugin is always valid - no properties are required
*/
@Override
public boolean validate(List<String> warnings) {
return true;
}
}

六、服务层代码自定义生成

重写Context,ConfigurationParserMyBatisGeneratorConfigurationParser,增加服务层生成逻辑。

先对Service基类进行介绍。

1)BaseService

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
复制代码package cn.xxx.core.base.service;

import java.util.List;

import org.apache.ibatis.annotations.Param;

import cn.xxx.core.base.model.BaseExample;
import cn.xxx.core.base.model.PageInfo;

public interface BaseService<T, Example extends BaseExample, ID> {

long countByExample(Example example);

int deleteByExample(Example example);

int deleteByPrimaryKey(ID id);

int insert(T record);

int insertSelective(T record);

List<T> selectByExample(Example example);

/**
* return T object
* @author Marvis
* @date May 23, 2018 11:37:11 AM
* @param example
* @return
*/
T selectByCondition(Example example);
/**
* if pageInfo == null<p/>
* then return result of selectByExample(example)
* @author Marvis
* @date Jul 13, 2017 5:24:35 PM
* @param example
* @param pageInfo
* @return
*/
List<T> selectByPageExmple(Example example, PageInfo pageInfo);

T selectByPrimaryKey(ID id);

int updateByExampleSelective(@Param("record") T record, @Param("example") Example example);

int updateByExample(@Param("record") T record, @Param("example") Example example);

int updateByPrimaryKeySelective(T record);

int updateByPrimaryKey(T record);
}

2)BaseServiceImpl

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
复制代码package cn.xxx.core.base.service.impl;

import java.util.List;

import cn.xxx.core.base.dao.BaseMapper;
import cn.xxx.core.base.model.BaseExample;
import cn.xxx.core.base.model.PageInfo;
import cn.xxx.core.base.service.BaseService;

public abstract class BaseServiceImpl<T, Example extends BaseExample, ID> implements BaseService<T, Example, ID> {

private BaseMapper<T, Example, ID> mapper;

public void setMapper(BaseMapper<T, Example, ID> mapper) {
this.mapper = mapper;
}

public long countByExample(Example example) {
return mapper.countByExample(example);
}

@Override
public int deleteByExample(Example example) {
return mapper.deleteByExample(example);
}

@Override
public int deleteByPrimaryKey(ID id) {
return mapper.deleteByPrimaryKey(id);
}

@Override
public int insert(T record) {
return mapper.insert(record);
}

@Override
public int insertSelective(T record) {
return mapper.insertSelective(record);
}

@Override
public List<T> selectByExample(Example example) {
return mapper.selectByExample(example);
}
@Override
public T selectByCondition(Example example) {

List<T> datas = selectByExample(example);
return datas != null && datas.size() == 0 ? null : datas.get(0);
}

@Override
public List<T> selectByPageExmple(Example example, PageInfo pageInfo) {

if(pageInfo != null){

example.setPageInfo(pageInfo);
pageInfo.setPageParams(Long.valueOf(this.countByExample(example)).intValue());
}
return this.selectByExample(example);
}

@Override
public T selectByPrimaryKey(ID id) {
return mapper.selectByPrimaryKey(id);
}

@Override
public int updateByExampleSelective(T record, Example example) {
return mapper.updateByExampleSelective(record, example);
}

@Override
public int updateByExample(T record, Example example) {
return mapper.updateByExample(record, example);
}

@Override
public int updateByPrimaryKeySelective(T record) {
return mapper.updateByPrimaryKeySelective(record);
}

@Override
public int updateByPrimaryKey(T record) {
return mapper.updateByPrimaryKey(record);
}
}

3)ServiceLayerPlugin

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
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
复制代码package run.override.service;

import org.mybatis.generator.api.GeneratedJavaFile;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.JavaTypeResolver;
import org.mybatis.generator.api.dom.java.CompilationUnit;
import org.mybatis.generator.api.dom.java.Field;
import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;
import org.mybatis.generator.api.dom.java.Interface;
import org.mybatis.generator.api.dom.java.JavaVisibility;
import org.mybatis.generator.api.dom.java.Method;
import org.mybatis.generator.api.dom.java.Parameter;
import org.mybatis.generator.api.dom.java.TopLevelClass;
import org.mybatis.generator.internal.types.JavaTypeResolverDefaultImpl;
import run.override.pagination.PaginationPlugin;
import run.override.proxyFactory.FullyQualifiedJavaTypeProxyFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class ServiceLayerPlugin extends PaginationPlugin {
/**
* 生成额外java文件
*/
@Override
public List<GeneratedJavaFile> contextGenerateAdditionalJavaFiles(IntrospectedTable introspectedTable) {

ContextOverride context = (ContextOverride) introspectedTable.getContext();

ServiceGeneratorConfiguration serviceGeneratorConfiguration;

if ((serviceGeneratorConfiguration = context.getServiceGeneratorConfiguration()) == null)
return null;

String targetPackage = serviceGeneratorConfiguration.getTargetPackage();
String targetProject = serviceGeneratorConfiguration.getTargetProject();
String implementationPackage = serviceGeneratorConfiguration.getImplementationPackage();

CompilationUnit addServiceInterface = addServiceInterface(introspectedTable, targetPackage);
CompilationUnit addServiceImplClazz = addServiceImplClazz(introspectedTable, targetPackage,
implementationPackage);

GeneratedJavaFile gjfServiceInterface = new GeneratedJavaFile(addServiceInterface, targetProject,
this.context.getProperty("javaFileEncoding"), this.context.getJavaFormatter());
GeneratedJavaFile gjfServiceImplClazz = new GeneratedJavaFile(addServiceImplClazz, targetProject,
this.context.getProperty("javaFileEncoding"), this.context.getJavaFormatter());

List<GeneratedJavaFile> list = new ArrayList<>();
list.add(gjfServiceInterface);
list.add(gjfServiceImplClazz);
return list;
}

protected CompilationUnit addServiceInterface(IntrospectedTable introspectedTable, String targetPackage) {

String entityClazzType = introspectedTable.getBaseRecordType();
String serviceSuperPackage = targetPackage;

String entityExampleClazzType = introspectedTable.getExampleType();
String domainObjectName = introspectedTable.getFullyQualifiedTable().getDomainObjectName();

JavaTypeResolver javaTypeResolver = new JavaTypeResolverDefaultImpl();

FullyQualifiedJavaType calculateJavaType = javaTypeResolver
.calculateJavaType(introspectedTable.getPrimaryKeyColumns().get(0));

StringBuilder builder = new StringBuilder();

FullyQualifiedJavaType superInterfaceType = new FullyQualifiedJavaType(

builder.append("BaseService<")
.append(entityClazzType)
.append(",")
.append(entityExampleClazzType)
.append(",")
.append(calculateJavaType.getShortName()).append(">").toString());

Interface serviceInterface = new Interface(
builder.delete(0, builder.length())
.append(serviceSuperPackage)
.append(".")
.append(domainObjectName)
.append("Service")
.toString()
);

serviceInterface.addSuperInterface(superInterfaceType);
serviceInterface.setVisibility(JavaVisibility.PUBLIC);

FullyQualifiedJavaType baseServiceInstance = FullyQualifiedJavaTypeProxyFactory.getBaseServiceInstance();
FullyQualifiedJavaType modelJavaType = new FullyQualifiedJavaType(entityClazzType);
FullyQualifiedJavaType exampleJavaType = new FullyQualifiedJavaType(entityExampleClazzType);
serviceInterface.addImportedType(baseServiceInstance);
serviceInterface.addImportedType(modelJavaType);
serviceInterface.addImportedType(exampleJavaType);
serviceInterface.addFileCommentLine("/*** copyright (c) 2019 Marvis ***/");


this.additionalServiceMethods(introspectedTable, serviceInterface);
return serviceInterface;
}

protected CompilationUnit addServiceImplClazz(IntrospectedTable introspectedTable, String targetPackage,
String implementationPackage) {

String entityClazzType = introspectedTable.getBaseRecordType();
String serviceSuperPackage = targetPackage;
String serviceImplSuperPackage = implementationPackage;
String entityExampleClazzType = introspectedTable.getExampleType();

String javaMapperType = introspectedTable.getMyBatis3JavaMapperType();

String domainObjectName = introspectedTable.getFullyQualifiedTable().getDomainObjectName();

JavaTypeResolver javaTypeResolver = new JavaTypeResolverDefaultImpl();
FullyQualifiedJavaType calculateJavaType = javaTypeResolver
.calculateJavaType(introspectedTable.getPrimaryKeyColumns().get(0));

StringBuilder builder = new StringBuilder();

FullyQualifiedJavaType superClazzType = new FullyQualifiedJavaType(

builder.append("BaseServiceImpl<")
.append(entityClazzType)
.append(",")
.append(entityExampleClazzType)
.append(",")
.append(calculateJavaType.getShortName()).append(">")
.toString()
);

FullyQualifiedJavaType implInterfaceType = new FullyQualifiedJavaType(

builder.delete(0, builder.length())
.append(serviceSuperPackage)
.append(".")
.append(domainObjectName)
.append("Service")
.toString()
);

TopLevelClass serviceImplClazz = new TopLevelClass(

builder.delete(0, builder.length())
.append(serviceImplSuperPackage)
.append(".")
.append(domainObjectName)
.append("ServiceImpl")
.toString()
);

serviceImplClazz.addSuperInterface(implInterfaceType);
serviceImplClazz.setSuperClass(superClazzType);
serviceImplClazz.setVisibility(JavaVisibility.PUBLIC);
serviceImplClazz.addAnnotation("@Service");

FullyQualifiedJavaType baseServiceInstance = FullyQualifiedJavaTypeProxyFactory.getBaseServiceImplInstance();
FullyQualifiedJavaType modelJavaType = new FullyQualifiedJavaType(entityClazzType);
FullyQualifiedJavaType exampleJavaType = new FullyQualifiedJavaType(entityExampleClazzType);
serviceImplClazz
.addImportedType(new FullyQualifiedJavaType("org.springframework.beans.factory.annotation.Autowired"));
serviceImplClazz.addImportedType(new FullyQualifiedJavaType("org.springframework.stereotype.Service"));
serviceImplClazz.addImportedType(baseServiceInstance);
serviceImplClazz.addImportedType(modelJavaType);
serviceImplClazz.addImportedType(exampleJavaType);
serviceImplClazz.addImportedType(implInterfaceType);

FullyQualifiedJavaType logType = new FullyQualifiedJavaType("org.slf4j.Logger");
FullyQualifiedJavaType logFactoryType = new FullyQualifiedJavaType("org.slf4j.LoggerFactory");
Field logField = new Field();
logField.setVisibility(JavaVisibility.PRIVATE);
logField.setStatic(true);
logField.setFinal(true);
logField.setType(logType);
logField.setName("logger");
logField.setInitializationString(
builder.delete(0, builder.length())
.append("LoggerFactory.getLogger(")
.append(domainObjectName)
.append("ServiceImpl.class)")
.toString()
);

logField.addAnnotation("");
logField.addAnnotation("@SuppressWarnings(\"unused\")");
serviceImplClazz.addField(logField);
serviceImplClazz.addImportedType(logType);
serviceImplClazz.addImportedType(logFactoryType);

String mapperName = builder.delete(0, builder.length())
.append(Character.toLowerCase(domainObjectName.charAt(0)))
.append(domainObjectName.substring(1))
.append("Mapper")
.toString();

FullyQualifiedJavaType JavaMapperType = new FullyQualifiedJavaType(javaMapperType);

Field mapperField = new Field();
mapperField.setVisibility(JavaVisibility.PUBLIC);
mapperField.setType(JavaMapperType);// Mapper.java
mapperField.setName(mapperName);
mapperField.addAnnotation("@Autowired");
serviceImplClazz.addField(mapperField);
serviceImplClazz.addImportedType(JavaMapperType);

Method mapperMethod = new Method();
mapperMethod.setVisibility(JavaVisibility.PUBLIC);
mapperMethod.setName("setMapper");
mapperMethod.addBodyLine("super.setMapper(" + mapperName + ");");
mapperMethod.addAnnotation("@Autowired");

serviceImplClazz.addMethod(mapperMethod);
serviceImplClazz.addFileCommentLine("/*** copyright (c) 2019 Marvis ***/");

serviceImplClazz
.addImportedType(new FullyQualifiedJavaType("org.springframework.beans.factory.annotation.Autowired"));

this.additionalServiceImplMethods(introspectedTable, serviceImplClazz, mapperName);

return serviceImplClazz;
}

protected void additionalServiceMethods(IntrospectedTable introspectedTable, Interface serviceInterface) {

if (this.notHasBLOBColumns(introspectedTable))
return;

introspectedTable.getGeneratedJavaFiles().stream().filter(file -> file.getCompilationUnit().isJavaInterface()
&& file.getCompilationUnit().getType().getShortName().endsWith("Mapper")).map(GeneratedJavaFile::getCompilationUnit).forEach(
compilationUnit -> ((Interface) compilationUnit).getMethods().forEach(

m -> serviceInterface.addMethod(this.additionalServiceLayerMethod(serviceInterface, m))));
}

protected void additionalServiceImplMethods(IntrospectedTable introspectedTable, TopLevelClass clazz,
String mapperName) {

if (this.notHasBLOBColumns(introspectedTable))
return;

introspectedTable.getGeneratedJavaFiles().stream().filter(file -> file.getCompilationUnit().isJavaInterface()
&& file.getCompilationUnit().getType().getShortName().endsWith("Mapper")).map(GeneratedJavaFile::getCompilationUnit).forEach(
compilationUnit -> ((Interface) compilationUnit).getMethods().forEach(m -> {

Method serviceImplMethod = this.additionalServiceLayerMethod(clazz, m);
serviceImplMethod.addAnnotation("@Override");
serviceImplMethod.addBodyLine(this.generateBodyForServiceImplMethod(mapperName, m));

clazz.addMethod(serviceImplMethod);
}));
}


private boolean notHasBLOBColumns(IntrospectedTable introspectedTable) {
return !introspectedTable.hasBLOBColumns();
}

private Method additionalServiceLayerMethod(CompilationUnit compilation, Method m) {

Method method = new Method();
method.setVisibility(JavaVisibility.PUBLIC);
method.setName(m.getName());

List<Parameter> parameters = m.getParameters();

method.getParameters().addAll(parameters.stream().peek(param -> param.getAnnotations().clear()).collect(Collectors.toList()));
method.setReturnType(m.getReturnType());
compilation.addImportedType(
new FullyQualifiedJavaType(m.getReturnType().getFullyQualifiedNameWithoutTypeParameters()));
return method;
}

private String generateBodyForServiceImplMethod(String mapperName, Method m) {
StringBuilder sbf = new StringBuilder("return ");
sbf.append(mapperName).append(".").append(m.getName()).append("(");

boolean singleParam = true;
for (Parameter parameter : m.getParameters()) {

if (singleParam)
singleParam = !singleParam;
else
sbf.append(", ");
sbf.append(parameter.getName());

}

sbf.append(");");
return sbf.toString();
}

}

4)ContextOverride

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
复制代码package run.override.service;

import java.util.List;

import org.mybatis.generator.api.dom.xml.XmlElement;
import org.mybatis.generator.config.Context;
import org.mybatis.generator.config.ModelType;

public class ContextOverride extends Context{
//添加ServiceGeneratorConfiguration
private ServiceGeneratorConfiguration serviceGeneratorConfiguration;

public ContextOverride(ModelType defaultModelType) {
super(defaultModelType);
}

public ServiceGeneratorConfiguration getServiceGeneratorConfiguration() {
return serviceGeneratorConfiguration;
}

public void setServiceGeneratorConfiguration(ServiceGeneratorConfiguration serviceGeneratorConfiguration) {
this.serviceGeneratorConfiguration = serviceGeneratorConfiguration;
}

@Override
public void validate(List<String> errors) {
if(serviceGeneratorConfiguration != null)
serviceGeneratorConfiguration.validate(errors, this.getId());

super.validate(errors);
}

public XmlElement toXmlElement() {

XmlElement xmlElement = super.toXmlElement();
if (serviceGeneratorConfiguration != null)
xmlElement.addElement(serviceGeneratorConfiguration.toXmlElement());
return xmlElement;
}
}

5)MyBatisGeneratorConfigurationParserOverride

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
复制代码package run.override.service;

import java.util.Properties;

import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.Context;
import org.mybatis.generator.config.JavaClientGeneratorConfiguration;
import org.mybatis.generator.config.ModelType;
import org.mybatis.generator.config.PluginConfiguration;
import org.mybatis.generator.config.xml.MyBatisGeneratorConfigurationParser;
import org.mybatis.generator.exception.XMLParserException;
import org.mybatis.generator.internal.util.StringUtility;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class MyBatisGeneratorConfigurationParserOverride extends MyBatisGeneratorConfigurationParser {

public MyBatisGeneratorConfigurationParserOverride(Properties extraProperties) {
super(extraProperties);
}

private void parseJavaServiceGenerator(Context context, Node node) {

ContextOverride contextOverride = ContextOverride.class.cast(context); ////替换Context

ServiceGeneratorConfiguration serviceGeneratorConfiguration = new ServiceGeneratorConfiguration();

contextOverride.setServiceGeneratorConfiguration(serviceGeneratorConfiguration);
Properties attributes = parseAttributes(node);

String targetPackage = attributes.getProperty("targetPackage");
String targetProject = attributes.getProperty("targetProject");
String implementationPackage = attributes.getProperty("implementationPackage");

serviceGeneratorConfiguration.setTargetPackage(targetPackage);
serviceGeneratorConfiguration.setTargetProject(targetProject);
serviceGeneratorConfiguration.setImplementationPackage(implementationPackage);

NodeList nodeList = node.getChildNodes();
for (int i = 0; i < nodeList.getLength(); i++) {
Node childNode = nodeList.item(i);
if (childNode.getNodeType() == Node.ELEMENT_NODE && "property".equals(childNode.getNodeName()))
parseProperty(serviceGeneratorConfiguration, childNode);
}

}

@Override
public Configuration parseConfiguration(Element rootNode) throws XMLParserException {
Configuration configuration = new Configuration();

NodeList nodeList = rootNode.getChildNodes();
for (int i = 0; i < nodeList.getLength(); ++i) {
Node childNode = nodeList.item(i);

if (childNode.getNodeType() != 1) {
continue;
}

if ("properties".equals(childNode.getNodeName()))
parseProperties(configuration, childNode);
else if ("classPathEntry".equals(childNode.getNodeName()))
parseClassPathEntry(configuration, childNode);
else if ("context".equals(childNode.getNodeName())) {
parseContext(configuration, childNode);
}
}

return configuration;
}

private void parseContext(Configuration configuration, Node node) {
Properties attributes = parseAttributes(node);
String defaultModelType = attributes.getProperty("defaultModelType");
String targetRuntime = attributes.getProperty("targetRuntime");
String introspectedColumnImpl = attributes.getProperty("introspectedColumnImpl");
String id = attributes.getProperty("id");
ModelType mt = defaultModelType != null ? ModelType.getModelType(defaultModelType) : null;
Context context = new ContextOverride(mt);
context.setId(id);
if (StringUtility.stringHasValue(introspectedColumnImpl))
context.setIntrospectedColumnImpl(introspectedColumnImpl);
if (StringUtility.stringHasValue(targetRuntime))
context.setTargetRuntime(targetRuntime);
configuration.addContext(context);
NodeList nodeList = node.getChildNodes();
for (int i = 0; i < nodeList.getLength(); i++) {
Node childNode = nodeList.item(i);
if (childNode.getNodeType() != 1)
continue;

if ("property".equals(childNode.getNodeName())) {
parseProperty(context, childNode);
continue;
}
if ("plugin".equals(childNode.getNodeName())) {
parsePlugin(context, childNode);
continue;
}
if ("commentGenerator".equals(childNode.getNodeName())) {
parseCommentGenerator(context, childNode);
continue;
}
if ("jdbcConnection".equals(childNode.getNodeName())) {
parseJdbcConnection(context, childNode);
continue;
}
if ("connectionFactory".equals(childNode.getNodeName())) {
parseConnectionFactory(context, childNode);
continue;
}
if ("javaModelGenerator".equals(childNode.getNodeName())) {
parseJavaModelGenerator(context, childNode);
continue;
}
if ("javaTypeResolver".equals(childNode.getNodeName())) {
parseJavaTypeResolver(context, childNode);
continue;
}
if ("sqlMapGenerator".equals(childNode.getNodeName())) {
parseSqlMapGenerator(context, childNode);
continue;
}
if ("javaClientGenerator".equals(childNode.getNodeName())) {
parseJavaClientGenerator(context, childNode);
continue;
}
if ("javaServiceGenerator".equals(childNode.getNodeName())) {
parseJavaServiceGenerator(context, childNode);
continue;
}
if ("table".equals(childNode.getNodeName()))
parseTable(context, childNode);
}
}

private void parsePlugin(Context context, Node node) {
PluginConfiguration pluginConfiguration = new PluginConfiguration();
context.addPluginConfiguration(pluginConfiguration);
Properties attributes = parseAttributes(node);
String type = attributes.getProperty("type");
pluginConfiguration.setConfigurationType(type);
NodeList nodeList = node.getChildNodes();
for (int i = 0; i < nodeList.getLength(); i++) {
Node childNode = nodeList.item(i);
if (childNode.getNodeType() == 1 && "property".equals(childNode.getNodeName()))
parseProperty(pluginConfiguration, childNode);
}

}

private void parseJavaClientGenerator(Context context, Node node) {
JavaClientGeneratorConfiguration javaClientGeneratorConfiguration = new JavaClientGeneratorConfiguration();
context.setJavaClientGeneratorConfiguration(javaClientGeneratorConfiguration);
Properties attributes = parseAttributes(node);
String type = attributes.getProperty("type");
String targetPackage = attributes.getProperty("targetPackage");
String targetProject = attributes.getProperty("targetProject");
String implementationPackage = attributes.getProperty("implementationPackage");
javaClientGeneratorConfiguration.setConfigurationType(type);
javaClientGeneratorConfiguration.setTargetPackage(targetPackage);
javaClientGeneratorConfiguration.setTargetProject(targetProject);
javaClientGeneratorConfiguration.setImplementationPackage(implementationPackage);
NodeList nodeList = node.getChildNodes();
for (int i = 0; i < nodeList.getLength(); i++) {
Node childNode = nodeList.item(i);
if (childNode.getNodeType() == 1 && "property".equals(childNode.getNodeName()))
parseProperty(javaClientGeneratorConfiguration, childNode);
}

}
}

6)ServiceGeneratorConfiguration

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
复制代码package run.override.service;

import java.util.List;

import org.mybatis.generator.api.dom.xml.Attribute;
import org.mybatis.generator.api.dom.xml.XmlElement;
import org.mybatis.generator.config.PropertyHolder;
import org.mybatis.generator.internal.util.StringUtility;
import org.mybatis.generator.internal.util.messages.Messages;

public class ServiceGeneratorConfiguration extends PropertyHolder {

private String targetPackage;
private String implementationPackage;
private String targetProject;
/**
*
*/
public ServiceGeneratorConfiguration() {
super();
}
public String getTargetPackage() {
return targetPackage;
}
public void setTargetPackage(String targetPackage) {
this.targetPackage = targetPackage;
}
public String getImplementationPackage() {
return implementationPackage;
}
public void setImplementationPackage(String implementationPackage) {
this.implementationPackage = implementationPackage;
}
public String getTargetProject() {
return targetProject;
}
public void setTargetProject(String targetProject) {
this.targetProject = targetProject;
}
public XmlElement toXmlElement() {
XmlElement answer = new XmlElement("javaServiceGenerator");

if (targetPackage != null) {
answer.addAttribute(new Attribute("targetPackage", targetPackage));
}

if (implementationPackage != null) {
answer.addAttribute(new Attribute("implementationPackage", targetPackage));
}
if (targetProject != null) {
answer.addAttribute(new Attribute("targetProject", targetProject));
}


addPropertyXmlElements(answer);

return answer;
}

@SuppressWarnings({ "rawtypes", "unchecked" })
public void validate(List errors, String contextId) {
if (!StringUtility.stringHasValue(getTargetProject()))
errors.add(Messages.getString("ValidationError.102", contextId));
if (!StringUtility.stringHasValue(getTargetPackage()))
errors.add(Messages.getString("ValidationError.112", "ServiceGenerator", contextId));
if (!StringUtility.stringHasValue(getImplementationPackage()))
errors.add(Messages.getString("ValidationError.120", contextId));
}

}

7)ConfigurationParserOverride

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
复制代码package run.override.service;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.config.xml.MyBatisGeneratorConfigurationParser;
import org.mybatis.generator.config.xml.ParserEntityResolver;
import org.mybatis.generator.config.xml.ParserErrorHandler;
import org.mybatis.generator.exception.XMLParserException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

public class ConfigurationParserOverride extends ConfigurationParser {

private List<String> warnings;
private List<String> parseErrors;
private Properties extraProperties;

public ConfigurationParserOverride(List<String> warnings) {
this(null, warnings);
}

public ConfigurationParserOverride(Properties extraProperties, List<String> warnings) {
super(extraProperties, warnings);
this.extraProperties = extraProperties;

if (warnings == null)
this.warnings = new ArrayList<>();
else {
this.warnings = warnings;
}

this.parseErrors = new ArrayList<>();
}

@Override
public Configuration parseConfiguration(File inputFile) throws IOException, XMLParserException {
FileReader fr = new FileReader(inputFile);

return parseConfiguration(fr);
}

@Override
public Configuration parseConfiguration(InputStream inputStream) throws IOException, XMLParserException {
InputSource is = new InputSource(inputStream);

return parseConfiguration(is);
}

@Override
public Configuration parseConfiguration(Reader reader) throws IOException, XMLParserException {
InputSource is = new InputSource(reader);

return parseConfiguration(is);
}

private Configuration parseConfiguration(InputSource inputSource) throws IOException, XMLParserException {
this.parseErrors.clear();
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(true);
try {
DocumentBuilder builder = factory.newDocumentBuilder();
builder.setEntityResolver(new ParserEntityResolver());

ParserErrorHandler handler = new ParserErrorHandler(this.warnings, this.parseErrors);

builder.setErrorHandler(handler);

Document document = null;
try {
document = builder.parse(inputSource);
} catch (SAXParseException e) {
throw new XMLParserException(this.parseErrors);
} catch (SAXException e) {
if (e.getException() == null)
this.parseErrors.add(e.getMessage());
else {
this.parseErrors.add(e.getException().getMessage());
}
}

if (this.parseErrors.size() > 0) {
throw new XMLParserException(this.parseErrors);
}

Element rootNode = document.getDocumentElement();
Configuration config = parseMyBatisGeneratorConfiguration(rootNode);

if (this.parseErrors.size() > 0) {
throw new XMLParserException(this.parseErrors);
}

return config;
} catch (ParserConfigurationException e) {
this.parseErrors.add(e.getMessage());
throw new XMLParserException(this.parseErrors);
}
}

private Configuration parseMyBatisGeneratorConfiguration(Element rootNode) throws XMLParserException {

//替换MyBatisGeneratorConfigurationParser
MyBatisGeneratorConfigurationParser parser = new MyBatisGeneratorConfigurationParserOverride(
this.extraProperties);

return parser.parseConfiguration(rootNode);
}

}

七、PluginChain

通过继承,把以上扩展Plugin串起来(SerializablePlugin一些项目中可能不需要,故不加入Chain。同时,其他也可以根据需要对Chain进行更改)。

1
2
3
4
5
复制代码package run.override;

import run.override.service.ServiceLayerPlugin;
public class PluginChain extends ServiceLayerPlugin {
}

八、generatorConfig.xml

增加javaServiceGenerator相关配置标签。本文使用内部DTD做示例,亦可通过外部DTD或xsd来实现。

1)generatorConfig.xml

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
182
183
184
185
186
187
188
189
190
191
复制代码<?xml version="1.0" encoding="UTF-8"?>
<!-- 内部DTD 亦可通过外部DTD来实现-->
<!DOCTYPE generatorConfiguration

[
<!ELEMENT generatorConfiguration (properties?, classPathEntry*, context+)>

<!ELEMENT properties EMPTY>
<!ATTLIST properties
resource CDATA #IMPLIED
url CDATA #IMPLIED>
<!--
括号里是声明出现的次序:
*: 出现任意次,包括0次
?: 出现最多一次
|:选择之一
+: 出现最少1次
如果没有上述符号:必须且只能出现一次
-->
<!ELEMENT context (property*, plugin*, commentGenerator?, (connectionFactory | jdbcConnection), javaTypeResolver?,
javaModelGenerator, sqlMapGenerator, javaClientGenerator, javaServiceGenerator,table+)>
<!ATTLIST context id ID #REQUIRED
defaultModelType CDATA #IMPLIED
targetRuntime CDATA #IMPLIED
introspectedColumnImpl CDATA #IMPLIED>

<!ELEMENT connectionFactory (property*)>
<!ATTLIST connectionFactory
type CDATA #IMPLIED>

<!ELEMENT jdbcConnection (property*)>
<!ATTLIST jdbcConnection
driverClass CDATA #REQUIRED
connectionURL CDATA #REQUIRED
userId CDATA #IMPLIED
password CDATA #IMPLIED>

<!ELEMENT classPathEntry EMPTY>
<!ATTLIST classPathEntry
location CDATA #REQUIRED>

<!ELEMENT property EMPTY>
<!ATTLIST property
name CDATA #REQUIRED
value CDATA #REQUIRED>

<!ELEMENT plugin (property*)>
<!ATTLIST plugin
type CDATA #REQUIRED>

<!ELEMENT javaModelGenerator (property*)>
<!ATTLIST javaModelGenerator
targetPackage CDATA #REQUIRED
targetProject CDATA #REQUIRED>

<!ELEMENT javaTypeResolver (property*)>
<!ATTLIST javaTypeResolver
type CDATA #IMPLIED>

<!ELEMENT sqlMapGenerator (property*)>
<!ATTLIST sqlMapGenerator
targetPackage CDATA #REQUIRED
targetProject CDATA #REQUIRED>

<!ELEMENT javaClientGenerator (property*)>
<!ATTLIST javaClientGenerator
type CDATA #REQUIRED
targetPackage CDATA #REQUIRED
targetProject CDATA #REQUIRED
implementationPackage CDATA #IMPLIED>

<!ELEMENT javaServiceGenerator (property*)>
<!ATTLIST javaServiceGenerator
targetPackage CDATA #REQUIRED
implementationPackage CDATA #REQUIRED
targetProject CDATA #REQUIRED>

<!ELEMENT table (property*, generatedKey?, domainObjectRenamingRule?, columnRenamingRule?, (columnOverride | ignoreColumn | ignoreColumnsByRegex)*) >
<!ATTLIST table
catalog CDATA #IMPLIED
schema CDATA #IMPLIED
tableName CDATA #REQUIRED
alias CDATA #IMPLIED
domainObjectName CDATA #IMPLIED
mapperName CDATA #IMPLIED
sqlProviderName CDATA #IMPLIED
enableInsert CDATA #IMPLIED
enableSelectByPrimaryKey CDATA #IMPLIED
enableSelectByExample CDATA #IMPLIED
enableUpdateByPrimaryKey CDATA #IMPLIED
enableDeleteByPrimaryKey CDATA #IMPLIED
enableDeleteByExample CDATA #IMPLIED
enableCountByExample CDATA #IMPLIED
enableUpdateByExample CDATA #IMPLIED
selectByPrimaryKeyQueryId CDATA #IMPLIED
selectByExampleQueryId CDATA #IMPLIED
modelType CDATA #IMPLIED
escapeWildcards CDATA #IMPLIED
delimitIdentifiers CDATA #IMPLIED
delimitAllColumns CDATA #IMPLIED>

<!ELEMENT columnOverride (property*)>
<!ATTLIST columnOverride
column CDATA #REQUIRED
property CDATA #IMPLIED
javaType CDATA #IMPLIED
jdbcType CDATA #IMPLIED
typeHandler CDATA #IMPLIED
isGeneratedAlways CDATA #IMPLIED
delimitedColumnName CDATA #IMPLIED>

<!ELEMENT ignoreColumn EMPTY>
<!ATTLIST ignoreColumn
column CDATA #REQUIRED
delimitedColumnName CDATA #IMPLIED>


<!ELEMENT ignoreColumnsByRegex (except*)>
<!ATTLIST ignoreColumnsByRegex
pattern CDATA #REQUIRED>

<!ELEMENT except EMPTY>
<!ATTLIST except
column CDATA #REQUIRED
delimitedColumnName CDATA #IMPLIED>

<!ELEMENT generatedKey EMPTY>
<!ATTLIST generatedKey
column CDATA #REQUIRED
sqlStatement CDATA #REQUIRED
identity CDATA #IMPLIED
type CDATA #IMPLIED>

<!ELEMENT domainObjectRenamingRule EMPTY>
<!ATTLIST domainObjectRenamingRule
searchString CDATA #REQUIRED
replaceString CDATA #IMPLIED>

<!ELEMENT columnRenamingRule EMPTY>
<!ATTLIST columnRenamingRule
searchString CDATA #REQUIRED
replaceString CDATA #IMPLIED>

<!ELEMENT commentGenerator (property*)>
<!ATTLIST commentGenerator
type CDATA #IMPLIED>
]
>

<generatorConfiguration>
<context id="ables" targetRuntime="MyBatis3">
<!--
添加Plugin
-->
<plugin type="run.override.PluginChain" />
<plugin type="run.override.SerializablePlugin" />
<plugin type="org.mybatis.generator.plugins.ToStringPlugin" />
<commentGenerator type="run.override.CommentGenerator"/>

<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://xxx.xxx.xxx.xxx:3306/xxx?characterEncoding=utf8"
userId="xxx" password="xxx">
</jdbcConnection>
<javaTypeResolver>
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<javaModelGenerator targetPackage="cn.xxx.elecsign.model" targetProject=".\src">
<property name="enableSubPackages" value="false" />
<property name="trimStrings" value="true" />
</javaModelGenerator>

<sqlMapGenerator targetPackage="mapper.cn.xxx.elecsign.dao" targetProject=".\src">
<property name="enableSubPackages" value="false" />
</sqlMapGenerator>

<javaClientGenerator type="XMLMAPPER" targetPackage="cn.xxx.elecsign.dao" targetProject=".\src">
<property name="enableSubPackages" value="false" />
</javaClientGenerator>
<!-- javaServiceGenerator -->
<javaServiceGenerator targetPackage="cn.xxx.elecsign.dly.service"
implementationPackage = "cn.xxx.elecsign.dly.service.impl" targetProject=".\src">
<property name="enableSubPackages" value="false" />
</javaServiceGenerator>

<!-- 批次表,针对批量的异步操作 -->
<table tableName="table" domainObjectName="Table"
alias="table">
<generatedKey column="id" sqlStatement="MySql" identity="true" />
</table>
</context>
</generatorConfiguration>

九、main启动

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
复制代码 package run.generator;


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

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

import run.override.service.ConfigurationParserOverride;

public class Generator {

public void generator() throws Exception{

List<String> warnings = new ArrayList<String>();
boolean overwrite = true;
File configFile = new File("generatorConfig.xml");
//替换ConfigurationParser
ConfigurationParserOverride cp = new ConfigurationParserOverride(warnings);
Configuration config = cp.parseConfiguration(configFile);
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);

myBatisGenerator.generate(null);

}
public static void main(String[] args) throws Exception {
try {
Generator generator = new Generator();
generator.generator();
} catch (Exception e) {
e.printStackTrace();
}

}

}

至此,对mybatis-generator的扩展生成代码完成。

来源:宜信技术学院

作者:马伟伟

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%