Java中BigDecimal序列化科学计数法前端展示问题踩坑实战
作者:小lee编程
前言:
在生产中出现一个问题,就是BigDecimal类型的字段在前端页面展示变成科学计数法,通过排查,发现里面的坑还是挺多的,所以特意记录下处理过程。Json序列化,不同项目中配置的都不一样,有些项目是使用springboot里面自带的jackson的,有些是使用fastjson处理,不同的序列化的处理方式也不一样。
1、fastJson对BigDecimal序列化和反序列化
字段返回完整的数字,避免科学计数法
我们看下JSON.toJSONString()的方法,我们可以看到,可以传进SerializerFeature的枚举
public static String toJSONString(Object object, SerializerFeature... features) { return toJSONString(object, DEFAULT_GENERATE_FEATURE, features); }
所以,我们这边传进WriteBigDecimalAsPlain枚举,就可以将数字完整返回
private static final SerializerFeature[] features = { SerializerFeature.WriteBigDecimalAsPlain}; public static String toString(Object data) { return JSON.toJSONString(data, features); }
PS: 大坑,我们可以发现这时候后端返回给前端是完整的数字,但是由于字段是数字类型,所以前端JS会把数字变成科学计数法展示,如下图展示,左边的数据是浏览器响应的数据,右边的数据是postman调用返回的数据,可以看到后端返回是没问题,但是由于前端JS的问题导致展示出现科学计数法。这时候,我们就需要考虑是不是返回给前端序列化成字符串类型返回。
1.1 fastJson对BigDecimal转成字符串类型返回(全局处理,推荐)
自定义序列化类实现ObjectSerializer接口重写里面write方法,并且把自定义序列化类放到fastJson序列化配置中
public class BigDecimalConfig implements ObjectSerializer { public static final BigDecimalConfig instance = new BigDecimalConfig(); @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; } out.writeString(((BigDecimal) object).stripTrailingZeros().toPlainString()); } }
public class JsonUtils { private static final SerializerFeature[] features = { SerializerFeature.WriteBigDecimalAsPlain }; private static final SerializeConfig serializeConfig = SerializeConfig.globalInstance; static { ParserConfig.getGlobalInstance().setAutoTypeSupport(true);//打开autotype功能 serializeConfig.put(BigDecimal.class, BigDecimalConfig.instance);//将BigDecimal转成字符串类型 } /** * 生成JSON字符串 */ public static String toString(Object data) { return JSON.toJSONString(data, serializeConfig, features);// 需要传入自定义的配置 } }
1.2 fastJson对BigDecimal转成字符串类型返回(局部特定处理)
由于项目前端历史问题,如果把BigDecimal类型的字段全部变成字符串类型,就有可能会引起其他问题,为了减少不必要的麻烦,特意搞了局部处理的方法,对某个字段做特殊处理。同样需要自定义序列化类实现ObjectSerializer接口重写里面write方法,然后在字段上加上序列化注解即可。@JSONField(serializeUsing = BigDecimalSerializer.class)
public class BigDecimalSerializer implements ObjectSerializer { @Override public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features) throws IOException { if (object == null) { serializer.out.writeNull(); return; } if (object instanceof BigDecimal) { // 将BigDecimal转换为字符串形式 serializer.write(((BigDecimal) object).stripTrailingZeros().toPlainString()); } else { // 非BigDecimal类型,使用默认序列化方式 serializer.write(object); } } }
@JSONField(serializeUsing = BigDecimalSerializer.class) private BigDecimal logisticsPrice;//物流单价
2、jackson对BigDecimal序列化和反序列化
自定义序列化和反序列类,然后编写配置类
public class BigDecimalSerializer extends JsonSerializer<BigDecimal> { @Override public void serialize(BigDecimal value, JsonGenerator gen, SerializerProvider serializerProvider) throws IOException { gen.writeString(value.stripTrailingZeros().toPlainString()); } }
public class BigDecimalDeserializer extends JsonDeserializer<BigDecimal> { @Override public BigDecimal deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { return new BigDecimal(p.getValueAsString()); } }
@Configuration public class JacksonConfig { @Bean public Jackson2ObjectMapperBuilder jacksonBuilder() { Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder(); builder.modules(new SimpleModule().addSerializer(BigDecimal.class, new BigDecimalSerializer()) .addDeserializer(BigDecimal.class, new BigDecimalDeserializer())); return builder; } }
2.1 jackson对BigDecimal转成字符串类型返回(全局处理)
自定义Jackson的JsonSerializer
实现
public class BigDecimalToStringSerializer extends JsonSerializer<BigDecimal> { @Override public void serialize(BigDecimal value, JsonGenerator gen, SerializerProvider serializers) throws IOException { gen.writeString(value.stripTrailingZeros().toPlainString()); } }
配置类中注册这个JsonSerializer
:
@Configuration public class JacksonConfig { // @Bean // public Jackson2ObjectMapperBuilder jacksonBuilder() { // Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder(); // builder.modules(new SimpleModule().addSerializer(BigDecimal.class, new BigDecimalSerializer()) // .addDeserializer(BigDecimal.class, new BigDecimalDeserializer())); // return builder; // } @Bean public ObjectMapper objectMapper() { ObjectMapper objectMapper = new ObjectMapper(); SimpleModule module = new SimpleModule(); module.addSerializer(BigDecimal.class, new BigDecimalToStringSerializer()); objectMapper.registerModule(module); return objectMapper; } }
2.2 jackson对BigDecimal转成字符串类型返回(局部处理)
第一步跟之前一样,自定义BigDecimalToStringSerializer序列化类,然后在某个字段上加上注解即可,@JsonSerialize(using = BigDecimalToStringSerializer.class)
@JsonSerialize(using = BigDecimalToStringSerializer.class) private BigDecimal rate;
3、总结
BigDecimal里面的坑还是挺多的,页面该类型字段科学计数法展示的话,我们要找清楚是什么原因,是后端返回有问题还是前端的问题,首先一定要保证后端返回的数据是正常完整的,不管是数字类型还是字符串类型。只要确保后端返回的数据是完整,剩下如果还有问题就可以协助前端一起排查处理了。
到此这篇关于Java中BigDecimal序列化科学计数法前端展示问题踩坑实战的文章就介绍到这了,更多相关BigDecimal序列化科学计数法前端展示内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!