java 代码生成数据字典

交接项目要给数据字典,项目又是中途接手,本来就没有,设计的又没做。搞个小工具,方便一下。

 

原理:通过DataSource 来获取数据库和表信息,比sql来得方便而且面向多数据源(起码测试过几种数据库都没有问题)。


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.sql.DataSource;
import java.io.FileOutputStream;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * 数据字典生成器
 */
public class DataDictionaryCreateUtil {
    private final static DataDictionaryCreateUtil instance = new DataDictionaryCreateUtil();
    private static final Logger log = LoggerFactory.getLogger(DataDictionaryCreateUtil.class);

    public DataDictionaryCreateUtil() {
    }

    public static DataDictionaryCreateUtil getInstance() {
        return instance;
    }

    public static class DataDictionaryInfo {
        private String tableName;
        private String tableRemarks;
        private String columnName;
        private String columnRemarks;
        private boolean nullAble;
        private String dataTypeName;
        private String tableSchemaName;

        public String getTableSchemaName() {
            return tableSchemaName;
        }

        public void setTableSchemaName(String tableSchemaName) {
            this.tableSchemaName = tableSchemaName;
        }

        public String getTableName() {
            return tableName;
        }

        public void setTableName(String tableName) {
            this.tableName = tableName;
        }

        public String getTableRemarks() {
            return tableRemarks;
        }

        public void setTableRemarks(String tableRemarks) {
            this.tableRemarks = tableRemarks;
        }

        public String getColumnName() {
            return columnName;
        }

        public void setColumnName(String columnName) {
            this.columnName = columnName;
        }

        public String getColumnRemarks() {
            return columnRemarks;
        }

        public void setColumnRemarks(String columnRemarks) {
            this.columnRemarks = columnRemarks;
        }

        public boolean isNullAble() {
            return nullAble;
        }

        public void setNullAble(boolean nullAble) {
            this.nullAble = nullAble;
        }

        public String getDataTypeName() {
            return dataTypeName;
        }

        public void setDataTypeName(String dataTypeName) {
            this.dataTypeName = dataTypeName;
        }
    }

