Spring:SpringMVC 视图解析 - ViewResolver&View
2016-09-14 18:08
477 查看
基本概念
所有的 MVC 框架都有一套它自己的解析视图的机制,springmvc 也不例外,它使用ViewResolver 进行视图解析,让用户在浏览器中渲染模型。Springmvc 处理视图最重要的两个接口是 ViewResolver 和 View :
ViewResolver 接口在视图名称和真正的视图之间提供映射,它是一种开箱即用的技术,能够解析 JSP、Velocity 模板和 XSLT 等多种视图:
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">interface</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">ViewResolver</span> {</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 关键 --> 根据 vieName 返回 View 视图</span> View resolveViewName(String viewName, Locale locale) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> Exception; }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>
View 接口则处理请求将真正的视图呈现给用户:
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">interface</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">View</span> {</span> String RESPONSE_STATUS_ATTRIBUTE = View.class.getName() + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">".responseStatus"</span>; String PATH_VARIABLES = View.class.getName() + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">".pathVariables"</span>; String SELECTED_CONTENT_TYPE = View.class.getName() + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">".selectedContentType"</span>; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 取得网页文件的类型和编码</span> String getContentType(); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 关键 --> 渲染页面</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> Exception; }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li></ul>
视图解析在 springmvc 中配置如下(以 InternalResourceViewResolver 为例 ):
bean :表示指定的 ViewResolver;
viewClass : 表示要解析的视图类型,如 JSP 等;
prefix/suffix : 表示路径前缀/后缀,假设 viewname 为 hello,则完整的路径为:“/WEB-INF/page/hello.jsp”
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><bean class=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"org.springframework.web.servlet.view.InternalResourceViewResolver"</span>> <property name=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"viewClass"</span> value=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"org.springframework.web.servlet.view.JstlView"</span> /> <property name=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"prefix"</span> value=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"/WEB-INF/page/"</span> /> <property name=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"suffix"</span> value=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">".jsp"</span> /> </bean></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-al 1d810 ign: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li></ul>
原理解释
1.过程
找到 DispatcherServlet 的 doDispatch 方法,该方法负责实现 springmvc 的请求转发过程,该过程最后一步就是处理请求结果,并进行视图渲染。<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">doDispatch</span>(HttpServletRequest request, HttpServletResponse response) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> Exception { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// ...</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">try</span> { ModelAndView mv = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>; Exception dispatchException = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// ...</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 调用控制器(controller)匹配请求路径的处理方法,并返回 mv</span> mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// ...</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 关键 --> 处理请求结果(同时在这里根据 mv 进行视图渲染)</span> processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">catch</span> (Exception ex) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// ...</span> } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">catch</span> (Error err) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// ...</span> } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">finally</span> { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// ...</span> } }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li></ul>
再来看 processDispatchResult 这个方法,该方法负责处理请求结果,并进行视图渲染。
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">processDispatchResult</span>(HttpServletRequest request, HttpServletResponse response, HandlerExecutionChain mappedHandler,ModelAndView mv, Exception exception) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> Exception { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">boolean</span> errorView = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">false</span>; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 异常处理...</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (mv != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span> && !mv.wasCleared()) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 渲染页面</span> render(mv, request, response); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (errorView) { WebUtils.clearErrorRequestAttributes(request); } } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 日志输出...</span> } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// ...</span> }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li></ul>
接着来看 render 方法,该方法负责视图渲染的过程。
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">render</span>(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> Exception { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 根据请求决定回复消息的 locale</span> Locale locale = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.localeResolver.resolveLocale(request); response.setLocale(locale); View view; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 判断 mv 是否字符串</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (mv.isReference()) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 关键 -> 解析视图名返回 view,为空则抛出异常</span> view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (view == <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 抛出异常...</span> } } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 若 mv 不是字符串直接取得视图,为空则抛出异常</span> view = mv.getView(); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (view == <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 抛出异常...</span> } } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 日志输出...</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">try</span> { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 关键 -> 由 View 进行真正的视图渲染</span> view.render(mv.getModelInternal(), request, response); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">catch</span> (Exception ex) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (logger.isDebugEnabled()) { logger.debug(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Error rendering view ["</span> + view + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"] in DispatcherServlet with name '"</span> + getServletName() + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"'"</span>, ex); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throw</span> ex; } }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li></ul>
最后来看看 resolveViewName,该方法在 mv 属于字符串类型时会被调用。
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> View <span class="hljs-title" style="box-sizing: border-box;">resolveViewName</span>(String viewName, Map<String, Object> model, Locale locale,HttpServletRequest request) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> Exception { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 遍历 Ioc 容器中定义的 ViewResolver </span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (ViewResolver viewResolver : <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.viewResolvers) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 关键 -> 调用 它的 resolveViewName 方法</span> View view = viewResolver.resolveViewName(viewName, locale); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 不为空,则返回 view</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (view != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> view; } } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>; }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li></ul>
2.总结
分析完 springmvc 视图解析过程,再来做下总结:请求转发过程中(doDispatch)最后进行请求结果的处理,同时会进行视图渲染(processDispatchResult);
处理完请求结果,调用 redner 方法进行视图渲染;
在渲染过程中,判断 mv 是否属于字符串类型,是的话调用 resolveViewName 方法(该方法会遍历 Ioc 容器中 ViewResolver ,并调用它的 resolveViewName )取得视图名,否则直接取得视图名。最后再调用 View 的 render 方法进行真正的视图渲染。
可以整个视图机制都围绕着 ViewResolver 和 View 两个接口展开,简单流程如下:
doDispatch - processDispatchResult - redner - resolveViewName - ViewResolver.resolveViewName - View.render
源码分析(ViewResolver)
分析完 springmvc 的视图解析机制,再来看看 ViewResovler 这个接口。上面提到过,它的主要作用是根据【视图名(ViewName)返回视图(View)】。首先来看它的继承关系:
1.AbstractCachingViewResolver
通过上面的继承关系图可以知道该类直接实现了 ViewResolver 接口,是带有缓存功能的基础实现抽象类。重点来看 resolveViewName 这个方法:
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 成员变量</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> DEFAULT_CACHE_LIMIT = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1024</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> Map<Object, View> viewAccessCache = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> ConcurrentHashMap<Object, View>(DEFAULT_CACHE_LIMIT); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> Map<Object, View> viewCreationCache = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> LinkedHashMap<Object, View>(DEFAULT_CACHE_LIMIT, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0.75</span>f, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span>) { <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">boolean</span> <span class="hljs-title" style="box-sizing: border-box;">removeEldestEntry</span>(Map.Entry<Object, View> eldest) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (size() > getCacheLimit()) { viewAccessCache.remove(eldest.getKey()); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span>; } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">false</span>; } } }; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 方法</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> View <span class="hljs-title" style="box-sizing: border-box;">resolveViewName</span>(String viewName, Locale locale) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> Exception { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 缓存功能是否打开,只要 cacheLimit(默认为 1024) 大于 0 就代表缓存功能默认打开</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (!isCache()) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 若缓存关闭,则创建视图</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> createView(viewName, locale); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 返回 viewName + "_" + locale</span> Object cacheKey = getCacheKey(viewName, locale); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 从 viewAccessCache 取得 view</span> View view = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.viewAccessCache.get(cacheKey); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (view == <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">synchronized</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.viewCreationCache) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 从 viewCreationCache 取得 view</span> view = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.viewCreationCache.get(cacheKey); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (view == <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 为空,创建视图</span> view = createView(viewName, locale); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 仍然为空,则标记为【不可解析视图】</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (view == <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span> && <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.cacheUnresolved) { view = UNRESOLVED_VIEW; } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (view != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 添加进缓存</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.viewAccessCache.put(cacheKey, view); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.viewCreationCache.put(cacheKey, view); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 日志输出...</span> } } } } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> ( view != UNRESOLVED_VIEW ? view : <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span> ); } }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li><li style="box-sizing: border-box; padding: 0px 5px;">50</li><li style="box-sizing: border-box; padding: 0px 5px;">51</li><li style="box-sizing: border-box; padding: 0px 5px;">52</li><li style="box-sizing: border-box; padding: 0px 5px;">53</li><li style="box-sizing: border-box; padding: 0px 5px;">54</li><li style="box-sizing: border-box; padding: 0px 5px;">55</li><li style="box-sizing: border-box; padding: 0px 5px;">56</li><li style="box-sizing: border-box; padding: 0px 5px;">57</li><li style="box-sizing: border-box; padding: 0px 5px;">58</li><li style="box-sizing: border-box; padding: 0px 5px;">59</li><li style="box-sizing: border-box; padding: 0px 5px;">60</li><li style="box-sizing: border-box; padding: 0px 5px;">61</li><li style="box-sizing: border-box; padding: 0px 5px;">62</li><li style="box-sizing: border-box; padding: 0px 5px;">63</li><li style="box-sizing: border-box; padding: 0px 5px;">64</li><li style="box-sizing: border-box; padding: 0px 5px;">65</li><li style="box-sizing: border-box; padding: 0px 5px;">66</li></ul>
再来看看它的 createView 方法,该方法负责视图的创建。
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> View <span class="hljs-title" style="box-sizing: border-box;">createView</span>(String viewName, Locale locale) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> Exception { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> loadView(viewName, locale); } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 抽象方法,留给子类做具体实现</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">abstract</span> View <span class="hljs-title" style="box-sizing: border-box;">loadView</span>(String viewName, Locale locale) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> Exception;</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li></ul>
观察代码,可以该类的视图解析过程如下:
缓存关闭,则创建视图;
缓存开启,先后从 viewCreationCache,viewCreationCache 这个两个缓存集合里查找视图,仍然为空,则创建视图,并分别添加进这两个缓存集合里。
2.UrlBasedViewResolver
继承自 AbstractCachingViewResolver 抽象类、并实现 Ordered 接口的类,是 ViewResolver 接口简单的实现类,该类重写了 createView,loadView 这两个方法。首先来看它的 createView 方法
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> View <span class="hljs-title" style="box-sizing: border-box;">createView</span>(String viewName, Locale locale) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> Exception { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 是否支持该视图的名的处理</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (!canHandle(viewName, locale)) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 返回 null 进入下一个视图解析器</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>; } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 检查是否以 "redirect" 开头</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (viewName.startsWith(REDIRECT_URL_PREFIX)) { String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length()); RedirectView view = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> RedirectView(redirectUrl, isRedirectContextRelative(), isRedirectHttp10Compatible()); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> applyLifecycleMethods(viewName, view); } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 检查是否以 "forward" 开头</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (viewName.startsWith(FORWARD_URL_PREFIX)) { String forwardUrl = viewName.substring(FORWARD_URL_PREFIX.length()); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> InternalResourceView(forwardUrl); } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 其他情况由父类处理,其实就是调用该类的 loadView 方法</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">super</span>.createView(viewName, locale); }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li></ul>
再来看看它 的 loadView 方法,如果视图名不包含 redirect,forward 时,调用父类的 createView 的时会调用到它。
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> View <span class="hljs-title" style="box-sizing: border-box;">loadView</span>(String viewName, Locale locale) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> Exception { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 关键 -> 根据 ViewName 取得 View</span> AbstractUrlBasedView view = buildView(viewName); View result = applyLifecycleMethods(viewName, view); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> ( view.checkResource(locale) ? result : <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span> ); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> AbstractUrlBasedView <span class="hljs-title" style="box-sizing: border-box;">buildView</span>(String viewName) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> Exception { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 实例化视图类(View) </span> AbstractUrlBasedView view = (AbstractUrlBasedView) BeanUtils.instantiateClass(getViewClass()); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 根据【前缀+视图名+后缀】生成 url,并添加进 View</span> view.setUrl(getPrefix() + viewName + getSuffix()); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 取得网页的类型和编码 ,并添加进 View</span> String contentType = getContentType(); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (contentType != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) { view.setContentType(contentType); } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 设置 View 的其他相关属性</span> view.setRequestContextAttribute(getRequestContextAttribute()); view.setAttributesMap(getAttributesMap()); Boolean exposePathVariables = getExposePathVariables(); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (exposePathVariables != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) { view.setExposePathVariables(exposePathVariables); } Boolean exposeContextBeansAsAttributes = getExposeContextBeansAsAttributes(); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (exposeContextBeansAsAttributes != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) { view.setExposeContextBeansAsAttributes(exposeContextBeansAsAttributes); } String [ ] exposedContextBeanNames = getExposedContextBeanNames(); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (exposedContextBeanNames != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) { view.setExposedContextBeanNames(exposedContextBeanNames); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> view; }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li></ul>
3.InternalResourceViewResolver
继承自 UrlBasedViewResolver ,以 InternalResourceView 作为视图,若项目中存在“javax.servlet.jsp.jstl.core.Config”该类,那么会以JstlView 作为视图。重写了 buildView 方法,主要就是为了给 InternalResourceView 视图设置属性。
源码分析(View)
View 负责视图的真正渲染。来看它的继承关系(部分显示):
1.AbstractView
View接口的基础实现抽象类,重点来看 render 方法:<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">render</span>(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> Exception { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 日志记录...</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 将属性合并到 map 中去</span> Map<String, Object> mergedModel = createMergedOutputModel(model, request, response); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 判断是否是下载资源,并设置请求头(为了解决 IE 下 https 下载请求的 bug)</span> prepareResponse(request, response); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 抽象方法,留给子类实现</span> renderMergedOutputModel(mergedModel, getRequestToExpose(request), response); }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li></ul>
createMergedOutputModel 方法:
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> Map<String, Object> <span class="hljs-title" style="box-sizing: border-box;">createMergedOutputModel</span>(Map<String, ?> model, HttpServletRequest request,HttpServletResponse response) { <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@SuppressWarnings</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"unchecked"</span>) Map<String, Object> pathVars = (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.exposePathVariables ?(Map<String, Object>) request.getAttribute(View.PATH_VARIABLES) : <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 把 exposePathVariables,staticAttributes,modelMap,以及 requestContextAttribute 的属性都添加进新的 map</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> size = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.staticAttributes.size(); size += (model != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span> ? model.size() : <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>); size += (pathVars != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span> ? pathVars.size() : <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>); Map<String, Object> mergedModel = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> LinkedHashMap<String, Object>(size); mergedModel.putAll(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.staticAttributes); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (pathVars != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) { mergedModel.putAll(pathVars); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (model != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) { mergedModel.putAll(model); } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Expose RequestContext?</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.requestContextAttribute != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) { mergedModel.put(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.requestContextAttribute, createRequestContext(request, response, mergedModel)); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> mergedModel; }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li></ul>
观察代码可以发现该类的主要工作是将各种属性都添加进 map 中,便于属性的传递,管理。
2.AbstractUrlBasedView
继承自 AbstractView 抽象类,增加了1个类型为 String 的 url 参数。
3.InternalResourceView
继承自 AbstractUrlBasedView 抽象类的类,该类重写了renderMergedOutputModel 这个方法:<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">renderMergedOutputModel</span>(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> Exception { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 将 map 的值添加 reqeust 的 attribute</span> exposeModelAsRequestAttributes(model, request); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Expose helpers as request attributes, if any.</span> exposeHelpers(request); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 验证要渲染的页面地址</span> String dispatcherPath = prepareForRendering(request, response); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 为指定的页面建立 RequestDispatcher </span> RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (rd == <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throw</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> ServletException(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Could not get RequestDispatcher for ["</span> + getUrl() + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"]: Check that the corresponding file exists within your web application archive!"</span>); } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 判断是 request 是 include 方法还是 forward 方法</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (useInclude(request, response)) { response.setContentType(getContentType()); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (logger.isDebugEnabled()) { logger.debug(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Including resource ["</span> + getUrl() + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"] in InternalResourceView '"</span> + getBeanName() + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"'"</span>); } rd.include(request, response); }<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Note: The forwarded resource is supposed to determine the content</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// type itself.</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (logger.isDebugEnabled()) { logger.debug(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Forwarding to resource ["</span> + getUrl() + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"] in InternalResourceView '"</span> + getBeanName() + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"'"</span>); } rd.forward(request, response); } }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li></ul>
实例探究
利用 ContentNegotiatingViewResolver 集成多种视图首先来看配置文件(这里集成 vm,jsp,json,xml 这四种视图显示)
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><bean class=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"org.springframework.web.servlet.view.ContentNegotiatingViewResolver"</span>> <!-- 内容协商管理器 --> <property name=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"contentNegotiationManager"</span> ref=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"contentNegotiationManager"</span>/> <!-- 视图解析器 --> <property name=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"viewResolvers"</span>> <list> <!--Veocity 视图解析器 --> <bean class=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"org.springframework.web.servlet.view.velocity.VelocityViewResolver"</span>> <property name=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"order"</span> value=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"0"</span>/> <property name=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"cache"</span> value=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"false"</span> /> <property name=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"suffix"</span> value=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">".vm"</span> /> </bean> <!--JSP 视图解析器 --> <bean class=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"org.springframework.web.servlet.view.InternalResourceViewResolver"</span>> <property name=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"viewClass"</span> value=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"org.springframework.web.servlet.view.JstlView"</span>/> <property name=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"prefix"</span> value=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"/WEB-INF/page/"</span>/> <property name=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"suffix"</span> value=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">".jsp"</span>></property> </bean> </list> </property> <!-- 默认视图 --> <property name=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"defaultViews"</span>> <list> <!-- json 视图解析 --> <bean class=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"org.springframework.web.servlet.view.json.MappingJackson2JsonView"</span> /> <!-- xml 视图解析 --> <bean class=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"org.springframework.web.servlet.view.xml.MarshallingView"</span> > <property name=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"marshaller"</span>> <bean class=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"org.springframework.oxm.xstream.XStreamMarshaller"</span>/> </property> </bean> </list> </property> </bean> <bean id=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"contentNegotiationManager"</span> class=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"org.springframework.web.accept.ContentNegotiationManagerFactoryBean"</span>> <!-- 根据请求参数或拓展名映射到相应的MIME类型 --> <property name=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"mediaTypes"</span>> <map> <entry key=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"json"</span> value=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"application/json"</span>/> <entry key=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"xml"</span> value=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"application/xml"</span>/> </map> </property> <!-- 设置默认的MIME类型,如果没有指定拓展名或请求参数,则使用此默认MIME类型解析视图 --> <property name=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"defaultContentType"</span> value=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"text/html"</span>/> <!-- 是否不适用请求头确定MIME类型 --> <property name=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"ignoreAcceptHeader"</span> value=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"true"</span>/> <!-- 是否根据路径拓展名确定MIME类型 --> <property name=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"favorPathExtension"</span> value=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"true"</span>/> <!-- 是否使用参数来确定MIME类型 --> <property name=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"favorParameter"</span> value=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"false"</span> /> </bean> <!-- Veocity 模版配置 --> <bean class=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"org.springframework.web.servlet.view.velocity.VelocityConfigurer"</span>> <property name=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"configLocation"</span> value=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"/WEB-INF/velocity.properties"</span> /> </bean></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li><li style="box-sizing: border-box; padding: 0px 5px;">50</li><li style="box-sizing: border-box; padding: 0px 5px;">51</li><li style="box-sizing: border-box; padding: 0px 5px;">52</li><li style="box-sizing: border-box; padding: 0px 5px;">53</li><li style="box-sizing: border-box; padding: 0px 5px;">54</li><li style="box-sizing: border-box; padding: 0px 5px;">55</li><li style="box-sizing: border-box; padding: 0px 5px;">56</li><li style="box-sizing: border-box; padding: 0px 5px;">57</li><li style="box-sizing: border-box; padding: 0px 5px;">58</li></ul>
Velocity 属性文件配置
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">input.encoding=UTF-<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8</span> output.encoding=UTF-<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8</span> contentType=text/html;charset=UTF-<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8</span> resource.loader=webapp webapp.resource.loader.class=org.apache.velocity.tools.view.WebappResourceLoader webapp.resource.loader.path=/WEB-INF/velocity/</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li></ul>
测试
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 先用 velocity 视图解析(order = 0),然后再用 jsp 视图解析</span> http:<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//localhost:8080/demo/hello</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 返回 json 视图</span> http:<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//localhost:8080/demo/hello.json</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 返回 xml 视图</span> http:<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//localhost:8080/demo/hello.xml</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li></ul>
注意:
这里利用路径扩展名(favorPathExtension)区分 MIME 类型,以此确定要返回的视图类型。也可以利用参数(默认为 fomart)来区分。
VelocityViewResolver(velocity 视图解析)的 order 优先级必须比 InternalResourceViewResolver(jsp 视图解析器)高。因为InternalResourceViewResolver 不管路径下是否存在指定 jsp 文件都会返回 View(视图),这样会导致 VelocityViewResolver 不生效。
参考
http://www.cnblogs.com/fangjian0423/p/springMVC-view-viewResolver.html
相关文章推荐
- springmvc中如何正确的解析视图InternalResourceViewResolver
- SpringMVC框架的视图解析器ViewResolver想用html不用jsp的spring-mvc.xml文件配置
- springMVC源码解析--ViewResolver视图解析器执行(三)
- SpringMVC源码情操陶冶-ViewResolver视图解析
- springMVC源码解析--ViewResolverComposite视图解析器集合(二)
- springMVC源码解析--ViewResolverComposite视图解析器集合(二)
- spring-mvc多视图解析配置实例 ContentNegotiatingViewResolver
- springmvc控制层返回org.springframework.web.portlet.ModelAndView视图解析器无法解析异常
- Spring的视图解析UrlBasedViewResolver与InternalResourceViewResolver比较
- SpringMVC 视图解析 - ViewResolver
- springMVC源码解析--ViewResolverComposite视图解析器集合(二)
- springMVC源码解析--ViewResolver视图解析器执行(三)
- springmvc 使用BeanNameViewResolver解析excel,pdf,json,xml视图
- springMVC源码解析--ViewResolver视图解析器执行(三)
- Spring源码追踪4——SpringMVC View解析
- Springmvc视图解析器(一)resolver解析器和view视图 【Springmvc】
- SpringMVC视图解析没按照ModelAndView的viewname跳转
- Spring Web MVC 多viewResolver视图解析器解决方案
- SpringMVC中的自定义视图使用BeanNameViewResolver出现了不能使用的错误解决
- SpringMVC介绍之视图解析器ViewResolver