当前位置: 首页 > article >正文

前后端的双精度浮点数精度不一致问题解决方案,自定义Spring的消息转换器处理JSON转换

在 Java 中,Long 是一个 64 位的长整型,通常用于表示很大的整数。在后端,Long 类型的数据没有问题,因为 Java 本身使用的是 64 位的整数,可以表示的范围非常大。

但是,在前端 JavaScript 中,Long 类型的数据可能会出现精度问题。原因在于 JavaScript 使用的是 双精度浮点数(Number 类型) 来表示数字,而双精度浮点数只能精确表示 最大 53 位的整数,超过 53 位的整数会丢失精度。

具体来说,JavaScript 的 Number 类型可以表示的最大整数是 2^53 - 1,即 9007199254740991。而任何超过这个范围的整数(比如某些大于 53 位的 ID)就会出现精度丢失,无法精确表示。

假设你在后端生成了一个大于 9007199254740991 的 Long 类型 ID,例如:

Long id = 1234567890123456789L;
然后通过接口返回给前端,在前端的 JavaScript 中,数字会被转换为 Number 类型,可能会出现精度丢失的情况:
let id = 1234567890123456789;  // JavaScript 会将其转换为双精度浮点数
console.log(id);  // 输出: 1234567890123456700

可以看到,前端打印出来的数字已经失去了精度,因为超出了 JavaScript Number 类型能精确表示的范围。

解决思想是将Long转化为String,但解决方式有很多,要么你在对应数据库表的实体类(比如User)的id类型设置为String,要么可以进行如下配置:

package com.xxx.xxxxx.common;import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import java.math.BigInteger;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;/*** 对象映射器:基于jackson将Java对象转为json,或者将json转为Java对象* 将JSON解析为Java对象的过程称为 [从JSON反序列化Java对象]* 从Java对象生成JSON的过程称为 [序列化Java对象到JSON]*/
public class JacksonObjectMapper extends ObjectMapper {public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";public JacksonObjectMapper() {super();//收到未知属性时不报异常this.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);//反序列化时,属性不存在的兼容处理this.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);SimpleModule simpleModule = new SimpleModule().addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT))).addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT))).addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT))).addSerializer(BigInteger.class, ToStringSerializer.instance).addSerializer(Long.class, ToStringSerializer.instance).addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT))).addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT))).addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));//注册功能模块 例如,可以添加自定义序列化器和反序列化器this.registerModule(simpleModule);}
}
package com.xxx.xxxxx.config;import com.xxx.xxxxx.common.JacksonObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;import java.util.List;@Slf4j
@Configuration
// 继承自 WebMvcConfigurationSupport,这表示让这个类成为 Spring MVC 配置的一部分,允许你定制 Spring MVC 的配置
public class WebConfig extends WebMvcConfigurationSupport {@Overrideprotected void addResourceHandlers(ResourceHandlerRegistry registry) {log.info("资源映射开始。。");registry.addResourceHandler("/backend/**").addResourceLocations("classpath:/backend/");registry.addResourceHandler("/front/**").addResourceLocations("classpath:/front/");}@Overrideprotected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {// 添加一个转换器,除自带八大转换器外,将Long装成StringMappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();converter.setObjectMapper(new JacksonObjectMapper());// 优先级设置到最高,让spring优先用咱自己自定义的转换器converters.add(0,converter);}
}
http://www.lryc.cn/news/2384960.html

相关文章:

  • docker安装es连接kibana并安装分词器
  • 线性回归中涉及的数学基础
  • 如何计算VLLM本地部署Qwen3-4B的GPU最小配置应该是多少?多人并发访问本地大模型的GPU配置应该怎么分配?
  • PostgreSQL日常维护
  • Attu下载 Mac版与Win版
  • V2X协议|如何做到“车联万物”?【无线通信小百科】
  • 【zookeeper】--部署3.6.3
  • [测试_3] 生命周期 | Bug级别 | 测试流程 | 思考
  • 物联网(IoT)智能项目全景指南:技术构架、实现细节与应用实践
  • 【Go】1、Go语言基础
  • RabbitMQ ⑤-顺序性保障 || 消息积压 || 幂等性
  • java基础知识回顾1(可用于Java基础速通)考前,面试前均可用!
  • 云原生CICD-Tekton入门到精通
  • CMake跨平台编译生成:从理论到实战
  • MCP 协议传输机制大变身:抛弃 SSE,投入 Streamable HTTP 的怀抱
  • opencv 图像的平移和旋转
  • IDEA2025版本使用Big Data Tools连接Linux上Hadoop的HDFS
  • hysAnalyser特色的TS流编辑、剪辑和转存MP4功能说明
  • Day125 | 灵神 | 二叉树 | 二叉树中的第K大层和
  • Google机器学习实践指南(学习速率篇)
  • JS实现直接下载PDF文件
  • 使用KubeKey快速部署k8s v1.31.8集群
  • FreeSWITCH 纯内网配置
  • leetcode hot100:十四、解题思路大全:真·大全!
  • kali的简化安装
  • 交换机的连接方式堆叠和级联
  • Vortex GPGPU的github流程跑通与功能模块波形探索(三)
  • React深度解析:Hooks体系与Redux Toolkit现代状态管理实践
  • 实用蓝牙耳机哪款好?先做好使用场景分析!
  • Rules and Monetization