SpringMVC執行流程講解

Spring Web MVC是一種基於Java的實現了Web MVC設計模式的請求驅動類型的輕量級Web框架,即使用了MVC架構模式的思想,將web層進行職責解耦,基於請求驅動指的就是使用請求-響應模型,框架的目的就是幫助我們簡化開發,Spring Web MVC也是要簡化我們日常Web開發的。
與之相反的是基於組件的、事件驅動的Web框架,如Tapestry、JSF等。
  Spring Web MVC也是服務到工作者模式的實現,但進行可優化。前端控制器是DispatcherServlet;應用控制器其實拆爲處理器映射器(Handler Mapping)進行處理器管理和視圖解析器(View Resolver)進行視圖管理;頁面控制器/動作/處理器爲Controller接口(僅包含ModelAndView handleRequest(request, response) 方法)的實現(也可以是任何的POJO類);支持本地化(Locale)解析、主題(Theme)解析及文件上傳等;提供了非常靈活的數據驗證、格式化和數據綁定機制;提供了強大的約定大於配置(慣例優先原則)的契約式編程支持。

  SpringMVC在Web應用中充當控制層(Controller)的角色,對請求進行分發處理。

一、Spring請求流程

1. 整體流程

 

 具體步驟:

  • 首先用戶發送請求到前端控制器,前端控制器根據請求信息(如 URL)來決定選擇哪一個頁面控制器進行處理並把請求委託給它,即以前的控制器的控制邏輯部分;圖中的 1、2 步驟;
  • 頁面控制器接收到請求後,進行功能處理,首先需要收集和綁定請求參數到一個對象,這個對象在 Spring Web MVC 中叫命令對象,並進行驗證,然後將命令對象委託給業務對象進行處理;處理完畢後返回一個 ModelAndView(模型數據和邏輯視圖名);圖中的 3、4、5 步驟;
  • 前端控制器收回控制權,然後根據返回的邏輯視圖名,選擇相應的視圖進行渲染,並把模型數據傳入以便視圖渲染;圖中的步驟 6、7;
  • 前端控制器再次收回控制權,將響應返回給用戶,圖中的步驟 8;至此整個結束。

2. 核心流程

具體步驟:

  • 第一步:發起請求到前端控制器(DispatcherServlet)
  • 第二步:前端控制器請求HandlerMapping查找 Handler (可以根據xml配置、註解進行查找)
  • 第三步:處理器映射器HandlerMapping向前端控制器返回Handler,HandlerMapping會把請求映射爲HandlerExecutionChain對象(包含一個Handler處理器(頁面控制器)對象,多個HandlerInterceptor攔截器對象),通過這種策略模式,很容易添加新的映射策略
  • 第四步:前端控制器調用處理器適配器去執行Handler
  • 第五步:處理器適配器HandlerAdapter將會根據適配的結果去執行Handler
  • 第六步:Handler執行完成給適配器返回ModelAndView
  • 第七步:處理器適配器向前端控制器返回ModelAndView (ModelAndView是springmvc框架的一個底層對象,包括 Model和view)
  • 第八步:前端控制器請求視圖解析器去進行視圖解析 (根據邏輯視圖名解析成真正的視圖(jsp)),通過這種策略很容易更換其他視圖技術,只需要更改視圖解析器即可
  • 第九步:視圖解析器向前端控制器返回View
  • 第十步:前端控制器進行視圖渲染 (視圖渲染將模型數據(在ModelAndView對象中)填充到request域)
  • 第十一步:前端控制器向用戶響應結果

下面我們對出現的一些組件進行詳細的介紹:

(1) 前端控制器DispatcherServlet(不需要程序員開發)。
  作用:接收請求,響應結果,相當於轉發器,中央處理器。有了DispatcherServlet減少了其它組件之間的耦合度。
(2) 處理器映射器HandlerMapping(不需要程序員開發)。
  作用:根據請求的url查找Handler。
(3) 處理器適配器HandlerAdapter(不需要程序員開發)。
  作用:按照特定規則(HandlerAdapter要求的規則)去執行Handler。
(4) 處理器Handler(需要程序員開發)。
  注意:編寫Handler時按照HandlerAdapter的要求去做,這樣適配器纔可以去正確執行Handler
(5) 視圖解析器ViewResolver(不需要程序員開發)。
  作用:進行視圖解析,根據邏輯視圖名解析成真正的視圖(view)
(6) 視圖View(需要程序員開發jsp)。
  注意:View是一個接口,實現類支持不同的View類型(jsp、freemarker、pdf…)

ps:不需要程序員開發的,需要程序員自己做一下配置即可。

可以總結出:需要我們開發的工作只有處理器 Handler 的編寫以及視圖比如JSP頁面的編寫。可能你還對諸如前端控制器、處理器映射器等等名詞不太理解,那麼接下來我們對其進行詳細的介紹。

二、SpringMVC組件配置或開發說明

根據前面所說,部分組件需要配置,部分組件需要程序員開發,接下來就介紹下如何配置和開發相關的組件。

1. 配置前端控制器(DispatcherServlet)

在web project的web.xml中配置:

<!-- 配置前端控制器DispatcherServlet -->
<servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!--springmvc.xml 是自己創建的SpringMVC全局配置文件,用contextConfigLocation作爲參數名來加載 
        如果不配置 contextConfigLocation,那麼默認加載的是/WEB-INF/servlet名稱-servlet.xml,在這裏也就是 
        springmvc-servlet.xml 參數多個值使用逗號隔開,如:a.xml,b.xml -->
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath*:springmvc.xml</param-value>
    </init-param>
