(二)SpringMVC之執行的過程
(DispatcherServlet在Spring當中充當一個前端控制器的角色,它的核心功能是分發請求。請求會被分發給對應處理的Java類,Spring MVC中稱為Handle。)
① 用戶把請求發送給DispatcherServlet服務器。
② DispatcherServlet對請求的URL(統一資源定位符)進行解析,得到URI(請求資源標識符)。然後根據該URI,調用HandlerMapping獲取該Handler配置的所有相關的對象,包括Handler對象以及Handler對象對應的攔截器,這些對象會被封裝到一個HandlerExecutionChain對象當中返回。
③ DisptcharServlet會根據獲得的Handler選擇一個合適的HandlerAdapter
④ 提取請求中的模型數據,開始執行Handler(Controller類)。在填充Handler的入參過程中,根據配置,Spring可以做消息轉換、數據轉換、數據格式化、數據驗證的工作。
⑤ Handler執行完成後,想DispatcherServlet發送一個ModelAndView對象,ModelAndView對象中應該包含視圖名或視圖名和模型。
⑥ 根據返回的ModelAndView對象,選擇一個合適的ViewResolver(視圖解析器)返回給DispatcherServlet。
⑦ ViewResolver結合Model和View來渲染視圖。
⑧ 將視圖渲染結果返回給客戶端。
我們可以看到,DispatcherServlet在這個執行過程中是一位大哥的角色,為森麽它會坐穩大佬的位置呢?我們可以看它的源碼:
protected void initStrategies(ApplicationContext context) { initMultipartResolver(context); //初始化上傳文件解析器 initLocaleResolver(context);//初始化本地解析器 initThemeResolver(context); // 初始化主體解析器 initHandlerMappings(context); //初始化處理器映射器,將請求映射到處理器 initHandlerAdapters(context); //初始化處理器適配器 initHandlerExceptionResolvers(context); //初始化處理異常解析器,如果執行過程中遇到異常將交給HandlerExceptionResolver來解析 initRequestToViewNameTranslator(context); //初始化請求到視圖名稱解析器 initViewResolvers(context); //初始化視圖解析器,通過ViewResolver解析邏輯視圖名到具體視圖實現 initFlashMapManager(context); //初始化flash映射管理器 }
接下來我們來看一下,整個流程的實現是怎麽樣的。
代碼實現:
① 引入spirng-framework的相關包和commons-logging包(WEB-INF/lib)。
② 在WEB-INF下的web.xml中進行配置(WEB-INF/web.xml):
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1"> <!-- 定義Spring MVC的前端控制器 --> <servlet> <!-- 配置前端控制器 --> <!-- DispatcherServlet在Spring當中充當一個前端控制器的角色,它的核心功能是分發請求。 請求會被分發給對應處理的Java類,Spring MVC中稱為Handle --> <!—配置一個名為springmvc的DispatcherServlet服務器 --> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <!-- 定位spring mvc的配置文件 --> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/springmvc-config.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <!-- 讓Spring mvc的前端控制器攔截所有請求 --> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
③ 編寫SpringMVC的配置文件,在WEB-INF下的springmvc-config.xml。(WEB-INF/springmvc-config.xml)
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd"> <!-- 配置handler,映射"/hello",或者可以直接在Controller類註解 --> <bean name="/hello" class="org.fkit.controller.HelloController"/> <!-- spring可以自動去掃描base-pack下面的包或者子包下面的Java文件 ,如果掃描到有Spring的相關註解的類,則把這些類註冊為Spring的bean --> <context:component-scan base-package="org.fkit.controller" /> <!-- 處理映射器將bean的name作為url進行查找,需要在配置Handle時指定name(即url) --> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> <!-- SimpleControllerHandlerAdapter是一個處理器適配器,所有處理適配器都要實現HandlerAdapter接口 --> <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/> <!-- 視圖解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"/> </beans>
④ Controller的實現,用於處理請求(org.fkit.controller.HelloController)。
package org.fkit.controller; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.Controller; public class HelloController implements Controller{ private static final Log logger = LogFactory.getLog(HelloController.class); public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { logger.info("handleRequest 被調用"); //創建準備返回的ModelAndView對象,該對象通常包含了返回視圖名、模型的名稱以及模型對象 ModelAndView mv = new ModelAndView(); //添加模型數據,可以是任意的POJO對象 mv.addObject("message","HelloWorld"); //設置邏輯視圖名,視圖解析器會根據該名字解析到具體的試圖頁面 mv.setViewName("/WEB-INF/content/welcome.jsp"); //返回ModelAndView對象 return mv; } }
⑤ 編寫視圖頁面,用於顯示已經處理好的View和Model的視圖渲染(WEB-INF/content/welcome.jsp)。
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Insert title here</title> </head> <body> ${requestScope.message } </body> </html>
(二)SpringMVC之執行的過程