当前位置:首页 > 技术文章 > 正文内容

Spring Boot3 中解决返回接口 Long 类型数据精度损失问题全解析

在互联网软件开发领域,Spring Boot 作为一款广受欢迎的框架,极大地简化了 Java 应用程序的开发过程。然而,在实际开发中,开发人员常常会遇到各种棘手的问题。其中,当 Spring Boot 3 项目的接口返回 Long 类型数据时,前端出现精度损失的情况,就像一颗隐藏在程序深处的 “暗雷”,让不少开发人员头疼不已。今天,咱们就一起来深入剖析这个问题,并探讨出切实可行的解决方案。

问题根源探究

在深入探讨解决方案之前,我们必须先搞清楚为什么会出现 Long 类型数据精度损失的问题。在 JavaScript 中,Number 类型所能表示的安全整数范围是有限的,其范围为 - 2^53 到 2^53(即 - 9007199254740992 到 9007199254740992)。一旦后端返回的 Long 类型数据超出了这个范围,前端在处理时就极有可能出现精度丢失的情况。这是因为 JavaScript 采用 IEEE 754 双精度浮点数格式来存储数字,该格式无法精准表示超过 53 位的整数。

例如,假设我们在后端有一个 Java 对象,其中某个属性为 Long 类型,值为 1234567890123456789L。当这个对象通过接口以 JSON 格式返回给前端时,在前端 JavaScript 环境中,这个值可能就会被错误地解析为 1234567890123456000,从而导致数据出现偏差,影响整个业务逻辑的正确性。

解决方案详解

(一)使用注解方式(局部处理)

针对特定的字段或类,我们可以利用 Jackson 的 @JsonSerialize 注解,将 Long 类型的数据以字符串的形式传输,从而巧妙地避开前端的精度问题。下面来看具体的代码示例:

import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;

public class YourClass {
    @JsonSerialize(using = ToStringSerializer.class)
    private Long id;
    // 其他属性和方法
}

在上述代码中,通过@JsonSerialize(using = ToStringSerializer.class)这行代码,我们告诉 Jackson 在序列化id这个 Long 类型字段时,将其转换为字符串形式。这样一来,前端接收到的数据就是字符串,不会因为 JavaScript 的数字精度限制而出现精度丢失的情况。这种方式非常灵活,适用于我们只需要对部分特定字段进行处理的场景。

全局配置 ObjectMapper

倘若我们希望一劳永逸,在整个项目中全局解决 Long 类型数据精度丢失的问题,那么可以通过修改 Spring Boot 中ObjectMapper的配置来实现。具体有以下两种常见的实现方式:

通过配置类

首先,我们创建一个 Jackson 的配置类,在这个类中定义一个 Bean 来配置ObjectMapper。代码如下:

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;

@Configuration
public class JacksonConfig {

    @Bean
    public ObjectMapper objectMapper() {
        ObjectMapper objectMapper = new ObjectMapper();
        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addSerializer(Long.class, new ToStringSerializer());
        simpleModule.addSerializer(Long.TYPE, new ToStringSerializer());
        objectMapper.registerModule(simpleModule);
        return objectMapper;
    }
}

在这个配置类中,我们创建了一个SimpleModule,并向其中添加了针对Long类型的序列化器ToStringSerializer。然后将这个模块注册到ObjectMapper中。经过这样的配置,Spring Boot 在进行 JSON 序列化时,所有的 Long 类型数据都会被自动转换为字符串类型,无需我们逐个字段去添加注解。

通过应用配置文件

除了通过配置类,我们还可以在application.properties或application.yml文件中添加配置,告诉 Jackson 将 Long 类型序列化为字符串。

如果是application.properties文件,添加如下配置:

spring.jackson.serialization.write-numbers-as-strings=true

若是application.yml文件,则配置如下:

spring:
  jackson:
    serialization:
      write-numbers-as-strings: true

这两种配置方式都能实现将 Long 类型字段全局序列化为字符串类型的目的。开发人员可以根据项目的实际情况和个人偏好来选择使用哪种方式。

方案对比与选择

(一)注解方式

