看了同事写的代码,我竟然开始默默的模仿了。。。(二)

578 阅读2分钟

「这是我参与11月更文挑战的第7天,活动详情查看:2021最后一次更文挑战」。

上文中我们已经完成了自定义参数解析器解决方案的基础搭建,至于该怎么来使用它呢?请跟随阿Q的文章往下看。

使用

使用方法非常简单,只需要在参数上引入注解就可以了

@RestController
@Slf4j
@RequestMapping("/xxx")
public class XxxCallbackController {

    /**
     * @param params
     * @return
     */
    @PostMapping("/callback")
    public String callback(@RsaVerify CallbackReq params) {
        log.info("receive callback req={}", params);
		//业务逻辑处理
		.....
		
        return "success";
    }
}

看到这里不知道你对文章中的内容有没有产生什么疑问呢?

问题一

细心的朋友应该会有所疑问:既然这边用到了自定义的注解,为什么不用切面来实现,而是使用自定义的参数解析器呢?Very Good!这也是阿Q提出的疑问,同事说是因为 jackson 的反序列化动作优先级远高于切面的优先级,所以还没进入切面就已经报反序列化失败的错误了。

问题二

为什么在 controller 中注解 @RequestBody 不见了?

要回答这个问题,我们就得了解下HandlerMethodArgumentResolverComposite这个类了,以下简称CompositeSpringMVC 在启动时会将所有的参数解析器放到 Composite 中,Composite 是所有参数的一个集合。当对参数进行解析时就会从该参数解析器集合中选择一个支持对 parameter 解析的参数解析器,然后使用该解析器进行参数解析。

又因为@RequestBody所以使用的参数解析器RequestResponseBodyMethodProcessor优先级高于我们自定义的参数解析器,所以如果共用会被前者拦截解析,所以为了正常使用,我们需要将@RequestBody 注解去掉。

以下是 HandlerMethodArgumentResolverComposite 中的部分源码:

/**
 * Find a registered {@link HandlerMethodArgumentResolver} that supports
 * the given method parameter.
 */
@Nullable
private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
    HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
    if (result == null) {
        for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {
            if (resolver.supportsParameter(parameter)) {
                result = resolver;
                this.argumentResolverCache.put(parameter, result);
                break;
            }
        }
    }
    return result;
}

用自定义参数解析器来解决参数的统一处理与验签的逻辑你学会了吗?下文我们将给出另一种解决方案。如果你有不同的意见或者更好的idea,欢迎联系阿Q,添加阿Q可以加入技术交流群参与讨论呦!