zoukankan      html  css  js  c++  java
  • 雪花算法ID在前端丢失精度解决方案

      首先说一下背景,目前笔者的工作是物联网方面的,设备有对应的智慧运营平台,平台开发中建表的主键用的是Mybatis plus默认的雪花算法来生成的,也就是分布式系统比较常用的雪花ID,技术栈就是常用的Spring boot+Spring could Alibaba,json工具用的是FastJson。

      在开发的过程中遇到了一个问题:前端接收到的数据在回传给后端的时候ID总是不对,仔细排查发现,前端接收到的数据的ID末尾两到三位数字都变成了0。雪花ID的长度是19位数字,系统在bean中的ID用的是Long类型,数据库建表用的是bigint,接收雪花ID自然没有问题,但是前端的number类型只能接收16位数字,准确的说是:2的53次方减1,即为9007199254740991,所以回传的ID不对是数字精度丢失的原因造成的。

      知道了原因,解决方案也很简单,后端传给前端时把ID转换位字符串类型,前端接收字符串就不会丢失精度了,前端把ID回传给后端的时候,Spring的反序列化会自动为我们转成Long类型,这么一来就解决问题了。针对这一思路,楼主想到了两种解决方案。

    1、@JsonSerialize注解

      JsonSerialize注解可以帮我们实现字段值的序列化和反序列话,@JsonSerialize(using = ToStringSerializer.class),代码如下:

    public class Device{
    
        @ApiModelProperty(value = "物联终端id")
        @TableId(type = IdType.ASSIGN_ID)
        @JsonSerialize(using = ToStringSerializer.class)
        private Long deviceId;
    
        ...  
    }

      在需要解决数字过长的字段上添加sonSerialize注解就可以完美解决这一问题,但是开发的时候一定要注意,万一漏掉很容易踩坑,所以在员工培训的时候一定要有所交待。

    2、过滤器

      过滤器是一种一劳永逸的方法,笔者的项目引入的是fastjson依赖,fastjson可以通过SerializeFilters定制序列化,非常方便,先上代码:

    package com.johanChan.app.config;
    
    import com.alibaba.fastjson.serializer.SerializerFeature;
    import com.alibaba.fastjson.serializer.ValueFilter;
    import com.alibaba.fastjson.support.config.FastJsonConfig;
    import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
    import org.apache.commons.lang3.StringUtils;
    import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.http.converter.HttpMessageConverter;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * @author JohanChan
     * @ProjectName Demo
     * @Description 与前端交互时对实体类中Long类型的ID字段序列号
     * @time 2021/6/23 11:30
     */
    @Configuration
    public class CustomFastJsonHttpMessageConverter {
        @Bean
        public HttpMessageConverters fastJsonHttpMessageConverters() {
            FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
            FastJsonConfig fastJsonConfig = new FastJsonConfig();
    
            List<SerializerFeature> list = new ArrayList<>();
            list.add(SerializerFeature.PrettyFormat);
            list.add(SerializerFeature.WriteMapNullValue);
            list.add(SerializerFeature.WriteNullStringAsEmpty);
            list.add(SerializerFeature.WriteNullListAsEmpty);
            list.add(SerializerFeature.QuoteFieldNames);
            list.add(SerializerFeature.WriteDateUseDateFormat);
            list.add(SerializerFeature.DisableCircularReferenceDetect);
            list.add(SerializerFeature.WriteBigDecimalAsPlain);
    
            fastJsonConfig.setSerializerFeatures(list.toArray(new SerializerFeature[list.size()]));
    
            fastConverter.setFastJsonConfig(fastJsonConfig);
            HttpMessageConverter<?> converter = fastConverter;
            fastJsonConfig.setSerializeFilters(new ValueFilter() {
                @Override
                public Object process(Object object, String name, Object value) {
                    /*if ((StringUtils.endsWith(name, "Id") || StringUtils.equals(name,"id")) && value != null
                            && value.getClass() == Long.class) {*/
                    if (value != null && value.getClass() == Long.class ) {
                        Long v = (Long) value;
                        if (v.toString().length() > 15) {
                            return String.valueOf(value);
                        }
                    }
                    return value;
                }
            });
            return new HttpMessageConverters(converter);
        }
    }

      在ValueFilter中自定义规则,long类型的变量值如果超过15位数则转化成字符串,前端的number类型可以接收16位数字,为什么不用16位判断呢?前面已经说过,前端虽然可以接收16位的数字,但最大是9007199254740991,如果用16位做判断,就会有漏网之鱼了。这种方法省心省力,基本上开发人员不需要再注意这种数字过大的问题,但是使用的时候也要有所考量,根据实际业务考虑系统中有没有其他需求需要用较长的数字,统一用过滤器会不会受到影响。

  • 相关阅读:
    C++ 复制控制之复制构造函数
    static关键字总结
    C++ 隐式类类型转换
    Unity 移动端触摸屏操作
    【原创】为什么要用规则引擎?
    【原创】你的Redis怎么持久化的
    【原创】JAVA中令人眼花撩乱的数字魔法
    【原创】谈谈redis的热key问题如何解决
    【原创】Mysql中事务ACID实现原理
    【原创】杂谈自增主键用完了怎么办
  • 原文地址:https://www.cnblogs.com/JohanChan/p/15141272.html
Copyright © 2011-2022 走看看