Python 让繁琐工作自动化
原因每次写完 DDL SQL 再手动对应的 POJOs,太繁琐了,为什么不写个脚本自动化下呢(还可以顺带检测下自己算法能力),说干就干,这就来了。
WARNING ⚠:别学我,IDEA 有 DDL 一键生成 POJOs 插件,我丫的是 VSCode 党 o( ̄┰ ̄*)ゞ
python,粘贴即使用,真方便
"""
从 DDL SQL 生成 java POJO
- 列名即 java field 名,不做下划线、驼峰命名等转换
- 使用 Lombok 注解替换 setter/getter
"""
from typing import Dict, List
import re
MYSQL_DATATYPE_NUMBER = {'TINYINT', 'SMALLINT', 'MEDIUMINT', 'INT', 'INTEGER', 'BIGINT', 'FLOAT', 'DOUBLE', 'DECIMAL'}
MYSQL_DATATYPE_DATE = {'DATE', 'TIME', 'DATETIME', 'TIMESTAMP'}
MYSQL_DATATYPE_TEXT = {'CHAR', 'VARCHAR', 'TINYBLOB', 'TINYTEXT', 'BLOB', 'TEXT', 'MEDIUMBLOB', 'MEDIUMTEXT', 'LONGBLOB', 'LONGTEXT'}
POJO_TEMPLAATE = """package {package};
{imports}
import lombok.Data;
@Data
public class {name} {{
{fields}
}}"""
def __generate_pojo_text(package_name: str, class_name: str, columns: Dict[str,str]) -> str:
"""
生成 pojo 文本
"""
field_rows = []
import_rows = set()
field_template = "private {} {};"
for name, type in columns.items():
field_class = __sql_java_type_mapping(type)
if field_class == "BigDecimal":
import_rows.add("import java.math.BigDecimal")
elif "Local" in field_class:
import_rows.add("import java.time.{};".format(field_class))
field_row = field_template.format(field_class, name)
field_rows.append(field_row)
pojo_fill_data = {
'package': package_name,
'name': class_name.title(),
'imports': "\n".join(import_rows),
'fields': "\n ".join(field_rows)
}
return POJO_TEMPLAATE.format_map(pojo_fill_data)
def __sql_java_type_mapping(sql_type: str) -> str:
"""
sql java 数据类型映射
"""
if sql_type in MYSQL_DATATYPE_TEXT:
return "String"
if sql_type in MYSQL_DATATYPE_NUMBER:
MAPPING = {
"BIGINT": "String",
"FLOAT": "Float",
"DOUBLE": "Double",
"DECIMAL": "BigDecimal"
}
return MAPPING.get(sql_type, "Integer")
if sql_type in MYSQL_DATATYPE_DATE:
MAPPING = {
"DATE": "LocalDate",
"TIME": "LocalTime",
"DATETIME": "LocalDateTime",
"TIMESTAMP": "LocalDateTime"
}
return MAPPING.get(sql_type, "Object")
return "Object"
def __parse_ddl(sql: str) -> Dict[str, Dict[str, str]]:
"""
解析 ddl sql
"""
def find_brackets_content(text: str) -> str:
"""
找到 (...) 里的内容
"""
left_brackets = 0
start, end = 0,0
for i, e in enumerate(text):
if e == '(':
left_brackets += 1
if start == 0: start = i
elif e == ')':
left_brackets -= 1
if left_brackets == 0:
end = i
break
return text[start+1:end].strip()
table_blocks = re.split("create table", sql, flags=re.I)[1:]
tables = {} # name: column
for block in table_blocks:
table_name = block.split()[0]
columns = {} # name: type
columns_block = find_brackets_content(block)
for column_block in columns_block.split(','):
# column_block = column_block.strip()
words = column_block.split()
if not words or len(words) < 2: continue
type = words[1] if '(' not in words[1] else words[1][:words[1].index('(')]
type = type.upper()
if type in MYSQL_DATATYPE_DATE or type in MYSQL_DATATYPE_NUMBER or type in MYSQL_DATATYPE_TEXT:
columns[words[0]] = type
tables[table_name] = columns
return tables
def __write_file(path, context):
with open(path, "w", encoding="UTF-8") as f:
f.write(context)
def generate_pojo(sql: str, package_name: str, target: str='./') ->List[str]:
"""
从 ddl sql 生成对应的 java pojo 类文件
Args:
- sql: ddl sql 字符串或 sql文件路径(必须以.sql为后缀)
- package_name: 生成的 POJO 所在的包名
- target: POJO的生成路径,默认是当前路径
Return:
List[str]: 表示 pojos
"""
if sql.endswith('.sql'):
with open(sql, 'r', encoding='utf-8') as f:
sql = f.read()
tables = __parse_ddl(sql)
pojos = []
pojos_name = []
for table_name, columns in tables.items():
pojo = __generate_pojo_text(package_name, table_name, columns)
pojos.append(pojo)
pojos_name.append(table_name.title())
import os
for pojo, name in zip(pojos, pojos_name):
path = os.path.join(target, name + '.java')
with open(path, 'w', encoding='utf-8') as f:
f.write(pojo)
print("[info] - class {}.{} is generated".format(package_name, name))
print("[info] - success, {} classes were generated".format(len(pojos)))
return pojos
TEST_SQL = """DROP TABLE IF EXISTS book
CREATE TABLE book (
id int AUTO_INCREMENT PRIMARY KEY,
title varchar(100) NOT NULL,
author varchar(50) NOT NULL,
translator varchar(50) NULL,
publisher varchar(50) NOT NULL,
publish_date date NOT NULL,
price int NOT NULL,
isbn varchar(50) NOT NULL
)
"""
# 测试
def test():
package_name = "com.onemsg.pojo.test"
sql_path = 'db/schema.sql'
target = 'db'
pojos = generate_pojo(sql_path, package_name=package_name, target=target)
if __name__ == "__main__":
test()
db/schema.sql
DROP TABLE IF EXISTS book
CREATE TABLE book (
id int AUTO_INCREMENT PRIMARY KEY,
title varchar(100) NOT NULL,
author varchar(50) NOT NULL,
translator varchar(50) NULL,
publisher varchar(50) NOT NULL,
publish_date date NOT NULL,
price int NOT NULL,
isbn varchar(50) NOT NULL
)
DROP TABLE IF EXISTS person
CREATE TABLE person (
id int AUTO_INCREMENT PRIMARY KEY,
name varchar(50) NOT NULL,
gender tinyint NULL,
birthday datetime NULL,
address varchar(100) NULL,
phone char(13) NULL,
email varchar(50) NULL
)
def test():
package_name = "com.onemsg.pojo.test"
sql_path = 'db/schema.sql'
target = 'db'
pojos = generate_pojo(sql_path, package_name=package_name, target=target)