解決Long類型后端到前端精度丟失問題
Long類型后端到前端精度丟失問題
在開發(fā)中,后端經(jīng)常需要處理一些大數(shù)值的 Long
類型數(shù)據(jù)(id等)。但當(dāng)這些數(shù)據(jù)通過接口傳遞到前端時(shí),可能會(huì)出現(xiàn)精度丟失的問題。
原因:
JavaScript 的 Number
類型遵循 IEEE 754 雙精度浮點(diǎn)數(shù)標(biāo)準(zhǔn),只能精確表示范圍在 -(2^53 - 1)
到 2^53 - 1
之間的整數(shù)(約等于 -9007199254740991
到 9007199254740991
)。
這意味著,任何超過這個(gè)范圍的整數(shù)在 JavaScript 中都無法精確表示。
例如:
console.log(9007199254740991); // 輸出:9007199254740991(準(zhǔn)確) console.log(9007199254740992); // 輸出:9007199254740992(準(zhǔn)確) console.log(9007199254740993); // 輸出:9007199254740992(精度丟失)
在后端(例如 Java)中,Long
類型的范圍是 -2^63
到 2^63 - 1
,即 -9223372036854775808
到 9223372036854775807
。
這種數(shù)值在 Java 中可以被精確表示,但當(dāng)通過 JSON 傳遞到前端的 JavaScript 環(huán)境時(shí),由于 JavaScript 數(shù)字精度限制,往往會(huì)出現(xiàn) 精度丟失 的問題。
典型場景
當(dāng)后端返回一個(gè) ID 值 1234567890123456789
,前端可能會(huì)收到 1234567890123456000
,這樣就導(dǎo)致了數(shù)據(jù)的錯(cuò)誤。
解決方案
方案一:后端將 Long 類型序列化為 String 類型
一種簡單有效的解決方案是,將后端的 Long
類型值序列化為 String
,這樣前端會(huì)將其當(dāng)作字符串處理,從而避免了精度丟失的問題。下面是具體的實(shí)現(xiàn)方法。
1. 使用@JsonSerialize注解單獨(dú)處理字段
如果只是需要處理某個(gè)特定字段(例如 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 }
配置了這個(gè) ObjectMapper
之后,所有的 Long
類型字段在序列化時(shí)都會(huì)被轉(zhuǎn)換為字符串格式,不再需要逐個(gè)字段添加注解。
2. 配置全局的ObjectMapper設(shè)置
如果需要對(duì)所有 Long
類型的字段進(jìn)行字符串處理,可以在 Spring Boot 的配置類中定義一個(gè)全局 ObjectMapper
Bean,使用 SimpleModule
注冊(cè) ToStringSerializer
,這會(huì)對(duì)所有 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 自動(dòng)配置 ObjectMapper
- Spring Boot 自帶 Jackson 作為默認(rèn)的 JSON 處理庫,并在后臺(tái)自動(dòng)配置了
ObjectMapper
。 - 當(dāng)你在項(xiàng)目中引入 Jackson 時(shí),Spring Boot 會(huì)自動(dòng)加載一個(gè)全局共享的
ObjectMapper
實(shí)例,用于所有 JSON 序列化和反序列化操作。
2.控制器的自動(dòng) JSON 轉(zhuǎn)換
- 在 Spring MVC 中,控制器(
@RestController
或@Controller
)中的方法返回值會(huì)被自動(dòng)轉(zhuǎn)換為 JSON 格式,這個(gè)轉(zhuǎn)換由 Spring Boot 的ObjectMapper
處理。 - 例如:
@RestController public class UserController { @GetMapping("/user") public User getUser() { return new User(123456789012345L, "Alice"); } }
- 當(dāng)
User
對(duì)象被返回時(shí),Spring MVC 會(huì)自動(dòng)使用ObjectMapper
將其序列化為 JSON 響應(yīng)發(fā)送給客戶端。 - 如果你配置了
JacksonConfig
類,Spring 會(huì)使用你配置的ObjectMapper
,因此所有Long
類型字段會(huì)自動(dòng)以字符串形式輸出,避免精度丟失。
3.自定義 ObjectMapper
配置的全局效果
通過自定義 JacksonConfig
,實(shí)際上是讓 Spring Boot 使用你定義的 ObjectMapper
Bean 作為全局配置。
Spring Boot 會(huì)自動(dòng)檢測(cè)應(yīng)用中的 ObjectMapper
Bean,并將其用于所有 JSON 序列化和反序列化操作,這包括:
@RestController
返回的對(duì)象。@RequestBody
和@ResponseBody
注解處理的 JSON 請(qǐng)求和響應(yīng)。- 其他 Spring Boot 內(nèi)部或第三方庫需要 JSON 處理的地方。
總結(jié)
在后端開發(fā)中處理 Long
類型數(shù)據(jù)時(shí),注意 JavaScript 的精度限制十分重要。
通過配置 Jackson 的 ObjectMapper
,可以讓所有 Long
類型字段序列化為字符串,從而避免精度丟失的問題。
Spring Boot 的自動(dòng)化配置特性讓我們無需手動(dòng)調(diào)用 ObjectMapper
,就能在全局范圍內(nèi)應(yīng)用此配置,使得后端傳遞到前端的數(shù)據(jù)在大數(shù)值時(shí)也能準(zhǔn)確無誤。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Servlet的兩種創(chuàng)建方式(xml?注解)示例詳解
這篇文章主要為大家介紹了Servlet的兩種創(chuàng)建方式(xml?注解)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08Spring?Boot?集成并開發(fā)?Sa-token示例詳解
Sa-token是一款高可用的權(quán)限認(rèn)證框架,他帶我們用最簡化的配置完成用?spring?security?需要進(jìn)行大量配置的才能完成的工作,這篇文章主要介紹了Spring?Boot?集成并開發(fā)?Sa-token,需要的朋友可以參考下2023-06-06Springboot實(shí)現(xiàn)過濾器的兩種方式
今天通過本文給大家分享Springboot實(shí)現(xiàn)過濾器的兩種方式,第一種是spring容器注冊(cè)filter,第二種方式是通過@WebFilter 注解來配置,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧2023-10-10如何在Spring Boot應(yīng)用中優(yōu)雅的使用Date和LocalDateTime的教程詳解
這篇文章主要介紹了如何在Spring Boot應(yīng)用中優(yōu)雅的使用Date和LocalDateTime,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-07-07java 實(shí)現(xiàn)web項(xiàng)目啟動(dòng)加載properties屬性文件
這篇文章主要介紹了java 實(shí)現(xiàn)web項(xiàng)目啟動(dòng)加載properties屬性文件,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08DolphinScheduler容錯(cuò)源碼分析之Worker
這篇文章主要為大家介紹了DolphinScheduler容錯(cuò)源碼分析之Worker,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02解決idea的debug模式突然變卡,項(xiàng)目啟動(dòng)變慢的狀況
這篇文章主要介紹了解決idea的debug模式突然變卡,項(xiàng)目啟動(dòng)變慢的狀況,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2021-02-02