SpringBoot 里的 RequestBodyAdviceAdapter 使用问题

一、问题

之前写过一篇《SpringBoot 接口参数解密的实现方法(使用注解)》,代码一直跑着都没问题,但是最近发现入参特别长的时候,inputMessage.getBody() 这段代码拿不到完整的入参,会被截断。

看了下源码,好像默认它转换的时候就截断了。

而且只有线上有问题,本地测试无法复现该问题。

二、解决办法

看了下源码,RequestBodyAdviceAdapter 这个静态类除了 beforeBodyRead 这个方法外,还有个 afterBodyRead 方法,原来我一直以为 beforeBodyReadController 层之前执行,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 协议》,转载必须注明作者和本文链接
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!