概述
问题描述
Java输出至前端的整数长度超过16位时,前端js在解析整数时,超过16位的整数时,后面的数字会损失精度。
问题原因
JS内置的number类型是基于32位整数,Number类型的最大安全整数为9007199254740991,当Java Long型的值大小超过JS Number的最大安全整数时,超出此范围的整数值可能会被破坏,丢失精度。
解决办法
在后台将整数转换成字符串,围绕这个目标,共探索出5种解决方案,能满足大部分的个性化需求。
解决方案
- 过滤器统一拦截
- 自定义Serializer序列化类
- POJO属性增加注解
- 修改Serializers源码
- 代码转化
项目环境:
Spring 3.X and Jackson 2.X
1)过滤器统一拦截
配置Spring消息转换器的ObjectMapper类,引用创建的自定义类型转换器类。
- 创建CustomObjectMapperForJackson类
package com.xiaodajia.framework.util.web.databind;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.SimpleDateFormat;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
public class CustomObjectMapperForJackson extends ObjectMapper {
public CustomObjectMapperForJackson() {
super();
// 设置日期转换yyyy-MM-dd HH:mm:ss
setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(BigDecimal.class,
ToStringSerializer.instance);
simpleModule.addSerializer(BigInteger.class,
ToStringSerializer.instance);
simpleModule.addSerializer(Long.class,
ToStringSerializer.instance);
simpleModule.addSerializer(Long.TYPE,
ToStringSerializer.instance);
registerModule(simpleModule);
}
}
- spring-mvc.xml配置objectMapper
<mvc:annotation-driven validator="validator" conversion-service="conversion-service">
<mvc:message-converters register-defaults="true">
<!-- 将StringHttpMessageConverter的默认编码设为UTF-8 -->
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg value="UTF-8" />
</bean>
<!-- 将Jackson2HttpMessageConverter的默认格式化输出设为true -->
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="prettyPrint" value="true"/>
<property name="objectMapper">
<bean class="com.xiaodajia.framework.util.web.databind.CustomObjectMapperForJackson"/>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
关键代码
当项目中使用Mybatis持久层框架,如果结果类型设置为resultType="map"
,将集合数据输出至前端时,Jackson会默认将数组、对象中的数值以BigDecimal
类型序列化,如果我们只配置了Long的序列化类,对map中数据是不会生效,还需要在自定义ObjectMapper中配置BigDecimal、BigInteger类的序列化
simpleModule.addSerializer(BigDecimal.class,ToStringSerializerForJackson.instance);
simpleModule