SpringMVC那些事-视图渲染

来源:互联网 发布:手机上怎么装修淘宝店 编辑:程序博客网 时间:2024/06/07 10:06

上一个阶段返回了ModelAndView(这里假设返回了MAV,我们讨论的是有视图渲染的情况),接下来就是视图渲染阶段了.
MAV包含了可以确定视图的信息,和需要渲染的数据,也就是model.

视图渲染阶段包括两个子阶段
1.使用视图解析器ViewResolver生成实例View
2.View.render渲染视图

1.视图View生成的过程

遍历ViewResolver,和hm一样的策略,生成具体的View,注意ViewResolver使用Order接口,也就是根据这个决定优先级.
最终生成的view表示具体的不同视图,例如JstlVIew, PDFView等.
->dispatcherservlet.processDispatchResult//处理返回的视图模型,
->dispatcherservlet.render
->dispatcherservlet.resolveViewName//
->dispatcherservlet.resolveViewName
->AbstractCachingViewResolver.resolveViewName
->AbstractCachingViewResolver.createView
->UrlBasedViewResolver.loadView
->UrlBasedViewResolver.buildView//生成view实例
->UrlBasedViewResolver.applyLifecycleMethods


2.视图view渲染过程(以JstlView举例)
直接使用视图的render方法渲染视图.这个过程会包括把国际化资源文件和request绑定,把model的数据放到
request attribute中等.最终使用的是RequestDispatcher完成视图的渲染处理.
->JstlView.render//调用具体的视图类渲染视图
->AbstractView.render
->AbstractView.createMergedOutputModel
->AbstractView.prepareResponse
->InternalResourceView.renderMergedOutputModel
->AbstractView.exposeModelAsRequestAttributes//把model放入request attributes, 这样才能使用jstl标签解析数据
->InternalResourceView.exposeHelpers//Exposes a JSTL LocalizationContext for Spring's locale and MessageSource
->InternalResourceView.getRequestDispatcher//获取RequestDispatcher,原生servlet+jsp 开发的常用, 看上去很高大上的东东,其实底层的东西都是这些,所有打好基础!
->RequestDispatcher.include/RequestDispatcher.forward//渲染或者跳转

插播一些简单知识:
RequestDispatcher.include给客户端返回视图
RequestDispatcher.forward服务器端跳转(浏览器url还是当前url)
response.sendRedirect客户端跳转(浏览器重新发送请求的地址)

相关类

View 视图抽象接口,所有视图的最高抽象

InternalResourceView

JstlView JSTL视图
  MessageSource//locale and resource bundle for JSTL's formatting and message tags国际化
 
ModelAndView 视图和模型
  Object view
  ModelMap defaultModel
  ModelMap redirectModel

ResourceBundleMessageSource  国际资源绑定文件(在配置文件中配置,以后详细介绍))
  String defaultEncoding
  ClassLoader bundleClassLoader
  ClassLoader beanClassLoader

ViewResolver  视图解析器接口

AbstractCachingViewResolver 具有缓存功能吃视图解析器抽象类
  Map<Object, View> viewAccessCache//缓存访问过的视图
  Map<Object, View> viewCreationCache//缓存生成过的视图

InternalResourceViewResolver 使用RequestDispatcher返回jsp等web内部资源文件


部分源码

DispatcherServlet


