如何实现后端开发框架(十)-自动生成代码
本文介绍了如何使用MyBatis-Plus代码生成工具快速创建MVC分层代码(Controller/Service/Mapper/Entity)。通过配置数据源、包路径和模板引擎,可自动根据数据库表生成Java类代码,支持自定义父类继承和Lombok注解,提升后端开发效率。
1.问题描述
Web系统后端一般会按照MVC的方式来分层存放代码,一般分为Controller,Service,Mapper,Entity类,那么是否能快速创建这些模板代码呢?
2.实现思路
我们可以利用Mybatis-Plus的代码生成工具mybatis-plus-generator根据数据库表来生成对应的后端模板代码。
3.实现步骤
3.1.添加依赖包
1
2
3
4
5
6
7
8
9
10
11
12
<!-- 代码生成工具 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.4.0</version>
</dependency>
<!-- 生成代码使用的模板引擎 -->
<dependency>
<groupId>com.ibeetl</groupId>
<artifactId>beetl</artifactId>
<version>3.0.16.RELEASE</version>
</dependency>
我这里使用的是老版本的mybatis-plus-generator,官方文档见:https://baomidou.com/reference/code-generator-configuration/
新版本mybatis-plus-generator的官方文档见:https://baomidou.com/reference/new-code-generator-configuration/
3.2.编写代码生成逻辑
在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
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
@Slf4j
public class CodeGenerator {
private static String url =
"jdbc:postgresql://localhost:5432/backend_framework_dev?stringtype=unspecified";
private static String username = "postgres";
private static String password = "postgres";
private static String driverClassName = "org.postgresql.Driver";
private static String schema = "public";
private static DbType dbType = DbType.POSTGRE_SQL;
private static String parentPackage = "com.framework.backend";
/** 读取控制台内容 */
public static String scanner(String tip) {
Scanner scanner = new Scanner(System.in);
StringBuilder help = new StringBuilder();
help.append("请输入").append(tip).append(":");
System.out.println(help.toString());
String input = scanner.nextLine();
return input;
}
/** RUN THIS */
public static void main(String[] args) {
// 代码生成器
AutoGenerator mpg = new AutoGenerator();
String rootProjectPath = System.getProperty("user.dir");
log.debug("rootProjectPath: " + rootProjectPath);
// 可以将代码生成到其它项目目录中去
// String childProjectName = scanner("子项目名称");
// String childProjectPath = rootProjectPath + "/" + childProjectName;
String childProjectName = scanner("子项目名称(填空表示生成代码到当前项目)");
// 默认将代码只生成到本项目目录中
String childProjectPath = rootProjectPath;
// childProjectName有值时将代码生成到其它子项目中去
if (StringUtils.isNotBlank(childProjectName)) {
childProjectPath =
rootProjectPath.substring(0, rootProjectPath.lastIndexOf("\\") + 1) + childProjectName;
}
// 全局配置
GlobalConfig gc = getGlobalConfig(childProjectPath);
mpg.setGlobalConfig(gc);
// 数据源配置
DataSourceConfig dsc = getDataSourceConfig();
mpg.setDataSource(dsc);
// 包配置
PackageConfig pc = getPackageConfig();
mpg.setPackageInfo(pc);
// 自定义配置
InjectionConfig cfg = getInjectionConfig(pc, childProjectPath);
mpg.setCfg(cfg);
// 模板配置
TemplateConfig templateConfig = getTemplateConfig();
mpg.setTemplate(templateConfig);
// 数据库表配置
StrategyConfig strategy = getStrategyConfig(pc);
mpg.setStrategy(strategy);
// 选择 Beetl 引擎需要指定如下加,注意 pom 依赖必须有!
mpg.setTemplateEngine(new BeetlTemplateEngine());
mpg.execute();
}
/** 全局配置 */
private static GlobalConfig getGlobalConfig(String childProjectPath) {
GlobalConfig gc = new GlobalConfig();
// 生成文件的输出目录
gc.setOutputDir(childProjectPath + "/src/main/java");
// 是否覆盖已有文件
gc.setFileOverride(false);
gc.setAuthor("code-generator");
// 是否打开输出目录
gc.setOpen(false);
// 实体命名方式,生成xxxEntity
gc.setEntityName("%s");
// mapper命名方式,生成xxxMapper
gc.setMapperName("%sMapper");
// Mapper xml命名方式,生成xxxMapper
gc.setXmlName("%sMapper");
// service命名方式,生成xxxService
gc.setServiceName("%sService");
// service impl命名方式,生成xxxServiceImpl
gc.setServiceImplName("%sServiceImpl");
// controller命名方式,生成xxxController
gc.setControllerName("%sController");
// 自动生成mapper.xml中的baseResultMap
gc.setBaseResultMap(true);
// 自动生成mapper.xml中的Base_Column_List
gc.setBaseColumnList(true);
// 已修改模板entity.java.btl来支持生成springdoc注解
gc.setSwagger2(true);
return gc;
}
/** 数据源配置 */
private static DataSourceConfig getDataSourceConfig() {
DataSourceConfig dsc = new DataSourceConfig();
dsc.setDbType(dbType);
dsc.setUrl(url);
// 数据库schema,POSTGRE_SQL,ORACLE,DB2类型的数据库需要指定SchemaName
dsc.setSchemaName(schema);
dsc.setDriverName(driverClassName);
dsc.setUsername(username);
dsc.setPassword(password);
return dsc;
}
/** 包配置 */
private static PackageConfig getPackageConfig() {
PackageConfig pc = new PackageConfig();
pc.setParent(parentPackage);
String moduleName = scanner("模块名");
// 模块名转成小写
pc.setModuleName(moduleName.toLowerCase());
return pc;
}
/** 自定义配置 */
private static InjectionConfig getInjectionConfig(PackageConfig pc, String childProjectPath) {
// 自定义配置
InjectionConfig cfg =
new InjectionConfig() {
@Override
public void initMap() {
// Map<String, Object> map = new HashMap<>();
// map.put("abc", this.getConfig().getGlobalConfig().getAuthor() + "-mp");
// this.setMap(map);
}
};
// ---------------------生成mapper.xml开始-------------------------------------
// // 如果模板引擎是beetl
// String templatePath = "/templates/mapper.xml.btl";
//
// // 自定义输出配置
// List<FileOutConfig> focList = new ArrayList<>();
// // 自定义配置会被优先输出
// focList.add(
// new FileOutConfig(templatePath) {
// @Override
// public String outputFile(TableInfo tableInfo) {
// // 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!
// return childProjectPath
// + "/src/main/resources/mapper/"
// + pc.getModuleName()
// + "/"
// + tableInfo.getEntityName()
// + "Mapper"
// + StringPool.DOT_XML;
// }
// });
// ---------------------生成mapper.xml结束-------------------------------------
//
// cfg.setFileCreate(
// new IFileCreate() {
// @Override
// public boolean isCreate(ConfigBuilder configBuilder, FileType fileType, String
// filePath) {
// // 判断自定义文件夹是否需要创建
// checkDir("调用默认方法创建的目录,自定义目录用");
// if (fileType == FileType.MAPPER) {
// // 已经生成 mapper 文件判断存在,不想重新生成返回 false
// return !new File(filePath).exists();
// }
// // 允许生成模板文件
// return true;
// }
// });
//
// ---------------------生成mapper.xml开始-------------------------------------
// cfg.setFileOutConfigList(focList);
// ---------------------生成mapper.xml结束-------------------------------------
return cfg;
}
/** 模板配置 */
private static TemplateConfig getTemplateConfig() {
TemplateConfig templateConfig = new TemplateConfig();
templateConfig.setEntity("templates/entity.java");
templateConfig.setController("templates/controller.java");
templateConfig.setServiceImpl("templates/serviceImpl.java");
templateConfig.setService("templates/service.java");
templateConfig.setMapper("templates/mapper.java");
// 此处生成的mapper.xml会放到java类目录中
// templateConfig.setXml("templates/mapper.xml");
// 设置mapper.xml使用自定义输出配置的方式来生成
// templateConfig.setXml(null);
// 设置为不生成mapper.xml
templateConfig.disable(TemplateType.XML);
return templateConfig;
}
/** 数据库表配置 */
private static StrategyConfig getStrategyConfig(PackageConfig pc) {
StrategyConfig strategy = new StrategyConfig();
// 配置数据表与实体类名之间映射的策略
strategy.setNaming(NamingStrategy.underline_to_camel);
// 配置数据表的字段与实体类的属性名之间映射的策略
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
// strategy.setSuperEntityClass("com.framework.backend.common.MyBaseEntity");
// strategy.setSuperMapperClass("com.framework.backend.common.MyBaseMapper");
// strategy.setSuperServiceClass("com.framework.backend.common.MyBaseService");
// strategy.setSuperServiceImplClass("com.framework.backend.common.MyBaseServiceImpl");
// strategy.setSuperControllerClass("com.framework.backend.common.MyBaseController");
strategy.setRestControllerStyle(true);
// 驼峰转连字符
strategy.setControllerMappingHyphenStyle(false);
// 启用lombok
strategy.setEntityLombokModel(true);
// 开启生成serialVersionUID
strategy.setEntitySerialVersionUID(true);
strategy.setInclude(scanner("表名").split(","));
// 不用生成父类上的基本数据库表字段
// strategy.setSuperEntityColumns(
// new String[] {"ID", "CREATE_USER", "CREATE_TIME", "UPDATE_USER", "UPDATE_TIME"});
// 配置表前缀,生成实体时去除表前缀
// 例:表名为utility_dicset,模块名为utility,去除前缀后剩下为dicset实体类。
strategy.setTablePrefix(pc.getModuleName() + "_");
return strategy;
}
}
上面的例子是根据postgresql数据库中的指定表来生成对应的Entity,Controller,Service和Mapper类。
请输入子项目名称:是指将生成的代码存放到哪个子项目中去。
请输入模块名:数据表名命名规则为“模块名_业务表名”,模块名会生成代码的包。
请输入表名:完整表名信息,为“模块名_业务表名”。
因为我自己并不使用mybatis xml文件,我使用的是java mapper类。如果想生成mapper.xml文件,那么就请根据官方文档来修改getInjectionConfig()里的代码。
如果希望修改官方的代码生成模板,我这里使用的是beetl模板引擎。那么就要自行修改resources/templates文件夹中对应的btl文件,具体内容见代码git仓库中的示例代码。
如果需要生成类继承父类,那么需要在代码中指定父类:
1
2
3
4
5
// strategy.setSuperEntityClass("com.framework.backend.common.MyBaseEntity");
// strategy.setSuperMapperClass("com.framework.backend.common.MyBaseMapper");
// strategy.setSuperServiceClass("com.framework.backend.common.MyBaseService");
// strategy.setSuperServiceImplClass("com.framework.backend.common.MyBaseServiceImpl");
// strategy.setSuperControllerClass("com.framework.backend.common.MyBaseController");
4.测试验证
执行main方法,输入所需参数,查看指定项目中是否生成了表对应的Entity,Controller,Service和Mapper类代码。
5.完整代码
完整代码见以下Git仓库中的”code-generator”子项目:
https://github.com/randy0098/framework-samples