引言
在現代 Web 開發中,選擇一個合適的框架對于項目的成功至關重要。Spring MVC 作為 Spring 框架的核心模塊之一,以其清晰的架構、強大的功能和高度的可配置性,成為了 Java Web 開發領域的主流選擇。本文將通過一個“動態時鐘”的實戰項目,深入分析 Spring MVC 模式,并分享在開發過程中遇到的問題及解決方案。
Spring MVC 模式分析
什么是 Spring MVC?
Spring MVC 是一個基于 Java 的 Web 框架,它實現了著名的 模型-視圖-控制器 (Model-View-Controller, MVC) 設計模式。它旨在分離應用程序的不同職責,使得開發人員能夠更清晰地組織代碼,提高可維護性和可擴展性。
MVC 模式的核心概念
在深入 Spring MVC 之前,我們先回顧一下 MVC 模式的三個核心組件:
-
Model (模型): 負責封裝應用程序的數據和業務邏輯。它獨立于用戶界面,處理數據的存儲、檢索、更新和驗證。在 Web 應用中,模型通常是 Java Bean 或 POJO (Plain Old Java Object)。
-
View (視圖): 負責數據的展示,即用戶界面。它從模型中獲取數據,并以用戶友好的方式呈現出來。視圖通常不包含任何業務邏輯,只負責顯示。在 Java Web 中,JSP (JavaServer Pages)、Thymeleaf、FreeMarker 等都可以作為視圖技術。
-
Controller (控制器): 充當模型和視圖之間的協調者。它接收用戶的輸入(通常是 HTTP 請求),處理這些輸入,調用模型來執行相應的業務邏輯,然后選擇合適的視圖來顯示結果。控制器本身不處理業務邏輯,它只是將請求轉發給模型,并將模型的結果傳遞給視圖。
Spring MVC 在 MVC 模式中的實現
Spring MVC 對 MVC 模式進行了精巧的實現,其核心是一個名為 DispatcherServlet
的前端控制器。以下是 Spring MVC 請求處理的典型流程:
-
DispatcherServlet
(前端控制器):-
作為整個 Spring MVC 應用程序的入口點,它攔截所有(或特定模式的)進來的 HTTP 請求。
-
它的作用類似于一個總調度員,將請求分發給合適的處理器。
-
-
Handler Mapping (處理器映射):
-
DispatcherServlet
接收到請求后,會查詢HandlerMapping
。 -
HandlerMapping
的職責是根據請求的 URL 路徑,找到能夠處理該請求的 處理器 (Handler),通常是帶有@Controller
和@RequestMapping
注解的控制器方法。
-
-
Controller (控制器):
-
找到對應的控制器方法后,
DispatcherServlet
會調用該方法。 -
控制器方法執行業務邏輯(可能通過調用服務層或數據訪問層),處理請求參數,并準備需要展示給視圖的數據。
-
控制器通常返回一個
ModelAndView
對象或一個邏輯視圖名,其中包含模型數據和視圖信息。
-
-
ModelAndView
(模型和視圖):-
這是一個封裝了模型數據和邏輯視圖名的對象。模型數據是鍵值對形式,視圖名是字符串,用于標識要渲染的視圖。
-
-
View Resolver (視圖解析器):
-
DispatcherServlet
接收到控制器返回的邏輯視圖名后,會將其交給ViewResolver
。 -
ViewResolver
的職責是將邏輯視圖名解析為實際的視圖資源(例如,一個 JSP 文件的路徑)。在我們的項目中,InternalResourceViewResolver
會將 "clock" 解析為/WEB-INF/views/clock.jsp
。
-
-
View (視圖):
-
一旦
ViewResolver
找到實際的視圖資源,DispatcherServlet
就會將模型數據傳遞給該視圖。 -
視圖負責渲染模型數據,生成最終的 HTML、XML 或其他格式的響應,并將其發送回客戶端瀏覽器。
-
Spring MVC 的優點
-
職責分離清晰: 模型、視圖、控制器各司其職,代碼結構清晰,易于理解和維護。
-
靈活性和可配置性: Spring MVC 提供了大量的可插拔組件(如
HandlerMapping
、ViewResolver
),允許開發人員根據需求進行高度定制。 -
易于測試: 由于各層職責分離,控制器可以獨立于視圖和模型進行單元測試,提高了測試效率。
-
強大的生態系統: 作為 Spring 框架的一部分,Spring MVC 可以無縫集成 Spring 的其他模塊,如 Spring Security、Spring Data 等,提供全面的企業級解決方案。
-
RESTful 支持: 內置對 RESTful Web 服務的強大支持,使得構建 API 變得簡單。
項目實戰:動態時鐘
項目目標
我們的目標是構建一個基于 Spring MVC 的 Web 應用程序,其中包含一個動態變化的模擬時鐘。時鐘的畫面將通過 JSP 頁面呈現,并利用前端技術(HTML、CSS、JavaScript)實現其動態效果和居中顯示。
技術棧
-
后端框架: Spring MVC
-
視圖技術: JSP (JavaServer Pages)
-
前端樣式: Tailwind CSS (通過 CDN 引入)
-
前端邏輯: JavaScript (實現指針動態旋轉)
-
構建工具: Maven
-
應用服務器: Apache Tomcat
項目結構概覽
一個典型的 Spring MVC Web 項目結構如下:
your-clock-project/
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── example/
│ │ │ └── controller/
│ │ │ └── ClockController.java <-- Spring MVC 控制器
│ │ ├── resources/
│ │ │ └── spring-mvc-config.xml <-- Spring MVC 配置文件
│ │ └── webapp/
│ │ ├── WEB-INF/
│ │ │ ├── web.xml <-- Web 應用部署描述符
│ │ │ └── views/
│ │ │ └── clock.jsp <-- JSP 視圖頁面
│ │ └── ...
├── pom.xml <-- Maven 項目對象模型文件
關鍵文件說明:
-
pom.xml
: Maven 項目配置文件,管理項目依賴(Spring MVC、JSP API、Servlet API 等)和構建插件(如maven-war-plugin
和tomcat8-maven-plugin
)。我們通過<finalName>web10</finalName>
將 WAR 包名稱設置為web10.war
。 -
web.xml
: Web 應用程序部署描述符,配置DispatcherServlet
作為前端控制器,并指定其 Spring MVC 配置文件的位置。 -
spring-mvc-config.xml
: Spring MVC 配置文件,啟用注解驅動的 MVC,配置組件掃描(掃描控制器),并定義InternalResourceViewResolver
來解析 JSP 視圖。 -
ClockController.java
: Spring MVC 控制器,使用@RequestMapping("/clock")
將 HTTP GET 請求映射到showClockPage()
方法,該方法返回邏輯視圖名"clock"
。 -
clock.jsp
: JSP 視圖頁面,包含動態時鐘的 HTML 結構、Tailwind CSS 樣式和 JavaScript 邏輯。前端 JavaScript 負責獲取當前時間并實時更新時針、分針、秒針的旋轉角度,實現動態效果。
部署與運行
-
構建 WAR 包: 在項目根目錄運行
mvn clean install
命令,將在target/
目錄下生成web10.war
文件。 -
部署到 Tomcat:
-
手動部署: 將
web10.war
復制到 Tomcat 安裝目錄下的webapps
文件夾。 -
使用 Maven 插件: 在
pom.xml
中配置tomcat8-maven-plugin
并設置settings.xml
中的 Tomcat 管理員憑據后,運行mvn tomcat8:deploy
(部署到外部 Tomcat) 或mvn tomcat8:run
(在嵌入式 Tomcat 中運行)。
-
-
訪問應用: 部署成功后,在瀏覽器中訪問
http://localhost:8080/web10/clock
即可看到動態時鐘。
項目效果截圖

