Spring MVC中的视图解析机制

视图解析的实现基础

ViewResolver 与 View 接口

  • AbstractCachingViewResolver
    用于缓存的Resolver,是一个抽象的基类,很多别的Resolver都是基于这个做的
  • UrlBasedViewResolver
  • FreeMarkerViewResolver
  • ContentNegotiatingViewResolver
    使用的是根据一个我可以接受的返回类型来选择合适的相应,比如说我要一个xml的相应,它就会返回一个xml的给我。
  • InternalResourceViewResolver
    默认的,在整个解析链中最后的一个内置解析器,处理jsp和jst2

在springmvc中,视图的解析主要靠ViewResolver 这个借口实现的,以上为用的比较多的Resolver

DispatcherServlet 中的视图解析逻辑

  • initStrategies()
    • initViewResolvers() 初始化了对应 ViewResolver
  • doDispatch() 具体的处理请求
    • processDispatchResult()
    • 没有返回视图的话,尝试 RequestToViewNameTranslator 做视图名到视图的解析
    • resolveViewName() 解析 View 对象

进入源码

进入DispatcherServlet,我们可以看到viewResolvers
在这里插入图片描述
这个list当中放了我们能在上下文当中取的所有viewResolver

用setDetectAllViewResolvers方法,设置一下我们是不是检测所有的viewResolvers,一般来说,它的默认为true,我们一般不改这个属性,就让它去检测所有的。
在这里插入图片描述

接下来是initStrategies初始化方法:
它在初始化的时候,会init这些viewResolver在这里插入图片描述
进入initViewResolvers方法:
我们可以看到,它从我们的BeanFactory中,取出所有viewResolver的bean,然后对它们做了一个排序。在这里,就完成了一个viewResolver的初始化的加载。
在这里插入图片描述
然后,寻找doDispatch方法:
在doDispatch当中,假如上面的方法正常无误加载完成,我们进入applyDefaultViewName方法。去判断,如果它还没找到一个视图的话,这里就会尝试加载一个默认的视图名字在这里插入图片描述
在processDispatchResult这个步骤当中,我们会做一些后置的与视图相关的处理,比如说如果这个地方是有异常的,这里就会做一个异常视图的处理。如果是正常的,没有异常的。那么,只要有modelandview,这里就会去做一个render,视图的渲染。在这里插入图片描述
然后,我们进入render:
它先取得了view的名字,然后通过resolveViewName的方式去解析出view
有了view之后,用它做一个视图的呈现。
在这里插入图片描述
我们以AbstractView为例:
一开始用prepareResponse做一个准备工作。然后用renderMergedOutputModel做一个Response输出。
在这里插入图片描述

DispatcherServlet 中的视图解析逻辑

使用 @ResponseBody 的情况
• 在 HandlerAdapter.handle() 的中完成了 Response 输出
• RequestMappingHandlerAdapter.invokeHandlerMethod()
• HandlerMethodReturnValueHandlerComposite.handleReturnValue()
• RequestResponseBodyMethodProcessor.handleReturnValue()
Response的处理完全是HandlerAdapter的处理当中完成的,在调用完具体的Controller方法之后,它立即对返回的对象做一个处理,而这个处理是在RequestMappingHandlerAdapter中的invokeHandlerMethod做的,具体它将会一步步的把这些结果的处理代理到最后的RequestResponseBodyMethodProcessor当中,也就是说我们最后的处理是在我们这个handleReturnValue方法中完成的。

具体源码

进入DispatcherServlet
找到AbstractHandlerMethodAdapter并进入
在这里插入图片描述
进入handleInternal方法
在这里插入图片描述
进入invokeHandlerMethod继续处理请求,处理请求之前,它会设置returnValueHandlers,这里其实是Handler的一个组合,在这里插入图片描述
然后一直往下走,走到invokeAndHandle,才是做一个真正的方法执行,在invokeAndHandle中,取得方法的返回值,取得returnValue,在 this.returnValueHandlers.handleReturnValue(returnValue, this.getReturnValueType(returnValue), mavContainer, webRequest);这里做returnValue的处理。
在这里插入图片描述
进入returnValue,它会尝试用我的writeWithMessageConverters去对我的结果做一个输出。
在这里插入图片描述
进入writeWithMessageConverters:
进行方法类型的处理在这里插入图片描述

重定向

两种不同的重定向前缀
• redirect
• forward
转发(forward)和重定向(redirect)的区别
从地址栏显示来说
forward是服务器请求资源,服务器直接访问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容再发给浏览器.浏览器根本不知道服务器发送的内容从哪里来的,所以它的地址栏还是原来的地址.
redirect是服务端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址.所以地址栏显示的是新的URL.

从效率来说
forward:高.
redirect:低

forward时会带上当前请求的信息,而redirect则是个纯粹的客户端重定向。

发布了59 篇原创文章 · 获赞 6 · 访问量 958

猜你喜欢

转载自blog.csdn.net/weixin_43790623/article/details/103458160
今日推荐