Spring Boot - 解决前后端Long类型数据传递失真问题

1、场景介绍

项目场景:目前市场上的大多数项目对于对象表建设的ID属性使用的是Long性并使用雪花算法生成,少量使用String的UUID,极少量的使用Long类型的自增长。

1.1 . Long型雪花算法ID

雪花算法 : 分布式id生成算法的有很多种,Twitter的SnowFlake就是其中经典的一种。

Spring Boot - 解决前后端Long类型数据传递失真问题_第1张图片

  • 优点:雪花算法id是一个64bits的Long数据,第一位为零表示其为正数,最后12位为其序列号,生成的id既能完美契合分布式ID的需求,同时后12位序列号也能够保证主键的有序性。

  • 缺点:雪花算法的长度是19(long型最多19位)位的,前端能够接收的数字最多只能是16位的,因此就会造成精度丢失,导致相关业务无法处理。

1.2  UUID

UUID : 是指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的。在UUID的算法中,可能会用到诸如网卡MAC地址,IP,主机名,进程ID等信息以保证其独立性。

  • 优点:UUID不是通过数据库的主键生成器生成的,在入库之前就能够获取到其主键,非常符合分布式主键的设计。

  • 缺点:UUID没有规律可循,无法保证主键的插入顺序型。且UUID在意外情况下(mac地址等其他生成UUID的因素相同的情况)可能会出现UUID相同。

1.3 自增Long型主键

  • 优点:自增主键保证了,插入数据的主键永远比已有的数据的主键大。(看不懂就去复习数据结构)

  • 缺点:需要等待插入完成才有主键,或者等待主键生成器返回才会有主键。不利于分布式的设计。

2、问题描述:

某次开发时前端直接给俺说ID传递到前端是失真了,俺一看果真如此,反应过来是ID过长导致失真,做个记录让遇到类似问题的小伙伴能够快速的解决。

错误如下:

Spring Boot - 解决前后端Long类型数据传递失真问题_第2张图片

3、原因分析

雪花算法生成的分布式ID长度为19位,前端JS接收数字能够达到的最大精度为16位,因此导致前端得到的ID不是真正的ID,导致后续操作无法进行。

4、解决方案

4.1 方案一

在相关需要转换的ID上加注解完成转换(需要在每一个res中的ID上加)

import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
@Data
public class BusinessTreeRes {

    /**
     * 方式一:JsonSerialize注解
     * 主键
     */
    @JsonSerialize(using = ToStringSerializer.class)
    private Long typeId;
}

4.2 在拦截器中加Long型数据转换方法(推荐使用)

@Configuration
@EnableWebMvc
public class InterceptorConfig implements WebMvcConfigurer {
    /**
     * 方式二:拦截器转换
     * web层统一处理Long转String问题
     * @param converters 需要转换的对象
     */
    public void extendMessageConverters(List> converters) {
        MappingJackson2HttpMessageConverter jackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
        ObjectMapper objectMapper = jackson2HttpMessageConverter.getObjectMapper();
        SimpleModule simpleModule = new SimpleModule();
        //将Long转为string 解决id过大 js显示问题
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
        objectMapper.registerModule(simpleModule);
        jackson2HttpMessageConverter.setObjectMapper(objectMapper);
        converters.add(0, jackson2HttpMessageConverter);
    }
}

4.3 自定义配置类

/**
 * 类型转换配置
 *
 * @author xiefei15
 * @version 1.0
 * @date 2020/6/5 15:20
 */
@Configuration
public class DataTypeConvertConfig{
    /**
     *
     * 方式三:采用objectMapper注入
     */
    @Bean
    public ObjectMapper objectMapper (Jackson2ObjectMapperBuilder builder) {
        ObjectMapper objectMapper = builder.createXmlMapper(false).build();
        SimpleModule simpleModule = new SimpleModule();
        // 直接将所有的Long类型转换为String
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        objectMapper.registerModule(simpleModule);
        return objectMapper;
    }
}

你可能感兴趣的:(#,Spring,Boot,spring,boot,Long类型,失真)