spring MVC工做機制與設計模式-讀後小結(三)

Control的調用(續)

接着對於(二)的補充:主要是小結下Control的處理邏輯的關鍵操做; java

對於control的處理關鍵就是:DispatcherServlet的handlerMappings集合中根據請求的URL匹配每個handlerMapping對象中的某個handler,匹配成功以後將會返回這個handler的處理鏈接handlerExecutionChain對象。而這個handlerExecutionChain對象中將會包含用戶自定義的多個handlerInterceptor對象。 spring

/**
	 * Return the HandlerExecutionChain for this request.
	 * <p>Tries all handler mappings in order.
	 * @param request current HTTP request
	 * @return the HandlerExecutionChain, or <code>null</code> if no handler could be found
	 */
	protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		for (HandlerMapping hm : this.handlerMappings) {
			if (logger.isTraceEnabled()) {
				logger.trace(
						"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
			}
			HandlerExecutionChain handler = hm.getHandler(request);
			if (handler != null) {
				return handler;
			}
		}
		return null;
	}
而對於handlerInterceptor接口中定義的三個方法中,preHandler和postHandler分別在handler的執行前和執行後執行,afterCompletion在view渲染完成、在DispatcherServlet返回以前執行。

PS:這麼咱們須要注意的是:當preHandler返回false時,當前的請求將在執行完afterCompletion後直接返回,handler也將不會執行。 app

在類HandlerExecutionChain中的getHandler()方法是返回object對象的; jsp

/**
	 * Return the handler object to execute.
	 * @return the handler object
	 */
	public Object getHandler() {
		return this.handler;
	}
這裏的handler是沒有類型的,handler的類型是由handlerAdapter決定的。dispatcherServlet會根據handler對象在其handlerAdapters集合中匹配哪一個HandlerAdapter實例支持該對象。接下來去執行handler對象的相應方法了,若是該handler對象的相應方法返回一個ModelAndView對象接下來就是去執行View渲染了。

/**
	 * Return the handler object to execute.
	 * @return the handler object
	 */
	public Object getHandler() {
		return this.handler;
	}

---------------------------------------邪惡的分割線--------------------------------------------- post

Model設計

若是handler兌現返回了ModelAndView對象,那麼說明Handler須要傳一個Model實例給view去渲染模版。除了渲染頁面須要model實例,在業務邏輯層一般也有Model實例。 this


ModelAndView對象是鏈接業務邏輯層與view展現層的橋樑,對spring MVC來講它也是鏈接Handler與view的橋樑。ModelAndView對象顧名思義會持有一個ModelMap對象和一個View對象或者View的名稱。ModelMap對象就是執行模版渲染時候所須要的變量對應的實例,如jsp的經過request.getAttribute(String)獲取的JSTL標籤名對應的對象。velocity中context.get(String)獲取$foo對應的變量實例。 spa

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;

.....

}

ModelMap其實也是一個Map,Handler中將模版中須要的對象存在這個Map中,而後傳遞到view對應的ViewResolver中。 設計

public interface ViewResolver {
	View resolveViewName(String viewName, Locale locale) throws Exception;

}

不一樣的ViewResolver會對這個Map中的對象有不一樣的處理方式; code

  • velocity中將這個Map保存到VelocityContext中。
  • JSP中將每個ModelMap中的元素分別設置到request.setAttribute(modelName,modelValue);

-----------------------邪惡的分割線----------------------------------------------- 對象

view設計

在spring MVC中,view模塊須要兩個組件來支持:RequestToViewNameTranslator和ViewResolver

public interface RequestToViewNameTranslator {

	/**
	 * Translate the given {@link HttpServletRequest} into a view name.
	 * @param request the incoming {@link HttpServletRequest} providing
	 * the context from which a view name is to be resolved
	 * @return the view name (or <code>null</code> if no default found)
	 * @throws Exception if view name translation fails
	 */
	String getViewName(HttpServletRequest request) throws Exception;

}
對於 ViewResolver,前面有寫到了,就不寫了;

-----------------------邪惡的分割線-------------------------------------------------

RequestToViewNameTranslator:主要支持用戶自定義對viewName的解析,如將請求的ViewName加上前綴或者後綴,或者替換成特定的字符串等。

ViewResolver:主要是根據用戶請求的viewName建立適合的模版引擎來渲染最終的頁面,ViewResolver會根據viewName建立一個view對象,調用view對象的Void render方法渲染出頁面;

public interface View {
void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception;
}
下面來總結下 Spring MVC解析View的邏輯:

  • dispatcherServlet方法調用getDefaultViewName()方法;

/**
	 * Translate the supplied request into a default view name.
	 * @param request current HTTP servlet request
	 * @return the view name (or <code>null</code> if no default found)
	 * @throws Exception if view name translation failed
	 */
	protected String getDefaultViewName(HttpServletRequest request) throws Exception {
		return this.viewNameTranslator.getViewName(request);
	}
  • 調用了RequestToViewNameTranslator的getViewName方法;

public interface RequestToViewNameTranslator {

	/**
	 * Translate the given {@link HttpServletRequest} into a view name.
	 * @param request the incoming {@link HttpServletRequest} providing
	 * the context from which a view name is to be resolved
	 * @return the view name (or <code>null</code> if no default found)
	 * @throws Exception if view name translation fails
	 */
	String getViewName(HttpServletRequest request) throws Exception;

}

  • 調用LocaleResolver接口的resolveLocale方法;

Locale resolveLocale(HttpServletRequest request);
  • 調用ViewResolver接口的resolveViewName方法,返回view對象

View resolveViewName(String viewName, Locale locale) throws Exception;
  • 調用render方法渲染出頁面
相關文章
相關標籤/搜索