SpringBoot 里的 RequestBodyAdviceAdapter 使用问题
一、问题#
之前写过一篇《SpringBoot 接口参数解密的实现方法(使用注解)》,代码一直跑着都没问题,但是最近发现入参特别长的时候,inputMessage.getBody () 这段代码拿不到完整的入参,会被截断。
看了下源码,好像默认它转换的时候就截断了。
而且只有线上有问题,本地测试无法复现该问题。
二、解决办法#
看了下源码,RequestBodyAdviceAdapter
这个静态类除了 beforeBodyRead
这个方法外,还有个 afterBodyRead
方法,原来我一直以为 beforeBodyRead
是 Controller
层之前执行,afterBodyRead
是在 Controller
层之后执行,后来我发现我理解错了,它们都是在 Controller
层之前执行。
并且,beforeBodyRead
方法是在 afterBodyRead
方法之前执行,走这两个方法之前都会走一次 supports
方法来判断是否执行。
于是我就把解密逻辑挪到了 afterBodyRead
方法里,就不存在入参超长被截断的问题了。
注意:刚刚另一个项目上线发现,afterBodyRead 读取的是 Controller 中 RequestBody 的实体类,若实体类中有可为空并且设置了默认值的,比如分页参数 pageNo 默认为 1,如果客户端没传,afterBodyRead 中读取到的就是 1,会解密失败。
/**
* 请求参数解密
* http://www.zzvips.com/article/187109.html
* https://www.cnblogs.com/shamo89/p/16498217.html
*/
@ControllerAdvice
@Slf4j
public class DecryptRequest extends RequestBodyAdviceAdapter {
@Override
public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
return methodParameter.hasMethodAnnotation(Decrypt.class) || methodParameter.hasParameterAnnotation(Decrypt.class);
}
@Override
public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
try {
String requestBody = JSONUtils.serializeObject(body);
// log.info("requestBody=" + requestBody);
// 转换为对象
JSONObject bodyObj = JSONObject.parseObject(requestBody);
// 定义无需解密参数
List<String> noDecryptFiled = Arrays.asList("appClient", "channel", "version", "token", "projectId");
// 定义解密后参数map
HashMap<String, String> decryptParam = new HashMap<>();
// 循环请求对象
for (Map.Entry<String, Object> stringObjectEntry : bodyObj.entrySet()) {
if (stringObjectEntry.getValue() == null) {
continue;
}
String key = stringObjectEntry.getKey();
String value = stringObjectEntry.getValue().toString();
// 如果是开发环境,无需解密
if (Result.getEnv().equals("dev")) {
decryptParam.put(key, value);
continue;
}
// 若是无需解密参数,直接put进decryptParam
if (noDecryptFiled.contains(stringObjectEntry.getKey())) {
decryptParam.put(key, value);
continue;
}
// 解密
decryptParam.put(key, AESUtil.decrypt(value, Result.SALT));
}
body = JSONObject.parseObject(JSON.toJSONString(decryptParam), targetType);
} catch (IOException e) {
throw new BaseException(SystemErrorType.BUSINESS_ERROR, "参数解密失败,请检查");
}
// log.info("body=" + JSON.toJSONString(body));
return super.afterBodyRead(body, inputMessage, parameter, targetType, converterType);
}
}
参考文章#
SpringMvc 里的 RequestBodyAdviceAdapter 使用问题
本作品采用《CC 协议》,转载必须注明作者和本文链接