最近在做一个Spring Boot项目的时候需要重写WebMvcConfigurer的beforeBodyWrite方法,想要对响应体数据进行一定的加密操作,在自己调试接口并测试时无任何问题,等到和前端联调的时候,却出现了后台传过去的Long类型数据精度丢失的问题。

这里简单说下为什么会出现long数据精度丢失的情况:这主要是因为Java中的long能表示的范围比js中number大,也就意味着部分数值在js中存不下(变成不准确的值),导致Id最后几位直接变成了0,所以导致精度丢失。这也是为什么自己用类似于postman之类的工具调试接口时,并无任何不妥,但是一旦与前端联调,就会经常出现数据不存在的情况。

正常情况下,针对精度丢失最常用的也是最简单的方法,就是在后端给前端传值的时候,将long类型的数据转换成String,前端拿到的是一个string字符串,这样就不会出现问题,如下:

@JsonSerialize(using = LongJsonSerializer.class)
@JsonDeserialize(using = LongJsonDeserializer.class)
private Long id;

正常情况下这样处理是没有任何问题的,但是,在我重写了WebMvcConfigurer的beforeBodyWrite方法后,却出问题了:这里的注解@JsonSerialize和@JsonDeserialize全部失效了!为了搞清这个问题,我也在网上查了很多的资料,后来才发现产生这个问题的原因是因为 beforeBodyWrite 方法允许你在控制器方法执行之后但在响应体写入之前修改响应体,当你修改响应体时,Spring Boot 默认不再使用 Jackson 的序列化机制,因此这里所加的 注解就不会生效。

所以回到了最初的问题:处理long数据精度丢失的问题。

解决办法

这个问题后来找了一下,没发现有更好的处理办法,只有自己写了一段代码,手动的去将返回数据里的long值转换成String,如下:

public static void convertLongToString(JSONObject jsonObject) {
    for (String key : jsonObject.keySet()) {
	    Object value = jsonObject.get(key);
		// 检查是否为 Long 类型
		if (value instanceof Long) {
		    // 将 Long 类型的值转换为 String 并更新 JSONObject
		    jsonObject.put(key,String.valueOf(value));
		 } else if (value instanceof JSONObject) {
		    // 如果是嵌套的 JSONObject,递归处理
		    convertLongToString((JSONObject) value);
		  }
	    }
   }

当然,还有更直接更方便的处理办法:就是直接将返回对象里面的Long类型数据,全部修改成String类型,然后在接口返回处做一下类型转换,手动set一下值即可,唯一的缺点就是如果值多的话,每个值都要set一下就比较费事,而且万一哪个值忘记set了,拿到的就会是一个空值。

如果还有更好的处理方法,欢迎一起交流~

GitHub 加速计划 / js / json
41.72 K
6.61 K
下载
适用于现代 C++ 的 JSON。
最近提交(Master分支:1 个月前 )
960b763e 4 个月前
8c391e04 6 个月前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