解決Long類型后端到前端精度丟失問題
Long類型后端到前端精度丟失問題
在開發(fā)中,后端經(jīng)常需要處理一些大數(shù)值的 Long 類型數(shù)據(jù)(id等)。但當這些數(shù)據(jù)通過接口傳遞到前端時,可能會出現(xiàn)精度丟失的問題。
原因:
JavaScript 的 Number 類型遵循 IEEE 754 雙精度浮點數(shù)標準,只能精確表示范圍在 -(2^53 - 1) 到 2^53 - 1 之間的整數(shù)(約等于 -9007199254740991 到 9007199254740991)。
這意味著,任何超過這個范圍的整數(shù)在 JavaScript 中都無法精確表示。
例如:
console.log(9007199254740991); // 輸出:9007199254740991(準確) console.log(9007199254740992); // 輸出:9007199254740992(準確) console.log(9007199254740993); // 輸出:9007199254740992(精度丟失)
在后端(例如 Java)中,Long 類型的范圍是 -2^63 到 2^63 - 1,即 -9223372036854775808 到 9223372036854775807。
這種數(shù)值在 Java 中可以被精確表示,但當通過 JSON 傳遞到前端的 JavaScript 環(huán)境時,由于 JavaScript 數(shù)字精度限制,往往會出現(xiàn) 精度丟失 的問題。
典型場景
當后端返回一個 ID 值 1234567890123456789,前端可能會收到 1234567890123456000,這樣就導致了數(shù)據(jù)的錯誤。
解決方案
方案一:后端將 Long 類型序列化為 String 類型
一種簡單有效的解決方案是,將后端的 Long 類型值序列化為 String,這樣前端會將其當作字符串處理,從而避免了精度丟失的問題。下面是具體的實現(xiàn)方法。
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);
具體工作原理
1.Spring Boot 自動配置 ObjectMapper
- Spring Boot 自帶 Jackson 作為默認的 JSON 處理庫,并在后臺自動配置了
ObjectMapper。 - 當你在項目中引入 Jackson 時,Spring Boot 會自動加載一個全局共享的
ObjectMapper實例,用于所有 JSON 序列化和反序列化操作。
2.控制器的自動 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 響應發(fā)送給客戶端。 - 如果你配置了
JacksonConfig類,Spring 會使用你配置的ObjectMapper,因此所有Long類型字段會自動以字符串形式輸出,避免精度丟失。
3.自定義 ObjectMapper 配置的全局效果
通過自定義 JacksonConfig,實際上是讓 Spring Boot 使用你定義的 ObjectMapper Bean 作為全局配置。
Spring Boot 會自動檢測應用中的 ObjectMapper Bean,并將其用于所有 JSON 序列化和反序列化操作,這包括:
@RestController返回的對象。@RequestBody和@ResponseBody注解處理的 JSON 請求和響應。- 其他 Spring Boot 內部或第三方庫需要 JSON 處理的地方。
總結
在后端開發(fā)中處理 Long 類型數(shù)據(jù)時,注意 JavaScript 的精度限制十分重要。
通過配置 Jackson 的 ObjectMapper,可以讓所有 Long 類型字段序列化為字符串,從而避免精度丟失的問題。
Spring Boot 的自動化配置特性讓我們無需手動調用 ObjectMapper,就能在全局范圍內應用此配置,使得后端傳遞到前端的數(shù)據(jù)在大數(shù)值時也能準確無誤。
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
Java弱鍵集合WeakHashMap及ConcurrentCache原理詳解
這篇文章主要介紹了Java弱鍵集合WeakHashMap及ConcurrentCache原理詳解,基于哈希表的Map接口實現(xiàn),支持null鍵和值,但是WeakHashMap具有弱鍵,可用來實現(xiàn)緩存存儲,在進行GC的時候會自動回收鍵值對,需要的朋友可以參考下2023-09-09
SpringMVC @RequestBody Date類型的Json轉換方式
這篇文章主要介紹了SpringMVC @RequestBody Date類型的Json轉換方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-10-10
springmvc字符編碼過濾器CharacterEncodingFilter的使用
這篇文章主要介紹了springmvc字符編碼過濾器CharacterEncodingFilter的使用,具有很好的參考價值,希望對大家有所幫助。2021-08-08