/** * Handle the result of handler selection and handler invocation, which is * either a ModelAndView or an Exception to be resolved to a ModelAndView. */private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {boolean errorView = false;//把异常转换成视图处理,还是需要提醒的是,我们可以在自定义拦截异常的时候,返回json这样格式的错误信息//一般在统一异常处理的时候需要这么多.if (exception != null) {if (exception instanceof ModelAndViewDefiningException) {logger.debug("ModelAndViewDefiningException encountered", exception);mv = ((ModelAndViewDefiningException) exception).getModelAndView();}else {Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);mv = processHandlerException(request, response, handler, exception);errorView = (mv != null);}}// Did the handler return a view to render?(判断处理器返回的是不是需要渲染的视图,假如使用@RequestBody就不需要渲染视图了)if (mv != null && !mv.wasCleared()) {//开始渲染视图render(mv, request, response);if (errorView) {WebUtils.clearErrorRequestAttributes(request);}}else {if (logger.isDebugEnabled()) {logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +"': assuming HandlerAdapter completed request handling");}}if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {// Concurrent handling started during a forwardreturn;}if (mappedHandler != null) {mappedHandler.triggerAfterCompletion(request, response, null);}}/** * 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 {// Determine locale for request and apply it to the response.Locale locale = this.localeResolver.resolveLocale(request);response.setLocale(locale);View view;//判断是否需要解析视图(可以在处理器返回字符串和ModelAndView)if (mv.isReference()) {// We need to resolve the view name.//获取视图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 {// No need to lookup: the ModelAndView object contains the actual View object.//ModelAndView中已经存在了视图,(例如我们在处理器返回AbstractpdfView视图的时候,就已经指定好了视图了)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() + "'");}}// Delegate to the View object for rendering.if (logger.isDebugEnabled()) {logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'");}try {//渲染视图,从mv中取出modelview.render(mv.getModelInternal(), request, response);}catch (Exception ex) {if (logger.isDebugEnabled()) {logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name '" +getServletName() + "'", ex);}throw ex;}}

AbstractCachingViewResolver


/** * Convenient base class for {@link org.springframework.web.servlet.ViewResolver} * implementations. Caches {@link org.springframework.web.servlet.View} objects * once resolved: This means that view resolution won't be a performance problem, * no matter how costly initial view retrieval is. * * <p>Subclasses need to implement the {@link #loadView} template method, * building the View object for a specific view name and locale. * * @author Rod Johnson * @author Juergen Hoeller * @see #loadView */public abstract class AbstractCachingViewResolver extends WebApplicationObjectSupport implements ViewResolver {/** Default maximum number of entries for the view cache: 1024 */public static final int DEFAULT_CACHE_LIMIT = 1024;/** Dummy marker object for unresolved views in the cache Maps */private static final View UNRESOLVED_VIEW = new View() {@Overridepublic String getContentType() {return null;}@Overridepublic void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) {}};/** The maximum number of entries in the cache */private volatile int cacheLimit = DEFAULT_CACHE_LIMIT;/** Whether we should refrain from resolving views again if unresolved once */private boolean cacheUnresolved = true;/** Fast access cache for Views, returning already cached instances without a global lock *///已经访问过的视图缓存private final Map<Object, View> viewAccessCache = new ConcurrentHashMap<Object, View>(DEFAULT_CACHE_LIMIT);/** Map from view key to View instance, synchronized for View creation */@SuppressWarnings("serial")//创建过的视图缓存private final Map<Object, View> viewCreationCache =new LinkedHashMap<Object, View>(DEFAULT_CACHE_LIMIT, 0.75f, true) {@Overrideprotected boolean removeEldestEntry(Map.Entry<Object, View> eldest) {if (size() > getCacheLimit()) {viewAccessCache.remove(eldest.getKey());return true;}else {return false;}}};/** * Specify the maximum number of entries for the view cache. * Default is 1024. */public void setCacheLimit(int cacheLimit) {this.cacheLimit = cacheLimit;}/** * Return the maximum number of entries for the view cache. */public int getCacheLimit() {return this.cacheLimit;}/** * Enable or disable caching. * <p>This is equivalent to setting the {@link #setCacheLimit "cacheLimit"} * property to the default limit (1024) or to 0, respectively. * <p>Default is "true": caching is enabled. * Disable this only for debugging and development. */public void setCache(boolean cache) {this.cacheLimit = (cache ? DEFAULT_CACHE_LIMIT : 0);}/** * Return if caching is enabled. */public boolean isCache() {return (this.cacheLimit > 0);}/** * Whether a view name once resolved to {@code null} should be cached and * automatically resolved to {@code null} subsequently. * <p>Default is "true": unresolved view names are being cached, as of Spring 3.1. * Note that this flag only applies if the general {@link #setCache "cache"} * flag is kept at its default of "true" as well. * <p>Of specific interest is the ability for some AbstractUrlBasedView * implementations (FreeMarker, Velocity, Tiles) to check if an underlying * resource exists via {@link AbstractUrlBasedView#checkResource(Locale)}. * With this flag set to "false", an underlying resource that re-appears * is noticed and used. With the flag set to "true", one check is made only. */public void setCacheUnresolved(boolean cacheUnresolved) {this.cacheUnresolved = cacheUnresolved;}/** * Return if caching of unresolved views is enabled. */public boolean isCacheUnresolved() {return this.cacheUnresolved;}@Overridepublic View resolveViewName(String viewName, Locale locale) throws Exception {if (!isCache()) {//1.如果没有有开启视图缓存,直接创建新的视图return createView(viewName, locale);}else {//视图的key为:viewName + "_" + localeObject cacheKey = getCacheKey(viewName, locale);View view = this.viewAccessCache.get(cacheKey);//2.从访问过的视图缓存中查找视图if (view == null) {synchronized (this.viewCreationCache) {view = this.viewCreationCache.get(cacheKey);//3.从创建的视图缓存查找视图if (view == null) {// Ask the subclass to create the View object.view = createView(viewName, locale);//4.两种缓存都找不到,那只能新创建一个视图了if (view == null && this.cacheUnresolved) {view = UNRESOLVED_VIEW;}if (view != null) {//5.新建的视图放入视图缓存中this.viewAccessCache.put(cacheKey, view);this.viewCreationCache.put(cacheKey, view);if (logger.isTraceEnabled()) {logger.trace("Cached view [" + cacheKey + "]");}}}}}return (view != UNRESOLVED_VIEW ? view : null);}}/** * Return the cache key for the given view name and the given locale. * <p>Default is a String consisting of view name and locale suffix. * Can be overridden in subclasses. * <p>Needs to respect the locale in general, as a different locale can * lead to a different view resource. */protected Object getCacheKey(String viewName, Locale locale) {return viewName + "_" + locale;}/** * Provides functionality to clear the cache for a certain view. * <p>This can be handy in case developer are able to modify views * (e.g. Velocity templates) at runtime after which you'd need to * clear the cache for the specified view. * @param viewName the view name for which the cached view object * (if any) needs to be removed * @param locale the locale for which the view object should be removed */public void removeFromCache(String viewName, Locale locale) {if (!isCache()) {logger.warn("View caching is SWITCHED OFF -- removal not necessary");}else {Object cacheKey = getCacheKey(viewName, locale);Object cachedView;synchronized (this.viewCreationCache) {this.viewAccessCache.remove(cacheKey);cachedView = this.viewCreationCache.remove(cacheKey);}if (logger.isDebugEnabled()) {// Some debug output might be useful...if (cachedView == null) {logger.debug("No cached instance for view '" + cacheKey + "' was found");}else {logger.debug("Cache for view " + cacheKey + " has been cleared");}}}}/** * Clear the entire view cache, removing all cached view objects. * Subsequent resolve calls will lead to recreation of demanded view objects. */public void clearCache() {logger.debug("Clearing entire view cache");synchronized (this.viewCreationCache) {this.viewAccessCache.clear();this.viewCreationCache.clear();}}/** * Create the actual View object. * <p>The default implementation delegates to {@link #loadView}. * This can be overridden to resolve certain view names in a special fashion, * before delegating to the actual {@code loadView} implementation * provided by the subclass. * @param viewName the name of the view to retrieve * @param locale the Locale to retrieve the view for * @return the View instance, or {@code null} if not found * (optional, to allow for ViewResolver chaining) * @throws Exception if the view couldn't be resolved * @see #loadView */protected View createView(String viewName, Locale locale) throws Exception {return loadView(viewName, locale);}/** * Subclasses must implement this method, building a View object * for the specified view. The returned View objects will be * cached by this ViewResolver base class. * <p>Subclasses are not forced to support internationalization: * A subclass that does not may simply ignore the locale parameter. * @param viewName the name of the view to retrieve * @param locale the Locale to retrieve the view for * @return the View instance, or {@code null} if not found * (optional, to allow for ViewResolver chaining) * @throws Exception if the view couldn't be resolved * @see #resolveViewName */protected abstract View loadView(String viewName, Locale locale) throws Exception;}

UrlBasedViewResolver

/** * Simple implementation of the {@link org.springframework.web.servlet.ViewResolver} * interface, allowing for direct resolution of symbolic view names to URLs, * without explicit mapping definition. This is useful if your symbolic names * match the names of your view resources in a straightforward manner * (i.e. the symbolic name is the unique part of the resource's filename), * without the need for a dedicated mapping to be defined for each view. * * <p>Supports {@link AbstractUrlBasedView} subclasses like {@link InternalResourceView}, * {@link org.springframework.web.servlet.view.velocity.VelocityView} and * {@link org.springframework.web.servlet.view.freemarker.FreeMarkerView}. * The view class for all views generated by this resolver can be specified * via the "viewClass" property. * * <p>View names can either be resource URLs themselves, or get augmented by a * specified prefix and/or suffix. Exporting an attribute that holds the * RequestContext to all views is explicitly supported. * * <p>Example: prefix="/WEB-INF/jsp/", suffix=".jsp", viewname="test" -> * "/WEB-INF/jsp/test.jsp" * * <p>As a special feature, redirect URLs can be specified via the "redirect:" * prefix. E.g.: "redirect:myAction.do" will trigger a redirect to the given * URL, rather than resolution as standard view name. This is typically used * for redirecting to a controller URL after finishing a form workflow. * * <p>Furthermore, forward URLs can be specified via the "forward:" prefix. E.g.: * "forward:myAction.do" will trigger a forward to the given URL, rather than * resolution as standard view name. This is typically used for controller URLs; * it is not supposed to be used for JSP URLs - use logical view names there. * * <p>Note: This class does not support localized resolution, i.e. resolving * a symbolic view name to different resources depending on the current locale. * * <p><b>Note:</b> When chaining ViewResolvers, a UrlBasedViewResolver will check whether * the {@link AbstractUrlBasedView#checkResource specified resource actually exists}. * However, with {@link InternalResourceView}, it is not generally possible to * determine the existence of the target resource upfront. In such a scenario, * a UrlBasedViewResolver will always return View for any given view name; * as a consequence, it should be configured as the last ViewResolver in the chain. * * @author Juergen Hoeller * @author Rob Harrop * @since 13.12.2003 * @see #setViewClass * @see #setPrefix * @see #setSuffix * @see #setRequestContextAttribute * @see #REDIRECT_URL_PREFIX * @see AbstractUrlBasedView * @see InternalResourceView * @see org.springframework.web.servlet.view.velocity.VelocityView * @see org.springframework.web.servlet.view.freemarker.FreeMarkerView */public class UrlBasedViewResolver extends AbstractCachingViewResolver implements Ordered {/** * Prefix for special view names that specify a redirect URL (usually * to a controller after a form has been submitted and processed). * Such view names will not be resolved in the configured default * way but rather be treated as special shortcut. */public static final String REDIRECT_URL_PREFIX = "redirect:";/** * Prefix for special view names that specify a forward URL (usually * to a controller after a form has been submitted and processed). * Such view names will not be resolved in the configured default * way but rather be treated as special shortcut. */public static final String FORWARD_URL_PREFIX = "forward:";private Class<?> viewClass;//根据这个生成具体的View实例private String prefix = "";private String suffix = "";private String contentType;//返回视图的类型,例如html,XML等private boolean redirectContextRelative = true;private boolean redirectHttp10Compatible = true;private String requestContextAttribute;/** Map of static attributes, keyed by attribute name (String) */private final Map<String, Object> staticAttributes = new HashMap<String, Object>();//暂时没弄明白什么东东private Boolean exposePathVariables;private String[] viewNames;private int order = Integer.MAX_VALUE;//默认最大优先级/** * Set the view class that should be used to create views. * @param viewClass class that is assignable to the required view class * (by default, AbstractUrlBasedView) * @see AbstractUrlBasedView */public void setViewClass(Class<?> viewClass) {if (viewClass == null || !requiredViewClass().isAssignableFrom(viewClass)) {throw new IllegalArgumentException("Given view class [" + (viewClass != null ? viewClass.getName() : null) +"] is not of type [" + requiredViewClass().getName() + "]");}this.viewClass = viewClass;}/** * Return the view class to be used to create views. */protected Class<?> getViewClass() {return this.viewClass;}/** * Return the required type of view for this resolver. * This implementation returns AbstractUrlBasedView. * @see AbstractUrlBasedView */protected Class<?> requiredViewClass() {return AbstractUrlBasedView.class;}/** * Set the prefix that gets prepended to view names when building a URL. */public void setPrefix(String prefix) {this.prefix = (prefix != null ? prefix : "");}/** * Return the prefix that gets prepended to view names when building a URL. */protected String getPrefix() {return this.prefix;}/** * Set the suffix that gets appended to view names when building a URL. */public void setSuffix(String suffix) {this.suffix = (suffix != null ? suffix : "");}/** * Return the suffix that gets appended to view names when building a URL. */protected String getSuffix() {return this.suffix;}/** * Set the content type for all views. * <p>May be ignored by view classes if the view itself is assumed * to set the content type, e.g. in case of JSPs. */public void setContentType(String contentType) {this.contentType = contentType;}/** * Return the content type for all views, if any. */protected String getContentType() {return this.contentType;}/** * Set whether to interpret a given redirect URL that starts with a * slash ("/") as relative to the current ServletContext, i.e. as * relative to the web application root. * <p>Default is "true": A redirect URL that starts with a slash will be * interpreted as relative to the web application root, i.e. the context * path will be prepended to the URL. * <p><b>Redirect URLs can be specified via the "redirect:" prefix.</b> * E.g.: "redirect:myAction.do" * @see RedirectView#setContextRelative * @see #REDIRECT_URL_PREFIX */public void setRedirectContextRelative(boolean redirectContextRelative) {this.redirectContextRelative = redirectContextRelative;}/** * Return whether to interpret a given redirect URL that starts with a * slash ("/") as relative to the current ServletContext, i.e. as * relative to the web application root. */protected boolean isRedirectContextRelative() {return this.redirectContextRelative;}/** * Set whether redirects should stay compatible with HTTP 1.0 clients. * <p>In the default implementation, this will enforce HTTP status code 302 * in any case, i.e. delegate to {@code HttpServletResponse.sendRedirect}. * Turning this off will send HTTP status code 303, which is the correct * code for HTTP 1.1 clients, but not understood by HTTP 1.0 clients. * <p>Many HTTP 1.1 clients treat 302 just like 303, not making any * difference. However, some clients depend on 303 when redirecting * after a POST request; turn this flag off in such a scenario. * <p><b>Redirect URLs can be specified via the "redirect:" prefix.</b> * E.g.: "redirect:myAction.do" * @see RedirectView#setHttp10Compatible * @see #REDIRECT_URL_PREFIX */public void setRedirectHttp10Compatible(boolean redirectHttp10Compatible) {this.redirectHttp10Compatible = redirectHttp10Compatible;}/** * Return whether redirects should stay compatible with HTTP 1.0 clients. */protected boolean isRedirectHttp10Compatible() {return this.redirectHttp10Compatible;}/** * Set the name of the RequestContext attribute for all views. * @param requestContextAttribute name of the RequestContext attribute * @see AbstractView#setRequestContextAttribute */public void setRequestContextAttribute(String requestContextAttribute) {this.requestContextAttribute = requestContextAttribute;}/** * Return the name of the RequestContext attribute for all views, if any. */protected String getRequestContextAttribute() {return this.requestContextAttribute;}/** * Set static attributes from a {@code java.util.Properties} object, * for all views returned by this resolver. * <p>This is the most convenient way to set static attributes. Note that * static attributes can be overridden by dynamic attributes, if a value * with the same name is included in the model. * <p>Can be populated with a String "value" (parsed via PropertiesEditor) * or a "props" element in XML bean definitions. * @see org.springframework.beans.propertyeditors.PropertiesEditor * @see AbstractView#setAttributes */public void setAttributes(Properties props) {CollectionUtils.mergePropertiesIntoMap(props, this.staticAttributes);}/** * Set static attributes from a Map, for all views returned by this resolver. * This allows to set any kind of attribute values, for example bean references. * <p>Can be populated with a "map" or "props" element in XML bean definitions. * @param attributes Map with name Strings as keys and attribute objects as values * @see AbstractView#setAttributesMap */public void setAttributesMap(Map<String, ?> attributes) {if (attributes != null) {this.staticAttributes.putAll(attributes);}}/** * Allow Map access to the static attributes for views returned by * this resolver, with the option to add or override specific entries. * <p>Useful for specifying entries directly, for example via * "attributesMap[myKey]". This is particularly useful for * adding or overriding entries in child view definitions. */public Map<String, Object> getAttributesMap() {return this.staticAttributes;}/** * Specify whether views resolved by this resolver should add path variables to the model or not. * <p>>The default setting is to let each View decide (see {@link AbstractView#setExposePathVariables}. * However, you can use this property to override that. * @param exposePathVariables * <ul> * <li>{@code true} - all Views resolved by this resolver will expose path variables * <li>{@code false} - no Views resolved by this resolver will expose path variables * <li>{@code null} - individual Views can decide for themselves (this is used by the default) * <ul> * @see AbstractView#setExposePathVariables */public void setExposePathVariables(Boolean exposePathVariables) {this.exposePathVariables = exposePathVariables;}/** * Return whether views resolved by this resolver should add path variables to the model or not. */protected Boolean getExposePathVariables() {return this.exposePathVariables;}/** * Set the view names (or name patterns) that can be handled by this * {@link org.springframework.web.servlet.ViewResolver}. View names can contain * simple wildcards such that 'my*', '*Report' and '*Repo*' will all match the * view name 'myReport'. * @see #canHandle */public void setViewNames(String... viewNames) {this.viewNames = viewNames;}/** * Return the view names (or name patterns) that can be handled by this * {@link org.springframework.web.servlet.ViewResolver}. */protected String[] getViewNames() {return this.viewNames;}/** * Set the order in which this {@link org.springframework.web.servlet.ViewResolver} * is evaluated. */public void setOrder(int order) {this.order = order;}/** * Return the order in which this {@link org.springframework.web.servlet.ViewResolver} * is evaluated. */@Overridepublic int getOrder() {return this.order;}@Overrideprotected void initApplicationContext() {super.initApplicationContext();if (getViewClass() == null) {throw new IllegalArgumentException("Property 'viewClass' is required");}}/** * This implementation returns just the view name, * as this ViewResolver doesn't support localized resolution. */@Overrideprotected Object getCacheKey(String viewName, Locale locale) {return viewName;}/** * Overridden to implement check for "redirect:" prefix. * <p>Not possible in {@code loadView}, since overridden * {@code loadView} versions in subclasses might rely on the * superclass always creating instances of the required view class. * @see #loadView * @see #requiredViewClass */@Overrideprotected View createView(String viewName, Locale locale) throws Exception {// If this resolver is not supposed to handle the given view,// return null to pass on to the next resolver in the chain.if (!canHandle(viewName, locale)) {return null;}// Check for special "redirect:" prefix.if (viewName.startsWith(REDIRECT_URL_PREFIX)) {String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length());RedirectView view = new RedirectView(redirectUrl, isRedirectContextRelative(), isRedirectHttp10Compatible());return applyLifecycleMethods(viewName, view);}// Check for special "forward:" prefix.if (viewName.startsWith(FORWARD_URL_PREFIX)) {String forwardUrl = viewName.substring(FORWARD_URL_PREFIX.length());return new InternalResourceView(forwardUrl);}// Else fall back to superclass implementation: calling loadView.return super.createView(viewName, locale);}/** * Indicates whether or not this {@link org.springframework.web.servlet.ViewResolver} can * handle the supplied view name. If not, {@link #createView(String, java.util.Locale)} will * return {@code null}. The default implementation checks against the configured * {@link #setViewNames view names}. * @param viewName the name of the view to retrieve * @param locale the Locale to retrieve the view for * @return whether this resolver applies to the specified view * @see org.springframework.util.PatternMatchUtils#simpleMatch(String, String) */protected boolean canHandle(String viewName, Locale locale) {String[] viewNames = getViewNames();return (viewNames == null || PatternMatchUtils.simpleMatch(viewNames, viewName));}/** * Delegates to {@code buildView} for creating a new instance of the * specified view class, and applies the following Spring lifecycle methods * (as supported by the generic Spring bean factory): * <ul> * <li>ApplicationContextAware's {@code setApplicationContext} * <li>InitializingBean's {@code afterPropertiesSet} * </ul> * @param viewName the name of the view to retrieve * @return the View instance * @throws Exception if the view couldn't be resolved * @see #buildView(String) * @see org.springframework.context.ApplicationContextAware#setApplicationContext * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet */@Overrideprotected View loadView(String viewName, Locale locale) throws Exception {AbstractUrlBasedView view = buildView(viewName);View result = applyLifecycleMethods(viewName, view);return (view.checkResource(locale) ? result : null);}private View applyLifecycleMethods(String viewName, AbstractView view) {return (View) getApplicationContext().getAutowireCapableBeanFactory().initializeBean(view, viewName);}/** * Creates a new View instance of the specified view class and configures it. * Does <i>not</i> perform any lookup for pre-defined View instances. * <p>Spring lifecycle methods as defined by the bean container do not have to * be called here; those will be applied by the {@code loadView} method * after this method returns. * <p>Subclasses will typically call {@code super.buildView(viewName)} * first, before setting further properties themselves. {@code loadView} * will then apply Spring lifecycle methods at the end of this process. * @param viewName the name of the view to build * @return the View instance * @throws Exception if the view couldn't be resolved * @see #loadView(String, java.util.Locale) */protected AbstractUrlBasedView buildView(String viewName) throws Exception {//构建view实例AbstractUrlBasedView view = (AbstractUrlBasedView) BeanUtils.instantiateClass(getViewClass());//设置视图的full URL,也就是视图的全文件路径,例如/WEB-INF/view/index.jsview.setUrl(getPrefix() + viewName + getSuffix());String contentType = getContentType();if (contentType != null) {view.setContentType(contentType);}view.setRequestContextAttribute(getRequestContextAttribute());view.setAttributesMap(getAttributesMap());Boolean exposePathVariables = getExposePathVariables();if (exposePathVariables != null) {view.setExposePathVariables(exposePathVariables);}return view;}}



0 0
原创粉丝点击