设计初衷

利用JFinal的代码生成可以为我们生成漂亮的数据字典。其格式类似Mysql的命令行,可见波总的用心。

Table: t_ad (广告表)
----------------+---------------------+------+-----+-------------------+---------
 Field          | Type                | Null | Key | Default           | Remarks 
----------------+---------------------+------+-----+-------------------+---------
 id             | INT UNSIGNED(10)    | NO   | PRI |                   | 主键id    
 ad_position_id | INT UNSIGNED(10)    | NO   |     | 0                 | 广告位id   
 title          | VARCHAR(64)         | NO   |     |                   | 广告标题    
 content        | VARCHAR(255)        | NO   |     |                   | 广告内容    
 media_type     | TINYINT UNSIGNED(2) | NO   |     | 0                 | 媒体类型    
 link           | VARCHAR(255)        | NO   |     |                   | 链接地址    
 image_url      | VARCHAR(255)        | NO   |     |                   | 图片地址    
 end_time       | DATETIME(19)        | NO   |     | CURRENT_TIMESTAMP | 结束时间    
 seq            | TINYINT(3)          | NO   |     | 0                 | 排序      
 enabled        | TINYINT UNSIGNED(2) | NO   |     | 1                 | 是否启用     
 creator        | VARCHAR(32)         | NO   |     |                   | 格式:创建者[id]
 updator        | VARCHAR(32)         | NO   |     |                   | 格式:创建者[id]
 create_time    | DATETIME(19)        | NO   |     | CURRENT_TIMESTAMP | 创建时间    
 update_time    | DATETIME(19)        | NO   |     | CURRENT_TIMESTAMP | 更新时间    
----------------+---------------------+------+-----+-------------------+---------

在实际工作中现在我们更多的是采用markdown格式的文档,研究一番可以发现JFinal生成的数据字典和markdown的Table比较类型。下面来看看我的改造过程。

改造数据字典格式

添加Druid链接参数

DruidPlugin druidPlugin = new DruidPlugin(jdbcUrl, user, password);
// remarks=true设置可以获取column remarks信息
// useInformationSchema=true设置可以获取tables remarks信息
druidPlugin.setConnectionProperties("useInformationSchema=true;remarks=true");
druidPlugin.start();
return druidPlugin.getDataSource();

重写DataDictionaryGenerator

import javax.sql.DataSource;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.generator.ColumnMeta;
import com.jfinal.plugin.activerecord.generator.TableMeta;

public class MyDataDictionaryGenerator extends com.jfinal.plugin.activerecord.generator.DataDictionaryGenerator {

	public DataDictionaryGenerator(DataSource dataSource, String dataDictionaryOutputDir) {
		super(dataSource, dataDictionaryOutputDir);
	}

	/**
	 * 重写掉生成换行
	 */
	@Override
	protected String genSeparateLine(TableMeta tm) {
		return "";
	}

	protected void generateTable(TableMeta tableMeta, StringBuilder ret) {
		ret.append("Table: ").append(tableMeta.name);
		if (StrKit.notBlank(tableMeta.remarks)) {
			ret.append("(").append(clearBlank(tableMeta.remarks)).append(")");
		}
		ret.append("\n");
		
		String sparateLine = genSeparateLine(tableMeta);
		ret.append(sparateLine);
		genTableHead(tableMeta, ret);
		ret.append(sparateLine);
		for (ColumnMeta columnMeta : tableMeta.columnMetas) {
			genColumn(tableMeta, columnMeta, ret);
		}
		ret.append(sparateLine);
		ret.append("\n");
	}

	/**
	 * 表头
	 */
	@Override
	protected void genTableHead(TableMeta tm, StringBuilder ret) {
		ret.append('\n').append('|');
		genCell(tm.colNameMaxLen, " ", "Field", " ", "|",  ret);
		genCell(tm.colTypeMaxLen, " ", "Type", " ", "|", ret);
		genCell("Null".length(), " ", "Null",  " ","|", ret);
		genCell("Key".length(), " ", "Key",  " ","|", ret);
		genCell(tm.colDefaultValueMaxLen, " ", "Default", " ", "|", ret);
		genCell("Remarks".length(), " ", "Remarks", " ", "|", ret);
		ret.append('\n').append('|');
		genCell(tm.colNameMaxLen, " ", "-", "-", "|",  ret);
		ret.replace(ret.length() - 2, ret.length() - 1, " ");
		genCell(tm.colTypeMaxLen, " ", "-", "-", "|", ret);
		ret.replace(ret.length() - 2, ret.length() - 1, " ");
		genCell("Null".length(), " ", "-",  "-","|", ret);
		ret.replace(ret.length() - 2, ret.length() - 1, " ");
		genCell("Key".length(), " ", "-",  "-","|", ret);
		ret.replace(ret.length() - 2, ret.length() - 1, " ");
		genCell(tm.colDefaultValueMaxLen, " ", "-", "-", "|", ret);
		ret.replace(ret.length() - 2, ret.length() - 1, " ");
		genCell("Remarks".length(), " ", "-", "-", "|", ret);
		ret.replace(ret.length() - 2, ret.length() - 1, " ");
		ret.append('\n');
	}

	/**
	 * 列
	 */
	@Override
	protected void genColumn(TableMeta tableMeta, ColumnMeta columnMeta, StringBuilder ret) {
		ret.append('|');
		genCell(tableMeta.colNameMaxLen, " ", columnMeta.name, " ", "|",  ret);
		genCell(tableMeta.colTypeMaxLen, " ", columnMeta.type, " ", "|", ret);
		genCell("Null".length(), " ", columnMeta.isNullable, " ", "|", ret);
		genCell("Key".length(), " ", columnMeta.isPrimaryKey, " ", "|", ret);
		genCell(tableMeta.colDefaultValueMaxLen, " ", columnMeta.defaultValue, " ", "|", ret);
		genCell("Remarks".length(), " ", clearBlank(columnMeta.remarks), " ", "|", ret);
		ret.append("\n");
	}
	
	/**
	 * 清除注释中的空白符
	 */
	private String clearBlank(String str) {
		return str.replaceAll("[ |\t|\n]+", "");
	}
}

配置新数据字典生成类

// 创建生成器
Generator generator = new Generator(dataSource, baseModelPackageName, baseModelOutputDir, modelPackageName, modelOutputDir);
DataDictionaryGenerator dg = new MyDataDictionaryGenerator(dataSource, modelOutputDir);
dg.setDataDictionaryFileName("数据字典.md");
generator.setDataDictionaryGenerator(dg);

到此大工搞成,迫不及待的看看效果展示了~

效果展示

Table: t_ad (广告表)

Field Type Null Key Default Remarks
id INT UNSIGNED(10) NO PRI   主键id
ad_position_id INT UNSIGNED(10) NO   0 广告位id
title VARCHAR(64) NO     广告标题
content VARCHAR(255) NO     广告内容
media_type TINYINT UNSIGNED(3) NO   0 媒体类型
link VARCHAR(255) NO     链接地址
image_url VARCHAR(255) NO     图片地址
end_time DATETIME(19) NO   CURRENT_TIMESTAMP 结束时间
seq TINYINT(3) NO   0 排序
enabled TINYINT UNSIGNED(3) NO   1  
creator VARCHAR(32) NO     格式:创建者[id]
updator VARCHAR(32) NO     格式:创建者[id]
create_time DATETIME(19) NO   CURRENT_TIMESTAMP 创建时间
update_time DATETIME(19) NO   CURRENT_TIMESTAMP 更新时间