解析Spring Mvc Long类型精度丢失问题

 更新时间:2021年06月07日 09:14:01   作者:诸葛小亮  
在平时开发过程中,经常会使用long类型作为id的类型,但是在使用过程中会导致long类型数据转换为number类型时的后两位变为0,今天小编给大家分享Spring Mvc Long类型精度丢失问题,需要的朋友参考下吧

背景

在使用Spring Boot Mvc的项目中,使用Long类型作为id的类型,但是当前端使用Number类型接收Long类型数据时,由于前端精度问题,会导致Long类型数据转换为Number类型时的后两位变为0

Spring Boot Controller

以下代码提供一个Controller,返回一个Dto, Dto的id是Long类型的,其中id的返回数据是1234567890102349123
@CrossOrigin 注解表示可以跨域访问

@RestController()
@RequestMapping
public class LongDemoController {

    @GetMapping("getLongValue")
    @CrossOrigin(origins = "*")
    public GetLongValueDto getLongValue(){
        GetLongValueDto result = new GetLongValueDto();
        result.setId(1234567890102349123L);
        return result;
    }

    @Data
    public static class GetLongValueDto{
        private Long id;
    }

}

前端调用

现在使用jquery调用后端地址,模拟前端调用

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>spring boot mvc long</title>
</head>
<body>
<p>Long:<span id='resId'></span></p>
<p>Id类型:<span id='idType'></span></p>
 
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
<script type="text/javascript">
$(document).ready(function(){
	console.log('init');
	$.ajax({url:"http://localhost:8080/getLongValue"})
		.then(res=>{
			console.log({
				'getLongValue':res
			});
			$('#resId').text(res.id);
			$('#idType').text(typeof res.id);
		})
});
</script>
</body>
</html>

运行结果

通过输出结果和查看网络的内容,发现实际上id返回的结果是1234567890102349000,最后几位都变成了00, 这是因为,javascript的Number类型最大长度是17位,而后端返回的Long类型有19位,导致js的Number不能解析。

方案

既然不能使用js的Number接收,那么前端如何Long类型的数据呢,答案是js使用string类型接收

方案一 @JsonSerialize 注解

修改Dto的id字段,使用@JsonSerialize注解指定类型为string。
这个方案有一个问题,就是需要程序员明确指定@JsonSerialize, 在实际的使用过程中,程序员会很少注意到Long类型的问题,只有和前端联调的时候发现不对。

@Data
    public static class GetLongValueDto{
        @JsonSerialize(using= ToStringSerializer.class)
        private Long id;
    }

方案二 全局处理器

添加Configuration, 处理 HttpMessageConverter

@Configuration
public class WebConfiguration implements WebMvcConfigurer {
    /**
     * 序列化json时,将所有的long变成string
     * 因为js中得数字类型不能包含所有的java long值
     */
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        MappingJackson2HttpMessageConverter jackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
        ObjectMapper objectMapper = new ObjectMapper();
        SimpleModule simpleModule=new SimpleModule();
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
        objectMapper.registerModule(simpleModule);
        jackson2HttpMessageConverter.setObjectMapper(objectMapper);
        converters.add(0,jackson2HttpMessageConverter);
    }
}
@Data
    public static class GetLongValueDto{
        private Long id;
    }

发现没有@JsonSerialize注解的信息,前端接收到的数据,也是string类型了。

与swagger集成

上面只是解决了传输时的long类型转string,但是当集成了swagger时,swagger文档描述的类型仍然是number类型的,这样在根据swagger文档生成时,会出现类型不匹配的问题

swagger 文档集成

pom或gradle

implementation group: 'io.springfox', name: 'springfox-boot-starter', version: '3.0.0'
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-boot-starter</artifactId>
    <version>3.0.0</version>
</dependency>

查看文档, 发现 GetLongValueDto 描述的id类型是 integer($int64)

swagger long类型描述为string

需要修改swagger的配置, 修改 Docket 的配置

.directModelSubstitute(Long.class, String.class)
                .directModelSubstitute(long.class, String.class)
