美文网首页探索Spring
Spring MVC返回视图原理(五)

Spring MVC返回视图原理(五)

作者: Real_man | 来源:发表于2018-08-22 20:40 被阅读34次

    Spring MVC非常灵活,在使用的时候可以返回视图,也可以直接返回普通数据,在想,内部是怎么实现的呢?

    经过了几天研究Spring MVC的源码,可以看前几篇文章,今天再弄明白下为什么有时候返回视图,有时候直接返回数据呢。

    分析

    1. 首先配置web.xml并且准备好视图,做一些准备工作
        <servlet>
            <servlet-name>dispatcher</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        </servlet>
    
        <servlet-mapping>
            <servlet-name>dispatcher</servlet-name>
            <url-pattern>/</url-pattern>
        </servlet-mapping>
    

    dispatcher-servlet.xml中视图配置

    
        <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
            <property name="prefix" value="/WEB-INF/view/"/>
            <property name="suffix" value=".jsp"/>
        </bean>
    
    

    Controller类

        @RequestMapping("/hello")
        @ResponseBody
        public String hello(){
            return "hello";
        }
    
        @RequestMapping("/index")
        public String indexView(){
            return "index";
        }
    
    image.png
    1. 访问进行调试,关于DispatcherServlet的流程,我们前面的文章已经都说过了,这里不做太多的赘述,getHandler, getHandlerAdapter,基本不变,在HandlerAdapter.handler(Handler)的时候内部有些不同。

    返回视图与返回数据刚开始步骤基本都一样,invoke返回的值也是相同的。

    真正产生变化的地方,在处理最后的返回值时

    image.png
    1. 处理返回值,在激发方法之后,要决定要用什么返回值处理器来处理返回的类型。其中涉及到一个接口HandlerMethodReturnValueHandler,真正用来处理的。

    HandlerMethodReturnValueHandler有两个方法:

    • supportsReturnType是否支持当前的返回值类型,如果支持的话使用当前的HandlerMethodReturnValueHandler处理
    • handleReturnValue,处理返回值
    /**
         * Iterate over registered {@link HandlerMethodReturnValueHandler}s and invoke the one that supports it.
         * @throws IllegalStateException if no suitable {@link HandlerMethodReturnValueHandler} is found.
         */
        @Override
        public void handleReturnValue(Object returnValue, MethodParameter returnType,
                ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
    
            HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
            if (handler == null) {
                throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
            }
            handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
        }
    
        private HandlerMethodReturnValueHandler selectHandler(Object value, MethodParameter returnType) {
            boolean isAsyncValue = isAsyncReturnValue(value, returnType);
            for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
                if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) {
                    continue;
                }
                if (handler.supportsReturnType(returnType)) {
                    return handler;
                }
            }
            return null;
        }
    
    image.png

    如果是@ResponseBody注解的时候由RequestResponseBodyMethodProcessor处理。

    //RequestResponseBodyMethodProcessor
    @Override
        public boolean supportsReturnType(MethodParameter returnType) {
           //判断是否有ResponseBody.class的注解
            return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
                    returnType.hasMethodAnnotation(ResponseBody.class));
        }
    

    返回值是String,但不加@ResponseBody注解的时候由ViewNameMethodReturnValueHandler处理。

      // ViewNameMethodReturnValueHandler
        @Override
        public boolean supportsReturnType(MethodParameter returnType) {
           //参数类型如果是void或者可以CharSequence.class.isAssignableFrom
            Class<?> paramType = returnType.getParameterType();
            return (void.class == paramType || CharSequence.class.isAssignableFrom(paramType));
        }
    

    如果返回值为ModelAndView的时候,由ModelAndViewMethodReturnValueHandler处理

    
        @Override
        public boolean supportsReturnType(MethodParameter returnType) {
            return ModelAndView.class.isAssignableFrom(returnType.getParameterType());
        }
    

    其余的可以自行查看。

    1. 上一步因为不同的ReturnValueHandler处理returnValue的结果不一样,Spring可以进行下一步的操作。

    对于返回数据类型的操作,其将mavContainer的requestHandled设置为true,然后ModelAndView就会返回为null,后续的处理就不按照视图来处理。

    如果返回的是视图,那么requestHandled仍然为false,后续再processDispatchResult中进行render.

    1. 后续和之前提到的DispatcherServlet都一样了。

    回顾

    Spring MVC对不同的返回值处理的方式不同,依靠的是HandlerMethodReturnValueHandler的不同实现。

    主要在invoke方法之后,返回值与刚才激发的方法都被封装在ServletInvocableHandlerMethod里面了,其可以通过Method对象获取加在方法上的注解,类等等信息,最后做出结果。

    最后

    抓住DispatcherServlet的大体框架之后,其中的细节就简答的多了。

    相关文章

      网友评论

        本文标题:Spring MVC返回视图原理(五)

        本文链接:https://www.haomeiwen.com/subject/wdquiftx.html