0

1

SpringBoot雪花算法主键ID传到前端后精度丢失问题如何解决

PHPz

PHPz

发布时间:2023-05-11 12:34:18

|

3799人浏览过

|

来源于亿速云

转载

问题描述

java后端long类型的范围

  • -2^63~2^63,即:-9223372036854775808~9223372036854775807,它是19位的。

  • 这个数字可以通过方法获得:Long.MAX_VALUE、Long_MIN_VALUE。

前端JS的数字类型的范围

  • -2^53~2^53,即:-9007199254740991~9007199254740991,它是16位的。

    立即学习前端免费学习笔记(深入)”;

  • 这个数字可以通过方法获得:Number.MAX_SAFE_INTEGER、Number.MIN_SAFE_INTEGER。

结论

可见,Java后端的Long宽度大于前端的。雪花算法一般会生成18位或者19位宽度的数字,那么这时就会出问题。

项目场景

1.表结构

主键类型是BIGINT,存储雪花算法生成的ID。

CREATE TABLE `user` (
  `id` BIGINT(32) NOT NULL COMMENT '用户id',
	...
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';

2.Entity

用Long 类型对应数据库ID的BIGINT类型。

这里使用 MybatisPlus 的雪花算法自动生成19位长度的纯数字作为主键ID。(当然也可以手动用雪花算法生成ID)

import lombok.Data;
 
@Data
public class User {
    @TableId(type = IdType.ASSIGN_ID)
    private Long id;
	
    //其他成员
}

3.响应给前端

以JSON数据响应给前端正常

{
  "id": 1352166380631257089,
   ...
}

问题描述

实例

Controller

package com.knife.controller;
 
import com.knife.entity.UserVO;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
 
@RestController
@RequestMapping("user")
public class UserController {
 
    @GetMapping("find")
    public UserVO find(Long id) {
        UserVO userVO = new UserVO();
        userVO.setId(id);
        userVO.setUsername("Tony");
 
        return userVO;
    }
}

Entity

package com.knife.entity;
 
import lombok.Data;
 
@Data
public class UserVO {
    private Long id;
 
    private String username;
}

测试

访问:http://localhost:8080/user/find?id=1352213368413982722

结果

SpringBoot雪花算法主键ID传到前端后精度丢失问题如何解决

问题复现

从上边可以看到,并没有问题。

为什么没有出问题?

前端传入后端:SpingMVC会自动将String类型的ID转为Long类型,不会出问题后端响应给前端:是JSON格式,与JS没有关系,不会出问题

什么时候会出问题?

前端接收到JSON之后,将其序列化为JS对象,然后进行其他操作。在JSON转JS对象时就会出问题,如下:

白果AI论文
白果AI论文

论文AI生成学术工具,真实文献,免费不限次生成论文大纲 10 秒生成逻辑框架,10 分钟产出初稿,智能适配 80+学科。支持嵌入图表公式与合规文献引用

下载

SpringBoot雪花算法主键ID传到前端后精度丢失问题如何解决

可以看到,原来id为1352213368413982722,序列化为JS对象后变成了 1352213368413982700

代码为:

const json = '{"id": 1352213368413982722, "name": "Tony"}';
const obj = JSON.parse(json);
 
console.log(obj.id);
console.log(obj.name);

解决方案

有如下两种方案

  • 将数据库表设计的id字段由 Long 类型改成 String 类型。

  • 前端用String类型来保存ID保持精度,后端及数据库继续使用Long(BigINT)类型

方案1使用String 类型做数据库ID,查询性能会大幅度下降。所以应该采用方案2。本文介绍方案2。

法1:全局处理

简介

自定义ObjectMapper。

方案1:ToStringSerializer(推荐)

package com.knife.config;
 
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
 
@Configuration
public class JacksonConfig {
 
    @Bean
    public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
        ObjectMapper objectMapper = builder.createXmlMapper(false).build();
 
        // 全局配置序列化返回 JSON 处理
        SimpleModule simpleModule = new SimpleModule();
        // 将使用String来序列化Long类型
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
        objectMapper.registerModule(simpleModule);
        return objectMapper;
    }
}

测试 

访问:http://localhost:8080/user/find?id=1352213368413982722

SpringBoot雪花算法主键ID传到前端后精度丢失问题如何解决

方案2:自定义序列化器(不推荐)

序列化器

package com.knife.config;
 
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JacksonStdImpl;
import com.fasterxml.jackson.databind.ser.std.NumberSerializer;
 
import java.io.IOException;
 
/**
 * 超出 JS 最大最小值 处理
 */
@JacksonStdImpl
public class BigNumberSerializer extends NumberSerializer {
 
	/**
	 * 根据 JS Number.MAX_SAFE_INTEGER 与 Number.MIN_SAFE_INTEGER 得来
	 */
	private static final long MAX_SAFE_INTEGER = 9007199254740991L;
	private static final long MIN_SAFE_INTEGER = -9007199254740991L;
 
	/**
	 * 提供实例
	 */
	public static final BigNumberSerializer instance = new BigNumberSerializer(Number.class);
 