@Configuration
public class SwaggerConfig {
    @Bean
    public Docket api() {
        return new Docket(DocumentationType.SWAGGER_2)
                .select()
                .apis(RequestHandlerSelectors.any())//api的配置路径
                .paths(PathSelectors.any())//扫描路径选择
                .build()
                .directModelSubstitute(Long.class, String.class)
                .directModelSubstitute(long.class, String.class)
                .apiInfo(apiInfo());
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("title") //文档标题
                .description("description")//接口概述
                .version("1.0") //版本号
                .termsOfServiceUrl(String.format("url"))//服务的域名
                //.license("LICENSE")//证书
                //.licenseUrl("http://www.guangxu.com")//证书的url
                .build();
    }

}

查看swagger文档 , 可以看到 文档中类型已经是 string了

总结

  • long类型传输到前端的两种方案:注解、修改HttpMessageConverter
  • 使用directModelSubstitute解决swagger文档中类型描述,避免生成代码器中描述的类型错误

以上就是Spring Mvc Long类型精度丢失的详细内容,更多关于Spring Mvc Long类型的资料请关注脚本之家其它相关文章!

相关文章

  • 详解SpringBoot是如何整合SpringDataRedis的?

    详解SpringBoot是如何整合SpringDataRedis的?

    今天给大家带来的是关于Java的相关知识,文章围绕着SpringBoot是如何整合SpringDataRedis展开,文中有非常详细的介绍及代码示例,需要的朋友可以参考下
    2021-06-06
  • SpringMVC运行时出现404错误的解决办法汇总(基本包含所有错误可能)

    SpringMVC运行时出现404错误的解决办法汇总(基本包含所有错误可能)

    初学SpringMVC基本都会碰到404问题(确实也困扰了我好长时间),但出现404问题的原因有很多,如果确认路径,代码没问题,并且服务器可以正常启动,依然出现404问题的话,就根据本篇步骤逐一排查,需要的朋友可以参考下
    2024-04-04
  • Java基础之SpringBoot整合knife4j

    Java基础之SpringBoot整合knife4j

    Swagger现在已经成了最流行的接口文档生成与管理工具,但是你是否在用的时候也在吐槽,它是真的不好看,接口测试的json数据没法格式化,测试地址如果更改了还要去改配置,接口测试时增加token验证是真的麻烦…针对Swagger的种种缺点,Knife4j就呼之欲出了.需要的朋友可以参考下
    2021-05-05
  • springboot多数据源使用@Qualifier自动注入无效的解决

    springboot多数据源使用@Qualifier自动注入无效的解决

    这篇文章主要介绍了springboot多数据源使用@Qualifier自动注入无效的解决,具有很好的参考价值,希望对大家有所帮助。也希望大家多多支持脚本之家
    2021-11-11
  • Spring Boot项目完美大一统(结果异常日志统一)

    Spring Boot项目完美大一统(结果异常日志统一)

    这篇文章主要为大家介绍了Spring Boot项目完美大一统(结果异常日志统一)的实详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2024-01-01
  • SpringBoot 整合Jest实例代码讲解

    SpringBoot 整合Jest实例代码讲解

    本文通过实例代码给大家介绍了SpringBoot 整合Jest的相关知识,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
    2018-08-08
  • JAVA获取文件绝对路径的方法

    JAVA获取文件绝对路径的方法

    这篇文章主要介绍了JAVA获取文件绝对路径的方法,涉及针对文件路径的操作技巧,需要的朋友可以参考下
    2015-02-02
  • 详解Java线程池如何统计线程空闲时间

    详解Java线程池如何统计线程空闲时间

    这篇文章主要和大家分享一个面试题:Java线程池是怎么统计线程空闲时间?文中的示例代码讲解详细,对我们掌握Java有一定帮助,需要的可以参考一下
    2022-11-11
  • 通过dom4j解析xml字符串(示例代码)

    通过dom4j解析xml字符串(示例代码)

    本篇文章主要是对通过dom4j解析xml字符串的示例代码进行了介绍,需要的朋友可以过来参考下,希望对大家有所帮助
    2013-12-12
  • java中的Object类的toSpring()方法

    java中的Object类的toSpring()方法

    这篇文章主要介绍了java中的Object类的toSpring()方法,Object是类层次结构的根,每个类都可以将Object作为超类。所有类都直接或者间接的继承自该类,下文相关资料,需要的朋友可以参考下
    2022-04-04

最新评论