Spring MVC 是 Spring 框架內置的 Web 模塊,基於前端控制器模式,將請求分發、模型綁定、視圖渲染等職責解耦。本文從核心組件架構、註解配置、數據綁定、視圖解析、RESTful 支持五個維度,構建完整知識體系。
用戶請求 HTTP Request
│
▼
┌───────────────────────┐
│ DispatcherServlet │ 前端控制器:統一入口、協調調度
└───────────┬───────────┘
│
▼
┌───────────────────────┐
│ HandlerMapping │ 處理器映射器:URL → Handler (Controller 方法)
│ (RequestMappingHandlerMapping) │
└───────────┬───────────┘
│
▼
┌───────────────────────┐
│ HandlerAdapter │ 處理器適配器:統一調用接口,支持多種 Handler 類型
│ (RequestMappingHandlerAdapter) │
└───────────┬───────────┘
│
▼
┌───────────────────────┐
│ Controller (Handler) │ 業務處理器:@Controller / @RestController 方法
└───────────┬───────────┘
│
▼
┌───────────────────────┐
│ ModelAndView / │ 模型數據 + 邏輯視圖名
│ @ResponseBody │
└───────────┬───────────┘
│
▼
┌───────────────────────┐
│ ViewResolver │ 視圖解析器:邏輯視圖名 → View 實例 (JSP/Thymeleaf/FreeMarker)
│ (InternalResourceViewResolver) │
└───────────┬───────────┘
│
▼
┌───────────────────────┐
│ View │ 視圖渲染:模板引擎輸出 HTML/JSON/XML
└───────────┬───────────┘
│
▼
用戶響應 HTTP Response
<servlet>
<servlet-name>dispatcher</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>dispatcher</servlet-name>
<url-pattern>/</url-pattern> <!-- 攔截所有請求,靜態資源需額外配置 -->
</servlet-mapping>
url-pattern 三種模式對比:
| 模式 | 示例 | 特點 | 建議 |
|---|---|---|---|
*.do / *.action | /user/login.do | 傳統風格,易區分靜態資源 | 老項目維護 |
/ | /user/login | RESTful 風格,攔截所有,**需配置靜態資源處理** | 新項目首選 |
/* | /user/login, /page.jsp | 連 JSP 也攔截,導致視圖解析失敗 (無限循環/404) | 嚴禁使用 |
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://www.springframework.org/schema/beans"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xmlns:context="https://www.springframework.org/schema/context"
xmlns:mvc="https://www.springframework.org/schema/mvc"
xsi:schemaLocation="...>
<!-- 1. 掃描 Controller (掃描不到則無法映射) -->
<context:component-scan base-package="com.test.controller" />
<!-- 2. 註解驅動:自動註冊 RequestMappingHandlerMapping/Adapter、參數綁定、格式化、驗證、消息轉換器 -->
<mvc:annotation-driven />
<!-- 3. 視圖解析器 (JSP 示例) -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
<!-- 4. 靜態資源處理 (配合 url-pattern: /) -->
<mvc:resources mapping="/static/**" location="/static/" />
<mvc:default-servlet-handler />
</beans>
| 註解 | HTTP 方法 | 說明 |
|---|---|---|
@RequestMapping | ALL | 通用映射,可窄化 method/params/headers/consumes/produces |
@GetMapping | GET | 組合註解,等同 @RequestMapping(method=GET) |
@PostMapping | POST | 表單提交、數據創建 |
@PutMapping | PUT | 全量更新 |
@PatchMapping | PATCH | 部分更新 |
@DeleteMapping | DELETE | 刪除資源 |
@Controller
@RequestMapping("/user") // 類級別:基礎路徑
public class UserController {
// 1. 路徑變量
@GetMapping("/{id}")
public User getUser(@PathVariable Long id) { ... }
// 2. 請求參數 (自動類型轉換、必填校驗、默認值)
@GetMapping("/list")
public List list(
@RequestParam(value = "page", defaultValue = "1") int page,
@RequestParam(value = "size", required = false) Integer size
) { ... }
// 3. 請求頭
@GetMapping("/header")
public String header(@RequestHeader("User-Agent") String ua) { ... }
// 4. Cookie
@GetMapping("/cookie")
public String cookie(@CookieValue("JSESSIONID") String sessionId) { ... }
// 5. 請求體 (JSON/XML → 對象) - 核心:@RequestBody + HttpMessageConverter
@PostMapping("/save")
public User save(@RequestBody @Valid User user, BindingResult result) { ... }
// 6. 表單對象綁定 (無註解,屬性名匹配)
@PostMapping("/form")
public String form(UserForm form) { ... } // 自動綁定 request parameters
// 7. 原生 Servlet API 直接注入
@GetMapping("/native")
public void nativeApi(HttpServletRequest req, HttpServletResponse resp, HttpSession session) { ... }
}
| 返回類型 | 處理邏輯 | 適用場景 |
|---|---|---|
ModelAndView | 攜帶模型數據 + 邏輯視圖名 | 傳統 MVC,需渲染頁面 |
String | 視為邏輯視圖名 → ViewResolver 解析 | 簡單頁面跳轉 |
void | 自行通過 response 輸出 / 轉發 / 重定向 | 文件下載、流式響應、手動控制 |
@ResponseBody + 對象 | 對象 → HttpMessageConverter → JSON/XML 直接寫入響應體 | REST API、AJAX |
ResponseEntity<T> | 完全控制:狀態碼、頭部、體 | 需自定義 HTTP 狀態碼 |
@ModelAttribute | 模型屬性,可用於頁面渲染 | 表單回顯 |
@GetMapping("/redirect")
public String redirect() {
return "redirect:/user/list"; // 瀏覽器重新發起 GET 請求,地址欄變化
}
@GetMapping("/forward")
public String forward() {
return "forward:/user/list"; // 服務端內部轉發,地址欄不變,共享 request 域
}
@RequestBody / @ResponseBody 背後依賴 RequestMappingHandlerAdapter 裝配的 HttpMessageConverter<?> 鏈:
<mvc:annotation-driven>
<mvc:message-converters>
<!-- 順序很重要:優先匹配 -->
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="com.fasterxml.jackson.databind.ObjectMapper">
<!-- 配置序列化特性 -->
<property name="serializationInclusion" value="NON_NULL" />
<property name="dateFormat">
<bean class="java.text.SimpleDateFormat">
<constructor-arg value="yyyy-MM-dd HH:mm:ss" />
</bean>
</property>
</bean>
</property>
</bean>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list><value>text/plain;charset=UTF-8</value></list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
@RequestParam(value="xxx") 是否一致,或設置 required=false。Content-Type 與消息轉換器支持類型不匹配(如發 JSON 卻無 Jackson 轉換器)。@JsonIgnore / @JsonBackReference / 配置 ObjectMapper 禁用循環引用檢測。url-pattern: / 必須配置 <mvc:resources> 和 <mvc:default-servlet-handler/>。/user/{email:.+} 使用正則捕獲完整路徑段。/cars;color=red;year=2020 需啟用 enableMatrixVariables=true (WebMvcConfigurer)。@Configuration
@EnableWebMvc // 等同 <mvc:annotation-driven/>
@ComponentScan("com.test.controller")
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.jsp("/WEB-INF/jsp/", ".jsp");
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**").addResourceLocations("/static/");
}
@Override
public void configureMessageConverters(List> converters) {
// 自定義 Jackson 配置
converters.add(new MappingJackson2HttpMessageConverter(customObjectMapper()));
}
// 文件上傳解析器
@Bean
public MultipartResolver multipartResolver() {
StandardServletMultipartResolver resolver = new StandardServletMultipartResolver();
return resolver;
}
}
Spring MVC 的設計精髓在於開放封閉原則:核心調度流程固化,擴展點(HandlerMapping、HandlerAdapter、HandlerExceptionResolver、ViewResolver、HttpMessageConverter)全面接口化。掌握註解驅動背後的組件裝配機制,能讓你在遇到疑難雜症時快速定位到具體擴展點進行定制。