简介
本文用示例介绍SpringBoot如何解决雪花算法主键ID传到前端后精度丢失问题。
项目场景
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.example.business.product.controller; import com.knife.example.business.product.vo.ProductVO; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.web.bind.annotation.*; @Api(tags = "商品") @RestController @RequestMapping("product") public class ProductController { @ApiOperation("查询") @GetMapping("query") public ProductVO query(Long id) { //省略查数据库等逻辑。 //为了简便,直接虚构一个vo ProductVO productVO = new ProductVO(); productVO.setId(id); productVO.setName("鼠标"); return productVO; } }
VO
package com.knife.example.business.product.vo; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.time.LocalDateTime; @Data @ApiModel("商品响应类") public class ProductVO { @ApiModelProperty("id") private Long id; @ApiModelProperty("名字") private String name; }
测试
访问:http://localhost:8080/product/query?id=1352213368413982722
结果
出现问题
从上边可以看到,并没有问题。
为什么没有出问题?
- 前端传入后端:SpingMVC会自动将String类型的ID转为Long类型,不会出问题
- 后端响应给前端:是JSON格式,与JS没有关系,不会出问题
什么时候会出问题?
前端接收到JSON之后,将其序列化为JS对象,然后进行其他操作。在JSON转JS对象时就会出问题,如下:
可以看到,原来id为1352213368413982722,序列化为JS对象后变成了 1352213368413982700
代码为:
const json = '{"id": 1352213368413982722, "name": "鼠标"}'; const obj = JSON.parse(json); console.log(obj.id); console.log(obj.name);
原因分析
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位宽度的数字,那么这时就会出问题。
解决方案
此内容仅限VIP查看,请先登录
请先
!