欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot雪花算法主鍵ID傳到前端后精度丟失問(wèn)題的解決

 更新時(shí)間:2022年08月09日 15:25:08   作者:IT利刃出鞘  
本文主要介紹了SpringBoot雪花算法主鍵ID傳到前端后精度丟失問(wèn)題的解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

簡(jiǎn)介

本文用示例介紹SpringBoot如何解決雪花算法主鍵ID傳到前端后精度丟失問(wèn)題。

問(wèn)題描述

Java后端Long類型的范圍

  • -2^63~2^63,即:-9223372036854775808~9223372036854775807,它是19位的。
  • 這個(gè)數(shù)字可以通過(guò)方法獲得:Long.MAX_VALUE、Long_MIN_VALUE。

前端JS的數(shù)字類型的范圍

  • -2^53~2^53,即:-9007199254740991~9007199254740991,它是16位的。
  • 這個(gè)數(shù)字可以通過(guò)方法獲得:Number.MAX_SAFE_INTEGER、Number.MIN_SAFE_INTEGER。

結(jié)論

可見,Java后端的Long寬度大于前端的。雪花算法一般會(huì)生成18位或者19位寬度的數(shù)字,那么這時(shí)就會(huì)出問(wèn)題。

項(xiàng)目場(chǎng)景

1.表結(jié)構(gòu)

主鍵類型是BIGINT,存儲(chǔ)雪花算法生成的ID。

CREATE TABLE `user` (
  `id` BIGINT(32) NOT NULL COMMENT '用戶id',
	...
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用戶表';

2.Entity

用Long 類型對(duì)應(yīng)數(shù)據(jù)庫(kù)ID的BIGINT類型。

這里使用 MybatisPlus 的雪花算法自動(dòng)生成19位長(zhǎng)度的純數(shù)字作為主鍵ID。(當(dāng)然也可以手動(dòng)用雪花算法生成ID)

import lombok.Data;
 
@Data
public class User {
    @TableId(type = IdType.ASSIGN_ID)
    private Long id;
	
    //其他成員
}

3.響應(yīng)給前端

以JSON數(shù)據(jù)響應(yīng)給前端正常

{
  "id": 1352166380631257089,
   ...
}

問(wèn)題描述

實(shí)例

Controller

package com.knife.controller;
 
import com.knife.entity.UserVO;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
 
@RestController
@RequestMapping("user")
public class UserController {
 
    @GetMapping("find")
    public UserVO find(Long id) {
        UserVO userVO = new UserVO();
        userVO.setId(id);
        userVO.setUsername("Tony");
 
        return userVO;
    }
}

Entity

package com.knife.entity;
 
import lombok.Data;
 
@Data
public class UserVO {
    private Long id;
 
    private String username;
}

測(cè)試

訪問(wèn):http://localhost:8080/user/find?id=1352213368413982722

結(jié)果

問(wèn)題復(fù)現(xiàn)

從上邊可以看到,并沒(méi)有問(wèn)題。

為什么沒(méi)有出問(wèn)題?

前端傳入后端:SpingMVC會(huì)自動(dòng)將String類型的ID轉(zhuǎn)為L(zhǎng)ong類型,不會(huì)出問(wèn)題后端響應(yīng)給前端:是JSON格式,與JS沒(méi)有關(guān)系,不會(huì)出問(wèn)題

什么時(shí)候會(huì)出問(wèn)題?

前端接收到JSON之后,將其序列化為JS對(duì)象,然后進(jìn)行其他操作。在JSON轉(zhuǎn)JS對(duì)象時(shí)就會(huì)出問(wèn)題,如下:

可以看到,原來(lái)id為1352213368413982722,序列化為JS對(duì)象后變成了 1352213368413982700

代碼為:

const json = '{"id": 1352213368413982722, "name": "Tony"}';
const obj = JSON.parse(json);
 
console.log(obj.id);
console.log(obj.name);

解決方案

有如下兩種方案

  • 將數(shù)據(jù)庫(kù)表設(shè)計(jì)的id字段由 Long 類型改成 String 類型。
  • 前端用String類型來(lái)保存ID保持精度,后端及數(shù)據(jù)庫(kù)繼續(xù)使用Long(BigINT)類型

方案1使用String 類型做數(shù)據(jù)庫(kù)ID,查詢性能會(huì)大幅度下降。所以應(yīng)該采用方案2。本文介紹方案2。

法1:全局處理

簡(jiǎn)介

自定義ObjectMapper。

方案1:ToStringSerializer(推薦)

package com.knife.config;
 
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
 
@Configuration
public class JacksonConfig {
 
    @Bean
    public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
        ObjectMapper objectMapper = builder.createXmlMapper(false).build();
 
        // 全局配置序列化返回 JSON 處理
        SimpleModule simpleModule = new SimpleModule();
        // 將使用String來(lái)序列化Long類型
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
        objectMapper.registerModule(simpleModule);
        return objectMapper;
    }
}

測(cè)試 

訪問(wèn):http://localhost:8080/user/find?id=1352213368413982722

方案2:自定義序列化器(不推薦)

序列化器

package com.knife.config;
 
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JacksonStdImpl;
import com.fasterxml.jackson.databind.ser.std.NumberSerializer;
 
import java.io.IOException;
 
/**
 * 超出 JS 最大最小值 處理
 */
@JacksonStdImpl
public class BigNumberSerializer extends NumberSerializer {
 
	/**
	 * 根據(jù) JS Number.MAX_SAFE_INTEGER 與 Number.MIN_SAFE_INTEGER 得來(lái)
	 */
	private static final long MAX_SAFE_INTEGER = 9007199254740991L;
	private static final long MIN_SAFE_INTEGER = -9007199254740991L;
 
