javascript技巧

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript技巧 > JavaScript大数ID精度丢失

JavaScript大数ID精度丢失问题的解决方案

作者:当归1024

在前后端分离的Web应用开发中,经常会遇到一个令人头疼的问题:JavaScript数字精度丢失,当后端使用Long类型生成的大数ID传递到前端时,会出现精度丢失,所以本文给大家介绍了JavaScript大数ID精度丢失问题解决方案,需要的朋友可以参考下

问题背景

在前后端分离的Web应用开发中,经常会遇到一个令人头疼的问题:JavaScript数字精度丢失。当后端使用Long类型生成的大数ID传递到前端时,会出现精度丢失,导致前端获取的ID与后端实际存储的ID不一致。

问题现象

在我们的若依(RuoYi)邮件服务器管理系统中,出现了以下问题:

问题根源分析

JavaScript数字精度限制

JavaScript中的数字都是以64位浮点数存储的,其中:

这意味着JavaScript能够安全表示的最大整数是 2^53 - 1 = 9007199254740991,即 Number.MAX_SAFE_INTEGER

雪花算法ID的特点

现代分布式系统中常用的雪花算法(Snowflake)生成的ID通常是19位的长整型数字,如:

1965951881494065154 (19位)

这个数字远远超过了JavaScript的安全整数范围,因此在JSON序列化传输到前端时会发生精度丢失。

解决方案

核心思路

将Long类型的ID在JSON序列化时转换为字符串,避免JavaScript的数字精度问题。

使用Jackson的ToStringSerializer

在Java实体类中,对ID字段添加 @JsonSerialize(using = ToStringSerializer.class) 注解。

实施步骤

1. 添加必要的导入

在实体类中添加Jackson相关的导入:

import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;

2. 在ID字段上添加注解

/** 服务器ID */
@JsonSerialize(using = ToStringSerializer.class)
private Long id;

3. 完整的实体类示例

package com.ruoyi.email.domain;

import java.io.Serializable;
import java.util.Date;
import javax.validation.constraints.*;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.ruoyi.common.annotation.Excel;
import com.ruoyi.common.annotation.Excel.ColumnType;
import lombok.Data;
import lombok.EqualsAndHashCode;

@Data
@EqualsAndHashCode
@TableName("tbl_email_server")
public class EmailServer implements Serializable
{
    private static final long serialVersionUID = 1L;

    /** 服务器ID */
    @JsonSerialize(using = ToStringSerializer.class)
    private Long id;
    
    // ... 其他字段
}

解决方案的工作原理

序列化过程

  1. 后端序列化: Long类型的ID 1965951881494065154 被序列化为字符串 "1965951881494065154"
  2. 前端接收: JavaScript接收到字符串格式的ID,不会有精度丢失
  3. 前端发送: 前端将字符串ID发送回后端
  4. 后端反序列化: Spring Boot自动将字符串转换回Long类型

JSON数据格式对比

修改前:

{
    "id": 1965951881494065200,  // 精度丢失!
    "serverCode": "EMAIL_001",
    "name": "主邮件服务器"
}

修改后:

{
    "id": "1965951881494065154", // 字符串格式,精度保持!
    "serverCode": "EMAIL_001", 
    "name": "主邮件服务器"
}

前端处理注意事项

HTML模板中的处理

由于ID现在是字符串格式,在前端模板中可以正常使用:

<template>
  <el-table :data="serverList">
    <el-table-column prop="id" label="ID" />
    <el-table-column label="操作">
      <template #default="{ row }">
        <!-- 字符串ID可以直接使用 -->
        <el-button @click="editServer(row.id)">编辑</el-button>
      </template>
    </el-table-column>
  </el-table>
</template>

JavaScript中的处理

// 接收数据
const serverData = {
    id: "1965951881494065154", // 字符串格式
    serverCode: "EMAIL_001",
    name: "主邮件服务器"
};

// 发送请求
updateEmailServer({
    id: serverData.id, // 直接使用字符串ID
    serverCode: "EMAIL_002"
});

验证结果

修改完成后,验证效果:

  1. 数据库ID: 1965951881494065154
  2. 前端接收ID: "1965951881494065154" (字符串格式)
  3. 前端发送ID: "1965951881494065154"
  4. 后端接收ID: 1965951881494065154 (自动转换为Long)

结果: ID数据在前后端传输过程中保持完全一致,修改操作成功!

适用场景

这个解决方案适用于以下情况:

  1. 雪花算法生成的ID: 通常是18-19位的长整型
  2. 时间戳ID: 毫秒级时间戳生成的长整型ID
  3. 其他超过JavaScript安全范围的Long类型字段: 如订单号、交易流水号等

性能影响

其他解决方案对比

方案一:前端使用BigInt

// 需要特殊处理
const id = BigInt("1965951881494065154");

缺点: 需要修改大量前端代码,兼容性问题

方案二:自定义JSON配置

@Configuration
public class JacksonConfig {
    @Bean
    public Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder() {
        return new Jackson2ObjectMapperBuilder()
                .simpleDateFormat("yyyy-MM-dd HH:mm:ss")
                .serializerByType(Long.class, ToStringSerializer.instance);
    }
}

缺点: 影响全局所有Long类型字段

方案三:使用@JsonSerialize注解

@JsonSerialize(using = ToStringSerializer.class)
private Long id;

优点:

总结

通过在Java实体类的ID字段上添加 @JsonSerialize(using = ToStringSerializer.class) 注解,我们成功解决了JavaScript大数精度丢失的问题。这个方案具有以下优势:

  1. 简单易实施: 只需添加一个注解
  2. 影响范围小: 只影响特定字段,不会波及其他功能
  3. 兼容性好: 前端代码无需修改
  4. 性能优秀: 几乎无性能损耗

这个问题在现代Web开发中非常常见,特别是在使用分布式ID生成算法的系统中。掌握这个解决方案能够帮助开发者快速解决类似的精度丢失问题,提高系统的稳定性和数据准确性。

以上就是JavaScript大数ID精度丢失问题的解决方案的详细内容,更多关于JavaScript大数ID精度丢失的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文