在Spring MVC DispatcherServlet.doDispatch中请求在经过handler处理返回一个ModelAndView.
那么ModelAndView又是如何最终转换为一个具体的View的呢?下面就对视图呈现部分作出一些简介。
视图的渲染是处理一个请求的最后阶段:
/** 根据ModelAndView中的视图名称进行解析,得到具体的视图对象
* Render the given ModelAndView.
* <p>This is the last stage in handling a request. It may involve resolving the view by name.
* @param mv the ModelAndView to render
* @param request current HTTP servlet request
* @param response current HTTP servlet response
* @throws ServletException if view is missing or cannot be resolved
* @throws Exception if there's a problem rendering the view
*/
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
// 确定请求的位置,并将位置信息应用到响应中
Locale locale = this.localeResolver.resolveLocale(request);
response.setLocale(locale);
View view;
// 如果只是一个视图的引用,则需要解析视图
if (mv.isReference()) {
// 解析视图名
view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
if (view == null) {
throw new ServletException(
"Could not resolve view with name '" + mv.getViewName() + "' in servlet with name '" +
getServletName() + "'");
}
}
else {
// 不需要解析视图名,从ModleAndView中获取实际的视图对象
view = mv.getView();
if (view == null) {
throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
"View object in servlet with name '" + getServletName() + "'");
}
}
// 将视图的渲染委派给视图对象,并通过HttpResponse把视图呈现给Http客户端
if (logger.isDebugEnabled()) {
logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'");
}
view.render(mv.getModelInternal(), request, response);
}
通过上面的代码可以发现对于视图的解析是使用如下方法:在该方法中遍历视图注册的视图解析器,如果优先级高的视图解析器可以解析出正确的视图对象,则直接放回视图对象。
/**
* 将给定的视图名称解析成一个将被渲染的视图对象
* 默认的实现要求调用所有的视图解析器。也可以基于特定的模型参数或请求参数使用自定义
* 策略重写。
* <p>The default implementations asks all ViewResolvers of this dispatcher.
* Can be overridden for custom resolution strategies, potentially based on
* specific model attributes or request parameters.
* @param viewName the name of the view to resolve
* @param model the model to be passed to the view
* @param locale the current locale
* @param request current HTTP servlet request
* @return the View object, or <code>null</code> if none found
* @throws Exception if the view cannot be resolved
* (typically in case of problems creating an actual View object)
* @see ViewResolver#resolveViewName
*/
protected View resolveViewName(String viewName, Map<String, Object> model, Locale locale,
HttpServletRequest request) throws Exception {
for (ViewResolver viewResolver : this.viewResolvers) {
View view = viewResolver.resolveViewName(viewName, locale);
if (view != null) {
return view;
}
}
return null;
}
自定义的一个JSON视图解析器:
**
*
* @author zhangwei_david
* @version $Id: JsonViewResolver.java, v 0.1 2014��11��30�� ����12:09:44 zhangwei_david Exp $
*/
public class JsonViewResolver implements ViewResolver, Ordered {
private static final Logger logger = LogManager.getLogger(JsonViewResolver.class);
private int order = Ordered.HIGHEST_PRECEDENCE;
private UrlPathHelper urlPathHelper;
/**
* @see org.springframework.web.servlet.ViewResolver#resolveViewName(java.lang.String, java.util.Locale)
*/
public View resolveViewName(String viewName, Locale locale) throws Exception {
RequestAttributes attrs = RequestContextHolder.getRequestAttributes();
Assert.isInstanceOf(ServletRequestAttributes.class, attrs);
HttpServletRequest request = ((ServletRequestAttributes) attrs).getRequest();
String uri = urlPathHelper.getRequestUri(request);
if (uri.contains(".json")) {
LogUtils.info(logger, "Handler the Uri {0} and Return A JSON View", uri);
return new MappingJacksonJsonView();
}
//
return null;
}
/**
* Getter method for property <tt>urlPathHelper</tt>.
*
* @return property value of urlPathHelper
*/
public UrlPathHelper getUrlPathHelper() {
return urlPathHelper;
}
/**
* Setter method for property <tt>urlPathHelper</tt>.
*
* @param urlPathHelper value to be assigned to property urlPathHelper
*/
public void setUrlPathHelper(UrlPathHelper urlPathHelper) {
this.urlPathHelper = urlPathHelper;
}
/**
* @see org.springframework.core.Ordered#getOrder()
*/
public int getOrder() {
return order;
}
/**
* Setter method for property <tt>order</tt>.
*
* @param order value to be assigned to property order
*/
public void setOrder(int order) {
this.order = order;
}
}