抛出问题
Java 服务端如果直接返回 Long 整型数据给前端,Javascript 会自动将其转换为 Number 类型(注:此类型为双精度浮点数,表示原理与取值范围等同于 Java 中的 Double)。
Long 类型能表示的最大值是 2 63 2^{63}2
63
- 1,在取值范围之内,超过 2 53 2^{53}2
53
(9007199254740992)的数值转化为 Javascript 的 Number 时,数值会产生精度损失。
扩展说明,在 Long 取值范围内,任何 2 的指数次的整数都是绝对不会存在精度损失的,所以说精度损失是一个概率问题。若浮点数尾数位与指数位空间不限,则可以精确表示任何整数,但很不幸,双精度浮点数的尾数位只有52 位。
解决问题
解决方法1:
对于需要使用超大整数的场景,服务端使用 String 字符串类型返回。
服务端与前端交互使用 String 类型,这样就不会存在精度损失问题,与数据库里是的Long 类型主键交互记得转换下就行。
(这里不建议用字符型做主键,会有索引上的性能损耗)
解决方法2:
如果使用的是 Jackson 序列包的话, 在 id 值上加如下注解.
/** * 用户ID * 将Long类型数字进行json格式转化时,转成String格式类型 */ @JsonSerialize(using = ToStringSerializer.class) private Long id;
如果使用的是 fastjson序列包的话, 在 id 值上加如下注解.
@JSONField(serializeUsing = String.class) private Long id;
缺点就是 需要在每个类的对应属性上加, 如果类很多的话,工作量还是蛮大的.
解决方法3:
因为服务端与前端交互都是通过 Json 格式的数据交互的,所以我们这要做一个全局配置告诉我们的JSON转换器,再遇到Long类型的属性时自动转换为String类型即可。
@Configuration public class JacksonConfig { @Bean @Primary @ConditionalOnMissingBean(ObjectMapper.class) public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder){ ObjectMapper objectMapper = builder.createXmlMapper(false).build(); // 全局配置序列化返回 JSON 处理 SimpleModule simpleModule = new SimpleModule(); //JSON Long ==> String simpleModule.addSerializer(Long.class, ToStringSerializer.instance); objectMapper.registerModule(simpleModule); return objectMapper; } }
解决方法:4
Springboot项目,在配置文件中添加一句即可。
spring.jackson.generator.write_numbers_as_strings = true