标签:
今天分析下ViewResolver和View的实现 下面是ModelAndView的实现
package org.springframework.web.servlet; import java.util.Map; import org.springframework.ui.ModelMap; import org.springframework.util.CollectionUtils; public class ModelAndView { /** View instance or view name String */ private Object view; /** Model Map */ private ModelMap model; /** Indicates whether or not this instance has been cleared with a call to {@link #clear()} */ private boolean cleared = false; /** * Default constructor for bean-style usage: populating bean * properties instead of passing in constructor arguments. * @see #setView(View) * @see #setViewName(String) */ public ModelAndView() { } public ModelAndView(String viewName) { this.view = viewName; } public ModelAndView(View view) { this.view = view; } public ModelAndView(String viewName, Map<String, ?> model) { this.view = viewName; if (model != null) { getModelMap().addAllAttributes(model); } } public ModelAndView(View view, Map<String, ?> model) { this.view = view; if (model != null) { getModelMap().addAllAttributes(model); } } public ModelAndView(String viewName, String modelName, Object modelObject) { this.view = viewName; addObject(modelName, modelObject); } public ModelAndView(View view, String modelName, Object modelObject) { this.view = view; addObject(modelName, modelObject); } public void setViewName(String viewName) { this.view = viewName; } /** * Return the view name to be resolved by the DispatcherServlet * via a ViewResolver, or <code>null</code> if we are using a View object. */ public String getViewName() { return (this.view instanceof String ? (String) this.view : null); } /** * Set a View object for this ModelAndView. Will override any * pre-existing view name or View. */ public void setView(View view) { this.view = view; } /** * Return the View object, or <code>null</code> if we are using a view name * to be resolved by the DispatcherServlet via a ViewResolver. */ public View getView() { return (this.view instanceof View ? (View) this.view : null); } /** * Indicate whether or not this <code>ModelAndView</code> has a view, either * as a view name or as a direct {@link View} instance. */ public boolean hasView() { return (this.view != null); } /** * Return whether we use a view reference, i.e. <code>true</code> * if the view has been specified via a name to be resolved by the * DispatcherServlet via a ViewResolver. */ public boolean isReference() { return (this.view instanceof String); } protected Map<String, Object> getModelInternal() { return this.model; } public ModelMap getModelMap() { if (this.model == null) { this.model = new ModelMap(); } return this.model; } public Map<String, Object> getModel() { return getModelMap(); } public ModelAndView addObject(String attributeName, Object attributeValue) { getModelMap().addAttribute(attributeName, attributeValue); return this; } public ModelAndView addObject(Object attributeValue) { getModelMap().addAttribute(attributeValue); return this; } public ModelAndView addAllObjects(Map<String, ?> modelMap) { getModelMap().addAllAttributes(modelMap); return this; } public void clear() { this.view = null; this.model = null; this.cleared = true; } public boolean isEmpty() { return (this.view == null && CollectionUtils.isEmpty(this.model)); } public boolean wasCleared() { return (this.cleared && isEmpty()); } @Override public String toString() { StringBuilder sb = new StringBuilder("ModelAndView: "); if (isReference()) { sb.append("reference to view with name ‘").append(this.view).append("‘"); } else { sb.append("materialized View is [").append(this.view).append(‘]‘); } sb.append("; model is ").append(this.model); return sb.toString(); } }
与逻辑视图紧紧相连的View
package org.springframework.web.servlet; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public interface View { String RESPONSE_STATUS_ATTRIBUTE = View.class.getName() + ".responseStatus"; String getContentType(); void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception; }
ViewResolver的一个实现类
package org.springframework.web.servlet.view; import java.util.HashMap; import java.util.Locale; import java.util.Map; import java.util.Properties; import org.springframework.beans.BeanUtils; import org.springframework.core.Ordered; import org.springframework.util.CollectionUtils; import org.springframework.util.PatternMatchUtils; import org.springframework.web.servlet.View; public class UrlBasedViewResolver extends AbstractCachingViewResolver implements Ordered { public static final String REDIRECT_URL_PREFIX = "redirect:"; public static final String FORWARD_URL_PREFIX = "forward:"; private Class viewClass; private String prefix = ""; private String suffix = ""; private String[] viewNames = null; private String contentType; private boolean redirectContextRelative = true; private boolean redirectHttp10Compatible = true; private String requestContextAttribute; private int order = Integer.MAX_VALUE; private final Map<String, Object> staticAttributes = new HashMap<String, Object>(); 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; } protected Class getViewClass() { return this.viewClass; } protected Class requiredViewClass() { return AbstractUrlBasedView.class; } public void setPrefix(String prefix) { this.prefix = (prefix != null ? prefix : ""); } protected String getPrefix() { return this.prefix; } public void setSuffix(String suffix) { this.suffix = (suffix != null ? suffix : ""); } protected String getSuffix() { return this.suffix; } public void setContentType(String contentType) { this.contentType = contentType; } protected String getContentType() { return this.contentType; } public void setRedirectContextRelative(boolean redirectContextRelative) { this.redirectContextRelative = redirectContextRelative; } protected boolean isRedirectContextRelative() { return this.redirectContextRelative; } public void setRedirectHttp10Compatible(boolean redirectHttp10Compatible) { this.redirectHttp10Compatible = redirectHttp10Compatible; } protected boolean isRedirectHttp10Compatible() { return this.redirectHttp10Compatible; } public void setRequestContextAttribute(String requestContextAttribute) { this.requestContextAttribute = requestContextAttribute; } protected String getRequestContextAttribute() { return this.requestContextAttribute; } public void setAttributes(Properties props) { CollectionUtils.mergePropertiesIntoMap(props, this.staticAttributes); } public void setAttributesMap(Map<String, ?> attributes) { if (attributes != null) { this.staticAttributes.putAll(attributes); } } public Map<String, Object> getAttributesMap() { return this.staticAttributes; } public void setViewNames(String[] viewNames) { this.viewNames = viewNames; } protected String[] getViewNames() { return this.viewNames; } public void setOrder(int order) { this.order = order; } public int getOrder() { return this.order; } @Override protected void initApplicationContext() { super.initApplicationContext(); if (getViewClass() == null) { throw new IllegalArgumentException("Property ‘viewClass‘ is required"); } } @Override protected Object getCacheKey(String viewName, Locale locale) { return viewName; } @Override protected 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()); return new RedirectView(redirectUrl, isRedirectContextRelative(), isRedirectHttp10Compatible()); } // 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); } /** protected boolean canHandle(String viewName, Locale locale) { String[] viewNames = getViewNames(); return (viewNames == null || PatternMatchUtils.simpleMatch(viewNames, viewName)); } @Override protected View loadView(String viewName, Locale locale) throws Exception { AbstractUrlBasedView view = buildView(viewName); View result = (View) getApplicationContext().getAutowireCapableBeanFactory().initializeBean(view, viewName); return (view.checkResource(locale) ? result : null); } protected AbstractUrlBasedView buildView(String viewName) throws Exception { AbstractUrlBasedView view = (AbstractUrlBasedView) BeanUtils.instantiateClass(getViewClass()); view.setUrl(getPrefix() + viewName + getSuffix()); String contentType = getContentType(); if (contentType != null) { view.setContentType(contentType); } view.setRequestContextAttribute(getRequestContextAttribute()); view.setAttributesMap(getAttributesMap()); return view; } }
/* * Copyright 2002-2009 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.web.servlet.view; import java.util.HashMap; import java.util.Locale; import java.util.Map; import org.springframework.web.context.support.WebApplicationObjectSupport; import org.springframework.web.servlet.View; import org.springframework.web.servlet.ViewResolver; /** * 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 { /** Whether we should cache views, once resolved */ private boolean cache = true; /** Map from view key to View instance */ private final Map<Object, View> viewCache = new HashMap<Object, View>(); /** * Enable or disable caching. * <p>Default is "true": caching is enabled. * Disable this only for debugging and development. * <p><b>Warning: Disabling caching can severely impact performance.</b> */ public void setCache(boolean cache) { this.cache = cache; } /** * Return if caching is enabled. */ public boolean isCache() { return this.cache; } public View resolveViewName(String viewName, Locale locale) throws Exception { if (!isCache()) { return createView(viewName, locale); } else { Object cacheKey = getCacheKey(viewName, locale); synchronized (this.viewCache) { View view = this.viewCache.get(cacheKey); if (view == null) { // Ask the subclass to create the View object. view = createView(viewName, locale); this.viewCache.put(cacheKey, view); if (logger.isTraceEnabled()) { logger.trace("Cached view [" + cacheKey + "]"); } } return view; } } } /** * 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 (!this.cache) { logger.warn("View caching is SWITCHED OFF -- removal not necessary"); } else { Object cacheKey = getCacheKey(viewName, locale); Object cachedView; synchronized (this.viewCache) { cachedView = this.viewCache.remove(cacheKey); } if (cachedView == null) { // Some debug output might be useful... if (logger.isDebugEnabled()) { logger.debug("No cached instance for view ‘" + cacheKey + "‘ was found"); } } else { if (logger.isDebugEnabled()) { 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.viewCache) { this.viewCache.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</code> 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</code> 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</code> 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; }
标签:
原文地址:http://www.cnblogs.com/wuxinliulei/p/5065345.html