什么是Spring MVC
Spring MVC 是 Spring 框架的一個 基于 Java 的 Web 開發模塊,它實現了 MVC(Model-View-Controller)架構模式,用于構建靈活、松耦合的 Web 應用程序。
它是 Spring 生態的核心組件之一,通過簡化 HTTP 請求處理、數據綁定和視圖渲染,幫助開發者高效構建企業級 Web 應用。
Spring MVC的優點
Spring MVC 是 Spring 生態中用于構建 Web 應用的核心模塊,它的核心優勢在于 模塊化設計 和 注解驅動開發,能夠高效處理 HTTP 請求并支持靈活的視圖技術。我個人認為它的主要優點可以從以下幾個方面展開:
(1) 松耦合的模塊化設計
首先,Spring MVC 基于 前端控制器模式(DispatcherServlet
),將請求分發、業務處理、視圖渲染等職責分離。
這種設計讓各組件(如 Controller
、ViewResolver
)可以獨立替換或擴展,比如從 JSP 切換到 Thymeleaf 只需修改配置,無需改動業務代碼。
(2) 注解驅動的開發效率
其次,它通過 注解(如 @Controller
、@GetMapping
)極大簡化了開發。對比傳統的 Servlet 或 Struts2,代碼量減少 50% 以上,且意圖更清晰。
(3) 強大的數據綁定與驗證
Spring MVC 支持 自動參數綁定(如 @RequestParam
、@ModelAttribute
)和 JSR-303 驗證(如 @Valid
)。開發者無需手動解析 HTTP 參數,還能通過 BindingResult
統一處理校驗錯誤,提升代碼健壯性。
(4) 靈活的視圖技術整合
它支持多種視圖技術(JSP、Thymeleaf、Freemarker),并能無縫切換。對于前后端分離項目,還可以直接返回 JSON/XML(通過 @ResponseBody
),適應現代開發需求。
(5) 與 Spring 生態深度集成
作為 Spring 的一部分,它可以輕松整合其他組件,比如用 @Transactional
管理事務,或通過 Spring Security
實現權限控制。這種一致性降低了學習成本,也便于維護。
綜上,Spring MVC 特別適合 需要快速開發 且 要求高可維護性 的項目,比如企業級后臺管理系統或 RESTful API。它的靈活性和與 Spring 生態的無縫整合,是許多團隊選擇它的主要原因。
Spring MVC的主要組件
Spring MVC 主要組件
Spring MVC 框架由多個核心組件組成,它們協同工作來處理 HTTP 請求并生成響應。以下是主要組件及其功能:
DispatcherServlet (前端控制器)
- 核心控制器,負責接收所有請求
- 將請求委托給其他組件處理
- 繼承自 HttpServlet
HandlerMapping (處理器映射器)
- 確定哪個 Controller 應該處理當前請求
- 默認實現:RequestMappingHandlerMapping
- 將 URL 映射到對應的處理方法
HandlerAdapter (處理器適配器)
- 實際調用處理器方法
- 處理不同類型的處理器
- 默認實現:RequestMappingHandlerAdapter
Controller (控制器)
- 處理業務邏輯
- 返回 ModelAndView 或直接響應
- 通常使用 @Controller 注解標記
ViewResolver (視圖解析器)
- 解析邏輯視圖名到實際視圖
- 常見實現:InternalResourceViewResolver
- 支持多種視圖技術(JSP, Thymeleaf等)
View (視圖)
- 負責渲染模型數據
- 生成最終響應內容(HTML, JSON等)
HandlerExceptionResolver (異常處理器)
- 處理控制器執行過程中拋出的異常
- 可以自定義異常處理邏輯
MultipartResolver (文件上傳解析器)
- 處理 multipart 文件上傳請求
- 常見實現:CommonsMultipartResolver
什么是DispatcherServlet?
DispatcherServlet 是 Spring MVC 框架的核心組件,它充當了前端控制器的角色,負責協調整個請求處理流程。
主要職責
- 請求接收:作為 Servlet,它接收所有的 HTTP 請求
- 請求分發:將請求委托給適當的控制器進行處理
- 視圖渲染:協調視圖解析和渲染過程
- 異常處理:處理請求處理過程中出現的異常
- 結果返回:將最終響應返回給客戶端
工作原理
- 接收客戶端請求
- 查詢 HandlerMapping 確定處理請求的 Controller
- 通過 HandlerAdapter 調用實際的 Controller 方法
- 處理 Controller 返回的 ModelAndView 或直接響應
- 通過 ViewResolver 解析視圖名稱
- 渲染視圖并返回響應
什么是Spring MVC框架的控制器?
簡明定義(先給結論)
Spring MVC控制器是處理客戶端請求并返回響應的核心組件,它負責接收用戶請求、協調業務邏輯處理,并決定如何響應客戶端。
核心特性(展示深度)
可以補充以下關鍵點:
- 注解驅動:主要通過
@Controller
和@RestController
注解標識 - 請求映射:使用
@RequestMapping
及其變體(@GetMapping
等)定義URL映射 - 多返回值支持:可以返回視圖名稱、ModelAndView、響應體或ResponseEntity
- 松散耦合:與視圖技術解耦,支持JSP、Thymeleaf等多種視圖
- REST支持:通過
@RestController
簡化RESTful API開發
工作流程(結合架構)
在Spring MVC架構中,控制器位于DispatcherServlet之后:
- DispatcherServlet接收到請求后
- 通過HandlerMapping找到匹配的控制器方法
- 方法執行后返回處理結果
- 結果經過視圖解析器或消息轉換器處理
- 最終生成響應返回客戶端
Spring MVC的控制器是不是單例模式,如果是,有什么問題,怎么解決?
Spring MVC中的控制器默認是單例的(Singleton),這是由Spring容器的默認作用域決定的。在Spring中,所有Bean默認都是單例的,包括使用@Controller
和@RestController
注解的類。
單例模式帶來的潛在問題
- 線程安全問題
- 多個HTTP請求會并發訪問同一個控制器實例
- 如果控制器有實例變量(成員變量),這些變量會被所有請求共享
- 可能導致數據混亂或并發修改異常
- 狀態保持問題
- 單例控制器不適合保存請求特定的狀態
- 例如:在成員變量中存儲請求相關的數據會導致不同請求間的數據污染。
解決方案
1. 避免使用實例變量(推薦)
最佳實踐是控制器中不定義任何實例變量,所有請求特定的數據都應通過方法參數傳遞。
2. 使用方法局部變量
所有請求特定的數據都應在方法內部創建:
請描述Spring MVC的工作流程?描述一下 DispatcherServlet 的工作流程?
時序圖
注意:
- HandlerMapping返回的是Hander或者是處理器鏈(處理器+攔截器);
- 攔截器執行的三個時機:
(1)適配器調用前執行 (preHandle
)
- 時機:在 HandlerAdapter 調用控制器方法之前
- 作用:權限校驗、日志記錄、參數預處理等
- 中斷能力:若任一攔截器的
preHandle
返回false
,后續攔截器和控制器方法均不會執行 - 順序:按攔截器配置的正序執行
(2)適配器調用后執行 (postHandle
)
- 時機:在 HandlerAdapter 調用控制器方法之后,但在視圖渲染之前
- 作用:修改模型數據、記錄執行結果等
- 注意:此時控制器已執行完畢,但響應未寫入客戶端
- 順序:按攔截器配置的逆序執行;
(3)請求完成后執行 (afterCompletion
)
- 時機:在視圖渲染完成后(整個請求處理完畢時)
- 作用:資源清理、性能監控統計等
- 特點:無論請求成功或異常都會執行
- 順序:按攔截器配置的逆序執行
過濾器和攔截器
特性 | 過濾器(Filter) | 攔截器(Interceptor) |
所屬規范 | Servlet 規范 | Spring MVC 機制 |
執行位置 | DispatcherServlet 前 | DispatcherServlet 后 |
依賴 | 依賴 Servlet 容器 | 依賴 Spring 容器 |
可訪問對象 | ServletRequest/Response | 可以獲取 HandlerMethod 等Spring對象 |
使用場景 | 底層請求/響應處理 | 業務相關的橫切關注點 |
Spring MVC常用的注解有哪些?
Spring MVC 提供了豐富的注解來簡化 Web 開發,以下是常用注解分類整理:
請求映射相關
注解 | 作用 | 示例 |
| 通用請求映射(可指定HTTP方法、頭等) |
|
| 簡化GET請求映射 |
|
| 簡化POST請求映射 |
|
| 簡化PUT請求映射 |
|
| 簡化DELETE請求映射 |
|
| 簡化PATCH請求映射 |
|
參數處理
注解 | 作用 | 示例 |
| 獲取URL查詢參數或表單數據 |
|
| 獲取URI模板變量 |
|
| 接收JSON/XML請求體 |
|
| 獲取請求頭值 |
|
| 獲取Cookie值 |
|
| 綁定參數到模型對象 |
|
響應處理
注解 | 作用 | 示例 |
| 將返回值直接寫入HTTP響應體 |
|
| 自定義HTTP響應狀態碼 |
|
|
|
|
異常處理
注解 | 作用 | 示例 |
| 處理控制器內的異常 |
|
| 全局異常處理(配合 |
|
數據驗證
注解 | 作用 | 示例 |
| 觸發JSR-303驗證 |
|
| Spring的驗證注解(支持分組驗證) |
|
| 字段非空校驗(需配合 |
|
視圖與模型
注解 | 作用 | 示例 |
| 定義控制器類 |
|
| 模型屬性存入Session |
|
| 解決跨域問題 |
|
其他實用注解
注解 | 作用 | 示例 |
| 自定義數據綁定邏輯 |
|
| 日期格式轉換 |
|
完整代碼示例
關鍵說明:
- 組合注解:如
@RestController
是@Controller
+@ResponseBody
的組合 - 參數綁定:
@RequestParam
默認必傳,可通過required=false
改為可選 - 驗證聯動:
@Valid
需與JSR-303注解(如@NotNull
)配合使用 - RESTful設計:推薦使用
@GetMapping
/@PostMapping
等簡化注解
掌握這些注解可以覆蓋90%的Spring MVC開發場景!
@Controller注解的作用
@Controller
是 Spring MVC 中最核心的注解之一,用于標記一個類作為控制器(Controller),專門處理 HTTP 請求并返回響應。以下是它的詳細作用解析:
- 標識控制器類
告訴 Spring 容器:當前類是一個 MVC 控制器,需要被掃描并管理其生命周期。 - 接收 HTTP 請求
與@RequestMapping
等注解配合,定義處理特定 URL 請求的方法。 - 協調模型(Model)和視圖(View)
在傳統 MVC 模式中,控制器負責處理業務邏輯,返回視圖名稱(如 JSP/Thymeleaf),由視圖解析器渲染。
@RequestMapping注解的作用
@RequestMapping
是 Spring MVC 中最核心的注解之一,用于將 HTTP 請求映射到特定的控制器方法或類上。它提供了靈活的 URL 匹配規則,支持定義請求方法、參數、頭部等條件。以下是詳細解析:
- URL 路徑映射
將 HTTP 請求的 URL 路徑與控制器方法綁定,支持:
- 精確路徑(如
/users
) - 路徑變量(如
/users/{id}
) - 通配符(如
/resources/**
)
- HTTP 方法約束
指定處理的請求類型(GET/POST/PUT/DELETE 等)。 - 請求參數/頭部過濾
通過附加條件(如參數必須存在、頭部匹配)進一步篩選請求。
@ResponseBody注解的作用
@ResponseBody
是 Spring MVC 中用于將方法返回值直接寫入 HTTP 響應體的核心注解,通常用于構建 RESTful API 或處理 AJAX 請求。以下是它的詳細解析:
- 跳過視圖渲染
不再通過視圖解析器(如 JSP/Thymeleaf)渲染,而是直接將返回值序列化為 JSON/XML 等格式寫入響應體。 - 自動內容協商
根據請求的Accept
頭或 URL 后綴(如.json
),自動選擇合適的HttpMessageConverter
進行序列化。 - 支持多種返回類型
可返回 Java 對象、集合、字符串等,Spring 會自動處理序列化。
@PathVariable和@RequestParam的區別
@PathVariable
和 @RequestParam
是 Spring MVC 中用于處理 HTTP 請求參數的兩種核心注解,它們的主要區別體現在 參數來源、使用場景 和 URL 風格 上。以下是詳細對比:
核心區別總結
特性 |
|
|
參數來源 | 從 URL 路徑 中提取 | 從 URL 查詢字符串 或 表單數據 中提取 |
URL 示例 |
|
|
是否必傳 | 默認必傳(除非指定默認值) | 可通過 設為可選 |
RESTful 風格 | 是(推薦用于資源標識) | 否(傳統查詢方式) |
數據類型轉換 | 自動(Spring 類型轉換機制) | 自動(Spring 類型轉換機制) |
使用場景對比
1. @PathVariable
(路徑變量)
- 適用場景:標識 RESTful 資源唯一性(如 ID、用戶名等)
- 示例代碼:
- URL 風格:
2. @RequestParam
(請求參數)
- 適用場景:過濾、排序、分頁等非核心參數
- 示例代碼:
- URL 風格: