解决BigDecimal序列化科学计数法前端展示问题(大坑)

解决BigDecimal序列化科学计数法前端展示问题(大坑)

前言:在生产中出现一个问题,就是BigDecimal类型的字段在前端页面展示变成科学计数法,通过排查,发现里面的坑还是挺多的,所以特意记录下处理过程。Json序列化,不同项目中配置的都不一样,有些项目是使用springboot里面自带的jackson的,有些是使用fastjson处理,不同的序列化的处理方式也不一样。

1、fastJson对BigDecimal序列化和反序列化

字段返回完整的数字,避免科学计数法

我们看下JSON.toJSONString()的方法,我们可以看到,可以传进SerializerFeature的枚举

java 复制代码
public static String toJSONString(Object object, SerializerFeature... features) {
    return toJSONString(object, DEFAULT_GENERATE_FEATURE, features);
}

所以,我们这边传进WriteBigDecimalAsPlain枚举,就可以将数字完整返回

java 复制代码
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序列化配置中

java 复制代码
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());
    }
}
java 复制代码
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)

java 复制代码
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);
        }
    }
}
java 复制代码
@JSONField(serializeUsing = BigDecimalSerializer.class)
private BigDecimal logisticsPrice;//物流单价

2、jackson对BigDecimal序列化和反序列化

自定义序列化和反序列类,然后编写配置类

java 复制代码
public class BigDecimalSerializer extends JsonSerializer<BigDecimal> {
    @Override
    public void serialize(BigDecimal value, JsonGenerator gen, SerializerProvider serializerProvider) throws IOException {
        gen.writeString(value.stripTrailingZeros().toPlainString());
    }
}
java 复制代码
public class BigDecimalDeserializer extends JsonDeserializer<BigDecimal> {

    @Override
    public BigDecimal deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        return new BigDecimal(p.getValueAsString());
    }
}
java 复制代码
@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实现

java 复制代码
public class BigDecimalToStringSerializer extends JsonSerializer<BigDecimal> {

    @Override
    public void serialize(BigDecimal value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        gen.writeString(value.stripTrailingZeros().toPlainString());
    }
}

配置类中注册这个JsonSerializer:

java 复制代码
@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.1 jackson对BigDecimal转成字符串类型返回(局部处理)

第一步跟之前一样,自定义BigDecimalToStringSerializer序列化类,然后在某个字段上加上注解即可,@JsonSerialize(using = BigDecimalToStringSerializer.class)

java 复制代码
@JsonSerialize(using = BigDecimalToStringSerializer.class)
private BigDecimal rate;

3、总结

BigDecimal里面的坑还是挺多的,页面该类型字段科学计数法展示的话,我们要找清楚是什么原因,是后端返回有问题还是前端的问题,首先一定要保证后端返回的数据是正常完整的,不管是数字类型还是字符串类型。只要确保后端返回的数据是完整,剩下如果还有问题就可以协助前端一起排查处理了。

相关推荐
揣一尾游鱼yu37 分钟前
Spring上(IOC)笔记
java·笔记·spring·ioc
荣码1 小时前
长上下文与大文档处理:200页PDF怎么喂给AI,我踩了4个坑
java·python
极限挑战哥1 小时前
共享电单车联营平台分账架构实践:二清合规与自动分账零人工方案
java·大数据·人工智能·微信小程序·架构·微信公众平台
皮皮林5511 小时前
比 VMware 更快,更轻的虚拟机,横空出世!
java
Thomas.Sir2 小时前
第13课:MyBatis-Plus整合SpringBoot4.x,分页、条件查询、逻辑删除实战
java·spring boot
meiying88382 小时前
多快递公司快递单号批量查询接口怎么对接?Python 聚合查询实现
java·大数据·python
古法安卓2 小时前
Android-GPU压测工具
android·java·android studio
SL_staff3 小时前
10人团队如何用轻量私有化文档平台实现知识复用提效?技术视角拆解B/S架构下的协作闭环
java·开源·全栈
释厄6233 小时前
同性线套娃律——圆面积必然=1+2+...+n 的求和·圆心不与 π 相关
java·人工智能·算法·1024程序员节
猫猫.1534 小时前
IO、存储、硬盘、文件系统详细总结
java·java-ee