    /**
     * html模板body前缀
     */
    String templateHtmlPrefix = "\n" +
            "\n" +
            "\n" +
            "\n" +
            "\n" +
            "\n" +
            "\n";
    /**
     * html模板body后缀
     */
    String templateHtmlSuffix =
            "\n" +
            "";
    /**
     * html 内容表格模板前缀
     */
    String templateHtmlContentPrefix ="\n\n";
    /**
     * html 内容表格模板前缀
     */
    String templateHtmlContentSuffix ="
字段名是否必填数据类型注释
\n"; /** * html 内容表格模板 */ String templateHtmlContent = "%s%s%s%s\n"; /** * 获取数据库下面所有表 * @param dataSource * @param database * @return * @throws Exception */ public List getDatatable(DataSource dataSource,String database) throws Exception { Connection connection = dataSource.getConnection(); DatabaseMetaData metaData = connection.getMetaData(); ResultSet tables = metaData.getTables(null, database, "%", new String[]{"TABLE"}); List list = new ArrayList<>(); while (tables.next()) { // 根据指定列名称获取数据 String TABLE_NAME = tables.getString("TABLE_NAME"); list.add(TABLE_NAME); } return list; } /** * 保存表数据 * @param fileUrl * @param dataSource * @param database * @param tables * @throws Exception */ public void saveTables(String fileUrl, DataSource dataSource,String database, List tables) throws Exception { Connection conn = dataSource.getConnection(); ResultSet rs = null; StringBuffer sb = new StringBuffer(); try { for (String table : tables) { //表名备注 String tableNameRemark = null; List list = new ArrayList<>(); /** * 设置连接属性,使得可获取到列的REMARK(备注) */ DatabaseMetaData dbmd = conn.getMetaData(); rs = dbmd.getTables(null, database, table, null); while (rs.next()) { tableNameRemark = rs.getString("REMARKS"); //表类别(可能为空) } /** * 获取可在指定类别中使用的表列的描述。 * 方法原型:ResultSet getColumns(String catalog,String schemaPattern,String tableNamePattern,String columnNamePattern) * catalog - 表所在的类别名称;""表示获取没有类别的列,null表示获取所有类别的列。 * schema - 表所在的模式名称(oracle中对应于Tablespace);""表示获取没有模式的列,null标识获取所有模式的列; 可包含单字符通配符("_"),或多字符通配符("%"); * tableNamePattern - 表名称;可包含单字符通配符("_"),或多字符通配符("%"); * columnNamePattern - 列名称; ""表示获取列名为""的列(当然获取不到);null表示获取所有的列;可包含单字符通配符("_"),或多字符通配符("%"); */ rs = dbmd.getColumns(null, database, table, null); while (rs.next()) { DataDictionaryInfo dataDictionaryInfo = new DataDictionaryInfo(); String tableCat = rs.getString("TABLE_CAT"); //表类别(可能为空) String tableSchemaName = rs.getString("TABLE_SCHEM"); //表模式(可能为空),在oracle中获取的是命名空间,其它数据库未知 String tableName_ = rs.getString("TABLE_NAME"); //表名 String columnName = rs.getString("COLUMN_NAME"); //列名 int dataType = rs.getInt("DATA_TYPE"); //对应的java.sql.Types的SQL类型(列类型ID) String dataTypeName = rs.getString("TYPE_NAME"); //java.sql.Types类型名称(列类型名称) int columnSize = rs.getInt("COLUMN_SIZE"); //列大小 int decimalDigits = rs.getInt("DECIMAL_DIGITS"); //小数位数 int numPrecRadix = rs.getInt("NUM_PREC_RADIX"); //基数(通常是10或2) --未知 /** * 0 (columnNoNulls) - 该列不允许为空 * 1 (columnNullable) - 该列允许为空 * 2 (columnNullableUnknown) - 不确定该列是否为空 */ int nullAble = rs.getInt("NULLABLE"); //是否允许为null String remarks = rs.getString("REMARKS"); //列描述 String columnDef = rs.getString("COLUMN_DEF"); //默认值 int charOctetLength = rs.getInt("CHAR_OCTET_LENGTH"); // 对于 char 类型,该长度是列中的最大字节数 int ordinalPosition = rs.getInt("ORDINAL_POSITION"); //表中列的索引(从1开始) // String pkName = rs.getString("PK_NAME"); //主键名称 /** * ISO规则用来确定某一列的是否可为空(等同于NULLABLE的值:[ 0:'YES'; 1:'NO'; 2:''; ]) * YES -- 该列可以有空值; * NO -- 该列不能为空; * 空字符串--- 不知道该列是否可为空 */ String isNullAble = rs.getString("IS_NULLABLE"); /** * 指示此列是否是自动递增 * YES -- 该列是自动递增的 * NO -- 该列不是自动递增 * 空字串--- 不能确定该列是否自动递增 */ //String isAutoincrement = rs.getString("IS_AUTOINCREMENT"); //该参数测试报错 // log.info(GsonHelper.defaultGson().toJson(rs)); // System.out.println(tableCat + " - " + tableSchemaName + " - " + tableName_ + " - " + columnName + // " - " + dataType + " - " + dataTypeName + " - " + columnSize + " - " + decimalDigits + " - " // + numPrecRadix + " - " + nullAble + " - " + remarks + " - " + columnDef + " - " + charOctetLength // + " - " + ordinalPosition + " - " + isNullAble ); //表名 String tableName = tableName_; //SchemaName String SchemaName = tableSchemaName; //字段名 columnName; //是否必填 nullAble //数据类型 dataTypeName dataDictionaryInfo.setTableSchemaName(tableSchemaName); dataDictionaryInfo.setTableName(tableName); dataDictionaryInfo.setColumnName(columnName); if ("varchar".equals(dataTypeName)) { dataDictionaryInfo.setDataTypeName(dataTypeName + "(" + columnSize + ")"); } else { dataDictionaryInfo.setDataTypeName(dataTypeName); } dataDictionaryInfo.setNullAble(nullAble == 1); dataDictionaryInfo.setTableRemarks(tableNameRemark); dataDictionaryInfo.setColumnRemarks(remarks); // log.info(GsonHelper.defaultGson().toJson(dataDictionaryInfo)); list.add(dataDictionaryInfo); } if(list.size()==0){ log.error("找不到行参数:"+table); continue; } sb.append("

表名:" + list.get(0).getTableName() + "(" + tableNameRemark + ")" + ",模式:" + list.get(0).getTableSchemaName() + "

").append("\n"); sb.append(templateHtmlContentPrefix); for (DataDictionaryInfo dataDictionaryInfo : list) { sb.append(String.format(templateHtmlContent, dataDictionaryInfo.getColumnName(), !dataDictionaryInfo.nullAble ? "是" : "否", dataDictionaryInfo.getDataTypeName(), dataDictionaryInfo.getColumnRemarks() == null ? "" : dataDictionaryInfo.getColumnRemarks())).append("\n"); } sb.append(templateHtmlContentSuffix); sb.append("
").append("\n"); } } catch (SQLException ex) { ex.printStackTrace(); } finally { close(rs, conn); } String fileData = templateHtmlPrefix + sb.toString() + templateHtmlSuffix; saveFile(fileUrl, fileData); } /** * 保存文件 * @param fileUrl * @param data */ private void saveFile(String fileUrl, String data) { FileOutputStream fos = null; try { fos = new FileOutputStream(fileUrl + "/TempDataDictionary.html"); fos.write(data.getBytes()); fos.flush(); fos.close(); } catch (Exception e) { e.printStackTrace(); } } //关闭连接 public static void close(Object o) { if (o == null) { return; } if (o instanceof ResultSet) { try { ((ResultSet) o).close(); } catch (SQLException e) { e.printStackTrace(); } } else if (o instanceof Statement) { try { ((Statement) o).close(); } catch (SQLException e) { e.printStackTrace(); } } else if (o instanceof Connection) { Connection c = (Connection) o; try { if (!c.isClosed()) { c.close(); } } catch (SQLException e) { e.printStackTrace(); } } } public void close(ResultSet rs, Connection conn) { close(rs); close(conn); } }

使用方式:暂定3种(1、指定单个表来生成;2、指定多个表来生成;3、获取该数据库中的所有表),里面的DataSource自己看着办,普通的直接spring自动注入就好,多数据自己看着是用什么框架来动态切换。

