在开发中,后端经常需要处理一些大数值的
Long
类型数据(id等)。但当这些数据通过接口传递到前端时,可能会出现精度丢失的问题。
原因:JavaScript 的
Number
类型遵循 IEEE 754 双精度浮点数标准,只能精确表示范围在
-(2^53 - 1)
到
2^53 - 1
之间的整数(约等于
-9007199254740991
到
9007199254740991
)。这意味着,任何超过这个范围的整数在 JavaScript 中都无法精确表示。例如:
console.log(9007199254740991); // 输出:9007199254740991(准确)
console.log(9007199254740992); // 输出:9007199254740992(准确)
console.log(9007199254740993); // 输出:9007199254740992(精度丢失)
在后端(例如 Java)中,
Long
类型的范围是
-2^63
到
2^63 - 1
,即
-9223372036854775808
到
9223372036854775807
。这种数值在 Java 中可以被精确表示,但当通过 JSON 传递到前端的 JavaScript 环境时,由于 JavaScript 数字精度限制,往往会出现 精度丢失 的问题。
典型场景
当后端返回一个 ID 值
1234567890123456789
,前端可能会收到
1234567890123456000
,这样就导致了数据的错误。
解决方案
方案一:后端将
Long
类型序列化为
String
类型
一种简单有效的解决方案是,将后端的
Long
类型值序列化为
String
,这样前端会将其当作字符串处理,从而避免了精度丢失的问题。下面是具体的实现方法。
1. 使用
@JsonSerialize
注解单独处理字段
如果只是需要处理某个特定字段(例如
id
),可以在字段上添加
@JsonSerialize
注解,指定 Jackson 使用
ToStringSerializer
序列化器。
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
public class PassengerQueryResp {
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
private Long memberId;
private String name;
private String idCard;
// Getter 和 Setter
}
配置了这个
ObjectMapper
之后,所有的
Long
类型字段在序列化时都会被转换为字符串格式,不再需要逐个字段添加注解。
2. 配置全局的
ObjectMapper
设置
如果需要对所有
Long
类型的字段进行字符串处理,可以在 Spring Boot 的配置类中定义一个全局
ObjectMapper
Bean,使用
SimpleModule
注册
ToStringSerializer
,这会对所有
Long
类型字段生效。
@Configuration
public class JacksonConfig {
@Bean
public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
ObjectMapper objectMapper = builder.createXmlMapper(false).build();
SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
objectMapper.registerModule(simpleModule);
return objectMapper;
}
}
配置类的作用详解
在
JacksonConfig
类中,通过以下代码将
Long
类型序列化为
String
:
SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
objectMapper.registerModule(simpleModule);
具体工作原理
- Spring Boot 自动配置
ObjectMapper
Spring Boot 自带 Jackson 作为默认的 JSON 处理库,并在后台自动配置了ObjectMapper
。当你在项目中引入 Jackson 时,Spring Boot 会自动加载一个全局共享的ObjectMapper
实例,用于所有 JSON 序列化和反序列化操作。 - 控制器的自动 JSON 转换 在 Spring MVC 中,控制器(
@RestController
或@Controller
)中的方法返回值会被自动转换为 JSON 格式,这个转换由 Spring Boot 的ObjectMapper
处理。例如:
@RestController
public class UserController {
@GetMapping("/user")
public User getUser() {
return new User(123456789012345L, "Alice");
}
}
- 当
User
对象被返回时,Spring MVC 会自动使用ObjectMapper
将其序列化为 JSON 响应发送给客户端。如果你配置了JacksonConfig
类,Spring 会使用你配置的ObjectMapper
,因此所有Long
类型字段会自动以字符串形式输出,避免精度丢失。
**3.自定义
ObjectMapper
配置的全局效果**
通过自定义
JacksonConfig
,实际上是让 Spring Boot 使用你定义的
ObjectMapper
Bean 作为全局配置。Spring Boot 会自动检测应用中的
ObjectMapper
Bean,并将其用于所有 JSON 序列化和反序列化操作,这包括:
@RestController
返回的对象。@RequestBody
和@ResponseBody
注解处理的 JSON 请求和响应。- 其他 Spring Boot 内部或第三方库需要 JSON 处理的地方。
总结
在后端开发中处理
Long
类型数据时,注意 JavaScript 的精度限制十分重要。通过配置 Jackson 的
ObjectMapper
,可以让所有
Long
类型字段序列化为字符串,从而避免精度丢失的问题。Spring Boot 的自动化配置特性让我们无需手动调用
ObjectMapper
,就能在全局范围内应用此配置,使得后端传递到前端的数据在大数值时也能准确无误。
版权归原作者 qq_44199605 所有, 如有侵权,请联系我们删除。