代碼生成器使用原理以及使用方法
版本號: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改進建議
用絕對路徑非常不友好,不方便移植。