	/**
	 * 提供實(shí)例
	 */
	public static final BigNumberSerializer instance = new BigNumberSerializer(Number.class);
 
	public BigNumberSerializer(Class<? extends Number> rawType) {
		super(rawType);
	}
 
	@Override
	public void serialize(Number value, JsonGenerator gen, SerializerProvider provider) throws IOException {
		// 超出范圍 序列化位字符串
		if (value.longValue() > MIN_SAFE_INTEGER && value.longValue() < MAX_SAFE_INTEGER) {
			super.serialize(value, gen, provider);
		} else {
			gen.writeString(value.toString());
		}
	}
}

ObjectMapper配置

package com.knife.config;
 
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
 
@Configuration
public class JacksonConfig {
 
    @Bean
    public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
        ObjectMapper objectMapper = builder.createXmlMapper(false).build();
 
        // 全局配置序列化返回 JSON 處理
        SimpleModule simpleModule = new SimpleModule();
        // 將使用自定義序列化器來(lái)序列化Long類型
        simpleModule.addSerializer(Long.class, BigNumberSerializer.instance);
        simpleModule.addSerializer(Long.TYPE, BigNumberSerializer.instance);
        objectMapper.registerModule(simpleModule);
        return objectMapper;
    }
}

測(cè)試 

訪問(wèn):http://localhost:8080/user/find?id=1352213368413982722

法2:局部處理

說(shuō)明

在字段上加:@JsonSerialize(using= ToStringSerializer.class)。

實(shí)例

package com.knife.entity;
 
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data;
 
@Data
public class UserVO {
    @JsonSerialize(using= ToStringSerializer.class)
    private Long id;
 
    private String username;
}

測(cè)試 

訪問(wèn):http://localhost:8080/user/find?id=1352213368413982722

 到此這篇關(guān)于SpringBoot雪花算法主鍵ID傳到前端后精度丟失問(wèn)題的解決的文章就介紹到這了,更多相關(guān)SpringBoot雪花算法主鍵ID精度丟失內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java高并發(fā)的用戶線程和守護(hù)線程詳解

    java高并發(fā)的用戶線程和守護(hù)線程詳解

    本篇文章主要介紹了淺談java中守護(hù)線程與用戶線程,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2021-10-10
  • Go Java 算法之迷你語(yǔ)法分析器示例詳解

    Go Java 算法之迷你語(yǔ)法分析器示例詳解

    這篇文章主要為大家介紹了Go Java 算法之迷你語(yǔ)法分析器示例詳解,
    有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • Java中詳細(xì)解析Map接口

    Java中詳細(xì)解析Map接口

    這篇文章主要介紹了Java8 中 Map 接口的新方法,本文通過(guò)代碼實(shí)例給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-08-08
  • SpringBoot各種事務(wù)操作實(shí)戰(zhàn)(自動(dòng)回滾、手動(dòng)回滾、部分回滾)

    SpringBoot各種事務(wù)操作實(shí)戰(zhàn)(自動(dòng)回滾、手動(dòng)回滾、部分回滾)

    本文主要介紹了SpringBoot各種事務(wù)操作實(shí)戰(zhàn),包含自動(dòng)回滾、手動(dòng)回滾、部分回滾這三種,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2024-05-05
  • 使用JavaMail發(fā)送郵件保證成功的方法

    使用JavaMail發(fā)送郵件保證成功的方法

    JavaMail是利用現(xiàn)有的郵件賬戶發(fā)送郵件的工具,使用過(guò)JavaMail的api發(fā)送郵件的人可能會(huì)有這樣一個(gè)疑惑:我如何知道我調(diào)用該api發(fā)送的郵件是否成功呢?那么通過(guò)下面這篇文章大家一起來(lái)看看使用JavaMail保證郵件發(fā)送成功的方法,有需要的朋友們可以參考借鑒。
    2016-11-11
  • ajax實(shí)時(shí)監(jiān)測(cè)與springboot的實(shí)例分析

    ajax實(shí)時(shí)監(jiān)測(cè)與springboot的實(shí)例分析

    本文將介紹如何使用 AJAX 技術(shù)結(jié)合 Spring Boot 構(gòu)建一個(gè)實(shí)時(shí)反饋用戶輸入的應(yīng)用,我們將創(chuàng)建一個(gè)簡(jiǎn)單的輸入框,當(dāng)用戶在輸入框中鍵入文本時(shí),應(yīng)用將異步地向后端發(fā)送請(qǐng)求,感興趣的朋友跟隨小編一起看看吧
    2024-07-07
  • Java新手學(xué)習(xí)之IO流的簡(jiǎn)單使用

    Java新手學(xué)習(xí)之IO流的簡(jiǎn)單使用

    IO主要用于設(shè)備之間的數(shù)據(jù)傳輸,Java將操作數(shù)據(jù)流的功能封裝到了IO包中,這篇文章主要給大家介紹了關(guān)于Java新手學(xué)習(xí)之IO流簡(jiǎn)單使用的相關(guān)資料,需要的朋友可以參考下
    2021-10-10
  • Java中反射的應(yīng)用

    Java中反射的應(yīng)用

    這篇文章主要介紹了Java中反射的應(yīng)用,通過(guò)反射,我們可以在運(yùn)行時(shí)檢查類的屬性、方法和構(gòu)造函數(shù),并且可以在不知道類名的情況下創(chuàng)建對(duì)象、調(diào)用方法和訪問(wèn)屬性,需要的朋友可以參考下
    2023-10-10
  • 最新評(píng)論