1. 程式人生 > >8.Spring MVC重要元件概述

8.Spring MVC重要元件概述

       這裡說的元件指的是DispatcherServlet中直接初始化的那9個元件;

HandlerMapping

       HandlerMapping的作用是根據request找到相應的處理器Handler和Interceptors;

       HandlerMapping接口裡面只有一個方法,方法的實現非常靈活,只要使用Request返回HandlerExecutionChain即可;

       你可以把HandlerExecutionChain看做是Handler+Interceptors;

HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;

       HandlerMapping需要註冊到Spring MVC的容器裡面才可以使用,註冊也很簡單,只需要在配置檔案裡面配置一個Bean就可以了,Spring MVC會按照型別將它註冊到HandlerMapping中;


       可能有多個HandlerMapping可以處理同個url,可以用order標註優先順序,order越小越先使用;

       查詢Handler是按順序遍歷所有的HandlerMapping,當找到一個HandlerMapping後立即停止查詢並返回;

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		if (this.handlerMappings != null) {
			for (HandlerMapping hm : this.handlerMappings) {
				......
				HandlerExecutionChain handler = hm.getHandler(request);
				if (handler != null) {
					return handler;    //立即返回
				}
			}
		}
		return null;
}

HandlerAdapter

       可以理解為使用Handler的人;它裡面共有三個方法,

       supports(Object handler)判斷是否可以使用某個Handler;

       handler方法是用來具體使用Handler幹活的;

       getLastModified是獲取資源的Last-Modified,Last-Modified是資源最後一次修改的時間;

public interface HandlerAdapter {
    boolean supports(Object handler);   //注意:是Object型別
    ModeAndView handle(HttpServletRequest request,HttpServletResponse response,Object handler) throws Exception;
    long getLastModified(HttpServletRequest request,Object handler); 
}

      之所以要使用HandlerAdapter是因為Spring MVC中並沒有對Handler做任何限制,Handler可以以任意合理的方式來實現,可以是個類,也可以是個方法,還可以是別的合理的形式;從supports方法的引數是Object型別就可以看出這一點;

//這是Spring MVC自帶的HandlerAdapter
public class SimpleControllerHandlerAdapter implements HandlerAdapter {

	@Override
	public boolean supports(Object handler) {
		return (handler instanceof Controller);   //實現了Controller介面的Handler
	}

	@Override
	@Nullable
	public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
                //直接呼叫handleRequest方法
		return ((Controller) handler).handleRequest(request, response);
	}

	@Override
	public long getLastModified(HttpServletRequest request, Object handler) {
		if (handler instanceof LastModified) {
			return ((LastModified) handler).getLastModified(request);
		}
		return -1L;
	}
}

       選擇使用哪個HandlerAdapter的過程在getHandlerAdapter方法中,它的邏輯是遍歷所有的Adapter,然後檢查哪個可以處理當前的Handler,找到第一個可以處理Handler的Adapter後就停止查詢並將其返回;既然查詢,那肯定有個順序,這順序也是通過Order屬性來設定的;

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
      if (this.handlerAdapters != null) {
		for (HandlerAdapter ha : this.handlerAdapters) {
			......
			if (ha.supports(handler)) {
				return ha;
			}
		}
       }
       throw new ServletException("No adapter for handler [" + handler +
			"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}

      HandlerAdapter需要註冊到Spring MVC的容器裡,註冊方法和HandlerMapping一樣,只要配置一個Bean就可以了;Handler是從HandlerMapping裡返回的;

HandlerExceptionResolver

       處理異常,根據異常設定ModelAndView,之後再交給render方法進行渲染;render只負責將ModelAndView渲染成頁面,具體ModelAndView從哪裡來的不重要;

        從doDispatcher的分析可以知道,HandlerExceptionResolver只是用於解析對請求做處理的過程中產生的異常,而渲染環節產生的異常不歸它管,現在我們知道原因了:它是在render之前工作的,先解析出ModelAndView之後render才去渲染,當然它就不能處理render過程中的異常了;

public interface HandlerExceptionResolver {
        //異常--> ModelAndView
	@Nullable
	ModelAndView resolveException(
			HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex);

}

       具體實現上,維護一個異常為key,View為value的Map,解析的時候直接從Map裡獲取View就可以了,如果在Map裡沒有相應的異常可以返回預設的View;我們可以在這個View上顯示一些關於錯誤的細節;

ViewResolver

       ViewResolver將String型別的檢視名和Locale解析為View;

public interface ViewResolver {
        //檢視名和Locale,不過一般情況下,只需要根據檢視名找到對應的檢視,然後渲染就行了
        //locale,是用來達到,不同地區使用不同的View,一般用不到
	@Nullable
	View resolveViewName(String viewName, Locale locale) throws Exception;

}

ViewResolver的使用需要註冊到Spring MVC的容器中,預設使用的是org.spring.framework.web.servlet.view.InternalResourceViewResolver;

RequestToViewNameTranslator

       ViewResolver是根據ViewName查詢View,但有的Handler處理完成之後並沒有設定View也沒有設定viewName,這時就需要從request中獲取viewName,而如何從request中獲取ViewName就是RequestToViewNameTranslator要做的事情;

public interface RequestToViewNameTranslator {
     String getViewName(HttpServletRequest request) throws Exception;
}


FlashMapManager

          FlashMap主要用在redirect中傳遞引數,而FlashMapManager是用來管理FlashMap的;

public interface FlashMapManager {
        //恢復引數,並將恢復過額度和超時的引數從FlashMap中刪除
	@Nullable
	FlashMap retrieveAndUpdate(HttpServletRequest request, HttpServletResponse response);
	//將引數儲存起來
	void saveOutputFlashMap(FlashMap flashMap, HttpServletRequest request, HttpServletResponse response);
}

          預設實現是SessionFlashMapManager,它是將引數儲存到session中;