问题
用户在使用thub产品时发现展示的执行结果中,Long类型数据发生精度丢失问题。
实际值: 588208228525821697
前端显示 588208228525821700
排查发现后端返回数据数据是正确的,在前端显示出错了。
原因
参考文章 https://blog.csdn.net/u010028869/article/details/86563382
js使用双精度存储方式,因此对超长的整数值会丢失精度。
解决办法
后端对执行结果进行序列化,以格式化的字符串方式传输,字符串不存在精度问题 (需要改造数据格式,成本高)。
后端增加converter,在序列化的时候将long类型数据转成String (但是会对http接口产生全局影响)。(ToStringSerializer也可自定义实现) FastJsonConfig fastJsonConfig = new FastJsonConfig();
SerializeConfig serializeConfig = SerializeConfig.globalInstance;
serializeConfig.put(BigInteger.class, ToStringSerializer.instance);
serializeConfig.put(Long.class, ToStringSerializer.instance);
serializeConfig.put(Long.TYPE, ToStringSerializer.instance);
fastJsonConfig.setSerializeConfig(serializeConfig);
fastConverter.setFastJsonConfig(fastJsonConfig);
converters.add(fastConverter);
自定义序列化方式,将超出表示范围的整数值在服务端存储时转为String (db存储会丢失真正数据类型)。 public class ThubLongSerializer implements ObjectSerializer {
public static ThubLongSerializer instance = new ThubLongSerializer();
@Override
public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features)
throws IOException {
SerializeWriter out = serializer.out;
if (object == null) {
out.writeNull();
return;
}
if (object instanceof Long) {
Long value = (Long)object;
if (value <= 9007199254740991L && value >= -9007199254740991L) {
out.writeLong(value);
if (out.isEnabled(SerializerFeature.WriteClassName) //
&& value <= Integer.MAX_VALUE && value >= Integer.MIN_VALUE //
&& fieldType != Long.class
&& fieldType != long.class) {
out.write('L');
}
return;
}
}
String strVal = object.toString();
out.writeString(strVal);
}
}
// 调用方式
SerializeConfig serializeConfig = new SerializeConfig();
serializeConfig.put(BigInteger.class, ThubLongSerializer.instance);
serializeConfig.put(Long.class, ThubLongSerializer.instance);
serializeConfig.put(Long.TYPE, ThubLongSerializer.instance);
String responseStr = JSONObject.toJSONString(record.getResponse(), serializeConfig,
SerializerFeature.WriteMapNullValue);
返回前端时特殊处理(遍历对象进行修改,实现比较复杂。继承并修改DefaultJSONParser类实现反序列化-麻烦,放弃)
效果
public static void main(String[] args) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("test", 600008228525821697L);
SerializeConfig serializeConfig = new SerializeConfig();
serializeConfig.put(BigInteger.class, ThubLongSerializer.instance);
serializeConfig.put(Long.class, ThubLongSerializer.instance);
serializeConfig.put(Long.TYPE, ThubLongSerializer.instance);
String responseStr = JSONObject.toJSONString(jsonObject, serializeConfig,
SerializerFeature.WriteMapNullValue);
System.out.println(responseStr);
responseStr = JSONObject.toJSONString(jsonObject,
SerializerFeature.WriteMapNullValue);
System.out.println(responseStr);
}
{"test":"600008228525821697"}
{"test":600008228525821697}