解決Long類型后端到前端精度丟失問題
Long類型后端到前端精度丟失問題
在開發(fā)中,后端經常需要處理一些大數值的 Long
類型數據(id等)。但當這些數據通過接口傳遞到前端時,可能會出現(xiàn)精度丟失的問題。
原因:
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 環(huán)境時,由于 JavaScript 數字精度限制,往往會出現(xiàn) 精度丟失 的問題。
典型場景
當后端返回一個 ID 值 1234567890123456789
,前端可能會收到 1234567890123456000
,這樣就導致了數據的錯誤。
解決方案
方案一:后端將 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
類型數據時,注意 JavaScript 的精度限制十分重要。
通過配置 Jackson 的 ObjectMapper
,可以讓所有 Long
類型字段序列化為字符串,從而避免精度丟失的問題。
Spring Boot 的自動化配置特性讓我們無需手動調用 ObjectMapper
,就能在全局范圍內應用此配置,使得后端傳遞到前端的數據在大數值時也能準確無誤。
以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
Java弱鍵集合WeakHashMap及ConcurrentCache原理詳解
這篇文章主要介紹了Java弱鍵集合WeakHashMap及ConcurrentCache原理詳解,基于哈希表的Map接口實現(xiàn),支持null鍵和值,但是WeakHashMap具有弱鍵,可用來實現(xiàn)緩存存儲,在進行GC的時候會自動回收鍵值對,需要的朋友可以參考下2023-09-09SpringMVC @RequestBody Date類型的Json轉換方式
這篇文章主要介紹了SpringMVC @RequestBody Date類型的Json轉換方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-10-10springmvc字符編碼過濾器CharacterEncodingFilter的使用
這篇文章主要介紹了springmvc字符編碼過濾器CharacterEncodingFilter的使用,具有很好的參考價值,希望對大家有所幫助。2021-08-08