/** * Copyright (c) 2011-2017, James Zhan 詹波 (jfinal@126.com). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.jfinal.plugin.activerecord.generator; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import javax.sql.DataSource; import com.jfinal.kit.LogKit; import com.jfinal.kit.StrKit; /** * DataDictionary 数据字典生成器 */ public class DataDictionaryGenerator { protected DataSource dataSource; protected String dataDictionaryOutputDir; protected String dataDictionaryFileName = "_DataDictionary.txt"; public DataDictionaryGenerator(DataSource dataSource, String dataDictionaryOutputDir) { this.dataSource = dataSource; this.dataDictionaryOutputDir = dataDictionaryOutputDir; } public void setDataDictionaryOutputDir(String dataDictionaryOutputDir) { if (StrKit.notBlank(dataDictionaryOutputDir)) { this.dataDictionaryOutputDir = dataDictionaryOutputDir; } } public void setDataDictionaryFileName(String dataDictionaryFileName) { if (StrKit.notBlank(dataDictionaryFileName)) { this.dataDictionaryFileName = dataDictionaryFileName; } } public void generate(List<TableMeta> tableMetas) { System.out.println("Generate DataDictionary file ..."); System.out.println("Data Dictionary Output Dir: " + dataDictionaryOutputDir); rebuildColumnMetas(tableMetas); StringBuilder ret = new StringBuilder(); for (TableMeta tableMeta : tableMetas) { generateTable(tableMeta, ret); } writeToFile(ret); } protected void generateTable(TableMeta tableMeta, StringBuilder ret) { ret.append("Table: ").append(tableMeta.name); if (StrKit.notBlank(tableMeta.remarks)) { ret.append("\tRemarks: ").append(tableMeta.remarks); } 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"); } /* -----------+---------+------+-----+---------+---------------- Field | Type | Null | Key | Default | Remarks -----------+---------+------+-----+---------+---------------- id | int(11) | NO | PRI | NULL | remarks here */ protected void genCell(int columnMaxLen, String preChar, String value, String fillChar, String postChar, StringBuilder ret) { ret.append(preChar); ret.append(value); for (int i=0, n=columnMaxLen-value.length() + 1; i<n; i++) { ret.append(fillChar); // 值后的填充字符,值为 " "、"-" } ret.append(postChar); } protected String genSeparateLine(TableMeta tm) { StringBuilder ret = new StringBuilder(); genCell(tm.colNameMaxLen, "-", "---", "-", "+", ret); genCell(tm.colTypeMaxLen, "-", "---", "-", "+", ret); genCell("Null".length(), "-", "---", "-", "+", ret); genCell("Key".length(), "-", "---", "-", "+", ret); genCell(tm.colDefaultValueMaxLen, "-", "---", "-", "+", ret); genCell("Remarks".length(), "-", "---", "-", "", ret); ret.append("\n"); return ret.toString(); } protected void genTableHead(TableMeta tm, StringBuilder ret) { 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"); } protected void genColumn(TableMeta tableMeta, ColumnMeta columnMeta, StringBuilder ret) { 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(), " ", columnMeta.remarks, " ", "", ret); ret.append("\n"); } protected void rebuildColumnMetas(List<TableMeta> tableMetas) { Connection conn = null; try { conn = dataSource.getConnection(); DatabaseMetaData dbMeta = conn.getMetaData(); for (TableMeta tableMeta : tableMetas) { // 重建整个 TableMeta.columnMetas tableMeta.columnMetas = new ArrayList<ColumnMeta>(); // 通过查看 dbMeta.getColumns(...) 源码注释,还可以获取到更多 meta data ResultSet rs = dbMeta.getColumns(conn.getCatalog(), null, tableMeta.name, null); while (rs.next()) { ColumnMeta columnMeta = new ColumnMeta(); columnMeta.name = rs.getString("COLUMN_NAME"); // 名称 columnMeta.type = rs.getString("TYPE_NAME"); // 类型 if (columnMeta.type == null) { columnMeta.type = ""; } int columnSize = rs.getInt("COLUMN_SIZE"); // 长度 if (columnSize > 0) { columnMeta.type = columnMeta.type + "(" + columnSize; int decimalDigits = rs.getInt("DECIMAL_DIGITS"); // 小数位数 if (decimalDigits > 0) { columnMeta.type = columnMeta.type + "," + decimalDigits; } columnMeta.type = columnMeta.type + ")"; } columnMeta.isNullable = rs.getString("IS_NULLABLE"); // 是否允许 NULL 值 if (columnMeta.isNullable == null) { columnMeta.isNullable = ""; } columnMeta.isPrimaryKey = " "; String[] keys = tableMeta.primaryKey.split(","); for (String key : keys) { if (key.equalsIgnoreCase(columnMeta.name)) { columnMeta.isPrimaryKey = "PRI"; break; } } columnMeta.defaultValue = rs.getString("COLUMN_DEF"); // 默认值 if (columnMeta.defaultValue == null) { columnMeta.defaultValue = ""; } columnMeta.remarks = rs.getString("REMARKS"); // 备注 if (columnMeta.remarks == null) { columnMeta.remarks = ""; } if (tableMeta.colNameMaxLen < columnMeta.name.length()) { tableMeta.colNameMaxLen = columnMeta.name.length(); } if (tableMeta.colTypeMaxLen < columnMeta.type.length()) { tableMeta.colTypeMaxLen = columnMeta.type.length(); } if (tableMeta.colDefaultValueMaxLen < columnMeta.defaultValue.length()) { tableMeta.colDefaultValueMaxLen = columnMeta.defaultValue.length(); } tableMeta.columnMetas.add(columnMeta); } rs.close(); } } catch (SQLException e) { throw new RuntimeException(e); } finally { if (conn != null) { try {conn.close();} catch (SQLException e) {LogKit.error(e.getMessage(), e);} } } } /** * _DataDictionary.txt 覆盖写入 */ protected void writeToFile(StringBuilder ret) { FileWriter fw = null; try { File dir = new File(dataDictionaryOutputDir); if (!dir.exists()) { dir.mkdirs(); } String target = dataDictionaryOutputDir + File.separator + dataDictionaryFileName; fw = new FileWriter(target); fw.write(ret.toString()); } catch (IOException e) { throw new RuntimeException(e); } finally { if (fw != null) { try {fw.close();} catch (IOException e) {LogKit.error(e.getMessage(), e);} } } } }