代码生成器使用原理以及使用方法
版本号:1.0
二Ο二五年二月
目录
文档介绍
1.1编写目的
1.2文档范围
1.3读者对象
系统设计
2.1设计目标
2.2设计思路
2.3代码实现原理
使用方法
3.1如何使用
3.2如何修改?
对原程序的bug修改及简化
4.1 一个bug
4.2 Controler层三个if改成接口形式1->3
4.3引擎中几次替换修改为小的方法调用
4.4改进建议
文档介绍
1.1编写目的
1.让修改者了解代码执行过程,为未来可能的修改做准备。
2.让使用者了解怎么使用,需要输入哪些参数才能执行
1.2文档范围
代码模块组成,代码执行过程解析,先前代码的错误原因分析以及修改方法。
1.3读者对象
有一定java基础 知晓”类” ”注解”这些java内容以及使用方式。
系统设计
2.1设计目标
通用的代码生成器。有几个部分:
第一个部分:代码模板的生成。
第二个部分:webmodelvo参数构建。
第三部分:webmodelvo转为map。
第四部分:构建模板位置及目标位置。
第五部分:引擎实现。
2.2设计思路
代码生成器几乎代码都是是通过 `OnlineGeneratorController` 类开始执行的。正常使用时应当从浏览器端输入,下面介绍的是用main制作的样例输入。
1. 初始化 `onewebModelVo` 对象
WebModelVo onewebModelVo = OneMockWebModelVo.initWo();
作用
调用 `OneMockWebModelVo.initWo()` 方法,初始化一个 `WebModelVo` 对象 `onewebModelVo`。
这个对象通常是一个数据模型(DTO 或 VO),用于描述单表模型的结构。
`onewebModelVo` 包含 14 个字段,其中 11 个是 `String` 类型。
思路
通过模拟数据(Mock Data)生成一个单表模型的数据对象,为后续的代码生成提供输入。
---
2.初始化 `OnlineGeneratorController` 并设置模板引擎
OnlineGeneratorController onlineGeneratorController = new OnlineGeneratorController();
onlineGeneratorController.setFreemakerEngine(new FreemakerEngineImpl());
作用
创建 `OnlineGeneratorController` 的实例,用于控制代码生成的过程。
设置 `FreemakerEngineImpl` 作为模板引擎,用于解析和生成代码模板。
思路
`Freemaker` 是一个模板引擎,可以根据模板文件和数据模型生成代码。
这里通过 `setFreemakerEngine` 方法将 `FreemakerEngineImpl` 注入到 `OnlineGeneratorController` 中,以便后续使用。
---
3.生成单表模型的代码
onlineGeneratorController.codeGeneratesingletablewithouttree(onewebModelVo);
作用
调用 `codeGeneratesingletablewithouttree` 方法,传入 `onewebModelVo` 作为参数,生成单表模型的代码。
思路
`onewebModelVo` 描述了单表模型的结构,`codeGeneratesingletablewithouttree` 方法会根据这个结构生成对应的代码文件(如实体类、DAO、Service 等)。
4.初始化 `treewebModelVo` 对象
WebModelVo treewebModelVo = TreeMockWebModelVo.initWo();
作用
调用 `TreeMockWebModelVo.initWo()` 方法,初始化一个 `WebModelVo` 对象 `treewebModelVo`。
这个对象通常用于描述树形结构模型(如菜单、分类等)。
思路
通过模拟数据生成一个树形结构模型的数据对象,为后续的代码生成提供输入。
5.生成树形结构模型的代码
onlineGeneratorController.codeGeneratesingletablewithouttree(treewebModelVo);
作用
调用 `codeGeneratesingletablewithouttree` 方法,传入 `treewebModelVo` 作为参数,生成树形结构模型的代码。
思路
`treewebModelVo` 描述了树形结构模型的结构,`codeGeneratesingletablewithouttree` 方法会根据这个结构生成对应的代码文件。
6.初始化 `onetomanywebModelVo` 对象
WebModelVo onetomanywebModelVo = OneToManyMockWebModelVo.initWo();
作用
调用 `OneToManyMockWebModelVo.initWo()` 方法,初始化一个 `WebModelVo` 对象 `onetomanywebModelVo`。
这个对象通常用于描述一对多关系模型(如订单和订单项)。
思路
通过模拟数据生成一个一对多关系模型的数据对象,为后续的代码生成提供输入。
7.生成一对多关系模型的代码
onlineGeneratorController.codeGeneratesingletablewithouttree(onetomanywebModelVo);
作用
调用 `codeGeneratesingletablewithouttree` 方法,传入 `onetomanywebModelVo` 作为参数,生成一对多关系模型的代码。
思路
`onetomanywebModelVo` 描述了一对多关系模型的结构,`codeGeneratesingletablewithouttree` 方法会根据这个结构生成对应的代码文件。
---
总结
这段代码的核心思路是通过模拟数据生成不同类型的模型(单表模型、树形结构模型、一对多关系模型),然后调用 `OnlineGeneratorController` 的 `codeGeneratesingletablewithouttree` 方法生成对应的代码。
每个步骤的作用如下:
1. 初始化数据模型对象(`onewebModelVo`、`treewebModelVo`、`onetomanywebModelVo`)。
2. 设置模板引擎(`FreemakerEngineImpl`)。
3. 调用代码生成方法,根据不同的模型生成代码。
这种设计模式非常适合需要快速生成代码的场景,例如代码生成器、低代码平台等。
2.3代码实现原理
2.2中提到了设计思路以及在什么时候调用什么类什么方法,这些都是在main函数里能看到的 2.3将进入这些类和方法作进一步研究。
先顺着main往下看,WebModelVO是遇到的第一个类,里面的代码定义了一个名为 `WebModelVo` 的 Java 类,它是一个数据模型类(Value Object,VO),用于封装代码生成器所需的相关配置和数据。以下是对代码的详细解释:
1.类定义与注解
```java
@Slf4j
@Data
@SuperBuilder
@AllArgsConstructor
@NoArgsConstructor
@Component
public class WebModelVo implements Serializable {
@Slf4j
这是 Lombok 提供的注解,用于自动生成日志对象 `log`,方便在类中直接使用日志功能。
@Data
Lombok 注解,自动生成 `getter`、`setter`、`toString`、`equals` 和 `hashCode` 方法。
@SuperBuilder
Lombok 注解,支持继承的 Builder 模式,允许通过链式调用的方式创建对象。
@AllArgsConstructor 和 @NoArgsConstructor
分别生成全参构造函数和无参构造函数。
@Component
将该类标记为 Spring 的组件,使其可以被 Spring 容器管理。
implements Serializable
实现 `Serializable` 接口,表示该类的对象可以被序列化(例如存储到文件或通过网络传输)。
2.字段定义
2.1 基本字段
private String author = "demo"; // 作者名称,默认值为 "demo"
private String testmodulename = ""; // 测试模块名称
private String deploymodulename = ""; // 部署模块名称
private String testuserDefinePackage = ""; // 测试用户自定义包名
private String deployuserDefinePackage = ""; // 部署用户自定义包名
private EnumDeployWay enumDeployWay; // 部署方式枚举
这些字段用于存储代码生成器的配置信息,例如作者名称、模块名称、包名等。
部分字段有默认值(如 `author`),其他字段需要外部赋值。
2.2 客户端相关字段
@NotEmpty
@Length(min = 10, max = 50)
private String codefromClientGUID = UUID.randomUUID().toString(); // 客户端生成的唯一标识
```
-@NotEmpty
表示该字段不能为空。
@Length(min = 10, max = 50)
表示该字段的长度必须在 10 到 50 之间。
UUID.randomUUID().toString()
生成一个唯一的标识符,用于标识客户端请求。
2.3 输出目录字段
@NotNull
private String destinationOutPutDir; // 代码生成目录
@Length(min = 0, max = 100)
private String frontDestionOutPutDir; // 前端代码生成目录
@NotNull
表示该字段不能为 `null`。
@Length(min = 0, max = 100)
表示该字段的长度不能超过 100。
2.4 服务名称与包名
private String servicename = "service"; // 服务名称,默认值为 "service"
@Length(min = 5, max = 50)
private String packageName; // 包名,长度在 5 到 50 之间
servicename
表示服务名称,默认值为 `"service"`。
packageName
表示代码生成的包名,长度限制在 5 到 50 之间。
2.5 模型类型与表信息
private String jformType = "1"; // 表单类型,默认值为 "1"
@NotNull
private EnumModelType modeltype; // 模型类型枚举
@NotNull
@Valid
private TableVoDomain tableVoDomain; // 表信息对象
jformType
表示表单类型,默认值为 `"1"`。
EnumModelType
枚举类型,表示模型的类型(如单表模型、树形模型等)。
TableVoDomain
表示表信息的对象,使用 `@Valid` 注解表示需要对该对象进行嵌套验证。
3.设计思路
数据封装
`WebModelVo` 类封装了代码生成器所需的所有配置信息,包括作者、模块名称、包名、输出目录、模型类型等。
数据验证:
使用 Hibernate Validator 注解(如 `@NotEmpty`、`@NotNull`、`@Length`)对字段进行校验,确保数据的合法性。
默认值
部分字段(如 `author`、`servicename`、`jformType`)设置了默认值,简化了对象创建过程。
嵌套对象
通过 `TableVoDomain` 对象封装表信息,支持复杂数据结构的嵌套验证。
4.使用场景
代码生成器
该类用于代码生成器的配置管理,通过传入不同的 `WebModelVo` 对象,生成不同类型的代码(如单表模型、树形模型等)。
数据校验
通过 Hibernate Validator 注解,确保传入的数据合法,避免生成错误的代码。
Spring 集成
通过 `@Component` 注解,该类可以被 Spring 容器管理,方便在其他组件中注入和使用。
总结
`WebModelVo` 是一个用于代码生成器的数据模型类,封装了代码生成所需的配置信息,并通过注解实现了数据校验和默认值设置。它的设计简洁且易于扩展,适合用于代码生成器、低代码平台等场景。
OneMockWebMode.intWo()的使用
public static WebModelVo initWo() throws Exception{
WebModelVo wm = initWebModel();
setWebModelWithoutTree(wm);
return wm;
}//此方法在main第一个地方用到过 用于给别的变量赋值
//initWo 是一个静态方法,用于初始化并返回一个 WebModelVo 对象。
//该方法调用了两个辅助方法:initWebModel() 和 setWebModelWithoutTree(WebModelVo wm)。
这里的两个辅助方法不再作详细介绍 有兴趣可以观看 他们在同一个目录底下。
OnlineGeneratorController onlineGeneratorController=new OnlineGeneratorController();
onlineGeneratorController.setFreemakerEngine(new FreemakerEngineImpl());
这里创建了onlineGeneratorController这个变量并实例化 下文简称小o
第二行,帮助小o选择了FreemakerEngine接口底下的FreemakerEngineImpl这个类,小o里面的freemakerEngine变量接的就是FreemakerEngineImpl类了
注意!!!这个 FreemakerEngineImpl 类是一个基于 FreeMarker 模板引擎的代码生成器实现类。它的主要功能是根据模板文件和输入的数据模型(Map<String, Object>),生成目标代码文件,在模板路径和目标路径的地方用到了硬编码,直接移植有可能出错。
onlineGeneratorController.codeGeneratesingletablewithouttree(onewebModelVo)
从这一步,正式开始执行引擎作用
这段代码是一个 Spring Boot 控制器中的方法,用于根据传入的 `WebModelVo` 对象生成代码文件。它通过调用 `FreemakerEngine` 实现类(如 `FreemakerEngineImpl`)来处理 FreeMarker 模板,生成目标代码文件。以下是代码的详细解释:
1.方法签名
public Result<?> codeGeneratesingletablewithouttree(@RequestBody @Validated WebModelVo webModelVo) throws Exception
作用
这是一个 RESTful API 方法,用于处理 POST 请求。
接收一个 JSON 格式的请求体,并将其转换为 `WebModelVo` 对象。
使用 `@Validated` 注解对 `WebModelVo` 对象进行校验。
返回值
返回 `Result<?>` 对象,表示操作结果(成功或失败)。
2.方法逻辑
2.1 初始化模板路径
定义一个空字符串 `templatepath`,用于存储模板路径。
创建一个 `ExtTemplateLocaltion` 对象,用于管理模板路径。
2.2 初始化数据模型
创建一个 `Map<String, Object>` 对象 `map`,用于存储模板中需要替换的变量。
从 `webModelVo` 中获取模型类型(`enumModelType`),并根据模型类型设置不同的模板路径和数据模型。
2.3 根据模型类型处理不同场景
`default.one`(单表模型)
设置模板路径为单表模型的路径。
使用 `OneMapSet` 类生成数据模型(`map`)。
templatepath = "C:\\Users\\413448405\\Desktop\\codetemplateservice-master\\jeecg-boot\\jeecg-module-system\\jeecg-system-biz\\src\\main\\resources\\jeecg\\code-template-online\\default\\one\\java";
ParentMapSetFromWebModelVo oneMapSet = new OneMapSet();
oneMapSet.buildMap(map, webModelVo);
`default.tree`(树形结构模型)
设置模板路径为树形结构模型的路径。
使用 `TreeMapSet` 类生成数据模型(`map`)。
templatepath = "C:\\Users\\413448405\\Desktop\\codetemplateservice-master\\jeecg-boot\\jeecg-module-system\\jeecg-system-biz\\src\\main\\resources\\jeecg\\code-template-online\\default\\tree\\java";
new TreeMapSet().buildMap(map, webModelVo);
`default.onetomany`(一对多关系模型):
设置模板路径为一对多关系模型的路径。
使用 `OneToManyMapSet` 类生成数据模型(`map`),包括主表和子表的信息。
templatepath = "C:\\Users\\413448405\\Desktop\\codetemplateservice-master\\jeecg-boot\\jeecg-module-system\\jeecg-system-biz\\src\\main\\resources\\jeecg\\code-template-online\\erp\\onetomany\\java";
OneToManyMapSet om = new OneToManyMapSet();
om.buildMap(map, webModelVo);
om.buildSonTableMap(map, webModelVo);
om.buildSonTableColumnMap(map, webModelVo);
map.put("ftl_description", webModelVo.getTableVoDomain().getTableTxt());
2.4补充数据模型
向 `map` 中添加当前日期和格式化工具类:
map.put("currentDate", NonceUtils.nowformat());
map.put("Format", new SimpleFormat());
2.5设置生成文件的路径
创建一个 `ExtDestinationLocation` 对象,用于管理生成文件的目标路径。
设置实体名称和包名:
destinationLocation.setEntityname(webModelVo.getTableVoDomain().getEntityName());
destinationLocation.setEntitypackage(webModelVo.getPackageName());
如果 `webModelVo` 中包含测试模块名称,则使用测试模块名称作为包名:
if (webModelVo.getTestmodulename() != null) {
destinationLocation.setEntitypackage(webModelVo.getTestmodulename());
}
2.6 生成文件
调用 `freemakerEngine.processextenh` 方法,生成目标代码文件:
freemakerEngine.processextenh(map, templateLocaltion, destinationLocation);
2.7 返回结果
返回操作成功的消息:
return Result.ok("转换成功");
3. 代码中的关键点
模板路径
模板路径是硬编码的,建议将路径配置在配置文件中,便于维护和移植。
数据模型生成
根据不同的模型类型(单表、树形结构、一对多关系),调用不同的类(如 `OneMapSet`、`TreeMapSet`、`OneToManyMapSet`)生成数据模型。
文件生成
使用 `FreemakerEngine` 实现类(如 `FreemakerEngineImpl`)处理 FreeMarker 模板,生成目标代码文件。
使用方法
3.1如何使用
本程序的要点就在于FreemakerEngine这一部分,引擎有三个输入 分别是map,模板路径,目标路径,简单原理则为将map内容贴到模板上生成到目标路径上。调用OnlineGeneratorController 里的内容可以修改输入的map,更改templatepath可以变更模板位置,更改destinationLocation可以更新目标路径
3.2如何修改?
如果想增加模版类型,就新增一个类挂在Select接口下面,如图
如果想修改生成位置 在下图所示部分修改
destinationLocation类如图部分 修改路径(生成位置)
对原程序的bug修改及简化
4.1 一个bug
Bug位于FreemakerEngineImpl类中,原先代码实现生成结束后,tablename这一位置永远是null,经过debug发现在引擎部分tablenanme根本没有被添加到路径上,经过更改后tablename已经被添加,在图中if和else中用了两种方式,if中使用destinationLocation.getEntitypackage()方法从传入的参数找路径,else则是用String entitypackage = (String) map.get("tableName");直接去上一场map对象里去挖路径。
4.2 Controler层三个if改成接口形式1->3
把它改成接口类型 这样后续改进时候只需要新增类 而不需要在controller里面修改
以前输入方式是直接更改代码,更改为从浏览器输入更为合适。
图中红框为代替controller里if的部分
4.3引擎中几次替换修改为小的方法调用
4.4改进建议
用绝对路径非常不友好,不方便移植。