        String handleType = (String) data.get("handleType");
        if (StringUtils.isEmpty(handleType)) {
            return ResponseResult.createFailResult("缺少操作类型", null);
        }

        String datasource = (String) data.get("datasource");
        if (StringUtils.isEmpty(datasource)) {
            return ResponseResult.createFailResult("缺少datasource", null);
        }


        String fileUrl = (String) data.get("fileUrl");
        if (StringUtils.isEmpty(fileUrl)) {
            return ResponseResult.createFailResult("缺少fileUrl", null);
        }
        //指定数据库
        String database = (String) data.get("database");
        if (StringUtils.isEmpty(database)) {
            return ResponseResult.createFailResult("缺少database", null);
        }
        List tables = new ArrayList<>();
        switch (handleType){
            case "one":
                //指定单个表来生成
                String datatable = (String) data.get("datatable");
                if (StringUtils.isEmpty(datatable)) {
                    return ResponseResult.createFailResult("缺少datatable", null);
                }
                tables.add(datatable);
                break;
            case "list":
                //指定多个表来生成
                String datatables = (String) data.get("datatables");
                if (StringUtils.isEmpty(datatables)) {
                    return ResponseResult.createFailResult("缺少datatables", null);
                }
                String[] tempList = datatables.split(",");
                if(tempList.length<1){
                    return ResponseResult.createFailResult("解析后的数据库列表为空", null);
                }
                tables.addAll(Arrays.asList(tempList));
                break;
            case "database":
                //获取该数据库中的所有表
                try {
                    DynamicDataSourceContext.set(datasource);
                    List tableList = DataDictionaryCreateUtil.getInstance().getDatatable(dataSource,database);
                    if(tableList==null||tableList.size()<1){
                        return ResponseResult.createFailResult("查询后发现该数据库下没有表", null);
                    }
                    tables.addAll(tableList);
                } catch (Exception e) {
                    e.printStackTrace();
                    return ResponseResult.createFailResult("操作失败:" + e.getMessage(), null);
                }
                break;
//            case "datasource":
//                //获取该数据源所有的数据库中的所有表
            default:
                return ResponseResult.createFailResult("没有对应的操作类型", null);
        }
        try {
             //多数据源切换
            DynamicDataSourceContext.set(datasource);
            DataDictionaryCreateUtil.getInstance().saveTables(fileUrl,dataSource,database,tables);
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseResult.createFailResult("操作失败:" + e.getMessage(), null);
        }

最终的界面(当然自己去改html,或者换一个方式显示也可以,主要这个不是给我自己看,懒得搞那么好看了哈)

java 代码生成数据字典_第1张图片

你可能感兴趣的:(知识点,java,数据库,数据字典)