现象
前端js获取id然后查询详情信息,发现查询不到结果,然而id值时后端传给前台的,前端获取到id值然后到后端去请求,发现查询不到结果,然后代码跟踪,发现前端传的id参数值和后端传回的值不一样,后面几位莫名其妙变成0了。
原因
js long过大会导致精度丢失。(大整数的精度丢失和浮点数本质上是一样的,尾数位最大是 52 位,因此 JS 中能精准表示的最大整数是 Math.pow(2, 53),十进制即 9007199254740992。大于 9007199254740992 的可能会丢失精度)
解决思路
后端返回json格式数据的,对id进行转换,转换成字符串,这样避免的js long精度丢失问题。
解决办法
springMVC项目
第一步:自定义消息转换器
自定义消息转换器,转换long型为String型,代码如下所示:
import java.io.IOException;import java.math.BigInteger;import java.sql.Timestamp;import java.text.SimpleDateFormat;import java.util.Date;import java.util.TimeZone;import org.springframework.stereotype.Component;import com.fasterxml.jackson.core.JsonGenerator;import com.fasterxml.jackson.core.JsonProcessingException;import com.fasterxml.jackson.databind.JsonSerializer;import com.fasterxml.jackson.databind.ObjectMapper;import com.fasterxml.jackson.databind.SerializerProvider;import com.fasterxml.jackson.databind.module.SimpleModule;/*** @Title CustomObjectMapper.java* @Description*/@Component("customObjectMapper")public class CustomObjectMapper extends ObjectMapper {private static final long serialVersionUID = 1L;public CustomObjectMapper() {// 日期转换SimpleModule module = new SimpleModule();module.addSerializer(Date.class, new JsonSerializer<Date>() {@Overridepublic void serialize(Date date, JsonGenerator jsonGenerator, SerializerProvider arg2) throws IOException, JsonProcessingException {SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd");jsonGenerator.writeString(sdf1.format(date));}});this.registerModule(module);// Long to StringSimpleModule module2 = new SimpleModule();module2.addSerializer(Long.class, new JsonSerializer<Long>() {@Overridepublic void serialize(Long value, JsonGenerator jsonGenerator, SerializerProvider arg2) throws IOException, JsonProcessingException {if (value != null) {jsonGenerator.writeString(value.toString());}}});this.registerModule(module2);// 设置时区this.setTimeZone(TimeZone.getDefault());// getTimeZone("GMT+8:00")}}
第二步:mvc xml中配置自定义消息转换器
第三步:mybatis mapper xml文件中返回resultType=”map”,申明javaType
PS:经过几番测试,如果resultType=”map”,不会调用自定义Long to String转换器模块,只有自定义返回map,并且申明javaType=”java.lang.Long”,才会走自定义Long to String转换器模块,因为mybatis默认是BigDecimal。
springBoot项目
第一步:自定义转换器继承jackson2HttpMessageConverter
自定义转换器继承jackson2HttpMessageConverter,自定义实例化MappingJackson2HttpMessageConverterbean,代码如下所示:
package com.ruoyi.framework.config;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;import com.fasterxml.jackson.annotation.JsonInclude;import com.fasterxml.jackson.databind.MapperFeature;import com.fasterxml.jackson.databind.ObjectMapper;import com.fasterxml.jackson.databind.module.SimpleModule;import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;/*** Jackson配置*/@Configurationpublic class JacksonConfig {@Beanpublic MappingJackson2HttpMessageConverter jackson2HttpMessageConverter() {final Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();builder.serializationInclusion(JsonInclude.Include.NON_NULL);final ObjectMapper objectMapper = builder.build();SimpleModule simpleModule = new SimpleModule();// Long 转为 String 防止 js 丢失精度simpleModule.addSerializer(Long.class, ToStringSerializer.instance);objectMapper.registerModule(simpleModule);// 忽略 transient 关键词属性objectMapper.configure(MapperFeature.PROPAGATE_TRANSIENT_MARKER, true);return new MappingJackson2HttpMessageConverter(objectMapper);}}
第二步:mybatis mapper xml文件中返回resultType=”map”,申明javaType
PS:经过几番测试,如果resultType=”map”,不会调用自定义Long to String转换器模块,只有自定义返回map,并且申明javaType=”java.lang.Long”,才会走自定义Long to String转换器模块,因为mybatis默认是BigDecimal。
