• Long类型雪花算法ID返回前端后三位精度缺失问题解决


    一、问题描述

    Java 后端使用雪花算法生成 Long 类型的主键 ID,在返回前端后,会出现后三位精度丢失的问题。

    在这里插入图片描述

    在这里插入图片描述

    我们写一个 ControllerAdvice 打印一下返回结果看下:

    在这里插入图片描述

    我们可以看到返回结果是没有问题的,但是返回到前端就会丢失两位精度

    二、问题复现

    这里主要描述问题的复现过程和代码,不需要的可以直接跳过。

    1.Maven依赖

    
    <dependency>
        <groupId>cn.hutoolgroupId>
        <artifactId>hutool-allartifactId>
        <version>5.8.16version>
    dependency>
    
    
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-thymeleafartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    2.application.yml 配置

    server:
      port: 8080
    
    spring:
      mvc:
        view:
          prefix: /templates/
          suffix: .html
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    3.DemoController.java

    import cn.hutool.core.util.IdUtil;
    import com.demo.common.Result;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    /**
     * 

    @Title DemoController *

    @Description 测试Controller * * @author ACGkaka * @date 2023/4/24 18:02 */ @Slf4j @Controller @RequestMapping("/demo") public class DemoController { @GetMapping("/snowflakePage") public String snowflakePage() { return "snowflakePage"; } @GetMapping("/snowflakeId") @ResponseBody public Result<Object> snowflakeId() { return Result.succeed().setData(IdUtil.getSnowflakeNextId()); } }

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    4.snowflakePage.html 页面

    页面文件在 resources/templates/ 路径下。

    在这里插入图片描述

    DOCTYPE html>
    <html>
    <head>
        <title>调用接口并打印返回值title>
    head>
    <body>
    <button onclick="getSnowflakeId()">调用接口button>
    <script>
        function getSnowflakeId() {
            fetch('/demo/snowflakeId')
                .then(response => response.json())
                .then(data => {
                    console.log(data.data);
                    document.body.innerHTML += `

    ${data.data}

    `
    ; }) .catch(error => console.log(error)); }
    script> body> html>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    5.DemoControllerAdvice.java 监听

    import org.springframework.core.MethodParameter;
    import org.springframework.http.MediaType;
    import org.springframework.http.server.ServerHttpRequest;
    import org.springframework.http.server.ServerHttpResponse;
    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
    
    /**
     * 

    @Title DemoControllerAdvice *

    @Description Controller增强 * * @author ACGkaka * @date 2023/4/25 21:07 */ @ControllerAdvice public class DemoControllerAdvice implements ResponseBodyAdvice { @Override public boolean supports(MethodParameter methodParameter, Class aClass) { return true; } @Override public Object beforeBodyWrite(Object body, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) { System.out.println("body is: " + body); return body; } }

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    6.问题复现

    请求地址:http://localhost:8080/demo/snowflakePage

    在这里插入图片描述

    在这里插入图片描述

    精度丢失问题复现,下面我们来分析下导致问题的原因。

    三、原因分析

    • 后端返回:1703327682407702528
    • 前端接收:1703327682407702500

    这是因为 JS 是弱语言,前端接收数字类型参数为 number最大接受长度为 16 位超出长度则会丢失精度。而 JavaLong 类型长度是 19 位,所以传输到前端的后三位精度丢失。

    解决问题的思路:把 Java 中 Long 类型转换为 String 类型返回给前端。

    四、问题解决

    方案一

    将所有 ID 使用 String 类型存储,缺点是字符串做 ID 查询效率比较低

    方案二

    使用注解、配置类,改变序列化过程。

    注解方式,适用于 pojo 的 id 属性上。

    import com.baomidou.mybatisplus.annotation.TableId;
    import com.fasterxml.jackson.databind.annotation.JsonSerialize;
    import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
    
    /**
     * 主键
     */
    @TableId
    @JsonSerialize(using = ToStringSerializer.class)
    private Long id;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    配置类方式,适用于全局配置。

    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.databind.module.SimpleModule;
    import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Primary;
    import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
    
    @Configuration
    public class JacksonConfig {
      @Bean
      @Primary
      @ConditionalOnMissingBean(ObjectMapper.class)
      public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder)
      {
        ObjectMapper objectMapper = builder.createXmlMapper(false).build();
        // 全局配置序修改列化返回 Json 处理方案
        SimpleModule simpleModule = new SimpleModule();
        // Json Long --> String
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        objectMapper.registerModule(simpleModule);
        return objectMapper;
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    根据问题复现代码,再次请求地址:http://localhost:8080/demo/snowflakePage

    在这里插入图片描述

    在这里插入图片描述

    精度丢失问题已修复。

    整理完毕,完结撒花~ 🌻





    参考地址:

    1.解决雪花算法生成的ID传输前端后精度丢失,https://blog.csdn.net/weixin_48841931/article/details/127966871

  • 相关阅读:
    LeetCode70-爬楼梯
    sonar扫描安装前端
    vue3 组件篇 tag
    目录启示:PHP 与命名空间的声明
    探索MacOS:苹果电脑的操作系统的魅力
    actuator--基础--07--自定义Endpoint
    R-CNN、Fast RCNN和Faster RCNN的详细讲解
    LeetCode142.环形链表-II
    检测滑动是否到达底部
    【云原生 | 从零开始学Kubernetes】十二、k8spod的生命周期与容器钩子
  • 原文地址:https://blog.csdn.net/qq_33204709/article/details/132948147