使用 JFinal 自动生成数据库字段常量 —— 告别复制粘贴
在使用 JFinal 开发时,我们经常需要用到数据库表名和字段名,要么手动复制粘贴,要么定义常量,例如:
public interface UserFields {
String USER_ID = "user_id";
String USER_NAME = "user_name";
String LOGIN_TIME = "login_time";
}手动复制粘贴字段名、表名很难维护,一旦修改要大量改动代码;手动编写定义常量不仅繁琐,还容易出错——尤其是当字段名为 createTime、user_ageYear 等混合命名时,常量名到底该写成 CREATE_TIME 还是 USER_AGE_YEAR?复制粘贴更是效率低下。
现在给你分享一个小技巧:借助 JFinal 的代码生成器(Generator) + Enjoy 模板,我们可以一键自动生成标准的大写下划线常量名!
✅ 支持任意命名风格
无论你的数据库字段是:
标准下划线:
session_key驼峰命名:
userId混合风格:
user_ageYear、device_macAddress
都能自动转换为正确的常量名:
SESSION_KEYUSER_IDUSER_AGE_YEARDEVICE_MAC_ADDRESS
✅ 实现原理(JFinal代码生成器 + Enjoy 模板)
依赖:commons-lang3 3.18+,生成时间需要 hutool。
在你的 base_model_template.jf 中加入以下模板代码:
javapackage #(baseModelPackageName);
import com.jfinal.plugin.activerecord.Model;
import com.jfinal.plugin.activerecord.IBean;
/**
* Generated by JFinal, do not modify this file.
* #(cn.hutool.core.date.DateUtil::format(cn.hutool.core.date.LocalDateTimeUtil::now(), "yyyy-MM-dd HH:mm:ss"))
*/
#if (generateChainSetter)
@SuppressWarnings({"serial", "unchecked"})
#else
@SuppressWarnings("serial")
#end
public abstract class #(tableMeta.baseModelName)<M extends #(tableMeta.baseModelName)<M>> extends Model<M>
implements IBean {
//>>>>>>>>>>>>>>>>加入以下代码<<<<<<<<<<<<<<<<<
public interface #(tableMeta.modelName)Fields {
/** Table */
String TABLE_NAME = "#(tableMeta.name??)";
#for(cm : tableMeta.columnMetas)
#set(parts = cm.name.split("_"))
#set(tokens = [])
#for(part : parts)
#if(!part.isEmpty())
#set(camelParts = org.apache.commons.lang3.StringUtils::splitByCharacterTypeCamelCase(part))
#for(cp : camelParts)
#set(tokens.add(cp))
#end
#end
#end
#set(tokenArray = tokens.toArray())
#set(snakeName = org.apache.commons.lang3.StringUtils::join(tokenArray, '_'))
#set(upperSnake = snakeName.toUpperCase(java.util.Locale::ENGLISH))
#if (cm.remarks)
/** #(cm.name) : #(cm.remarks) */
#end
String #(upperSnake) = "#(cm.name)";
#end
}
//>>>>>>>>>>>>>>>>加入以上代码<<<<<<<<<<<<<<<<<
#set(b = generateChainSetter)
#for(cm : tableMeta.columnMetas)
#if (cm.remarks)
/** #(cm.remarks) */
#end
#set(argName = javaKeyword.contains(cm.attrName) ? '_' + cm.attrName : cm.attrName)
public #(b ? 'M' : 'void') set#(firstCharToUpperCase(cm.attrName))(#(cm.javaType) #(argName)) {
set("#(cm.name)", #(argName));
#if (b)
return (M)this;
#end
}
#if (cm.remarks)
/** #(cm.remarks) */
#end
#set(getterOfModel = getterTypeMap.get(cm.javaType))
#if (isBlank(getterOfModel))
#set(getterOfModel = 'get')
#end
public #(cm.javaType) get#(firstCharToUpperCase(cm.attrName))() {
return #(getterOfModel)("#(cm.name)");
}
#end
}在你的 model_template.jf 中加入以下模板代码(实现接口):
javapackage #(modelPackageName);
import #(baseModelPackageName).#(tableMeta.baseModelName);
import #(baseModelPackageName).#(tableMeta.baseModelName).#(tableMeta.modelName)Fields; //添加
/**
* Generated by JFinal, do not modify this file.
* #(cn.hutool.core.date.DateUtil::format(cn.hutool.core.date.LocalDateTimeUtil::now(), "yyyy-MM-dd HH:mm:ss"))
*/
@SuppressWarnings("serial")
public class #(tableMeta.modelName) extends #(tableMeta.baseModelName)<#(tableMeta.modelName)>
implements #(tableMeta.modelName)Fields { //添加实现代码
#if(generateDaoInModel)
public static final #(tableMeta.modelName) dao = new #(tableMeta.modelName)().dao();
#end
}💡 依赖说明:确保项目中已引入 commons-lang3 3.18+,生成时间需要 hutool。
🚀 使用效果
运行 Generator 后,自动生成:
public abstract class BaseUser<M extends BaseUser<M>> extends Model<M> implements IBean {
public interface UserFields {
/** Table */
String TABLE_NAME = "user";
/** id */
String ID = "id";
/** lastLoginIp */
String LAST_LOGIN_IP = "lastLoginIp";
/** user_ageYear */
String USER_AGE_YEAR = "user_ageYear";
}
/** ID */
public M setId(java.lang.Long id) {
set("id", id);
return (M)this;
}
/** ID */
public java.lang.Long getId() {
return getLong("id");
}
...
}
public class User extends BaseUser<User> implements UserFields {
public static final User dao = new User().dao();
}无需手动处理命名转换,彻底告别复制粘贴!
✅ 直接使用常量
然后你就可以在你需要的地方直接使用 类名.属性名:
System.out.println(User.TABLE_NAME); System.out.println(User.ID); System.out.println(User.LAST_LOGIN_IP); System.out.println(User.USER_AGE_YEAR);
✅ 优势总结
全自动:建完表,跑一次 Generator 即可
智能转换:正确处理驼峰、下划线、混合命名
零维护:表结构变更后重新生成即可同步,哪里引用出错一眼便能看到
类型安全:常量名与字段名严格一致,避免拼写错误
📌 小贴士
若项目未启用静态方法调用,需在 configEngine 中添加(jfinal代码生成器已自动加入,你自己写的要手动加入):
me.setStaticFieldExpression(true); //开启静态属性访问 me.setStaticMethodExpression(true); //开启静态方法调用
从此,字段常量自动生成,调用更是简单,只需 类名.属性名,开发效率翻倍!
JFinal 不仅快,还能让你写更少的代码,做更多的事。
我在 aifei-db 中是先创建了一个 Table 类,然后生成了针对它的初始化:
public static final Table TABLE = new Table(
"user",
"id",
new String[]{"id"},
User.class,
new HashMap>() {{
put("id", Integer.class);
}}
);
思路差不多,省去了启动时对数据库的读取与反射,启动速度仅为 300 毫秒。