解決Long類型后端到前端精度丟失問(wèn)題
Long類型后端到前端精度丟失問(wèn)題
在開(kāi)發(fā)中,后端經(jīng)常需要處理一些大數(shù)值的 Long 類型數(shù)據(jù)(id等)。但當(dāng)這些數(shù)據(jù)通過(guò)接口傳遞到前端時(shí),可能會(huì)出現(xiàn)精度丟失的問(wèn)題。
原因:
JavaScript 的 Number 類型遵循 IEEE 754 雙精度浮點(diǎn)數(shù)標(biāo)準(zhǔn),只能精確表示范圍在 -(2^53 - 1) 到 2^53 - 1 之間的整數(shù)(約等于 -9007199254740991 到 9007199254740991)。
這意味著,任何超過(guò)這個(gè)范圍的整數(shù)在 JavaScript 中都無(wú)法精確表示。
例如:
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)通過(guò) JSON 傳遞到前端的 JavaScript 環(huán)境時(shí),由于 JavaScript 數(shù)字精度限制,往往會(huì)出現(xiàn) 精度丟失 的問(wèn)題。
典型場(chǎng)景
當(dāng)后端返回一個(gè) ID 值 1234567890123456789,前端可能會(huì)收到 1234567890123456000,這樣就導(dǎo)致了數(shù)據(jù)的錯(cuò)誤。
解決方案
方案一:后端將 Long 類型序列化為 String 類型
一種簡(jiǎn)單有效的解決方案是,將后端的 Long 類型值序列化為 String,這樣前端會(huì)將其當(dāng)作字符串處理,從而避免了精度丟失的問(wèn)題。下面是具體的實(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 類中,通過(guò)以下代碼將 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 處理庫(kù),并在后臺(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 配置的全局效果
通過(guò)自定義 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)部或第三方庫(kù)需要 JSON 處理的地方。
總結(jié)
在后端開(kāi)發(fā)中處理 Long 類型數(shù)據(jù)時(shí),注意 JavaScript 的精度限制十分重要。
通過(guò)配置 Jackson 的 ObjectMapper,可以讓所有 Long 類型字段序列化為字符串,從而避免精度丟失的問(wèn)題。
Spring Boot 的自動(dòng)化配置特性讓我們無(wú)需手動(dòng)調(diào)用 ObjectMapper,就能在全局范圍內(nèi)應(yīng)用此配置,使得后端傳遞到前端的數(shù)據(jù)在大數(shù)值時(shí)也能準(zhǔn)確無(wú)誤。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
詳解如何Java中實(shí)現(xiàn)Excel的注釋和批注
注釋及批注是?Excel?中比較常用的功能,這篇文章主要為大家詳細(xì)介紹了如何在Java中實(shí)現(xiàn)Excel的注釋和批注,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-12-12
Java弱鍵集合WeakHashMap及ConcurrentCache原理詳解
這篇文章主要介紹了Java弱鍵集合WeakHashMap及ConcurrentCache原理詳解,基于哈希表的Map接口實(shí)現(xiàn),支持null鍵和值,但是WeakHashMap具有弱鍵,可用來(lái)實(shí)現(xiàn)緩存存儲(chǔ),在進(jìn)行GC的時(shí)候會(huì)自動(dòng)回收鍵值對(duì),需要的朋友可以參考下2023-09-09
SpringMVC @RequestBody Date類型的Json轉(zhuǎn)換方式
這篇文章主要介紹了SpringMVC @RequestBody Date類型的Json轉(zhuǎn)換方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10
springmvc字符編碼過(guò)濾器CharacterEncodingFilter的使用
這篇文章主要介紹了springmvc字符編碼過(guò)濾器CharacterEncodingFilter的使用,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。2021-08-08
基于JavaMail實(shí)現(xiàn)郵件發(fā)送
這篇文章主要為大家詳細(xì)介紹了基于JavaMail實(shí)現(xiàn)郵件發(fā)送功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-03-03

