SpringMVC 是一個(gè)基于 Java 的實(shí)現(xiàn)了 MVC 設(shè)計(jì)模式的請(qǐng)求驅(qū)動(dòng)類型的輕量級(jí) Web 框架,它通過一套 MVC 注解,讓 POJO 成為處理請(qǐng)求的控制器,而無(wú)須實(shí)現(xiàn)任何接口。本文將詳細(xì)剖析 SpringMVC 的請(qǐng)求流程,幫助大家深入理解其工作機(jī)制。
SpringMVC 整體架構(gòu)概述
SpringMVC 的核心是 DispatcherServlet,它是整個(gè)請(qǐng)求處理的調(diào)度中心。當(dāng)客戶端發(fā)送請(qǐng)求時(shí),首先會(huì)到達(dá) DispatcherServlet,然后 DispatcherServlet 會(huì)根據(jù)請(qǐng)求的信息調(diào)用相應(yīng)的組件進(jìn)行處理,最終將處理結(jié)果返回給客戶端。SpringMVC 的主要組件包括 HandlerMapping、HandlerAdapter、ViewResolver 等,這些組件協(xié)同工作,完成請(qǐng)求的處理和響應(yīng)。
請(qǐng)求流程詳細(xì)步驟
1. 客戶端發(fā)送請(qǐng)求
客戶端(如瀏覽器)通過 URL 向服務(wù)器發(fā)送 HTTP 請(qǐng)求,這個(gè)請(qǐng)求包含了請(qǐng)求的方法(GET、POST 等)、請(qǐng)求的路徑、請(qǐng)求參數(shù)等信息。例如,用戶在瀏覽器中輸入 http://example.com/user/info?id=1 并回車,就會(huì)向服務(wù)器發(fā)送一個(gè) GET 請(qǐng)求。
2. 請(qǐng)求到達(dá) DispatcherServlet
在 Web 應(yīng)用啟動(dòng)時(shí),SpringMVC 會(huì)將 DispatcherServlet 注冊(cè)到 Servlet 容器中。當(dāng)客戶端的請(qǐng)求到達(dá)服務(wù)器時(shí),Servlet 容器會(huì)根據(jù)請(qǐng)求的 URL 匹配到 DispatcherServlet,并將請(qǐng)求交給它處理。在 web.xml 中通常會(huì)有如下配置:
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>這里將所有的請(qǐng)求都映射到了 DispatcherServlet 上。
3. HandlerMapping 查找 Handler
DispatcherServlet 接收到請(qǐng)求后,會(huì)調(diào)用 HandlerMapping 來查找處理該請(qǐng)求的 Handler。HandlerMapping 會(huì)根據(jù)請(qǐng)求的 URL 等信息,將請(qǐng)求映射到相應(yīng)的 Handler(通常是一個(gè)控制器方法)。SpringMVC 提供了多種 HandlerMapping 實(shí)現(xiàn),如 BeanNameUrlHandlerMapping、RequestMappingHandlerMapping 等。例如,使用 @RequestMapping 注解的控制器方法:
@Controller
public class UserController {
@RequestMapping("/user/info")
public String getUserInfo(@RequestParam("id") int id, Model model) {
// 處理業(yè)務(wù)邏輯
model.addAttribute("user", new User(id, "John"));
return "userInfo";
}
}RequestMappingHandlerMapping 會(huì)根據(jù)請(qǐng)求的 URL “/user/info” 找到對(duì)應(yīng)的 getUserInfo 方法作為 Handler。
4. HandlerAdapter 執(zhí)行 Handler
找到 Handler 后,DispatcherServlet 會(huì)通過 HandlerAdapter 來執(zhí)行該 Handler。HandlerAdapter 負(fù)責(zé)將請(qǐng)求的參數(shù)傳遞給 Handler 方法,并調(diào)用 Handler 方法進(jìn)行業(yè)務(wù)處理。SpringMVC 也提供了多種 HandlerAdapter 實(shí)現(xiàn),如 SimpleControllerHandlerAdapter、RequestMappingHandlerAdapter 等。對(duì)于上面的 @RequestMapping 注解的方法,會(huì)使用 RequestMappingHandlerAdapter 來執(zhí)行。
5. Handler 處理業(yè)務(wù)邏輯
Handler 方法接收到請(qǐng)求參數(shù)后,會(huì)執(zhí)行相應(yīng)的業(yè)務(wù)邏輯。例如,從數(shù)據(jù)庫(kù)中查詢用戶信息,進(jìn)行數(shù)據(jù)處理等。在上面的 getUserInfo 方法中,會(huì)根據(jù)傳入的用戶 ID 查詢用戶信息,并將用戶信息添加到 Model 中。
6. 返回 ModelAndView
Handler 方法處理完業(yè)務(wù)邏輯后,會(huì)返回一個(gè) ModelAndView 對(duì)象,該對(duì)象包含了模型數(shù)據(jù)和視圖名稱。模型數(shù)據(jù)用于傳遞給視圖進(jìn)行渲染,視圖名稱用于指定要使用的視圖。在上面的例子中,返回的視圖名稱是 “userInfo”,模型中包含了用戶信息。
7. ViewResolver 解析視圖
DispatcherServlet 接收到 ModelAndView 對(duì)象后,會(huì)調(diào)用 ViewResolver 來解析視圖名稱,將其解析為具體的 View 對(duì)象。SpringMVC 提供了多種 ViewResolver 實(shí)現(xiàn),如 InternalResourceViewResolver、FreeMarkerViewResolver 等。例如,使用 InternalResourceViewResolver 的配置:
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
</bean>這里會(huì)將視圖名稱 “userInfo” 解析為 “/WEB-INF/views/userInfo.jsp”。
8. View 渲染視圖
解析得到 View 對(duì)象后,DispatcherServlet 會(huì)將 Model 中的數(shù)據(jù)傳遞給 View,View 會(huì)根據(jù)這些數(shù)據(jù)進(jìn)行渲染,生成最終的 HTML 頁(yè)面。例如,在 userInfo.jsp 中可以使用 EL 表達(dá)式來顯示用戶信息:
<html>
<body>
<h1>User Info</h1>ID: ${user.id}Name: ${user.name}</body>
</html>9. 返回響應(yīng)給客戶端
View 渲染完成后,DispatcherServlet 會(huì)將生成的 HTML 頁(yè)面作為響應(yīng)返回給客戶端,客戶端的瀏覽器會(huì)顯示該頁(yè)面。
請(qǐng)求流程中的異常處理
在請(qǐng)求處理過程中,可能會(huì)出現(xiàn)各種異常,如業(yè)務(wù)異常、系統(tǒng)異常等。SpringMVC 提供了異常處理機(jī)制來處理這些異常??梢允褂?@ExceptionHandler 注解在控制器中定義異常處理方法,也可以使用 @ControllerAdvice 注解定義全局異常處理類。例如:
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public ModelAndView handleException(Exception e) {
ModelAndView mav = new ModelAndView();
mav.addObject("error", e.getMessage());
mav.setViewName("error");
return mav;
}
}當(dāng)請(qǐng)求處理過程中拋出異常時(shí),會(huì)自動(dòng)調(diào)用相應(yīng)的異常處理方法,返回錯(cuò)誤頁(yè)面給客戶端。
總結(jié)
SpringMVC 的請(qǐng)求流程是一個(gè)復(fù)雜而又有序的過程,通過 DispatcherServlet、HandlerMapping、HandlerAdapter、ViewResolver 等組件的協(xié)同工作,完成了請(qǐng)求的接收、處理和響應(yīng)。深入理解 SpringMVC 的請(qǐng)求流程,有助于我們更好地開發(fā)和調(diào)試 SpringMVC 應(yīng)用,提高開發(fā)效率和應(yīng)用的穩(wěn)定性。
希望本文能夠幫助大家對(duì) SpringMVC 的請(qǐng)求流程有更深入的理解,在實(shí)際開發(fā)中能夠靈活運(yùn)用 SpringMVC 的各種組件和特性。