扩展MetaBuilder类,用于解决老项目中的数据库表没有主键,导致使用Generator生成Model类时报错的问题。
主要是重写MetaBuilder.build()方法,增加处理数据库表没有主键的那些表。
JFinal版本:3.4,之前分享的代码片段有bug,已解决
1. 重写类_MetaBuilder
/** * 扩展自定义 MetaBuilder * * @author Fancye * */ public class _MetaBuilder extends MetaBuilder { // protected String[] removedTableNamePrefixes = null;// 前缀 protected String[] removedTableNameSuffixes = null;// 后缀 protected String[] skipTableSuffixes = null; // public String[] getRemovedTableNamePrefixes() { // return removedTableNamePrefixes; // } // public void setRemovedTableNamePrefixes(String[] removedTableNamePrefixes) { // this.removedTableNamePrefixes = removedTableNamePrefixes; // } public String[] getRemovedTableNameSuffixes() { return removedTableNameSuffixes; } public void setRemovedTableNameSuffixes(String... removedTableNameSuffixes) { this.removedTableNameSuffixes = removedTableNameSuffixes; } public String[] getSkipTableSuffixes() { return skipTableSuffixes; } public void setSkipTableSuffixes(String... skipTableSuffixes) { this.skipTableSuffixes = skipTableSuffixes; } public _MetaBuilder(DataSource dataSource) { super(dataSource); } public List<TableMeta> build() { System.out.println("Build TableMeta ..."); try { conn = dataSource.getConnection(); dbMeta = conn.getMetaData(); List<TableMeta> ret = new ArrayList<TableMeta>(); buildTableNames(ret); for (TableMeta tableMeta : ret) { buildColumnMetas(tableMeta); buildPrimaryKeyIsNull(tableMeta); } return ret; } catch (SQLException e) { throw new RuntimeException(e); } finally { if (conn != null) try {conn.close();} catch (SQLException e) {throw new RuntimeException(e);} } } /** * 如果没有主键,使用所有字段作为联合主键 * @param tableMeta */ private void buildPrimaryKeyIsNull(TableMeta tableMeta) throws SQLException { ResultSet rs = dbMeta.getPrimaryKeys(conn.getCatalog(), null, tableMeta.name); String primaryKey = ""; int index = 0; while (rs.next()) { if (index++ > 0) { primaryKey += ","; } primaryKey += rs.getString("COLUMN_NAME"); } if (StrKit.isBlank(primaryKey)) { System.out.println(tableMeta.name + "表没有主键,使用以下字段作为联合主键"); String columns = ""; for (ColumnMeta cm : tableMeta.columnMetas) { // 使用表字段联合主键 // tableMeta.primaryKey += cm.attrName + ","; columns += cm.attrName + ","; } columns = columns.substring(0, columns.length() - 1); System.out.println(tableMeta.name + "[" + columns + "]"); tableMeta.primaryKey = columns; } else { tableMeta.primaryKey = primaryKey; } rs.close(); } /** * 构造 colName 所对应的 attrName,mysql 数据库建议使用小写字段名或者驼峰字段名 * Oralce 反射将得到大写字段名,所以不建议使用驼峰命名,建议使用下划线分隔单词命名法 */ protected String buildAttrName(String colName) { if (dialect instanceof OracleDialect) { colName = colName.toLowerCase(); } return uperToLowerCase(StrKit.toCamelCase(colName)); } /** * 构造 modelName,mysql 的 tableName 建议使用小写字母,多单词表名使用下划线分隔,不建议使用驼峰命名 * oracle 之下的 tableName 建议使用下划线分隔多单词名,无论 mysql还是 oralce,tableName 都不建议使用驼峰命名 */ protected String buildModelName(String tableName) { // 移除表名前缀仅用于生成 modelName、baseModelName,而 tableMeta.name 表名自身不能受影响 if (removedTableNamePrefixes != null) { for (String prefix : removedTableNamePrefixes) { if (tableName.startsWith(prefix)) { tableName = tableName.replaceFirst(prefix, ""); break; } } } if(removedTableNameSuffixes != null) { for (String suffix : removedTableNameSuffixes) { if (tableName.endsWith(suffix)) { tableName = tableName.substring(0, tableName.length() - suffix.length()); break; } } } // 将 oralce 大写的 tableName 转成小写,再生成 modelName if (dialect instanceof OracleDialect) { tableName = tableName.toLowerCase(); } return StrKit.firstCharToUpperCase(StrKit.toCamelCase(tableName)); } /** * 如果是oracle数据库,使用此方法覆盖源代码实现方式 */ // protected String buildModelName(String tableName) { // // 移除表名前缀仅用于生成 modelName、baseModelName,而 tableMeta.name 表名自身不能受影响 // if (removedTableNamePrefixes != null) { // for (String prefix : removedTableNamePrefixes) { // if (tableName.startsWith(prefix)) { // tableName = tableName.replaceFirst(prefix, ""); // break; // } // } // } // // // 将 oralce 大写的 tableName 转成小写,再生成 modelName // if (dialect instanceof OracleDialect) { // tableName = tableName.toLowerCase(); // } // // return StrKit.firstCharToUpperCase(StrKit.toCamelCase(tableName)); // } private String uperToLowerCase(String colName) { char[] arrays = colName.toCharArray(); if(Character.isUpperCase(arrays[0])) { return colName.toLowerCase(); } else { return colName; } } /** * 通过继承并覆盖此方法,跳过一些不希望处理的 table,定制更加灵活的 table 过滤规则 * 此处定制以某些后缀名(skipTableSuffixes)结束的table将不会处理 * @return 返回 true 时将跳过当前 tableName 的处理 */ protected boolean isSkipTable(String tableName) { boolean isSkip = false; if(skipTableSuffixes != null) { for(String suffix : skipTableSuffixes) { if (tableName.endsWith(suffix)) { isSkip = true; break; } } } return isSkip; } }
2. 在Model生成器主类中替换MetaBuilder
Generator gernerator = new Generator(getDataSource(), baseModelPackageName, baseModelOutputDir, modelPackageName, modelOutputDir); // 扩展自定义 MetaBuilder _MetaBuilder myMetaBuilder = new _MetaBuilder(getDataSource()); gernerator.setMetaBuilder(myMetaBuilder);
因为 model 是 Active Record 模式,这个模式的核心就是一个 model 对应一条数据库的 record,对应的起来的机制就是 “主键”, 失去主键就没有了这个机制,很多 API 自然就无法工作
当然,不排除有同学生成 model 后不使用那些 API,感谢分享