摘要:本文主要介绍由Spring Cloud中国社区发起的以Spring Cloud为主的代码生成器,目的是快速,按需勾选,生成最优实践的Spring Cloud工程。欢迎有想法的小伙伴加入Spring Cloud中国社区开源战队,关于代码生成器和spring-cloud-codegen的设计细节后面将有一系列的文章介绍。

一.Spring Cloud CodeGen概述

1.1 为什么要开发Spring Cloud CodeGen

如何生成项目的代码? 不少开发人员都会使用Maven的Archetype或IDEA的Gradle插件,通过几个简单的交互就可以快速完成项目的结构和对应的代码生成。但是Spring官方也给我们提供了http://start.spring.io 生成,道理很简单:UI可视化,选择项多,更新快。但是例如:application.properties文件的生成,官方是不会生成对应的配置项的 因此也有不少公司对其进行代码增强处理二次开发处理。


根据目前社区和现在使用代码生成器的现状,迫切希望打造一个如下的代码生成器:

  • 业界最佳Spring Cloud微服务实战经验打造最佳代码生成模板
  • 容器化/Docker支持: 根据你选择的dependency,自动生成docker-compose.yml文件,如选择mysql,redis等,会在docker-compse.yml自动添加对应的镜像配置,方便使用docker compose进行环境配置和组件编排。
  • application.properties文件生成: 官方是不会生成对应的配置项的,但是我们将会结合Spring Cloud的最优实践配置,不仅如此我们将会集成市面上口碑最好的中间件给出最优配置。
  • 规范:pom.xml的规范,application.properties的规范等,提供默认配置,只需要稍微调整一下或者不需要任何调整就可以使用。
  • 其他标准文件的规范:.gitignore, logback-spring.xml等。 如果你选择mybatis会自动生成mybatis-config.xml文件等。
  • 持续集成:自动生成 .gitlab-ci.yml 文件,自动集成 Gitlab CI

基于如上原因和愿景,因此我们需要开发一个最优Spring Cloud实践的代码生成器。

1.2 Spring Cloud CodeGen概述

spring-cloud-codegen是由Spring Cloud中国社区发起的一个代码生成器开源项目,目前该开源项目由许进,任浩军,李云龙,刘美胜奇持续开发迭代。基于Freemarker+模板文件的代码生成器,可以按需勾选组件,轻松快速实现对框架代码的一键创建(例如业务部门实现对基础架构部提供的框架快速搭建),实现对Spring Cloud的最优实践和配置工具化和规范化。

1.3 功能

最终功能包含如下,包括屏蔽XXX注解和配置

  • generate app structure ——>状态doing
  • generate java code and resources ——>状态todo
  • generate docker-compose.yml ——>状态todo
  • generate .gitlab-ci.yml ——>状态todo
  • generate DDD structure ——>状态todo

二.走进Spring Cloud CodeGen

2.1 项目介绍

项目Demo地址:http://start.springcloud.cn/
项目开发人员:许进,任浩军,刘美胜奇,李云龙
github地址:
https://github.com/springcloud/spring-cloud-codegen
https://github.com/springcloud/spring-cloud-skeleton

2.2 项目技术选型

Spring Boot+Spring MVC+FreeMarker+Vue

2.3 代码生成器配置

1.skeleton-data.properties
用来描述模板文件的全局配置值,里面的值替换模板文件里的动态变量(用${}表示)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# ---------- 工程配置 ----------
# moduleName=sales-project
moduleName=sales
basePackage=cn.springcloud
pomGroupId=cn.springcloud
pomArtifactId=sales
pomName=springcloud sales
pomVersion=1.0.0
springCloudVersion=Dalston.SR4
springBootVersion=1.5.6.RELEASE
javaVersion=1.8

# ---------- 框架配置 ----------
serviceName=spring-cloud-sales
port=2222
eurekaEnabled=true
eurekaUrl=http://localhost:1111/eureka/

  1. skeleton-description.xml

如上图所示,用来描述模界面驱动和渲染的组件,分为Group和Entity结构,一个Group包含多个Entity,其他属性比较容易理解,主要介绍如下
highlightable - 标识为高亮项,一般组件渲染成高亮方式,例如Label红色字体,提示使用者着重关注
defaultable - 标识为默认项,一般组件渲染成默认项方式,提示使用者可以不修改对应值
emptiable - 标识为留空项,一般组件渲染成留空项方式,提示使用者对应值可以为空
editable - 标识为不可编辑项,一般组件渲染成不可编辑项方式,如果false则把组件灰掉,提示使用者对应值不可编辑

