作为开发人员,或多或少都会接触过代码生成器,而亲自写过代码生成器的,可能就不会不少。本文以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
复制代码