您的位置:首页 > 编程语言 > Java开发

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  spring spring mvc