示例Demo数据如下:

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
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
<?xml version="1.0" encoding="UTF-8"?>
<skeleton>
<!-- 工程基本配置 -->
<group>
<key>basic</key>
<label></label>
<description></description>
<entity>
<key>pomGroupId</key>
<label>Group</label>
<description></description>
<type>TEXTFIELD</type>
<highlightable>true</highlightable>
<defaultable>false</defaultable>
<emptiable>false</emptiable>
<editable>true</editable>
</entity>
<entity>
<key>pomArtifactId</key>
<label>Artifact</label>
<description></description>
<type>TEXTFIELD</type>
<highlightable>true</highlightable>
<defaultable>false</defaultable>
<emptiable>false</emptiable>
<editable>true</editable>
</entity>
<entity>
<key>moduleName</key>
<label>工程模块名</label>
<description>moduleName</description>
<note>【必改项】首字母必须小写,中间只允许出现“-”</note>
<type>TEXTFIELD</type>
<highlightable>true</highlightable>
<defaultable>false</defaultable>
<emptiable>false</emptiable>
<editable>true</editable>
</entity>
<entity>
<key>basePackage</key>
<label>上层包路径</label>
<description>basePackage</description>
<note>【必改项】该路径会作为所有Java代码的上层路径。moduleName、basePackage和projectType三者组合起来解析出相关目录和结构规则,例如moduleName=payment-ccb,basePackage=com.nepxion,projectType=server,那么工程名为payment-ccb-server,类路径为com.nepxion.payment.ccb.server
</note>
<type>TEXTFIELD</type>
<highlightable>true</highlightable>
<defaultable>false</defaultable>
<emptiable>false</emptiable>
<editable>true</editable>
</entity>
<entity>
<key>javaVersion</key>
<label>Java Version</label>
<description></description>
<type>COMBOBOX</type>
<options>1.8;1.7;1.6</options>
<highlightable>false</highlightable>
<defaultable>false</defaultable>
<emptiable>false</emptiable>
<editable>true</editable>
</entity>
</group>

<!-- 是否Docker化 -->
<group>
<key>docker-template</key>
<label>Docker模板</label>
<description></description>
<type>RADIO_GROUP</type>
<layout>HORIZONTAL</layout>
<entity>
<key>true</key>
<label></label>
<description></description>
<type>RADIO</type>
<value>false</value>
<highlightable>false</highlightable>
<defaultable>false</defaultable>
<emptiable>false</emptiable>
<editable>true</editable>
</entity>
<entity>
<key>false</key>
<label></label>
<description></description>
<type>RADIO</type>
<value>false</value>
<highlightable>false</highlightable>
<defaultable>false</defaultable>
<emptiable>false</emptiable>
<editable>true</editable>
</entity>
</group>

<!-- 应用类型 -->
<group>
<key>appType</key>
<label>应用类型</label>
<description></description>
<type>RADIO_GROUP</type>
<layout>HORIZONTAL</layout>
<entity>
<key>Spring Boot</key>
<label>Spring Boot</label>
<description></description>
<type>RADIO</type>
<value>false</value>
<highlightable>false</highlightable>
<defaultable>false</defaultable>
<emptiable>false</emptiable>
<editable>true</editable>
</entity>
<entity>
<key>Spring Cloud</key>
<label>Spring Cloud</label>
<note>Spring Cloud应用</note>
<description></description>
<type>RADIO</type>
<value>false</value>
<highlightable>false</highlightable>
<defaultable>false</defaultable>
<emptiable>false</emptiable>
<editable>true</editable>
</entity>
<entity>
<key>war</key>
<label>war应用</label>
<description></description>
<type>RADIO</type>
<value>false</value>
<highlightable>false</highlightable>
<defaultable>false</defaultable>
<emptiable>false</emptiable>
<editable>true</editable>
</entity>
</group>

