什么東東
用過mybatis的同學都知道,手工寫mapper和xml是一件很痛苦的事兒,幸好官方提供了Mybatis-Generator,但是這家伙生成的東西不開放不方便修改,而且項目中的代碼生成需求不只是數據訪問層,比如說view、service、controller,這些地方到處充斥着重復代碼,有什么好辦法了,反正我是見識少,只能自己動手了。
設計思路
簡單點,設計的思路簡單點,只有簡單別人才好上手。
- 1.利用模板引擎加載模型,渲染模板,生成文件。
- 2.模型由模型構建器加載,要內置mysql元數據作為模型,支持自定義其他模型構建器
- 3.模型和模板文件要分離,這樣模型可以重用到其他模板
- 4.模型和模板文件是一對多的關系,方面根據一個表生成po、mapper、service
- 5.支持一個模型批量生成,如數據庫表這種,不能每個表對應一個模型吧
先不要想那么多,就這些吧
使用方式設計
很多同學一上來就寫代碼,最后根據功能設計使用方式,我更傾向於先把使用方式設計好,俗話說好的開始是成功的一半。
- 代碼生成方式簡單點,那就 java -jar xxxx.jar吧,然后在ohmyzsh里配置一下alias就爽了。
- 配置文件用json 簡單好維護,文件名和路徑默認,支持修改。
- 發布包提供樣板,方便學習和使用。
好了,先YY一個配置文件,看看:
{
"modelBuilders": [
{
"name": "mysql", //模型構建器名稱要
"type": "db:mysql", //構建器類型
"configPath": "modelBuilders/mysql.json" //數據庫配置
}
],
"templates": [
{
"name": "beanClass",
"modelBuilderName": "mysql", //關聯的模型構建器name
"templateFilename": "beanClass.ftl",
"outputPath": "output/bean"
}
]
}
恩就這樣,是不是有點暈,我解釋一下:
- 1.首先我們的框架加載配置文件。
- 2.然后根據配置文件中的modelBuilders加載指定type的模型構建器
- 3.然后將configPath指定的配置文件傳給模型構建器,用於構建數據模型
- 4.框架根據配置文件中的templates中的每一個元素的modelBuilderName屬性去關聯已經構建好的模型構建器。
- 5.然后框架使用模型構建器構建Model,並根據templateFilename指定的模板文件進行渲染(使用freemarker)
- 6.輸出文件到outputPath
最終效果
github: https://github.com/BigMaMonkey/easygen
其實框架的代碼很簡單,重點還是設計好使用方式,簡單並可擴展,其實過程中還需要一些其他特性:
- 基於freemarker的模板語法,上手簡單
- 內置mysql、json模型構建器,並支持自定義
- 支持生成指定表、去掉表前綴、轉換大小寫等
- 支持模型與模板的一對多關系(模型與模板的分離)
- 支持List類型的模型,批量生成。
- 支持自定義文件名生成規則
- 支持自定義輸出路徑
- 支持模板自定義參數
以下示例演示了應用於mybatis的代碼生成使用。
1.首先下載easygen發布包 下載
解壓后,包含以下幾部分:
- easygen-1.0-SNAPSHOT.jar:這是easygen主程序,負責讀取配置文件並生成代碼
- config.json:這是easy主配置文件
- modelBuildrs:這里存放的是模型構建器的配置文件
- templates:這是里存放的是模板文件
- lib:這里存放的是easygen引用的第三方jar包
2.編寫主配置文件
目錄下的config.json為主配置文件, 發布包已經給出了一個比較完整的配置,包括型構建器配置和模板配置,包括生成bean、mapperclass、mapperxml、serviceInterface、serviceImpl、view、dbtojson(生成數據庫元數據)很簡單自己看配置和代碼就行了。。。
{
"modelBuilders": [
{
"name": "mysql", //構建器名稱要唯一
"type": "db:mysql", //構建器類型目前只支持mysql和json兩種
"configPath": "modelBuilders/mysql.json" //數據庫配置和生成表指定
},
{
"name": "json",
"type": "json",
"configPath": "modelBuilders/data.json" //與mysql構建器不同的是,這里直接是模型數據。
},
{
"name": "http",
"type": "custom", //自定義的構建器
"configPath": "modelBuilders/xxx.json", //這個json反序列化類型需要在IModelBuilder的泛型參數中指出。
"modelBuilderClassName": "org.BigMaMonkey.XXX.XXX" //自定義的構建器需要實現類,實現IModelBuilder借口
}
],
"templates": [
{
"name": "mapperXml",
"modelBuilderName": "json", //關聯的構建器名稱,不是類型
"templateFilename": "data.ftl", //ftl模板文件
"outputPath": "output/data", //輸出目錄,會自動遞歸創建目錄。
"outputFilenameRule": "data_{name}.xml", //輸出文件名規則,{}內變量為模型的字段field
"options": {} //自定義模板參數,可以在模板中使用,請自由發揮。
},
{
"name": "mapperXml",
"modelBuilderName": "mysql",
"templateFilename": "mapperXml.ftl",
"outputPath": "output/mapperXml",
"outputFilenameRule": "{upperCaseName}Mapper.xml",
"options": {
"mapperns": "org.bigmonkey.robot.mapper",
"pons": "org.bigmonkey.robot.entity.po"
}
},
{
"name": "beanClass",
"modelBuilderName": "mysql",
"templateFilename": "beanClass.ftl",
"outputPath": "output/bean",
"outputFilenameRule": "{upperCaseName}.java",
"options": {
"pons": "org.bigmonkey.robot.entity.po"
}
},
{
"name": "mapperClass",
"modelBuilderName": "mysql",
"templateFilename": "mapperClass.ftl",
"outputPath": "output/mapper",
"outputFilenameRule": "{upperCaseName}Mapper.java",
"options": {
"pons": "org.bigmonkey.robot.entity.po",
"mpns": "org.bigmonkey.robot.mapper"
}
},
{
"name": "serviceInterface",
"modelBuilderName": "mysql",
"templateFilename": "serviceInterface.ftl",
"outputPath": "output/service",
"outputFilenameRule": "I{simpleName}Service.java",
"options": {
"pons": "org.bigmonkey.robot.entity.po",
"itns": "org.bigmonkey.robot.service"
}
},
{
"name": "serviceImpl",
"modelBuilderName": "mysql",
"templateFilename": "serviceImpl.ftl",
"outputPath": "output/service",
"outputFilenameRule": "{simpleName}ServiceImpl.java",
"options": {
"pons": "org.bigmonkey.robot.entity.po",
"imns": "org.bigmonkey.robot.service.impl"
}
},
{
"name": "view",
"modelBuilderName": "mysql",
"templateFilename": "view.ftl",
"outputPath": "output/view",
"outputFilenameRule": "{name}view.vue",
"options": {}
},
{
"name": "db-to-json",
"modelBuilderName": "mysql",
"templateFilename": "dbtojson.ftl",
"outputPath": "output/json",
"outputFilenameRule": "{name}.json",
"options": {}
}
]
}
3.編寫模板
其實模板的編寫很簡單,你只需要掌握freemarker的ftl語法,以及基本的json知識就可以了。
這里只講解mybatis內置構建器的使用
3.1.首先是構建器配置
{
"name": "mysql", //構建器名稱要唯一
"type": "db:mysql", //構建器類型目前只支持mysql和json兩種
"configPath": "modelBuilders/mysql.json" //數據庫配置和生成表指定
}
type中db:mysql指定使用內置的mysql構建器,configPath指定構建器的配置文件,配置如下:
{
"dbUrl": "jdbc:mysql://localhost:3306/device_manage",
"driverClassName": "com.mysql.jdbc.Driver",
"username": "root",
"password": "root",
"tables": "sys_user,pub_dict" //用,分割指定生成的表名,也可以留空表示生成所有表
}
3.2.需要給出的是內置mysql構建器的模型結構,你才能在ftl中使用
{
"name": "sys_user", //原始表名
"upperCaseName": "SYS_User", //前綴大寫+首字符大寫表名,用於創建PO、Mapper等
"simpleName": "User", // 去掉前綴的表名,目前只支持_分割的表名,如sys_user
"pkgs": [
"java.util.Date" // 字段類型對應的Java包,import到java文件
],
"fields": [
{
"name": "name", //原始字段名
"upperCaseName": "Name", //首字母大寫字段名
"dataType": "12", // 字段類型值,對應 java.sql.Types中的枚舉值
"typeName": "VARCHAR", //字段數據庫類型,其他類型參見源碼:TableField.java
"columnSize": "32", //字段大小
"columnType": {
"javaType": "String", //對應的java類型
"pkg": null //基礎類型為null,不需要import
}
}
],
"primaryKey": {
//同field中的元素屬性
}
}
在ftl中模型的跟是model,例如你要在ftl中輸出一個表名${model.name}, 又或者是主鍵的名稱${model.primaryKey.name}
如果你在模板配置中設置了自定義模板參數options,請這樣使用它${options.xxx}
通過在outputFilenameRule中使用{XXX}可以引用model中根屬性,來自定義輸出文件名,如{upperCaseName}Mapper.java
4.最后使用方式相當簡單:
java -jar easygen-1.0-SNAPSHOT.jar
當然你也可以把代碼的執行集成到你自己的項目或工具:
public class App {
public static void main(String[] args) {
GeneratorManager generatorManager = new GeneratorManager();
try {
generatorManager.Start();
} catch (Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
}
}