优点

  • 灵活性高:可以针对具体的某个字段或类进行单独配置,对于一些局部性的需求,这种方式能够精准地满足。比如,在一个大型项目中,可能只有少数几个特定模块的 Long 类型字段需要特殊处理,此时使用注解方式就显得非常合适。
  • 对现有代码侵入性小:如果项目已经有大量的代码,并且大部分 Long 类型字段无需特殊处理,仅对个别字段使用注解,不会对整体代码结构造成太大的影响。

缺点

  • 工作量较大:当需要处理的 Long 类型字段较多时,就需要逐个字段或类去添加注解,这无疑会增加一定的开发工作量和维护成本。

(二)全局配置方式

优点

  • 一次配置,全局生效:只需要进行一次全局配置,项目中所有的 Long 类型数据在返回给前端时都会自动转换为字符串类型,大大提高了开发效率,尤其适用于整个项目中 Long 类型数据都可能存在精度问题的场景。
  • 便于维护:在后期维护过程中,如果需要对 Long 类型数据的处理方式进行调整,只需要在配置文件或配置类中修改一处即可,而不需要在大量的代码文件中逐个查找和修改注解。

缺点

  • 缺乏针对性:由于是全局配置,可能会对一些原本不需要将 Long 类型转换为字符串的场景也产生影响。比如,在某些特定的内部接口调用中,Long 类型数据的精度问题并不存在,此时全局配置可能会带来一些不必要的性能开销。

在实际项目中,我们需要根据具体的业务需求、项目规模以及代码结构等因素来综合考虑选择哪种解决方案。如果项目中大部分 Long 类型数据都需要避免精度损失,并且对全局配置的影响可以接受,那么全局配置ObjectMapper的方式会更加高效和便捷;而如果只是个别字段存在问题,或者对代码的灵活性要求较高,注解方式则是更好的选择。

总结

在 Spring Boot 3 开发中,解决返回接口 Long 类型数据精度损失问题是确保系统数据准确性和稳定性的重要一环。通过深入理解问题产生的根源,灵活运用注解方式和全局配置ObjectMapper这两种解决方案,我们能够有效地应对这一挑战。同时,在选择具体方案时,要充分权衡各种因素,以实现最佳的开发效果。希望本文所分享的内容能够帮助广大互联网软件开发人员在实际项目中顺利解决这一常见问题,提升项目的质量和用户体验。在不断变化的技术领域中,持续学习和探索,我们才能更好地应对各种新的挑战,创造出更加优秀的软件产品。

相关文章

7 款最佳 Linux 桌面发行版,颜值天花板

一、elementary OS二、Deepin三、Pop!_OS四、Manjaro Linux五、KDE Neon六、Zorin OS七、Nitrux OS想必大家都知道三大常用操作系统:Linux、...

「图解」父子组件通过 props 进行数据交互的方法

1.组件化开发,经常有这样的一个场景,就是父组件通过 Ajax 获取数据,传递给子组件,如何通过 props 进行数据交互来实现,便是本图解的重点。2.代码的结构3.具体代码 ①在父组件 data 中...

2个将HTML5打包成app的方法(h5打包成android)

越来越多的开发者热衷于使用html5+JavaScript开发移动Web App。不过,HTML5 Web APP的出现能否在未来取代移动应用,就目前来说,还是个未知数。那么,有什么办法,既可以使用H...

html5你能把太阳系动态做出来,但是你能把月亮也做出来吗?

需要源码请评论后加前端学习群470593776课题:HTML5加原生js打造一个炫酷动态的太阳系简介:首先对于太阳系各大星球的运转关系,速度等资料,不然弄出来也是被喷的下场, 还有对于逻辑思维,算法的...

一键看懂Html5,就这么简单(查看html的app推荐)

HTML5是WEB开发世界的一次重大的改变,事实上不管你是否喜欢,它都是代表着未来趋势。曾几何时,当HTML5出现在web端开发领域的时候,并没有引起太多人的注意,究其原因,一方面是它还没有被广泛的支...

2021系列——JavaScript比较数组的7种方法

本文我会介绍一些基于Property值对数组进行排序的方法,希望这些技巧能够对你2021年的JS代码编写有点点帮助。多多少少在JS中,我们会碰到某种方式来比较两个对象数组并找出差异,当然也可能是比较并...