写点什么

Spring-boot 项目练习笔记(一)JS 处理 Long 型数据精度丢失问题

作者:赵四司机
  • 2022 年 8 月 11 日
    广东
  • 本文字数:3296 字

    阅读完需:约 11 分钟

Spring-boot项目练习笔记(一)JS处理Long型数据精度丢失问题

前言:最近在跟着视频做 JAVA 入门项目,故开启这一系列的笔记,这也是我第一次进行系统性总结,我将会在这一系列的文章中记录我开发中遇到的问题,希望能帮到有遇到同样问题的人,当然如果有错的还请大家多多指教。

一:问题引入

在生成用户 id 时候,我们经常使用雪花算法来生成 id,以确保每个用户的 id 是不重复的,但是在根据 id 对数据进行更改操作时候,会发现程序不报错但是却没有更改成功的情况,不通过断点调试还真不知道哪里出了问题,下面我将演示这一过程:刚进入主界面按分页显示数据时候,按 F12 通过浏览器的调式工具查看响应回来的数据:



对比数据库中的数据:



可以看到响应回来的是正确的数据,但是如果这时候我想修改员工的状态信息,查看发送的数据:



打印日志:



可以看到这时候传过去的 id 是不正确的,这就会造成修改不成功但是不会报错。

二:原因

为什么会出现这样的情况呢?原因是分页查询时候服务端响应给页面的数据 id 的值为 19 位数字,类型为 Long,而 JS 处理 Long 型数字只能精确到前 16 位,最后三位会进行四舍五入处理,所以最终通过 ajax 请求提交给服务端的时候 id 会丢失精度。下面验证这一现象,验证方法也很简单,我们只需要 alert 一个 Long 型数字即可。执行代码 alert(1234567891234567891)



可以看到精度丢失了。

三:解决方案

在服务端给客户端页面响应数据时候,会用到 Spring mvc 的消息转换器,我们可以扩展这个消息转换器。既然 JS 处理 Long 型数据精度会丢失,那么我们可以在服务端给页面响应返回 JSON 数据时候进行处理,将 Long 型数据转换为 String 类型再进行返回就能确保到时候再传回来时精度不丢失。具体实现步骤:1.提供对象转换器 JacksonObjectMapper,基于 Jackson 进行 Java 对象到 Json 数据转换,此映射器除了能把 Java 对象转换为 json 数据之外,还能将日期类型数据进行转换以更方便查看。


package com.my.pro1.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) //处理Long型数据 .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); }}
复制代码


2.在 WebMvcConfig 配置类中扩展 Spring mvc 的消息转换器,在此消息转化器中使用提供的对象转换器进行 Java 对象到 json 数据转换。


package com.my.pro1.config;
import com.my.reggie.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@Configurationpublic class WebMvcConfig extends WebMvcConfigurationSupport { /** * 设置静态资源映射 */ @Override protected void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/**").addResourceLocations("classpath:/static/"); }
/** * 拓展mvc框架的消息转换器 * @param converters */ @Override protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) { //创建消息转换器对象 MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter(); //设置具体的对象映射器 messageConverter.setObjectMapper(new JacksonObjectMapper()); //通过设置索引,让自己的转换器放在最前面,否则默认的jackson转换器会在前面,用不上自己配置的转换器 converters.add(0,messageConverter); }}
复制代码


这里要注意最后一步要将自己的转换器放在最前面,否则默认的 jackson 转换器会在前面,用不上自己配置的转换器

四:处理结果

这时候再执行更新操作


    /**     * 修改员工状态     * @param employee  //传入的员工id及状态信息     * @return //R<String>     */    @PutMapping    public R<String> updateStatus(HttpServletRequest request,@RequestBody Employee employee){        Long id = (Long) request.getSession().getAttribute("employee");        employee.setUpdateUser(id);        employee.setUpdateTime(LocalDateTime.now());        log.info(employee.toString());        boolean b = employeeService.updateById(employee);        if(b){            return R.success("修改成功!");        }        return  R.error("修改失败!");    }
复制代码



可以看到传过来的参数没有问题,至此问题解决。

发布于: 刚刚阅读数: 4
用户头像

赵四司机

关注

还未添加个人签名 2022.08.06 加入

还未添加个人简介

评论

发布
暂无评论
Spring-boot项目练习笔记(一)JS处理Long型数据精度丢失问题_Java web_赵四司机_InfoQ写作社区