jfinal 支持mysql的json字段类型解决方案
目前使用的jfinal版本是4.2,mysql 版本是5.7,jar驱动版本mysql-connector-java-5.1.38.jar。默认对json类型的处理是当做字符串处理。即映射到BaseModel中对应的字段类型是String。如果希望实现映射到BaseModel中对应字段类型是JSON,则需要自行处理。解决方案如下:
思路:
- 确定射到BaseModel中对应的字段类型。这里我用的是com.alibaba.fastjson.JSON,这个可以根据项目需要定义。确定后就统一使用该类型映射json字段。
- 自动生成的BaseModel类映射json字段改为工具com.alibaba.fastjson.JSON。默认json字段生成的映射的类型是String。需要调整代码生成工具。
- 解决查询结果封装到Model对象时,映射正确的类型。
- 解决查询结果封装到Record对象时,映射正确的类型。
- 解决请求参数中json字符串封装到Model对象时,映射正确的类型。
- 解决执行保存或者更新sql时,com.alibaba.fastjson.JSON格式数据进行处理,保证sql顺利执行。
具体修改方案:
- 确定射到BaseModel中对应的字段类型。
com.alibaba.fastjson.JSON
- 调整代码生成工具。
这个需要分析源码,这里指贴出关键点。cm.javaType获取到映射的java类名称。
for (int i=1; i<=rsmd.getColumnCount(); i++) {ColumnMeta cm = new ColumnMeta();cm.name = rsmd.getColumnName(i);String typeStr = null;if("JSON".equals(rsmd.getColumnTypeName(i))) {typeStr = "com.alibaba.fastjson.JSON";}if (typeStr == null) {String colClassName = rsmd.getColumnClassName(i);typeStr = typeMapping.getType(colClassName);}if (typeStr == null) {int type = rsmd.getColumnType(i);if (type == Types.BINARY || type == Types.VARBINARY || type == Types.LONGVARBINARY || type == Types.BLOB) {typeStr = "byte[]";} else if (type == Types.CLOB || type == Types.NCLOB) {typeStr = "java.lang.String";} else {typeStr = "java.lang.String";}}cm.javaType = typeStr;
- 解决查询结果封装到Model对象时,映射正确的类型。
修改com.jfinal.plugin.activerecord.ModelBuilder类。


public class ModelBuilder {private static final Logger logger = Logger.getLogger("");public static final ModelBuilder me = new ModelBuilder();public final static int JSON = 2200;@SuppressWarnings({"rawtypes", "unchecked"})public <T> List<T> build(ResultSet rs, Class<? extends Model> modelClass) throws SQLException, ReflectiveOperationException, ParseException {List<T> result = new ArrayList<T>();ResultSetMetaData rsmd = rs.getMetaData();int columnCount = rsmd.getColumnCount();String[] labelNames = new String[columnCount + 1];int[] types = new int[columnCount + 1];buildLabelNamesAndTypes(rsmd, labelNames, types);while (rs.next()) {Model<?> ar = modelClass.newInstance();Map<String, Object> attrs = ar._getAttrs();for (int i=1; i<=columnCount; i++) {Object value;if (types[i] < Types.BLOB) {value = rs.getObject(i);} else {if (types[i] == Types.CLOB) {value = handleClob(rs.getClob(i));} else if (types[i] == Types.NCLOB) {value = handleClob(rs.getNClob(i));} else if (types[i] == Types.BLOB) {value = handleBlob(rs.getBlob(i));} else if (types[i] == JSON) {value = rs.getObject(i);if(value != null) {try {value = TypeConverter.me().convert(JSON.class, value.toString());} catch (ParseException e) {logger.error("转换失败!" + value, e);}}} else {value = rs.getObject(i);}}attrs.put(labelNames[i], value);}result.add((T)ar);}return result;}public void buildLabelNamesAndTypes(ResultSetMetaData rsmd, String[] labelNames, int[] types) throws SQLException {for (int i=1; i<labelNames.length; i++) {labelNames[i] = rsmd.getColumnLabel(i);types[i] = rsmd.getColumnType(i);//JSONString columnTypeName = rsmd.getColumnTypeName(i);if("JSON".equals(columnTypeName)) {types[i] = JSON;}}}
- 解决查询结果封装到Record对象时,映射正确的类型。
参考ModelBuilder的修改。修改com.jfinal.plugin.activerecord.RecordBuilder类。

- 解决请求参数中json字符串封装到Model对象时,映射正确的类型。
分析controller中封装Model的源码,比如 getBean(User.class,“”),

所以只需在TypeConverter中注册转换器就可以了。
新增JsonConverter
package com.jfinal.core.converter;import java.text.ParseException;import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;/**** 启动时注册转换器。 可以在JfinalServerConfig中注册,RegisterConverter.regist()* TypeConverter.me().regist(JSON.class, new JsonConverter());* @author xpl**/
public class JsonConverter implements IConverter<JSON>{/*** 数组返回 JSONArray,对象返回JSONObject* */@Overridepublic JSON convert(String s) throws ParseException {//不用考虑空值,调用前校验
// if(StrKit.isBlank(s)) {
// return null;
// }JSON json = (JSON) JSONObject.parse(s);return json;}}
然后再JfinalServerConfig中注册转换器:
TypeConverter.me().regist(JSON.class, new JsonConverter());
- 解决执行保存或者更新sql时,com.alibaba.fastjson.JSON格式数据进行处理,保证sql顺利执行。
修改com.jfinal.plugin.activerecord.dialect.MysqlDialect类。
/**** 对一些特殊值进行处理,否则会导致sql执行报错。比如JSON对象。2025-11-11* @param paras* @param val*/public void addPara(List<Object> paras, Object val) {if(val != null && val instanceof com.alibaba.fastjson.JSON) {paras.add( ((com.alibaba.fastjson.JSON)val).toJSONString() );}else {paras.add(val);}}




通过以上修改就可以实现了。
PS:前端查询结果改之前json字段返回的结果是字符串,修改后,返回的结果是json对象。这里需要注意一下。
