扩展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,感谢分享