zoukankan      html  css  js  c++  java
  • SpringMVC源码阅读(二)

    今天分析下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;
    	}
    
    }
    

    JSTLView

    package org.springframework.web.servlet.view;
    
    import javax.servlet.ServletContext;
    import javax.servlet.http.HttpServletRequest;
    import org.springframework.context.MessageSource;
    import org.springframework.web.servlet.support.JstlUtils;
    import org.springframework.web.servlet.support.RequestContext;
    
    public class JstlView
      extends InternalResourceView
    {
      private MessageSource messageSource;
      
      public JstlView() {}
      
      public JstlView(String url)
      {
        super(url);
      }
      
      public JstlView(String url, MessageSource messageSource)
      {
        this(url);
        this.messageSource = messageSource;
      }
      
      protected void initServletContext(ServletContext servletContext)
      {
        if (this.messageSource != null) {
          this.messageSource = JstlUtils.getJstlAwareMessageSource(servletContext, this.messageSource);
        }
        super.initServletContext(servletContext);
      }
      
      protected void exposeHelpers(HttpServletRequest request)
        throws Exception
      {
        if (this.messageSource != null) {
          JstlUtils.exposeLocalizationContext(request, this.messageSource);
        }
        else {
          JstlUtils.exposeLocalizationContext(new RequestContext(request, getServletContext()));
        }
      }
    }
    

      

    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;
    
    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;
    			}
    		}
    	}
    
    	 
    	protected Object getCacheKey(String viewName, Locale locale) {
    		return viewName + "_" + locale;
    	}
    
    	 
    	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();
    		}
    	}
    
    
    	 
    	protected View createView(String viewName, Locale locale) throws Exception {
    		return loadView(viewName, locale);
    	}
    
    	protected abstract View loadView(String viewName, Locale locale) throws Exception;
    
    }
    
    package org.springframework.web.servlet;
    
    import java.util.Locale;
    
    public abstract interface ViewResolver
    {
      public abstract View resolveViewName(String paramString, Locale paramLocale)
        throws Exception;
    }
    

      

  • 相关阅读:
    使用 asp.net mvc和 jQuery UI 控件包
    ServiceStack.Redis 使用教程
    HTC T8878刷机手册
    Entity Framework CodeFirst 文章汇集
    2011年Mono发展历程
    日志管理实用程序LogExpert
    使用 NuGet 管理项目库
    WCF 4.0路由服务Routing Service
    精进不休 .NET 4.0 (1) asp.net 4.0 新特性之web.config的改进, ViewStateMode, ClientIDMode, EnablePersistedSelection, 控件的其它一些改进
    精进不休 .NET 4.0 (7) ADO.NET Entity Framework 4.0 新特性
  • 原文地址:https://www.cnblogs.com/wuxinliulei/p/5065345.html
Copyright © 2011-2022 走看看