作爲開發人員,或多或少都會接觸過代碼生成器,而親自寫過代碼生成器的,可能就不會不少。本文以mysql爲例,py爲開發語言,講解代碼生成器原理及實現。java
代碼生成器:經過讀取數據庫元數據,而後定製模板,使用模板引擎輸出自定義頁面或文件的工具node
元數據,是指定義數據結構的數據。那麼數據庫元數據就是指定義數據庫各種對象結構的數據 。下面以mysql爲例,說明獲取元數據的方式。python
SELECT t.table_catalog,t.table_schema,t.table_name,table_type FROM information_schema.TABLES t where t.table_schema='db_name'
複製代碼
SELECT t.table_catalog,t.table_schema,t.table_name,table_type FROM information_schema.TABLES t where t.table_schema='db_name' and t.table_name = 'tb_name'
複製代碼
SELECT t.table_catalog,t.table_schema,t.table_name,table_type FROM information_schema.TABLES t where t.table_schema='db_name' and t.table_name like 'sys_%'
複製代碼
經常使用字段說明mysql
字段 | 說明 |
---|---|
table_catalog | 數據表登記目錄 |
table_schema | 數據表所屬的數據庫名 |
table_name | 表名稱 |
table_type | 表類型 |
show table status where NAME='tb_name'
複製代碼
經常使用字段說明git
字段 | 說明 |
---|---|
name | 表名稱 |
comment | 註釋 |
select k.column_name from information_schema.table_constraints t
join information_schema.key_column_usage k
using (constraint_name,table_schema,table_name)
where t.constraint_type='PRIMARY KEY'
and t.table_schema='db_name' and t.table_name='tb_name'
複製代碼
SELECT t.table_schema,t.table_name,t.column_name,t.column_default,
t.is_nullable,t.data_type,t.character_maximum_length,t.numeric_precision,
t.numeric_scale,t.column_type,t.column_key, t.column_comment
FROM information_schema.columns t
WHERE t.table_schema = 'db_name' AND t.table_name = 'tb_name'
複製代碼
經常使用字段說明sql
字段 | 說明 |
---|---|
table_schema | 所屬的數據庫名 |
table_name | 表名稱 |
column_name | 列名 |
column_default | 默認值 |
is_nullable | 是否爲空(YES->是,NO->否) |
data_type | 數據類型(char/varchar/int/datetime等無長度說明的定義) |
character_maximum_length | 字符串類型定義的長度 |
numeric_precision | 數值類型整型部分 |
numeric_scale | 數值類型小數點部分 |
column_type | 相似這種char(36)/int(6)有長度的定義 |
column_key | 約束條件(PRI->主鍵約束,UNI->惟一約束,MUL能夠重複) |
column_comment | 字段註釋 |
元數據轉換即將元數據轉換爲更爲清晰的數據結構,以方便模板引擎。下面使用json結構描述轉換後的數據結構(單表樣例)。shell
{
"tableName": "tb_name", // 表名稱
"tableCameName": "tbName", // 表小駝峯名(由表名稱轉換)
"tableType": "TABLE", // 表類型
"tableAlias":"xxx", // 表別名(ui層輸入)
"remark": "表註釋", // 表註釋
"entityName": "TbName", // 實體類名稱(由表名稱轉換)
"className": "TbName", // java類名稱(由表名稱轉換)
"schema": "db_name", // 表所屬數據庫
"primaryKeys": [{ // 主鍵列
"columnName": "id", // 列名
"remark": "主鍵" // 字段註釋
... // 以下同columns
}],
"columns": [{ // 表全部列
"tableName":"tb_name", // 表名
"columnName": "id", // 列名
"propertyName":"id", // 屬性名
"primaryKey": true, // 是否爲主鍵
"foreignKey": false, // 是否爲外鍵(保留,還沒有實現)
"size": 10, // 對應長度
"decimalDigits": 0 , // 小數點部分
"nullable": false, // 是否爲空
"autoincrement": false, // 是否默認自增(保留,還沒有實現)
"defaultValue": '', // 默認值
"remark": "主鍵",
"javaType": "String", // java對應數據類型(保留,py不實現)
"fullJavaType": "java.lang.String", // 同上
"dataType":"varchar", // 字段數據類型
"bigDecimal": false, // 同上
"setterMethodName": "setId", /// java set方法
"getterMethodName": "getId", // java get 方法
"date": false, // 是否日期類型
"treeProperty": false // 是否爲id/parent_id模型(樹)
},{
"columnName": "name", // 列名
"propertyName":"name", // 屬性名
"primaryKey": false, // 是否爲主鍵
"foreignKey": false, // 是否爲外鍵(保留,還沒有實現)
"size": 64, // 對應長度
"decimalDigits": 0 , // 小數點部分
"nullable": false, // 是否爲空
"autoincrement": false, // 是否默認自增
"defaultValue": '', // 默認值
"remark": "名稱",
"javaType": "String", // java對應數據類型(保留,py不實現)
"fullJavaType": "java.lang.String", // 同上
"dataType":"varchar", // 字段數據類型
"bigDecimal": false, // 同上
"setterMethodName": "setId", /// java set方法 (由列名轉換)
"getterMethodName": "getId", // java get 方法 (由列名轉換)
"date": false, // 是否日期類型
"treeProperty": false // 是否爲id/parent_id模型(樹)
}]
}
複製代碼
java能夠考慮:Freemarker、Thymeleaf、Velocity數據庫
nodejs能夠考慮:ejs、art-templatejson
python能夠考慮:Jinja2bash
樣例配置,使用yaml
database:
driverClass: "driverClass" # jdbc驅動
url: "url" # 數據庫地址
dbName: "dbName" # 數據庫名稱
username: "username" # 用戶名
password: "password" # 密碼
basePackage: "com.xxx.modules" # 包名
targetProject: "E:\\mldong\\test\\" # 生成代碼目標目錄
moduleName: "sys" # 模塊名
tables:
- tableName: "tb_name" # 表名
tableAlias: "TbName" # 表別名
remark: "表註釋" # 表註釋
- tableName: "sys_%" # 以sys_開頭
templates:
- name: "實體類" # 模板名稱
selected: True # 是否選中,選中則會生成對應代碼
covered: True # 文件存在是否覆蓋
templateFile: "entity.ftl" # 模板文件名稱
targetPath: "{{basePackage}}\\{{moduleName}}\\entity\\" # 代碼生成目錄
targetFileName: "{table.className}}.java" # 生成文件名(同上須要佔位符,代碼中要轉換)
encoding: "utf-8" # 生成文件編碼
- name: "持久層類" # 模板名稱
selected: True # 是否選中,選中則會生成對應代碼
covered: True # 文件存在是否覆蓋
templateFile: "mapper.ftl" # 模板文件名稱
targetPath: "{{basePackage}\\{{moduleName}}\\mapper\\" # 代碼生成目錄
targetFileName: "{{table.className}}.java" # 生成文件名(同上須要佔位符,代碼中要轉換)
encoding: "utf-8" # 生成文件編碼
複製代碼
注意:爲了方便模板引擎使用模板數據,從新組裝了數據結構以下:
{
...config/app.yml // 配置文件數據,
table: {
"tableName": "tb_name", // 表名稱
"tableCameName": "tbName", // 表小駝峯名(由表名稱轉換)
... 其餘元數據轉換後的數據
}
}
複製代碼
├── config
└── app.yml # 配置文件
├── templates # 模板目錄
├── entity.ftl # 實體類模板
└── mapper.ftl # 持久層模板
├── main.py # py腳本
└── requirements.txt # 依賴庫
複製代碼
main.py
python main.py
複製代碼
pip3 install requests -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com
複製代碼
pip3 freeze > requirements.txt
複製代碼
pip install -r requirements.txt -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com
複製代碼