【排错日记】前端js接收Long丢失精度

一. 问题引出

前段时间上线遇到一个问题,TiDB表的主键使用的是bigint + auto_random,值类似于【2017612633061982209】,查询接口正常返回后,前端读取到的却是【2017612633061982000】,精度丢失了?  

二. 本质原因

 1. js数字的精度是有限的,Java的Long类型的数字超出了JavaScript的处理范围。
 2. 内部只有一种数字类型Number,双精度64位格式存储,即使整数也是如此。
 3. 最大的数值应该是2的53次方-1,十进制是【9007199254740991】,16位。

三. 怎么解决?

前端解决

在浏览器环境中,使用json-bigint库替换默认的JSON库,保证精度不丢失。详细细节留给前端解决了,这里不赘述。

后端解决

  • 方案1. 后端的ID(Long)转成(String), 前端使用String类型的ID。
/**
 * WebMvc配置
 */
@Configuration
@Slf4j
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
 
    /**
     *添加消息转化类
     * @param list
     */
    @Override
    public void configureMessageConverters(List> list) {
        MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
        ObjectMapper objectMapper = jsonConverter.getObjectMapper();
        //序列换成json时,将所有的long变成string
        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
        objectMapper.registerModule(simpleModule);
        list.add(jsonConverter);
    }
}
  • 方案2. 增加配置(全局的)
spring:
  jackson:
    generator:
      write_numbers_as_strings: true

优点:方便。
缺点:所有的数字都被转成字符串输出了,包括按照timestamp格式输出的时间,影响范围大。

  • 方案3. 使用注解(字段级别)
@JsonSerialize(using=ToStringSerializer.class)
private Long bankcardHash;

优点:可在字段级别调整。

缺点:涉及字段多的话,就特别繁琐,改动比较多。

  • 方案4:覆写类方法
@Bean("jackson2ObjectMapperBuilderCustomizer")
public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
    Jackson2ObjectMapperBuilderCustomizer customizer = new Jackson2ObjectMapperBuilderCustomizer() {
        @Override
        public void customize(Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder) {
            jacksonObjectMapperBuilder.serializerByType(Long.class, ToStringSerializer.instance)
                    .serializerByType(Long.TYPE, ToStringSerializer.instance);
        }
    };
    return customizer;
}

哪个解决方案好点?

抛出问题:总而言之,上面后端的方案可以全局解决Long转string的问题,但有些时候,前端是需要number类型的数据的,这个时候就只能单独再处理了。

????哪个方案?

四.结论

建议前端引入插件【json-bigint】解决Long精度损失的问题,永久解决问题。

五.参考

https://blog.csdn.net/xhdxhdxhd/article/details/109164469

你可能感兴趣的:(排错日记,前端,javascript,java)