一. 前提
- 线上有一张表,主见id原来使用的是自增id。但是有一个新的业务,在做这个业务的时候,这个id被赋值为雪花算法。致使这个表的主见id值特别大。
- 线上有很多业务进行修改的时候,都是通过此表的id进行修改。突然,有人反馈说功能无法使用。这个时候我们立马进行排查,发现我们返回给前端id的值发生了四舍五入的情况。
- 后续通过网上查找,发现是说因为Long类型的数值太多,超过了前端js的显示长度,所以就会出现精度丢失的情况,需要将Long类型转换成String类型才不会精度丢失
二 . 解决办法
解决办法我们采取了全局配置,在序列化的时候将Long转换成String。如下
package cn.lili.common.config;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonGenerator;
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;
/**
* 返回Long转换为String
*
*
*/
public class JacksonMapper extends ObjectMapper {
public JacksonMapper() {
super();
this.configure(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN, true);
this.configure(JsonGenerator.Feature.IGNORE_UNKNOWN, true);
this.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
this.setSerializationInclusion(JsonInclude.Include.NON_NULL);
SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
simpleModule.addSerializer(long.class, ToStringSerializer.instance);
registerModule(simpleModule);
}
}
package cn.lili.common.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.context.annotation.Bean;
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.WebMvcConfigurer;
import java.util.List;
@Configuration
public class StringWebConfig implements WebMvcConfigurer {
@Autowired
private HttpMessageConverters httpMessageConverters;
/**
* MappingJackson2HttpMessageConverter 实现了HttpMessageConverter 接口,
* httpMessageConverters.getConverters() 返回的对象里包含了MappingJackson2HttpMessageConverter
* @return
*/
@Bean
public MappingJackson2HttpMessageConverter getMappingJackson2HttpMessageConverter() {
return new MappingJackson2HttpMessageConverter(new JacksonMapper());
}
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.addAll(httpMessageConverters.getConverters());
}
}
通过如上两个全局配置,在进行序列化的时候会自动将Long类型转换成String类型。问题得到成功的解决...............但是也埋下了一个坑。
三.踩坑
一开始说有问题的功能是得到了解决,返回给前端的值是正确的了。但是引发了另外一个问题,因为我们将Long类型转换成了String类型,页面上面有一些数据是经过前端进行运算的。所以转换类型成功后那么原本的运算 1+1 = 2 ,就变成了 "1" + "1" = 11 。如下图,就是错误的实力。相信看到这里大家就都悟了
原本的运算变成了字符串拼接了。导致页面上的很多数据显示有问题了。不过还是偷懒了,不应该让前端去进行运算的
四.另外一种解决办法
在返回的vo里面增对字段加上注解,即可解决问题。但是这种就是冗余了,每此返回这个主键id都要添加注解,目前为了不影响其他功能,只能先加上此注解
五.教训
全局的配置尽量要测试完成才能发布,不然就会像我这样,一个bug改成另外一个bug,哈哈哈