Heim > Java > javaLernprogramm > Hauptteil

So lösen Sie das Problem des Präzisionsverlusts, nachdem die Primärschlüssel-ID des SpringBoot-Snowflake-Algorithmus an das Frontend übertragen wurde

PHPz
Freigeben: 2023-05-11 12:34:18
nach vorne
2793 Leute haben es durchsucht

Problembeschreibung

Der Bereich des Java-Backend-Long-Typs

  • -2^63~2^63, das heißt: -9223372036854775808~9223372036854775807, also 19 Bit.

  • Diese Zahl kann über die Methoden erhalten werden: Long.MAX_VALUE, Long_MIN_VALUE.

Der Bereich der numerischen Typen von Front-End-JS

  • -2^53~2^53, das heißt: -9007199254740991~9007199254740991, also 16-Bit.

  • Diese Zahl kann über folgende Methoden ermittelt werden: Number.MAX_SAFE_INTEGER, Number.MIN_SAFE_INTEGER.

Fazit

Es ist ersichtlich, dass die lange Breite des Java-Backends größer ist als die des Frontends. Der Snowflake-Algorithmus generiert im Allgemeinen Zahlen mit einer Breite von 18 oder 19 Bit, sodass zu diesem Zeitpunkt Probleme auftreten.

Projektszenario

1. Tabellenstruktur

Der Primärschlüsseltyp ist BIGINT, der die vom Snowflake-Algorithmus generierte ID speichert.

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

2.Entity

Verwenden Sie den Long-Typ, um dem BIGINT-Typ der Datenbank-ID zu entsprechen.

Der Snowflake-Algorithmus von MybatisPlus wird hier verwendet, um automatisch eine 19-stellige reine Zahl als Primärschlüssel-ID zu generieren. (Natürlich können Sie die ID auch manuell mit dem Snowflake-Algorithmus generieren.)

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

3. Reagieren Sie auf das Frontend.

Reagieren Sie auf das Frontend wie gewohnt mit JSON-Daten

{
  "id": 1352166380631257089,
   ...
}
Nach dem Login kopieren

Entity

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;
    }
}
Nach dem Login kopieren

Test

Visit: http://localhost:8080/user/find?id=1352213368413982722

Result

Das Problem wird reproduziert

Wie Sie oben sehen können, gibt es ist kein Problem.

So lösen Sie das Problem des Präzisionsverlusts, nachdem die Primärschlüssel-ID des SpringBoot-Snowflake-Algorithmus an das Frontend übertragen wurde

Warum gibt es kein Problem?

Das Front-End wird an das Back-End übergeben: SpingMVC konvertiert die String-Typ-ID automatisch in den Long-Typ, und es gibt keine Probleme. Das Back-End antwortet dem Front-End: Es ist im JSON-Format und hat nichts mit JS zu tun, und es wird keine Probleme geben

Wann könnte was schief gehen?

Nachdem das Frontend den JSON empfangen hat, serialisiert es ihn in ein JS-Objekt und führt dann andere Vorgänge aus. Beim Konvertieren von JSON in JS-Objekte treten folgende Probleme auf:

Sie können sehen, dass die ursprüngliche ID 1352213368413982722 lautet und nach der Serialisierung in ein JS-Objekt zu 1352213368413982700 wird. Der Code lautet:

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

Lösung

So lösen Sie das Problem des Präzisionsverlusts, nachdem die Primärschlüssel-ID des SpringBoot-Snowflake-Algorithmus an das Frontend übertragen wurdeEs gibt die folgenden zwei Lösungen: Ändern Sie das ID-Feld des Datenbanktabellenentwurfs vom Typ „Lang“ in den Typ „String“.

Das Front-End verwendet den String-Typ, um die ID zu speichern und die Genauigkeit zu gewährleisten, und das Back-End und die Datenbank verwenden weiterhin den Long-Typ (BigINT).

Option 1 verwendet den String-Typ als Datenbank-ID , und die Abfrageleistung wird erheblich sinken. Daher sollte Option 2 übernommen werden. In diesem Artikel wird Option 2 vorgestellt.

    Methode 1: Globale Verarbeitung
  • Einführung
  • ObjectMapper anpassen.

  • Option 1: ToStringSerializer (empfohlen)
const json = '{"id": 1352213368413982722, "name": "Tony"}';
const obj = JSON.parse(json);
 
console.log(obj.id);
console.log(obj.name);
Nach dem Login kopieren

Test

Visit: http://localhost:8080/user/find?id=1352213368413982722

Option 2: Benutzerdefinierter Serializer (nicht empfohlen)

Serialisierer

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来序列化Long类型
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
        objectMapper.registerModule(simpleModule);
        return objectMapper;
    }
}
Nach dem Login kopieren

ObjectMapper-Konfiguration

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 {
 
	/**
	 * 根据 JS Number.MAX_SAFE_INTEGER 与 Number.MIN_SAFE_INTEGER 得来
	 */
	private static final long MAX_SAFE_INTEGER = 9007199254740991L;
	private static final long MIN_SAFE_INTEGER = -9007199254740991L;
 
	/**
	 * 提供实例
	 */
	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());
		}
	}
}
Nach dem Login kopieren

Test

Besuch: http://localhost:8080/user/find?id=1352213368413982722

So lösen Sie das Problem des Präzisionsverlusts, nachdem die Primärschlüssel-ID des SpringBoot-Snowflake-Algorithmus an das Frontend übertragen wurde

Methode 2: Lokale Verarbeitung

Anweisungen

at Hinzufügen: @JsonSerialize( using= ToStringSerializer.class) in das Feld ein.

InstanzSo lösen Sie das Problem des Präzisionsverlusts, nachdem die Primärschlüssel-ID des SpringBoot-Snowflake-Algorithmus an das Frontend übertragen wurde

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();
        // 将使用自定义序列化器来序列化Long类型
        simpleModule.addSerializer(Long.class, BigNumberSerializer.instance);
        simpleModule.addSerializer(Long.TYPE, BigNumberSerializer.instance);
        objectMapper.registerModule(simpleModule);
        return objectMapper;
    }
}
Nach dem Login kopieren

Test

Besuch: http://localhost:8080/user/find?id=1352213368413982722

Das obige ist der detaillierte Inhalt vonSo lösen Sie das Problem des Präzisionsverlusts, nachdem die Primärschlüssel-ID des SpringBoot-Snowflake-Algorithmus an das Frontend übertragen wurde. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:yisu.com
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage