Py小工具: .sql转JavaBean一步到位

  • Post author:
  • Post category:python

简介

  • 我一般数据表结构是用PowerDesigner来建, 建完就需要建Model也即一堆javaBean, 如果没有辅助工具挨个建要累死, 于是用python写了这样一个辅助小工具, 仅需复制下PowerDesigner中Preview中的sql语句, 然后双击下工具就直接生成出所有数据表的javaBean了

  • 效果如下

分析

  • 原理很简单, 解析SQL语句用了正则表达式, 将关键信息封装起来, 解析完返回后即可以进行拼凑成JavaBean了
  • SQL的解析如下, 其中get_tables即解析函数, 解析完最终返回一个Table对象的列表, 每张表对应一个Table对象, Table对象中有个Field列表, Field其实就是表里面的列
class Field:
    def __init__(self, name='', type='', comment=''):
        self.name = name
        self.type = type
        self.comment = comment
        self.is_not_null = False
        self.is_key = False
        self.is_auto_increase = False

    def __repr__(self):
        return "Field(name=%s, type=%s, comment=%s)" % (self.name, self.type, self.comment)

class Table:
    def __init__(self):
        self.name = ''
        self.comment = ''
        self.fields = []

    def __repr__(self):
        return "Table(name=%s, comment=%s, field=%s)" % (self.name, self.comment, repr(self.fields))


def get_tables(sql_text):
    """
    sql文本转Table对象列表
    :param sql_text: sql文本
    :return: list of Table
    """
    tables = []
    ret = re.findall(r'(create\stable\s(.+)[^(]+\(([^;]+)\);)', sql_text)
    for per_table_ret in ret:
        table_name = per_table_ret[1].replace('\r', '').replace('\n', '')
        table_body = per_table_ret[2]
        table_body_lines = list(map(lambda x: x.strip(), table_body.strip().splitlines()))
        new_table = Table()
        # 遍历( ... )里面的每一行
        key_names = []
        for line in table_body_lines:
            if 'primary key' in line:
                key_names.append(line[line.find('(') + 1:line.find(')')])
            if 'key ' not in line:
                ret_line = re.search(r'([\w_]+)\s+([^\s,]+)\s?(.*)', line)
                field_name = ret_line.group(1)
                field_type = ret_line.group(2)
                field_tail = ret_line.group(3)
                field_comment = '--'
                if 'comment ' in field_tail:
                    field_comment = re.search(r'[\w\s]+\'(.+)\'', line).group(1)
                new_field = Field(field_name, field_type, field_comment)
                if 'not null' in line:
                    new_field.is_not_null = True
                if 'auto_increment' in line:
                    new_field.is_auto_increase = True
                new_table.fields.append(new_field)
        # 处理primary key
        for per_field in new_table.fields:
            if per_field.name in key_names:
                per_field.is_key = True
        table_comment = 'null'
        ret_comment = re.search(
            r'alter\stable\s%s.+\'(.+)\'' % table_name.strip(), sql_text)
        if ret_comment is not None:
            table_comment = ret_comment.group(1)
        new_table.comment = table_comment
        new_table.name = table_name
        tables.append(new_table)
    return tables

  • 解析完得到Table的列表后, 剩下的就非常简单了, toString也好getter setter也好最终也仅仅是字符串的拼拼凑凑而已; 比较麻烦也就toString, 参照IDEA的toString格式的话, String类型在toString里面两边还挂着对单引号, 加上各种缩进转义啥的折腾起来有点乱. 代码如下
TO_STRING_TEMPLATE = """
    @Override
    public String toString() {{
        return {}
    }}

"""

def gen_tostring(class_name, typefield_list):
    """
    生成并返回tostring
    :param class_name
    :param typefield_list: 字段类型+名的元组列表 eg:[(int,id), (String,name), (Date,createTime)]
    :return: str
    """
    tostring = '\"' + class_name + '{\" +\n'
    tostring += '\t\t\"' + \
                typefield_list[0][1] + '=\" + ' + typefield_list[0][1] + ' +\n'
    typefield_list_ext_first = typefield_list[1:]
    for type_field in typefield_list_ext_first:
        single_quote_left = r"'" if type_field[0] == 'String' else ""
        single_quote_right = r" + '\''" if type_field[0] == 'String' else ""
        tostring += '\t\t\", ' + type_field[1] + '=' + single_quote_left + '\" + ' + type_field[
            1] + single_quote_right + ' + \n'
    tostring += "\t\t\'}\';"
    return TO_STRING_TEMPLATE.format(tostring)
  • 最终生成的toString效果如下:
@Override
    public String toString() {
        return "Job{" +
        "id=" + id +
        ", name='" + name + '\'' + 
        ", description='" + description + '\'' + 
        ", cronExpression='" + cronExpression + '\'' + 
        ", startTime='" + startTime + '\'' + 
        ", endTime='" + endTime + '\'' + 
        ", exeCount=" + exeCount + 
        ", maxExeCount=" + maxExeCount + 
        ", status='" + status + '\'' + 
        ", className='" + className + '\'' + 
        ", methodName='" + methodName + '\'' + 
        ", delayTime=" + delayTime + 
        ", intervalTime=" + intervalTime + 
        '}';
    }

  • 至于复制完直接双击就可以生成JavaBean, 这个则直接去拿剪贴板的数据然后判断是否是属于sql语句, 如果是则直接生成JavaBean

Ps

  • Sql2Bean本来给自己用的, 所以夹了点私货, 如多了@DescAnnotation注解等, 只要把Sql2Bean里面额IS_SIMBA变量置为False即可生成不带私货的JavaBean 🙂