项目场景:
后端数据库中主键使用Bigint类型,新增时通过MyBatis-Plus设置ID策略为雪花ID,后端接口返回主键为Long类型。
问题描述
后端接口编写完成后,在postman中测试新增、修改、删除和详情接口都正常。在同前端调试过程中发现无法通过主键对后端数据进行操作。
原因分析:
首先听到前端反馈这个问题时,内心深处在想这个前端怎么回事,怎么接口都不会调用(PS:我写的接口怎么可能有BUG),保险起见还是暗戳戳的通过postman测试了一遍接口发现一切正常,又打开测试环境通过浏览器检查查看接口调用情况,发现前端传递到后端的主键同后端返回的主键不相同。(PS:看果然是你前端的问题吧)
解决方案:
查询资料后发现前端的数据格式没有Long类型只有Number 和 BigInt,在接收后端数据时默认为Number 类型,当超出其安全范围(即大于 2^53 - 1)的整数,会丢失精度。
解决方案一:后端通过拦截器的方式在接口返回时将全部的Long类型转换为String类型返回到前端
解决方案二:前端在接收时强制转换为BigInt
解决方案三:前端使用支持大整数的库
本人更加倾向于采用第一种解决方案来解决这个问题,毕竟这个处理更加简单方便,代码如下:
/**
* 序列化为json时,将所有的long变成string,js中数字类型长度小于java中long值长度
* EnableWebMvc 开启springmvc的一个注解
*/
@EnableWebMvc
@Configuration
public class JacksonConfig implements WebMvcConfigurer {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
MappingJackson2HttpMessageConverter jackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
ObjectMapper objectMapper = new ObjectMapper();
SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
simpleModule.addSerializer(BigInteger.class, ToStringSerializer.instance);
// 反序列化时忽略多余字段
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
// 注册
objectMapper.registerModule(simpleModule);
jackson2HttpMessageConverter.setObjectMapper(objectMapper);
converters.add(jackson2HttpMessageConverter);
}
}