?
问题分析及解决方案
由于该字段是有单选改为多选,该字段的历史数据的格式不是JSONArray形式,所以导致查询结果类型与实体类中不匹配。 解决方案(建议使用第一种,不影响历史数据):
一、修改该字段的历史数据为JSONArray类型;
update deal_base a set fund_type = concat('["', a.fund_type, '"]');
二、删除该字段的历史数据;
该问题产生的背景
该错误出现的情况:数据表中有一个字段是fund_type,该字段用于存储基金的类型。起初设计的是基金类型单选(下拉单选),后来发现多选更适合,因此就把web页面上的改字段改为了多选,从而导致出现JSONException。
起初是这样的:
??
后来变成这样的:
简述:
就是把下拉单选换成了下拉多选。在这里我把原来的实体类字段属性变成了JSONArray以便将整个数组存入到数据库中。
@ApiModelProperty(value = "基金类型Str", position = 300)
private String fundTypeStr;
@ApiModelProperty(value = "基金类型", position = 300)
private JSONArray fundType;
public String getFundTypeStr() {
return fundTypeStr;
}
public void setFundTypeStr(String fundTypeStr) {
this.fundTypeStr = fundTypeStr;
}
public JSONArray getFundType() {
return fundType;
}
public void setFundType(JSONArray fundType) {
this.fundType = fundType;
}
在这里有一步很重要,就是需要实现Mybatis的插件,用于String和JSONArray的转换。附插件代码(具体代码及作用网上都是,不赘述):
@MappedTypes(JSONArray.class)
@MappedJdbcTypes(JdbcType.VARCHAR)
public class JsonTypeHandler extends BaseTypeHandler<JSONArray> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, JSONArray parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i, String.valueOf(parameter.toJSONString()));
}
@Override
public JSONArray getNullableResult(ResultSet rs, String columnName) throws SQLException {
String sqlJson = rs.getString(columnName);
if (null != sqlJson){
return JSONObject.parseArray(sqlJson);
}
return null;
}
@Override
public JSONArray getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
String sqlJson = rs.getString(columnIndex);
if (null != sqlJson){
return JSONObject.parseArray(sqlJson);
}
return null;
}
@Override
public JSONArray getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
String sqlJson = cs.getString(columnIndex);
if (null != sqlJson){
return JSONObject.parseArray(sqlJson);
}
return null;
}
}
在dao.xml中也要注意使用自定义的Mybatis插件进行转换(否则会无法正常启动系统)。 在xml文件中,我使用的是resultMap,将JSONArray字段使用自定义插件匹配,如下(根据自己的情况二选一):
<resultMap id="BaseResultMapJSON" type="com.anxin.deal.warehousing.entity.DealFofWarehousing">
<result column="fundType" property="fundType" typeHandler="com.anxin.common.mybatis.JsonTypeHandler" />
</resultMap>
<resultMap id="BaseResultMapJSON" type="com.anxin.deal.warehousing.entity.DealFofWarehousing">
<result column="fund_type" property="fundType" typeHandler="com.anxin.common.mybatis.JsonTypeHandler" />
</resultMap>
定义了该resultMap后,要在有fundType的字段的方法返回类型中使用resultMap。如:
<select id="getById" parameterType="String" resultMap="BaseResultMapJSON">
select
id as id,
name as name,
deal_type as dealType,
fund_type as fundType,
create_time as createTime,
update_time as updateTime
from deal_fof_warehousing
where del_flag = '0' and id = #{id}
</select>
到此,大功告成!启动测试。
查看日志输出:
10:54:47.967 [http-nio-8088-exec-27] ERROR c.a.f.w.e.GlobalExceptionHandler - [handleException,84] - 错误代码:E380nested exception is org.apache.ibatis.executor.result.ResultMapException: Error attempting to get column 'fundType' from result set. Cause: com.alibaba.fastjson.JSONException: syntax error, expect [, actual error, pos 0, fieldName null
org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.executor.result.ResultMapException: Error attempting to get column 'fundType' from result set. Cause: com.alibaba.fastjson.JSONException: syntax error, expect [, actual error, pos 0, fieldName null
at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:77)
at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:446)
at com.sun.proxy.$Proxy120.selectList(Unknown Source)
at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:230)
at org.apache.ibatis.binding.MapperMethod.executeForMany(MapperMethod.java:139)
at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:76)
at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:59)
at com.sun.proxy.$Proxy162.findSonListByDept(Unknown Source)
at com.anxin.deal.base.service.DealBaseService.findList(DealBaseService.java:474)
at com.anxin.deal.base.service.DealBaseService$$FastClassBySpringCGLIB$$9ffc5dd9.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
?报错了: exception is org.apache.ibatis.executor.result.ResultMapException: Error attempting to get column 'fundType' from result set. Cause: com.alibaba.fastjson.JSONException: syntax error, expect [, actual error, pos 0, fieldName null,
从字面意思不难理解是获取到fundType字段的数据错误。
在数据库中查看该字段,发现该字段中有的值不是数组类型(历史数据的问题),所以导致数据获取异常。 只需要将不是数据的数据该成数组数据,或将不是数组的数据删除即可完美解决该问题!
希望能帮助各位小伙伴!若有其他更好的方案,可关注评论!
|