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

简介: 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
@Configuration
public 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天前
|
JavaScript 前端开发
Angular.js 应用中数据模式的删除操作实现
Angular.js 应用中数据模式的删除操作实现
16 0
|
3天前
|
前端开发 JavaScript 算法
JavaScript 中实现常见数据结构:栈、队列与树
JavaScript 中实现常见数据结构:栈、队列与树
|
4天前
|
存储 JSON JavaScript
Node.js 上开发一个 HTTP 服务器,监听某个端口,接收 HTTP POST 请求并处理传入的数据
Node.js 上开发一个 HTTP 服务器,监听某个端口,接收 HTTP POST 请求并处理传入的数据
13 0
|
4天前
|
JavaScript 前端开发 C语言
JavaScript编程语法练习
本篇文章是对于javaScript中if ,switch,while ,do-while,,for语法的作业练习.对于我来说也是对自己知识掌握的一种检验.是对js的基础语法进行的一次练习,通过有趣的示例进行练习,使得对于代码能够增加印象,对于知识的掌握更加透彻.
|
4天前
|
JSON JavaScript Java
从前端Vue到后端Spring Boot:接收JSON数据的正确姿势
从前端Vue到后端Spring Boot:接收JSON数据的正确姿势
26 0
|
4天前
|
SQL Java 数据库连接
Springboot框架整合Spring JDBC操作数据
JDBC是Java数据库连接API,用于执行SQL并访问多种关系数据库。它包括一系列Java类和接口,用于建立数据库连接、创建数据库操作对象、定义SQL语句、执行操作并处理结果集。直接使用JDBC涉及七个步骤,包括加载驱动、建立连接、创建对象、定义SQL、执行操作、处理结果和关闭资源。Spring Boot的`spring-boot-starter-jdbc`简化了这些步骤,提供了一个在Spring生态中更便捷使用JDBC的封装。集成Spring JDBC需要添加相关依赖,配置数据库连接信息,并通过JdbcTemplate进行数据库操作,如插入、更新、删除和查询。
|
4天前
|
SQL Java 数据库连接
Springboot框架整合Spring Data JPA操作数据
Spring Data JPA是Spring基于ORM和JPA规范封装的框架,简化了数据库操作,提供增删改查等接口,并可通过方法名自动生成查询。集成到Spring Boot需添加相关依赖并配置数据库连接和JPA设置。基础用法包括定义实体类和Repository接口,通过Repository接口可直接进行数据操作。此外,JPA支持关键字查询,如通过`findByAuthor`自动转换为SQL的`WHERE author=?`查询。
|
4天前
|
缓存 监控 Java
【Spring系列笔记】AOP
面向切面编程就是面向特定方法编程。通过将横切关注点(cross-cutting concerns)从主要业务逻辑中分离出来,提供一种更好的代码模块化和可维护性。 横切关注点指的是在应用程序中横跨多个模块或层的功能,例如日志记录、事务管理、安全性、缓存、异常处理等。
25 0
|
4天前
|
存储 缓存 Java
【Spring系列笔记】依赖注入,循环依赖以及三级缓存
依赖注入: 是指通过外部配置,将依赖关系注入到对象中。依赖注入有四种主要方式:构造器注入、setter方法注入、接口注入以及注解注入。其中注解注入在开发中最为常见,因为其使用便捷以及可维护性强;构造器注入为官方推荐,可注入不可变对象以及解决循环依赖问题。本文基于依赖注入方式引出循环依赖以及三层缓存的底层原理,以及代码的实现方式。
24 0
|
4天前
|
前端开发 Java 数据格式
【Spring系列笔记】定义Bean的方式
在Spring Boot应用程序中,定义Bean是非常常见的操作,它是构建应用程序的基础。Spring Boot提供了多种方式来定义Bean,每种方式都有其适用的场景和优势。
32 2