1、场景
在日常的开发中,我们数据接口返回数据使用了FastJson序列化数据,当返回一个数据list时候出现" r e f " " ref" " ref"".data" 等类似乱码一样的数据,当时我比较匪夷所思,我写的代码这么完美,为什么会返回非正常数据数据呢?经过我多方查证,原来是FastJson框架自身的问题。
2、问题原因
使用FastJson的JSONArray类型作为返回数据,当像JSONArray对象中添加JSONObject对象,而JSONObject对象中包含相同的节点数据时,FastJson会防止返回数据栈溢出的问题,自动将JSONArray中相同的节点数据使用引用方式代替,即:{" r e f " : ref": ref":…[0]}
3、解决方案
强大的 FastJson 为我们提供了相关的配置参数来禁用循环引用
方法一:使用配置文件
**
* FastJson配置
*
* @author charles.yao
* @date 2023/8/8
**/
@Configuration
public class FastJsonConfiguration {
@Bean
public HttpMessageConverters getFastJSONHttpMessageConvert() {
// 定义一个转换消息的对象
FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
// 添加fastjson的配置信息 比如 :是否要格式化返回的json数据
FastJsonConfig fastJsonConfig = new FastJsonConfig();
// 修改配置返回内容的过滤
fastJsonConfig.setSerializerFeatures(
// 格式化输出
SerializerFeature.PrettyFormat,
// 消除循环引用
SerializerFeature.DisableCircularReferenceDetect,
// 返回结果保留null值
SerializerFeature.WriteMapNullValue,
// 将返回值为null的字符串转变成"",在这里可以自己设置
SerializerFeature.WriteNullStringAsEmpty,
// List字段如果为null,输出为[],而非null
SerializerFeature.WriteNullListAsEmpty
);
// 解决 SerializerFeature.WriteNullStringAsEmpty 不生效问题
ValueFilter valueFilter = (object, name, value) -> {
if (null == value){
value = "";
}
return value;
};
// 设置全局日期格式
fastJsonConfig.setDateFormat("yyyy-MM-dd HH:mm:ss");
// 注入过滤器
fastJsonConfig.setSerializeFilters(valueFilter);
// Long、BigDecimal 序列化时转 String
SerializeConfig serializeConfig = SerializeConfig.globalInstance;
serializeConfig.put(Long.class, ToStringSerializer.instance);
serializeConfig.put(Long.TYPE, ToStringSerializer.instance);
serializeConfig.put(BigDecimal.class, ToStringSerializer.instance);
// 在转换器中添加配置信息
fastJsonConfig.setSerializeConfig(serializeConfig);
fastConverter.setDefaultCharset(StandardCharsets.UTF_8);
fastConverter.setFastJsonConfig(fastJsonConfig);
// 解决中文乱码问题,相当于在Controller上的@RequestMapping中加了个属性produces = "application/json"
List<MediaType> mediaTypeList = new ArrayList<>();
mediaTypeList.add(MediaType.APPLICATION_JSON);
fastConverter.setSupportedMediaTypes(mediaTypeList);
return new HttpMessageConverters(fastConverter);
}
}
所有可选配置属性:
- SerializerFeature.PrettyFormat:格式化输出
- SerializerFeature.WriteMapNullValue:是否输出值为null的字段,默认为false
- SerializerFeature.DisableCircularReferenceDetect:消除循环引用
- SerializerFeature.WriteNullStringAsEmpty:将为null的字段值显示为""
- WriteNullListAsEmpty:List字段如果为null,输出为[],而非null
- WriteNullNumberAsZero:数值字段如果为null,输出为0,而非null
- WriteNullBooleanAsFalse:Boolean字段如果为null,输出为false,而非null
- SkipTransientField:如果是true,类中的Get方法对应的Field是transient,序列化时将会被忽略。默认为true
- SortField:按字段名称排序后输出。默认为false
- WriteDateUseDateFormat:全局修改日期格式,默认为false。JSON.DEFFAULT_DATE_FORMAT = “yyyy-MM-dd”;JSON.toJSONString(obj, SerializerFeature.WriteDateUseDateFormat);
- BeanToArray:将对象转为array输出
- QuoteFieldNames:输出key时是否使用双引号,默认为true
- UseSingleQuotes:输出key时使用单引号而不是双引号,默认为false(经测试,这里的key是指所有的输出结果,而非key/value的key,而是key,和value都使用单引号或双引号输出)
方法二(直接在返回数据禁止循环引用)
JSONArray jsonArrayUserNum = JSONArray.parseArray(JSON.toJSONString(resultJsonArr, SerializerFeature.DisableCircularReferenceDetect));