<!-- Spring Cloud独立部署组件 -->
<group>
<key>sc-alone</key>
<label>Spring Cloud</label>
<description></description>
<type>RADIO_GROUP</type>
<layout>HORIZONTAL</layout>
<entity>
<key>独立组件</key>
<label>独立组件</label>
<description></description>
<type>RADIO</type>
<value>false</value>
<highlightable>false</highlightable>
<defaultable>false</defaultable>
<emptiable>false</emptiable>
<editable>true</editable>
</entity>
<entity>
<key>service-provider</key>
<label>服务提供者</label>
<description></description>
<type>RADIO</type>
<value>false</value>
<highlightable>false</highlightable>
<defaultable>false</defaultable>
<emptiable>false</emptiable>
<editable>true</editable>
</entity>
<entity>
<key>service-consumer</key>
<label>服务消费者</label>
<description></description>
<type>RADIO</type>
<value>false</value>
<highlightable>false</highlightable>
<defaultable>false</defaultable>
<emptiable>false</emptiable>
<editable>true</editable>
</entity>
</group>

<!-- web基础框架 -->
<group>
<key>basic-framework</key>
<label>基础框架</label>
<description>基础框架-1</description>
<type>CHECKBOX_GROUP</type>
<layout>HORIZONTAL</layout>
<entity>
<key>spring-mvc</key>
<label>Spring MVC</label>
<description>Spring MVC</description>
<type>CHECKBOX</type>
<highlightable>false</highlightable>
<defaultable>true</defaultable>
<emptiable>false</emptiable>
<editable>true</editable>
</entity>
<entity>
<key>Mybatis</key>
<label>Mybatis</label>
<description>Mybatis</description>
<type>CHECKBOX</type>
<highlightable>false</highlightable>
<defaultable>false</defaultable>
<emptiable>false</emptiable>
<editable>true</editable>
</entity>
</group>

<!-- Spring Cloud独立部署单选组件 -->
<group>
<key>sc-alone-radio</key>
<label>独立组件</label>
<description></description>
<type>RADIO_GROUP</type>
<layout>HORIZONTAL</layout>
<entity>
<key>eureka-server</key>
<label>Eureka Server</label>
<description></description>
<type>RADIO</type>
<value>false</value>
<highlightable>false</highlightable>
<defaultable>false</defaultable>
<emptiable>false</emptiable>
<editable>true</editable>
</entity>
<entity>
<key>zuul-server</key>
<label>Zuul Server</label>
<description></description>
<type>RADIO</type>
<value>false</value>
<highlightable>false</highlightable>
<defaultable>false</defaultable>
<emptiable>false</emptiable>
<editable>true</editable>
</entity>
<entity>
<key>sc-gateway</key>
<label>SC Gateway</label>
<description></description>
<type>RADIO</type>
<value>false</value>
<highlightable>false</highlightable>
<defaultable>false</defaultable>
<emptiable>false</emptiable>
<editable>true</editable>
</entity>
<entity>
<key>config-server</key>
<label>Config Server</label>
<description></description>
<type>RADIO</type>
<value>false</value>
<highlightable>false</highlightable>
<defaultable>false</defaultable>
<emptiable>false</emptiable>
<editable>true</editable>
</entity>
<entity>
<key>zipkin-server</key>
<label>Zipkin Server</label>
<description></description>
<type>RADIO</type>
<value>false</value>
<highlightable>false</highlightable>
<defaultable>false</defaultable>
<emptiable>false</emptiable>
<editable>true</editable>
</entity>
</group>

<!-- Spring Cloud可组合多选组件 -->
<group>
<key>sc-group-checkBox</key>
<label>可组合组件</label>
<description>Spring Cloud组件</description>
<type>CHECKBOX_GROUP</type>
<layout>HORIZONTAL</layout>
<entity>
<key>fegin</key>
<label>Fegin</label>
<description>Spring MVC</description>
<type>CHECKBOX</type>
<highlightable>false</highlightable>
<defaultable>false</defaultable>
<emptiable>false</emptiable>
<editable>true</editable>
</entity>
<entity>
<key>hystrix</key>
<label>hystrix</label>
<description>hystrix</description>
<type>CHECKBOX</type>
<highlightable>false</highlightable>
<defaultable>true</defaultable>
<emptiable>false</emptiable>
<editable>true</editable>
</entity>
<entity>
<key>ribbon</key>
<label>Ribbon</label>
<description>Ribbon</description>
<type>CHECKBOX</type>
<highlightable>false</highlightable>
<defaultable>false</defaultable>
<emptiable>false</emptiable>
<editable>true</editable>
</entity>
</group>
</skeleton>

2.4 Spring-cloud-CodeGen开发接口

