后端传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 类型序列化为字符串类型。