動態時鐘效果截圖
遇到的問題與解決方案
在項目開發和部署過程中,我們遇到了一些常見的問題:
-
Missing artifact jakarta.servlet.jsp:jakarta.servlet.jsp-api:jar:2.3.3
:-
問題: Maven 無法找到或下載
jakarta.servlet.jsp-api
的2.3.3
版本依賴。這通常是由于本地倉庫緩存問題或遠程倉庫同步延遲導致。 -
解決方案:
-
首先嘗試運行
mvn clean install -U
強制更新依賴。 -
如果無效,將
pom.xml
中jakarta.servlet.jsp.version
的版本號更新到更穩定和常用的版本,例如3.0.0
。
-
-
-
ClassFormatException: Invalid byte tag in constant pool: 19
(Tomcat 版本與依賴不兼容):-
問題: 當使用
tomcat7-maven-plugin
(對應 Tomcat 7) 運行項目時,Tomcat 無法處理jakarta.xml.bind-api
等較新 Jakarta EE 依賴中包含的module-info.class
文件。這表明 Tomcat 7 的內部類加載器與這些新特性不兼容。 -
解決方案: 將
pom.xml
中的tomcat7-maven-plugin
替換為tomcat8-maven-plugin
并更新到兼容的版本(例如3.2.2
)。Tomcat 8.5+ 對 Java 8 和 Jakarta EE 8 的兼容性更好。
-
-
HTTP Status 404 - Not Found
(直接訪問WEB-INF
目錄下的 JSP):-
問題: 嘗試直接在瀏覽器中訪問
http://localhost:8080/web10/WEB-INF/views/clock.jsp
時,Tomcat 返回 404 錯誤。 -
解決方案: 這是 Java Web 應用程序的預期安全行為。
WEB-INF
目錄是受保護的,其中的資源不能被客戶端直接訪問。正確的訪問方式是通過 Spring MVC 控制器映射的 URL,即http://localhost:8080/web10/clock
。DispatcherServlet
會在服務器內部將請求轉發到WEB-INF
下的 JSP 視圖。
-
總結
通過本次動態時鐘 Web 應用的開發,我不僅實踐了 Spring MVC 框架的基本配置和使用,更深入理解了其背后的 MVC 設計模式原理。從請求的攔截、分發到視圖的渲染,Spring MVC 提供了一套清晰且高效的機制來構建可維護、可擴展的 Web 應用程序。同時,解決實際開發中遇到的依賴沖突和部署問題,也進一步加深了對 Maven、Tomcat 和 Java Web 規范的理解。