</servlet>

<servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <!--第一種配置:*.do,還可以寫*.action等等,表示以.do結尾的或者以.action結尾的URL都由前端控制器DispatcherServlet來解析 
        第二種配置:/,所有訪問的 URL 都由DispatcherServlet來解析,但是這裏最好配置靜態文件不由DispatcherServlet來解析,需要對靜態資源單獨處理 
        錯誤配置:/*,注意這裏是不能這樣配置的,因爲如果這樣寫,最後轉發到 jsp 頁面的時候,仍然會由DispatcherServlet進行解析, 而這時候會找不到對應的Handler,從而報404!!! -->
    <url-pattern>*.do</url-pattern>
</servlet-mapping>

2. 配置處理器映射器(HandlerMapping)

在 springmvc.xml 文件中配置。通俗來講就是請求的 URL 怎麼能被 SpringMVC 識別,從而去執行我們編寫好的 Handler。

(1) 第一種方法

<!-- 配置Handler -->   
<bean name="/hello.do" class="com.asiainfo.spring.controller.HelloController" />
 
<!-- 配置處理器映射器 將bean的name作爲url進行查找,需要在配置Handler時指定bean name(就是url)-->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />

這樣配置的話,那麼請求的 URL,必須爲 http://ip:port/項目名/hello.do

(2) 第二種方法

<!-- 配置Handler -->   
<bean id="hello" class="com.asiainfo.spring.controller.HelloController" />
<bean id="hello2" class="com.asiainfo.spring.controller.HelloController2" />
<!-- 簡單URL配置處理器映射器 -->
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
    <property name="mappings">
        <props>
            <prop key="/hello.do">hello</prop>
            <prop key="/hello2.do">hello2</prop>
        </props>
    </property>
</bean>

這種配置請求的 URL可以爲 http://ip:prot/項目名/hello.do,或者http://ip:port/項目名/hello2.do

注:上面兩種處理器映射器配置可以並存,前端控制器會正確的去判斷 url 用哪個 Handler 去處理。

3. 配置處理器適配器(HandlerAdapter)

在 springmvc.xml 文件中配置。用來約束我們所需要編碼的 Handler類。

第一種配置:編寫 Handler 時必須要實現 Controller,否則不能被適配器解析。

<!-- 配置處理器適配器,所有適配器都得實現 HandlerAdapter接口 -->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />

第二種配置:編寫 Handler 時必須要實現 HttpRequestHandler

<!-- 配置處理器適配器第二種方法,所有適配器都得實現 HandlerAdapter接口 ,這樣配置所有Handler都必須實現 HttpRequestHandler接口-->
<bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter" />

4. 開發處理器(Handler,即我們的Controller)

在 springmvc.xml 文件中配置。通俗來講,就是請求的 URL 到我們這裏所編寫的 Handler 類的某個方法進行一些業務邏輯處理。
我們在上面講解了兩個處理器適配器來約束 Handler,那麼我們就通過上面兩種配置分別編寫兩個 Handler:

(1) 第一種:實現Controller 接口

public class HelloController implements Controller {

    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        ModelAndView modelView = new ModelAndView();
        modelView.setViewName("/WEB-INF/jsp/index.jsp");
        return modelView;
    }
}

(2) 第二種:實現 HttpRequestHandler 接口

public class HelloController2 implements HttpRequestHandler {
    public void handleRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        request.setAttribute("name", "harvey");
        request.getRequestDispatcher("/WEB-INF/jsp/index.jsp").forward(request, response);
    }
}

通常我們使用第一種方式來編寫 Handler ,但是第二種沒有返回值,我們可以通過 response 修改相應內容,比如返回 json 數據:
response.setCharacterEncoding("utf-8");
response.setContentType("application/json;charset=utf-8");
response.getWriter().write("json字符串");

所以具體使用哪一種根據實際情況來判斷。

5. 配置視圖解析器(ViewResolver)

第一種配置:

<!-- 配置視圖解析器 進行jsp解析,默認使用jstl標籤,classpath下得有jstl的包-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" />

如果這樣配,那麼在 Handler 中返回的必須是路徑+jsp頁面名稱+".jsp"

第二種配置:

<!--配置視圖解析器  -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <!-- 返回視圖頁面的前綴 -->
    <property name="prefix" value="/WEB-INF/jsp/"></property>
    <!-- 返回頁面的後綴 -->
    <property name="suffix" value=".jsp"></property>
</bean>

如果這樣配,那麼在 Handler 中只需要返回在 jsp 文件夾下的jsp 頁面名就可以了。

6. DispatcherServlet.properties

上面我們講解了各種配置,可能有人會問這麼多配置,萬一少配置了一樣,那不就不能運行了,那我們能不能不配置呢?答案是肯定的,SpringMVC 給我們提供了一個 DispatcherServlet.properties 文件。系統會首先加載這裏面的配置,如果我們沒有配置,那麼就默認使用這個文件的配置;如果我們配置了,那麼就優先使用我們手動配置的。

在 SpringMVC 運行之前,會首先加載 DispatcherServlet.properties 文件裏面的內容
①、處理器適配器默認:org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter
②、處理器映射器默認:org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping
③、視圖解析器默認:org.springframework.web.servlet.view.InternalResourceViewResolver

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章