解决后端传long类型数据到前端精度丢失问题
作者:源末coco
后端传long类型数据到前端精度丢失
在 Spring Boot 中,将 long 类型传输到前端时,会发现该类型的值可能会出现精度丢失的问题。
这是因为在 JavaScript 中,数字类型默认会被转换为双精度浮点数,而双精度浮点数的精度有限,只能精确表示 2 的 53 次方以内(即 Number.MAX_SAFE_INTEGER,约为 9 x 10^15)的整数。
对于超过该范围的长整数,JavaScript 会发生精度丢失,导致值变得不准确。
解决方案一
将 long 转换为字符串
1:在后端将 long 类型的值转换为字符串类型,可以使用 String.valueOf()
方法或者 Long.toString()
方法
如下所示:
long num = 123456789012345L; String str = String.valueOf(num); // 或者 String str = Long.toString(num);
2:在前端通过 AJAX 请求获取该字符串类型的值,并将其解析为数字类型。
由于 JavaScript 中的数值类型默认使用 IEEE 754 标准的双精度浮点数表示,因此需要使用 JavaScript 的 BigInt()
方法将其转换为大整数类型。
let str = "123456789012345"; let num = BigInt(str);
解决方案二
使用第三方库进行高精度运算
1:在后端将 long 类型的值转换为 BigDecimal
类型(Java 中的高精度类型),并通过 JSON 序列化后传递到前端。
这里以 Spring Boot 中使用 FastJSON 序列化为例
如下所示:
BigDecimal num = new BigDecimal("123456789012345"); String jsonStr = JSON.toJSONString(num);
2:在前端使用第三方库 big.js
或 bignumber.js
进行高精度运算。
这里以 big.js
为例,首先需要引入 big.min.js
文件,在代码中使用 Big()
类构造高精度对象,并进行相应的运算。
<script src="big.min.js"></script> let num = new Big("123456789012345"); let result = num.plus(1);
还可以使用注解来解决long类型的精度丢失问题
Spring Boot 中提供了 @JsonFormat
注解,可以对实体类中的属性进行序列化和反序列化格式化。
对于 long 类型的属性,可以设置其格式为字符串类型,并在前端进行相应的处理,以保持其精度不丢失。
具体实现方式
1:在实体类中添加 @JsonFormat
注解,设置其 shape
属性为 JsonFormat.Shape.STRING
如下所示:
public class Example { @JsonFormat(shape = JsonFormat.Shape.STRING) private Long num; }
2:在前端获取该值时,直接使用字符串类型进行处理
如下所示:
let numStr = data.num;
Spring Boot 中可以通过配置文件来解决 long 类型的精度丢失问题。
在 Spring Boot 的配置文件 application.properties
中添加如下配置:
spring.jackson.serialization.WRITE_DATES_AS_TIMESTAMPS=false # 将 long 类型序列化为字符串类型 spring.jackson.serialization.WRITE_NUMBERS_AS_STRINGS=true
其中,
WRITE_DATES_AS_TIMESTAMPS
表示是否将日期类型序列化为时间戳类型,默认为true
,这里设置为false
如果需要将日期类型序列化为时间戳类型,则不需要设置此属性。- 而
WRITE_NUMBERS_AS_STRINGS
则表示是否将数字类型序列化为字符串类型,默认为false
,这里设置为true
即可将 long 类型序列化为字符串类型。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。