spring mvc 处理Controller返回结果和HandlerMethodReturnValueHandler使用

spring mvc 处理Controller返回结果

我们总有这样的需求,例如想动态的处理controller(或是一部分)的返回结果,增加某些字段,或是格式化返回结果。这就让我们想到了拦截器HandlerInterceptorAdapter和AOPAspect。当时使用AOPAspect可以实现,并且方便简单。网络上一大堆的使用方式,在此不做详细解释了。下面我们来说使用MVC拦截器的方式。

  • ModelAndView 返回
    可以使用postHandle在postHandle中处理model。就可以实现对返回值动态修改。
     @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response,
                           Object handler, ModelAndView modelAndView) throws Exception {

        Map<String, Object> model = modelAndView.getModel();

    }

以下这两篇文章
例子1
例子2
对于拦截器中返回值的介绍已经够充分,下面主要说下有问题的地方,对于HandlerMethodReturnValueHandler的使用,主要体现在DispatcherServlet.doDispatch之后一直会调用到 requestMappingMethod.invokeAndHandle(webRequest, mavContainer);

public void invokeAndHandle(ServletWebRequest webRequest,
            ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {

        Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);//这就是返回值
        setResponseStatus(webRequest);

        if (returnValue == null) {
            if (isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) {
                mavContainer.setRequestHandled(true);
                return;
            }
        }
        else if (StringUtils.hasText(this.responseReason)) {
            mavContainer.setRequestHandled(true);
            return;
        }

        mavContainer.setRequestHandled(false);
        try {
            this.returnValueHandlers.handleReturnValue(
                    returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
        }
        catch (Exception ex) {
            if (logger.isTraceEnabled()) {
                logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);
            }
            throw ex;
        }
    }

go on …

HandlerMethodReturnValueHandlerComposite.getReturnValueHandler

    /**
     * Find a registered {@link HandlerMethodReturnValueHandler} that supports the given return type.
     */
    private HandlerMethodReturnValueHandler getReturnValueHandler(MethodParameter returnType) {
        for (HandlerMethodReturnValueHandler returnValueHandler : returnValueHandlers) {
            if (logger.isTraceEnabled()) {
                logger.trace("Testing if return value handler [" + returnValueHandler + "] supports [" +
                        returnType.getGenericParameterType() + "]");
            }
            if (returnValueHandler.supportsReturnType(returnType)) {
                return returnValueHandler; //找到后立即返回,并且只返回一个
            }
        }
        return null;
    }

returnValueHandlers会包含多个,如下。

  private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {  
       List<HandlerMethodReturnValueHandler> handlers = new ArrayList<HandlerMethodReturnValueHandler>();  

       // Single-purpose return value types  
       handlers.add(new ModelAndViewMethodReturnValueHandler());  
       handlers.add(new ModelMethodProcessor());  
       handlers.add(new ViewMethodReturnValueHandler());  
       handlers.add(new ResponseBodyEmitterReturnValueHandler(getMessageConverters()));  
       handlers.add(new StreamingResponseBodyReturnValueHandler());  
       handlers.add(new HttpEntityMethodProcessor(getMessageConverters(),  
             this.contentNegotiationManager, this.requestResponseBodyAdvice));  
       handlers.add(new HttpHeadersReturnValueHandler());  
       handlers.add(new CallableMethodReturnValueHandler());  
       handlers.add(new DeferredResultMethodReturnValueHandler());  
       handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory));  
       handlers.add(new ListenableFutureReturnValueHandler());  
       if (completionStagePresent) {  
          handlers.add(new CompletionStageReturnValueHandler());  
       }  

       // Annotation-based return value types  
       handlers.add(new ModelAttributeMethodProcessor(false));  
       handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(),  
             this.contentNegotiationManager, this.requestResponseBodyAdvice));  

       // Multi-purpose return value types  
       handlers.add(new ViewNameMethodReturnValueHandler());  
       handlers.add(new MapMethodProcessor());  

       // 自己添加的HandlerMethodReturnValueHandler类型 
       if (getCustomReturnValueHandlers() != null) {  
          handlers.addAll(getCustomReturnValueHandlers());  
       }  

所以及时我们 returnValueHandlers.add(JsonReturnHandler()); 之后 我们自定义的HandlerMethodReturnValueHandler类型会被放置到大概 13的位置,对自定义返回的Controller 来说到第10个RequestResponseBodyMethodProcessor的时候就会被处理了,所以一直不会被我们自定义的ReturnValueHandler处理,那么怎么办呢?直接上我改好的

在 项目自己的 WebAppConfig( WebMvcConfigurerAdapter) 中
@Bean
    public MtopHandlerMethodReturnValueHandler getMtopHandlerMethodReturnValueHandler(){
        MtopHandlerMethodReturnValueHandler methodReturnValueHandler = new MtopHandlerMethodReturnValueHandler();
        return methodReturnValueHandler;
    }


    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        RequestMappingHandlerAdapter requestMappingHandlerAdapter = applicationContext.getBean(RequestMappingHandlerAdapter.class);
        List<HandlerMethodReturnValueHandler> returnValueHandlers = new ArrayList<>();
        returnValueHandlers.add(getMtopHandlerMethodReturnValueHandler());
        returnValueHandlers.addAll(requestMappingHandlerAdapter.getReturnValueHandlers());
        requestMappingHandlerAdapter.setReturnValueHandlers(returnValueHandlers);
    }

然后注意自定义的HandlerMethodReturnValueHandler的handleReturnValue 中 加入 mavContainer.setRequestHandled(true);这样我们就把HandlerMethodReturnValueHandler放到了最前面,直接就返回了,有同学要问了,那是不是这样就修改了returnValueHandlers内部的顺序会不会对源程序有影响?嗯 的确会的。所以我们可以在配置注解的方式(也就是上面的例子中supportsReturnType使用的方式),表明下只有加了注解的才进入自定义的HandlerMethodReturnValueHandler中就完美了。

以上内容都是我debug和分析源码找到的,并且已经实现。

    原文作者:Spring MVC
    原文地址: https://blog.csdn.net/Rylan11/article/details/79433192
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