前言:最近在跟着视频做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;
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);
}
}
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/");
}
@Override
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
messageConverter.setObjectMapper(new JacksonObjectMapper());
converters.add(0,messageConverter);
}
}
这里要注意最后一步要将自己的转换器放在最前面,否则默认的jackson转换器会在前面,用不上自己配置的转换器
四:处理结果
这时候再执行更新操作
@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("修改失败!");
}
可以看到传过来的参数没有问题,至此问题解决。
|