今天測試突然跟我說頁面顯示的數值和數據庫的對應不上,一開始我以爲是程序問題,把數據給修改了,但是後面檢查程序發現,沒有任務問題,用postman請求,發現數據也和數據庫的一致。但是頁面上面顯示的就是不一樣。
問題追蹤
一開始我懷疑是前端轉型把精度丟失,前端那邊直接是通過Number接收的,沒有任何轉型操作。後來我懷疑可能是因爲服務器是Long類型,前端是Number類型,可能是精度對應不上,後面一查資料發現還真是這個問題。
Number和Long精度
Number的最大長度是2的53次,也就是9007199254740992,而Long的最大長度是2的64次,也就是9223372036854775807。所以會出現精度丟失的情況。
解決方案
要解決這個問題其實不難,只要將Long類型變爲String類型即可,但是我們不可能直接將字段修改爲String,這樣會涉及很多模塊代碼的修改,工作量和安全性都會受到影響。
還有一種辦法是重新再添加一個新的字段,然後get的時候將需要的字段轉爲字符串返回即可,如下所示:
private Long userId;
private String userIdStr;
public String getUserIdStr() {
return this.userId+"";
}
public void setUserIdStr(String userIdStr) {
this.userIdStr = userIdStr;
}
但是這樣一方面需要修改dto對象的字段,另一方面前端也需要相應的修改,如果有很多地方需要這樣做,那工作量也是非常大的,所以這種方式也是不可取的。
方案篩選
最理想的方案應該是不修改字段任何屬性,因爲這樣前端就不需要變動。(如果前端指定具體接收類型,那就需要修改),在序列化返回給前端的時候將Long類型的字段轉爲String類型。
這邊就給大家介紹一下jackson是如何進行序列化和反序列化的。
首先我們來看一下沒有進行任何序列化修改,Long類型怎麼輸出的?我們先來看一下代碼。
@RequestMapping(value = "testDemo", method = RequestMethod.GET)
@ResponseBody
public TestDto testDemo() {
TestDto testDto = new TestDto();
testDto.setId(Long.valueOf("123456789012345678"));
return testDto;
}
@Data
public class TestDto {
/**
* ID標識
*/
private Long id;
}
接下來我們用postman請求一下,看看返回的結果是啥樣的?
{
"id": 123456789012345678
}
我們可以看到String類型的返回結果是沒有雙引號或者單引號的,我們修改一下id字段的類型(從Long類型修改爲String),看看輸出結果有什麼不一樣。
@Data
public class TestDto {
/**
* ID標識
*/
private String id;
}
輸出結果:
{
"id": "123456789012345678"
}
我們可以很明顯的看到,字段id值是有雙引號的。那我們如何在不修改任何代碼的情況下,返回值值從Long類型修改爲Stirng,返回給前端。
接下來就是重頭戲了,我們先寫一個Annotation註解,如下所示:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD})
@JacksonAnnotationsInside
@JsonSerialize(using = LongToStringSerializer.class)
public @interface LongToString {
}
不懂@Retention和@Target含義的童鞋,可以自行百度。
重點在LongToStringSerializer類中,該類的作用是進行json序列化,它有一個serialize方法,允許我們對序列化的字段進行修改,具體我們來看一下代碼:
public class LongToStringSerializer extends JsonSerializer<Object> {
@Override
public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeString(String.valueOf(value));
}
}
這邊我們將原來是Long類型的字段,重寫爲String類型,最後我們用postman來測試一下,返回結果是否包含雙引號。
{
"id": "123456789012345678"
}
從結果我們可以很明顯的看出,id字段的類型是String,期間我們沒有修改id字段的類型,但是通過jackson序列化的時候進行字段類型重寫,就可以輕輕鬆鬆實現類型的修改。
總結
用法雖然很簡單,但是這其中過程是怎麼樣的呢,到底在什麼時候會進行對象序列化輸出?我們下一節來具體給大家介紹一下。今天文章分享就到這邊,謝謝童鞋們的閱讀~
想要更多幹貨、技術猛料的孩子,快點拿起手機掃碼關注我,我在這裏等你哦~
林老師帶你學編程:https://wolzq.com