	public BigNumberSerializer(Class rawType) {
		super(rawType);
	}
 
	@Override
	public void serialize(Number value, JsonGenerator gen, SerializerProvider provider) throws IOException {
		// 超出范围 序列化位字符串
		if (value.longValue() > MIN_SAFE_INTEGER && value.longValue() < MAX_SAFE_INTEGER) {
			super.serialize(value, gen, provider);
		} else {
			gen.writeString(value.toString());
		}
	}
}

ObjectMapper配置

package com.knife.config;
 
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
 
@Configuration
public class JacksonConfig {
 
    @Bean
    public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
        ObjectMapper objectMapper = builder.createXmlMapper(false).build();
 
        // 全局配置序列化返回 JSON 处理
        SimpleModule simpleModule = new SimpleModule();
        // 将使用自定义序列化器来序列化Long类型
        simpleModule.addSerializer(Long.class, BigNumberSerializer.instance);
        simpleModule.addSerializer(Long.TYPE, BigNumberSerializer.instance);
        objectMapper.registerModule(simpleModule);
        return objectMapper;
    }
}

测试 

访问:http://localhost:8080/user/find?id=1352213368413982722

SpringBoot雪花算法主键ID传到前端后精度丢失问题如何解决

法2:局部处理

说明

在字段上加:@JsonSerialize(using= ToStringSerializer.class)。

实例

package com.knife.entity;
 
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data;
 
@Data
public class UserVO {
    @JsonSerialize(using= ToStringSerializer.class)
    private Long id;
 
    private String username;
}

测试 

访问:http://localhost:8080/user/find?id=1352213368413982722

SpringBoot雪花算法主键ID传到前端后精度丢失问题如何解决

相关专题

更多
Java编译相关教程合集
Java编译相关教程合集

本专题整合了Java编译相关教程,阅读专题下面的文章了解更多详细内容。

9

2026.01.21

C++多线程相关合集
C++多线程相关合集

本专题整合了C++多线程相关教程,阅读专题下面的的文章了解更多详细内容。

3

2026.01.21

无人机驾驶证报考 uom民用无人机综合管理平台官网
无人机驾驶证报考 uom民用无人机综合管理平台官网

无人机驾驶证(CAAC执照)报考需年满16周岁,初中以上学历,身体健康(矫正视力1.0以上,无严重疾病),且无犯罪记录。个人需通过民航局授权的训练机构报名,经理论(法规、原理)、模拟飞行、实操(GPS/姿态模式)及地面站训练后考试合格,通常15-25天拿证。

16

2026.01.21

Python多线程合集
Python多线程合集

本专题整合了Python多线程相关教程,阅读专题下面的文章了解更多详细内容。

1

2026.01.21

java多线程相关教程合集
java多线程相关教程合集

本专题整合了java多线程相关教程,阅读专题下面的文章了解更多详细内容。

3

2026.01.21

windows激活码分享 windows一键激活教程指南
windows激活码分享 windows一键激活教程指南

Windows 10/11一键激活可以通过PowerShell脚本或KMS工具实现永久或长期激活。最推荐的简便方法是打开PowerShell(管理员),运行 irm https://get.activated.win | iex 脚本,按提示选择数字激活(选项1)。其他方法包括使用HEU KMS Activator工具进行智能激活。

2

2026.01.21

excel表格操作技巧大全 表格制作excel教程
excel表格操作技巧大全 表格制作excel教程

Excel表格操作的核心技巧在于 熟练使用快捷键、数据处理函数及视图工具,如Ctrl+C/V(复制粘贴)、Alt+=(自动求和)、条件格式、数据验证及数据透视表。掌握这些可大幅提升数据分析与办公效率,实现快速录入、查找、筛选和汇总。

6

2026.01.21

毒蘑菇显卡测试网站入口 毒蘑菇测试官网volumeshader_bm
毒蘑菇显卡测试网站入口 毒蘑菇测试官网volumeshader_bm

毒蘑菇VOLUMESHADER_BM测试网站网址为https://toolwa.com/vsbm/,该平台基于WebGL技术通过渲染高复杂度三维分形图形评估设备图形处理能力,用户可通过拖动彩色物体观察画面流畅度判断GPU与CPU协同性能;测试兼容多种设备,但中低端手机易卡顿或崩溃,高端机型可能因发热降频影响表现,桌面端需启用独立显卡并使用支持WebGL的主流浏览器以确保准确结果

19

2026.01.21

github中文官网入口 github中文版官网网页进入
github中文官网入口 github中文版官网网页进入

github中文官网入口https://docs.github.com/zh/get-started,GitHub 是一种基于云的平台,可在其中存储、共享并与他人一起编写代码。 通过将代码存储在GitHub 上的“存储库”中,你可以: “展示或共享”你的工作。 持续“跟踪和管理”对代码的更改。

7

2026.01.21

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Redis6入门到精通超详细教程
Redis6入门到精通超详细教程

共47课时 | 5.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号