解决fastjson Long型精度损失问题
问题
简括:1.@JSONField不生效2.全局配置精度损失不生效
直接问题:使用fastjson @JSONField无法处理前端获取long型数据精度损失问题,无法全局配置fastjson的long型精度损失问题。
底层剖析:将springBoot默认使用的json转换器(Jackson)替换为阿里fastjson时,实现WebMvcConfigurer并重写configureMessageConverters方法的配置并未生效。
解决方法:直接向spring容器注册新的Bean
1.创建HttpMessageConvertersConfig类,并使用@Configuration标记(经测使用@Component也可以),使spring识别;配置fastjson long转string
@Configuration
public class HttpMessageConvertersConfig {
@Bean
public HttpMessageConverters fastJsonHttpMessageConverters() {
FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
FastJsonConfig fastJsonConfig = new FastJsonConfig();
SerializeConfig serializeConfig = SerializeConfig.globalInstance;
serializeConfig.put(Long.class, LongToStringSerializer.instance);
serializeConfig.put(Long.TYPE, LongToStringSerializer.instance);
fastJsonConfig.setSerializeConfig(serializeConfig);
fastConverter.setFastJsonConfig(fastJsonConfig);
HttpMessageConverter<?> converter = fastConverter;
return new HttpMessageConverters(converter);
}
}
2.创建LongToStringSerializer类,实现ObjectSerializer接口,重写write方法
public class LongToStringSerializer implements ObjectSerializer {
public static final LongToStringSerializer instance = new LongToStringSerializer();
@Override
public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features) throws IOException {
SerializeWriter out = serializer.out;
if (object == null) {
out.writeNull();
return;
}
if(object instanceof Long){
String strVal = object.toString();
out.writeString(strVal);
}
}
}
以上,为全局配置Long型转String,解决精度损失,如果想使用注解@JSONField,需要将注册的bean修改为以下配置(即去除long转string的配置内容),LongToStringSerializer类保留,在需要的Long型字段上加上@JSONField(serializeUsing = LongToStringSerializer.class)即可。
@Configuration
public class HttpMessageConvertersConfig {
@Bean
public HttpMessageConverters fastJsonHttpMessageConverters() {
FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
FastJsonConfig fastJsonConfig = new FastJsonConfig();
fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);
fastConverter.setFastJsonConfig(fastJsonConfig);
HttpMessageConverter<?> converter = fastConverter;
return new HttpMessageConverters(converter);
}
}
总结
之所以配置不生效、注解不能使用,根本问题其实都是因为Springboot默认会创建的MappingJackson2HttpMessageConverter转换器,而网上很多方法都是新建一个fastjson转换器,之后添加在列表后面,实际spring处理时,当有一个convert满足重写后,方法就直接返回了不会再交给下一个converter处理,因此之前自己写的convert并不能起作用。
所以我们应该直接修改springboot注册的MappingJackson2HttpMessageConverter 会使用到的ObjectMapper,或者自己注册一个MappingJackson2HttpMessageConverter bean,这样才能使自定义的转换器配置生效,本文即使用的是后者,前者的实现方法可以参考springboot2.0配置WebMvcConfigurer的configureMessageConverters方法不启用_小燃儿的博客-CSDN博客_configuremessageconverters。如果你想以更精准的粒度来控制那些Long型进行转换(比如只转换id类别的Long属性),请参考FastJson配置解决long类型在前端界面展示精度丢失问题_kangaroo的博客-CSDN博客_fastjson long的方法三,使用SerializeFilter。
他山之石
springboot2.0配置WebMvcConfigurer的configureMessageConverters方法不启用_小燃儿的博客-CSDN博客_configuremessageconverters
Springboot使用alibaba的fastJson,@JSONField不起作用的问题 - 穆晟铭 - 博客园 (cnblogs.com)
FastJson配置解决long类型在前端界面展示精度丢失问题_kangaroo的博客-CSDN博客_fastjson long
FastJson自定义全局序列化方式与源码解析_黄皮电耗子的博客-CSDN博客_fastjson全局自定义序列化
如有不当,欢迎指正