8

代码生成器原理

 3 years ago
source link: https://my.oschina.net/u/3658366/blog/4835273
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
代码生成器原理 - 猿敲月下码的个人空间 - OSCHINA - 中文开源技术交流社区

代码生成器原理很简单,用一句话概括就是:将数据库字段转换成Java字段并输出内容。

如下图所示:

输入图片说明

因此,首先需要做的是获取表信息以及表的字段信息,一般有两种方式,第一种:连接到数据库,执行相关SQL,查询出表结构信息。第二种:解析DDL,得到相关信息,code-gen采用第一种做法。

  • 获取表信息

包括表名称,表备注,Mysql可以使用下面这个SQL。(code-gen源码对应:com.gitee.gen.gen.mysql.MySqlTableSelector)

SHOW TABLE STATUS FROM table_name

如果需要指定某张表,直接加where条件即可

SHOW TABLE STATUS FROM table_name where name = 'user_info';

查询后结果如下:

Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment "user_info" "InnoDB" "10" "Dynamic" "0" "0" "16384" "0" "0" "0" "1" "2020-12-22 15:16:40"

"utf8_general_ci"

"用户信息表"

  • 获取表字段信息

Mysql可以用如下SQL(code-gen对应源码:com.gitee.gen.gen.mysql.MySqlColumnSelector):

SHOW FULL COLUMNS FROM  user_info;

查询后结果如下:

Field Type Collation Null Key Default Extra Privileges Comment "id" "int(11)"

"NO" "PRI"

"auto_increment" "select,insert,update,references" "自增主键" "name" "int(11)"

"NO"

"select,insert,update,references" "姓名" "create_time" "timestamp"

"NO"

"CURRENT_TIMESTAMP"

"select,insert,update,references" "添加时间"

从表格中,可以获取字段名称、类型、备注、是否主键、是否自增

查询出数据库的基本信息后,把这信息放到对象中,方便后续处理。

/**
 * 数据库表定义,从这里可以获取表名,字段信息
 */
public class TableDefinition {

    /**
     * 表名
     */
    private String tableName;

    /**
     * 表注释
     */
    private String comment;

    /**
     * 字段
     */
    private List<ColumnDefinition> columnDefinitions

    ... 省略 getter  setter

}

其中TableDefinition类存放表信息,ColumnDefinition类存放字段信息

接下来是将TableDefinition对象中的变量绑定到Velocity模板当中去。

VelocityContext context = new VelocityContext();

TableDefinition tableDefinition = ...

context.put("table", tableDefinition);
context.put("columns", tableDefinition.getColumnDefinitions());


return VelocityUtil.generate(context, template);

VelocityContext存放Velocity变量,在对象中放入两个变量table、columns,template是模板内容

然后再模板中就可以使用对应的变量了,对应的模板可以这么写:

/**
 * ${table.comment}
 */
public class ${context.javaBeanName} {

// Java字段信息
#foreach($column in $columns)
	/** ${column.comment} */
	private ${column.javaTypeBox} ${column.javaFieldName};
#end

// getter,setter部分
#foreach(${column} in ${columns})
	public void set${column.javaFieldNameUF}(${column.javaTypeBox} ${column.javaFieldName}) {
		this.${column.javaFieldName} = ${column.javaFieldName};
	}
	
	public ${column.javaTypeBox} get${column.javaFieldNameUF}() {
		return this.${column.javaFieldName};
	}
	
#end

}

得到生成结果后,把内容返回到前端页面。

处理多种数据库

如何处理多种数据库,这里的关键点是要获取数据库的表结构以及字段信息,每种数据库的获取SQL是不一样的,因此需要把获取表信息和获取字段信息抽象出来,然后让实际的数据库取实现抽象部分即可。

code-gen对应抽象类:

  • com.gitee.gen.gen.TableSelector 抽象类,用来获取表信息 子类:

    • com.gitee.gen.gen.mysql.MySqlTableSelector
    • com.gitee.gen.gen.oracle.OracleTableSelector
    • com.gitee.gen.gen.postgresql.PostgreSqlTableSelector
    • com.gitee.gen.gen.sqlserver.SqlServerTableSelector
  • com.gitee.gen.gen.ColumnSelector 抽象类,用来获取表字段信息 子类:

    • com.gitee.gen.gen.mysql.MySqlColumnSelector
    • com.gitee.gen.gen.oracle.OracleColumnSelector
    • com.gitee.gen.gen.postgresql.PostgreSqlColumnSelector
    • com.gitee.gen.gen.sqlserver.SqlServerColumnSelector

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK