代碼生成器原理及實現-Python3版

前言

作爲開發人員,或多或少都會接觸過代碼生成器,而親自寫過代碼生成器的,可能就不會不少。本文以mysql爲例,py爲開發語言,講解代碼生成器原理及實現。java

定義

代碼生成器:經過讀取數據庫元數據,而後定製模板,使用模板引擎輸出自定義頁面或文件的工具node

關於數據庫元數據

元數據,是指定義數據結構的數據。那麼數據庫元數據就是指定義數據庫各種對象結構的數據 。下面以mysql爲例,說明獲取元數據的方式。python

查詢數據庫名稱爲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'
複製代碼

查詢數據庫名稱爲db_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 = 'tb_name'
複製代碼

查詢數據庫名稱爲db_name,以sys_開頭的表

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
複製代碼

經常使用命令說明

  1. 安裝指定庫
pip3 install requests -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com
複製代碼
  1. 生成依賴
pip3 freeze  > requirements.txt 
複製代碼
  1. 安裝依賴
pip install -r requirements.txt -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com
複製代碼

源碼地址

相關文章
相關標籤/搜索