根据配置文件进行界面驱动的元数据接口

1
2
@RequestMapping(value = "/getMetaData", method = RequestMethod.GET)
public List<SkeletonGroup> getMetaData()

返回JSON格式的文件,简单介绍一下格式:

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
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
[
{
"key": "basic",
"label": "",
"description": "",
"type": "NORMAL_GROUP",
"layoutType": "VERTICAL",
"entityList": [
{
"key": "pomGroupId",
"label": "Group",
"description": "",
"note": null,
"value": "cn.springcloud",
"type": "TEXTFIELD",
"options": null,
"highlightable": true,
"defaultable": false,
"emptiable": false,
"editable": true
},
{
"key": "pomArtifactId",
"label": "Artifact",
"description": "",
"note": null,
"value": "sales",
"type": "TEXTFIELD",
"options": null,
"highlightable": true,
"defaultable": false,
"emptiable": false,
"editable": true
},
{
"key": "moduleName",
"label": "工程模块名",
"description": "moduleName",
"note": "【必改项】首字母必须小写,中间只允许出现“-”",
"value": "sales",
"type": "TEXTFIELD",
"options": null,
"highlightable": true,
"defaultable": false,
"emptiable": false,
"editable": true
},
{
"key": "basePackage",
"label": "上层包路径",
"description": "basePackage",
"note": "【必改项】该路径会作为所有Java代码的上层路径。moduleName、basePackage和projectType三者组合起来解析出相关目录和结构规则,例如moduleName=payment-ccb,basePackage=com.nepxion,projectType=server,那么工程名为payment-ccb-server,类路径为com.nepxion.payment.ccb.server",
"value": "cn.springcloud",
"type": "TEXTFIELD",
"options": null,
"highlightable": true,
"defaultable": false,
"emptiable": false,
"editable": true
},
{
"key": "javaVersion",
"label": "Java Version",
"description": "",
"note": null,
"value": "1.8",
"type": "COMBOBOX",
"options": [
"1.8",
"1.7",
"1.6"
],
"highlightable": false,
"defaultable": false,
"emptiable": false,
"editable": true
}
]
},
{
"key": "docker-template",
"label": "Docker模板",
"description": "",
"type": "RADIO_GROUP",
"layoutType": "HORIZONTAL",
"entityList": [
{
"key": "true",
"label": "是",
"description": "",
"note": null,
"value": null,
"type": "RADIO",
"options": null,
"highlightable": false,
"defaultable": false,
"emptiable": false,
"editable": true
},
{
"key": "false",
"label": "否",
"description": "",
"note": null,
"value": null,
"type": "RADIO",
"options": null,
"highlightable": false,
"defaultable": false,
"emptiable": false,
"editable": true
}
]
},
{
"key": "appType",
"label": "应用类型",
"description": "",
"type": "RADIO_GROUP",
"layoutType": "HORIZONTAL",
"entityList": [
{
"key": "Spring Boot",
"label": "Spring Boot",
"description": "",
"note": null,
"value": null,
"type": "RADIO",
"options": null,
"highlightable": false,
"defaultable": false,
"emptiable": false,
"editable": true
},
{
"key": "Spring Cloud",
"label": "Spring Cloud",
"description": "",
"note": "Spring Cloud应用",
"value": null,
"type": "RADIO",
"options": null,
"highlightable": false,
"defaultable": false,
"emptiable": false,
"editable": true
},
{
"key": "war",
"label": "war应用",
"description": "",
"note": null,
"value": null,
"type": "RADIO",
"options": null,
"highlightable": false,
"defaultable": false,
"emptiable": false,
"editable": true
}
]
},
{
"key": "sc-alone",
"label": "Spring Cloud",
"description": "",
"type": "RADIO_GROUP",
"layoutType": "HORIZONTAL",
"entityList": [
{
"key": "独立组件",
"label": "独立组件",
"description": "",
"note": null,
"value": null,
"type": "RADIO",
"options": null,
"highlightable": false,
"defaultable": false,
"emptiable": false,
"editable": true
},
{
"key": "service-provider",
"label": "服务提供者",
"description": "",
"note": null,
"value": null,
"type": "RADIO",
"options": null,
"highlightable": false,
"defaultable": false,
"emptiable": false,
"editable": true
},
{
"key": "service-consumer",
"label": "服务消费者",
"description": "",
"note": null,
"value": null,
"type": "RADIO",
"options": null,
"highlightable": false,
"defaultable": false,
"emptiable": false,
"editable": true
}
]
},
{
"key": "basic-framework",
"label": "基础框架",
"description": "基础框架-1",
"type": "CHECKBOX_GROUP",
"layoutType": "HORIZONTAL",
"entityList": [
{
"key": "spring-mvc",
"label": "Spring MVC",
"description": "Spring MVC",
"note": null,
"value": null,
"type": "CHECKBOX",
"options": null,
"highlightable": false,
"defaultable": true,
"emptiable": false,
"editable": true
},
{
"key": "Mybatis",
"label": "Mybatis",
"description": "Mybatis",
"note": null,
"value": null,
"type": "CHECKBOX",
"options": null,
"highlightable": false,
"defaultable": false,
"emptiable": false,
"editable": true
}
]
},
{
"key": "sc-alone-radio",
"label": "独立组件",
"description": "",
"type": "RADIO_GROUP",
"layoutType": "HORIZONTAL",
"entityList": [
{
"key": "eureka-server",
"label": "Eureka Server",
"description": "",
"note": null,
"value": null,
"type": "RADIO",
"options": null,
"highlightable": false,
"defaultable": false,
"emptiable": false,
"editable": true
},
{
"key": "zuul-server",
"label": "Zuul Server",
"description": "",
"note": null,
"value": null,
"type": "RADIO",
"options": null,
"highlightable": false,
"defaultable": false,
"emptiable": false,
"editable": true
},
{
"key": "sc-gateway",
"label": "SC Gateway",
"description": "",
"note": null,
"value": null,
"type": "RADIO",
"options": null,
"highlightable": false,
"defaultable": false,
"emptiable": false,
"editable": true
},
{
"key": "config-server",
"label": "Config Server",
"description": "",
"note": null,
"value": null,
"type": "RADIO",
"options": null,
"highlightable": false,
"defaultable": false,
"emptiable": false,
"editable": true
},
{
"key": "zipkin-server",
"label": "Zipkin Server",
"description": "",
"note": null,
"value": null,
"type": "RADIO",
"options": null,
"highlightable": false,
"defaultable": false,
"emptiable": false,
"editable": true
}
]
},
{
"key": "sc-group-checkBox",
"label": "可组合组件",
"description": "Spring Cloud组件",
"type": "CHECKBOX_GROUP",
"layoutType": "HORIZONTAL",
"entityList": [
{
"key": "fegin",
"label": "Fegin",
"description": "Spring MVC",
"note": null,
"value": null,
"type": "CHECKBOX",
"options": null,
"highlightable": false,
"defaultable": false,
"emptiable": false,
"editable": true
},
{
"key": "hystrix",
"label": "hystrix",
"description": "hystrix",
"note": null,
"value": null,
"type": "CHECKBOX",
"options": null,
"highlightable": false,
"defaultable": true,
"emptiable": false,
"editable": true
},
{
"key": "ribbon",
"label": "Ribbon",
"description": "Ribbon",
"note": null,
"value": null,
"type": "CHECKBOX",
"options": null,
"highlightable": false,
"defaultable": false,
"emptiable": false,
"editable": true
}
]
}
]

下载脚手架Zip文件的接口,返回Zip文件的byte数组类型,Body的内容为src\main\resources\config\skeleton-data.properties

1
2
@RequestMapping(value = "/downloadBytes", method = RequestMethod.POST)
public byte[] downloadBytes(@RequestBody String config)

下载脚手架Zip文件的接口,返回Zip文件的ResponseEntity类型

1
2
@RequestMapping(value = "/downloadResponse", method = RequestMethod.POST)
public ResponseEntity<Resource> downloadResponse(@RequestBody String config)

2.5 前端运行

spring-cloud-codegen-ui采用Vue开发,本地开发调试,采用如下命令安装。

1
2
3
4
5
6
7
8
# install dependencies
npm install

# serve with hot reload at localhost:8081
npm run dev

# build for production with minification
npm run build
感谢您的阅读,本文由 许进沉思录-专注于互联网与中间件基础架构技术研究 版权所有。如若转载,请注明出处:许进沉思录-专注于互联网与中间件基础架构技术研究(http://xujin.org/ex/sc-codegen/
Spring initializr源码工程解析
基于Spring Cloud的几个自研微服务组件