SpringMVC 和 Struts2 就像武林中的兩大門派,雖然都是處理 Web 請求的高手(MVC 框架),但招式風格和內功心法大不相同。來,咱們用最接地氣的方式掰扯掰扯,保準你笑著記住!
核心區別一句話概括:
Struts2 像是個 “中央集權” 的大家長,啥事兒都得經過它規定的流程(攔截器棧);SpringMVC 則像是個 “自由靈活” 的居委會,搭好平臺讓大家(各種組件)按約定自己玩兒(依賴注入+IoC),它主要當個協調員(DispatcherServlet)。
詳細版 “找不同” (帶段子和例子):
-
出身和 “靠山”:
- Struts2: 是 Struts1 和 WebWork 的 “混血兒”。它自己就是一個獨立的、完整的 MVC 框架,像一家自給自足的 “家族企業”。
- SpringMVC: 是 Spring 這個龐大 “生態帝國” 的親兒子!它天生就和 Spring 的核心功能(IoC, AOP, 事務管理等)無縫集成,就像帝國里的 “皇太子”,資源豐富,調用其他部門(Spring Bean)超級方便。
- 段子時刻: 面試官問 Struts2:“你爸是誰?” Struts2:“我自成一家!” 問 SpringMVC:“你爸是誰?” SpringMVC 驕傲一指:“看!那邊那個叫 Spring 的超級大佬就是我爹!我出門辦事刷他臉就行!”
-
核心控制器 (Front Controller - “門衛大爺”):
- Struts2:
FilterDispatcher
(老版本) 或StrutsPrepareAndExecuteFilter
(新版本)。它是一個強大的過濾器(Filter)。所有請求都得先過它這關,它負責整個請求生命周期的調度,權力很大。 - SpringMVC:
DispatcherServlet
。它是一個標準的 Servlet。它更像一個總協調員,收到請求后自己不干所有活,而是把任務分派給其他組件(HandlerMapping, Controller, ViewResolver 等)。 - 類比: Struts2 的門衛大爺不光看門,還兼任登記、查包裹、甚至幫你把快遞送到家門口。SpringMVC 的門衛大爺就負責登記來訪者(請求)是誰,然后喊:“小王(HandlerMapping),查下這人去哪屋!小李(Controller),3號屋的客人來了,你接待一下!老張(ViewResolver),客人要看資料,你幫忙找找!”
- Struts2:
-
控制器 (Controller - “業務處理員”):
- Struts2: Action 類。通常需要繼承特定的基類(如
ActionSupport
)。Action 類本身在 Struts2 中默認是多例的(每次請求創建一個新實例)。 - SpringMVC:
@Controller
注解標記的類(或者實現Controller
接口,但注解方式更流行)。不需要繼承特定類,就是一個普通的 POJO (Plain Old Java Object)。控制器方法用@RequestMapping
等注解標記。SpringMVC 的控制器默認是單例的(由 Spring IoC 容器管理),更輕量高效。 - 例子 & 類比:
- Struts2 Action:
像是一個有固定工位和固定任務清單(繼承public class LoginAction extends ActionSupport {private String username; // 屬性!自動封裝請求參數private String password;public String execute() throws Exception {// 業務邏輯if ("admin".equals(username) && "123456".equals(password)) {return SUCCESS; // 返回字符串結果,對應struts.xml里的result} else {return ERROR;}}// Getter/Setter 必須!用于參數封裝 }
ActionSupport
帶來的功能) 的員工。每次來新活(請求),就克隆一個新員工來處理(多例)。 - SpringMVC Controller:
像一個自由職業者,掛靠在 Spring 平臺(@Controller @RequestMapping("/user") public class UserController {@Autowiredprivate UserService userService; // 輕松注入其他Spring管理的Bean!@GetMapping("/login") // 更精細的映射public String login(@RequestParam String username, @RequestParam String password, Model model) {// 業務邏輯,通常調用Serviceboolean success = userService.authenticate(username, password);if (success) {model.addAttribute("message", "登錄成功!");return "welcome"; // 返回視圖名} else {model.addAttribute("error", "用戶名或密碼錯誤!");return "login";}} }
@Controller
)。平臺給他派活(@RequestMapping
指定他能接什么活)。他干活需要的工具(UserService
),平臺直接提供(@Autowired
依賴注入)。他本身是個固定員工(單例),高效復用。
- Struts2 Action:
- Struts2: Action 類。通常需要繼承特定的基類(如
-
請求參數處理 (“收快遞”):
- Struts2: 主要依賴屬性封裝! 在 Action 類中定義與請求參數同名的屬性,并提供 public 的 getter/setter 方法。Struts2 會利用 OGNL (Object-Graph Navigation Language) 自動把請求參數塞到這些屬性里。也可以使用
ModelDriven
接口封裝到模型對象。耦合性相對較高(Action 類里一堆屬性)。 - SpringMVC: 方式超級靈活!
- 方法參數綁定: 直接在控制器方法參數列表聲明,用注解指定來源:
@RequestParam
:獲取單個請求參數。@PathVariable
:獲取 RESTful 風格的 URL 路徑變量。@RequestBody
:獲取請求體內容(如 JSON,自動綁定到對象)。@ModelAttribute
:綁定到模型對象(也可以用于非請求參數的預加載)。HttpServletRequest
,HttpSession
等:直接獲取原生對象。
- 對象自動封裝: 如果方法參數是一個 POJO,SpringMVC 會嘗試自動將匹配的請求參數綁定到該對象的屬性(同樣需要 setter)。
- 方法參數綁定: 直接在控制器方法參數列表聲明,用注解指定來源:
- 類比: Struts2 收快遞,要求你必須在家門口放好對應大小和名字的空箱子(Action 里的屬性),快遞員(框架)按名字把包裹(參數)塞進去。SpringMVC 收快遞,你可以告訴快遞員:“放桌上(
@RequestParam
)”、“放廚房第二個柜子(@PathVariable
)”、“整個包裹給我我親自拆(HttpServletRequest
)” 或者 “按說明書組裝好放客廳(自動綁定到POJO)”。
- Struts2: 主要依賴屬性封裝! 在 Action 類中定義與請求參數同名的屬性,并提供 public 的 getter/setter 方法。Struts2 會利用 OGNL (Object-Graph Navigation Language) 自動把請求參數塞到這些屬性里。也可以使用
-
攔截機制 (“關卡檢查”):
- Struts2: 核心是 Interceptor (攔截器) 和 Interceptor Stack (攔截器棧)。Struts2 的整個處理流程(參數準備、驗證、執行Action、結果渲染等)都是由一系列定義好的攔截器完成的。開發者可以配置使用哪些攔截器以及它們的順序。攔截器是 Struts2 的絕對核心!
- SpringMVC: 使用 HandlerInterceptor 接口。開發者可以實現該接口定義 preHandle, postHandle, afterCompletion 方法,并在配置中注冊。攔截器主要作用于 Controller 方法執行的前后以及視圖渲染之后。SpringMVC 的核心流程(映射、適配、執行、渲染)是相對固定的,攔截器是在這個流程的特定點插入的鉤子。另外,Spring 強大的 AOP (面向切面編程) 也可以用于實現更通用的橫切關注點。
- 段子時刻: 想象你進 Struts2 大樓辦事。門口安檢(攔截器1)-> 登記(攔截器2)-> 業務審核(攔截器3)-> 見辦事員(Action)-> 結果蓋章(攔截器4)-> 離開通知(攔截器5)。必須走完整個預設的安檢通道! 進 SpringMVC 大樓,門口保安(
DispatcherServlet
)問你去哪,然后你直接去辦事員(Controller)那。但保安可以在你進辦事員門前(preHandle
)、出辦事員門后(postHandle
)、離開大樓時(afterCompletion
)對你進行抽查(HandlerInterceptor)。更自由,檢查點可選!
-
視圖技術 (“展示成果”):
- Struts2: 默認使用 OGNL 表達式 在視圖(如 JSP)中訪問值棧(ValueStack)中的數據。值棧是 Struts2 存儲 Action 和相關對象的地方。也支持 JSP, FreeMarker, Velocity 等。
- SpringMVC: 解耦得非常好! 通過
ViewResolver
和View
接口實現。開發者配置好ViewResolver
(如InternalResourceViewResolver
對應 JSP,FreeMarkerViewResolver
對應 FreeMarker),控制器只需要返回一個邏輯視圖名(字符串),ViewResolver
負責找到真正的視圖實現(View
對象)來渲染。在視圖中,通常使用 JSTL/EL 表達式 (JSP) 或模板引擎自己的語法來訪問模型數據(放在Model
/ModelMap
/ModelAndView
對象中的數據)。更標準,更符合 Servlet/JSP 規范。 - 類比: Struts2 展示成果,辦事員(Action)把報告直接放在一個特定的展示臺(ValueStack)上,觀眾(視圖)必須用特制的眼鏡(OGNL)才能看清楚內容。SpringMVC 展示成果,辦事員(Controller)把報告交給講解員(
ViewResolver
和View
)說:“這是給客戶的報告(邏輯視圖名'report'
)”。講解員根據客戶類型(配置的視圖技術),決定是用普通話講(JSP+EL)、用英語講(FreeMarker)還是放幻燈片(PDF 視圖),并用客戶能理解的方式(EL/模板語法)展示報告內容(模型數據)。
-
配置方式 (“定規矩”):
- Struts2: 重度依賴
struts.xml
文件。Action、Result、Interceptor、常量配置等都在這里。雖然支持注解,但核心配置還是 XML 為主。比較集中,但也可能變得龐大。 - SpringMVC: 極其靈活!
- XML 配置: 傳統的
*-servlet.xml
文件配置HandlerMapping
,ViewResolver
, 攔截器等。 - 純 Java 配置 (主流): 使用
@Configuration
類,結合@EnableWebMvc
和實現WebMvcConfigurer
接口來配置所有 MVC 相關組件。干凈、類型安全、現代! - 注解驅動 (主流中的主流): 大量使用
@Controller
,@RequestMapping
,@RequestParam
,@PathVariable
,@ResponseBody
等注解在代碼中聲明式配置,極大簡化開發。結合 Java 配置,XML 幾乎可以消失。
- XML 配置: 傳統的
- 類比: Struts2 定規矩像寫一本厚厚的公司制度手冊(
struts.xml
),所有流程寫得清清楚楚,改制度就得翻手冊。SpringMVC 定規矩,你可以選擇寫手冊(XML),也可以選擇開個會口頭宣布(Java 配置),或者給每個員工發個電子備忘錄(注解),方式靈活,與時俱進。
- Struts2: 重度依賴
-
性能和社區:
- Struts2: 歷史包袱較重,早期版本因 OGNL 和安全問題(如遠程代碼執行漏洞)受到詬病。性能相對 SpringMVC 稍遜一籌(主要因為攔截器棧的深度和 ValueStack 的操作)。社區活躍度和新特性發展相對緩慢。很多新項目不再選擇。
- SpringMVC: 作為 Spring 生態一部分,性能優化好,輕量高效(尤其默認單例 Controller)。社區極其活躍,文檔豐富,與 Spring Boot 結合后成為 Java Web 開發事實上的標準。安全性和最佳實踐更受推崇。
終極總結 & 面試金句:
- 架構哲學: Struts2 是 “重量級、侵入式、流程固定” 的中央集權;SpringMVC 是 “輕量級、非侵入式(相對)、高度可定制、與 Spring 生態深度集成” 的自由聯邦。
- 核心差異點:
- 控制器: Struts2 需繼承(多例),SpringMVC 是 POJO + 注解(單例)。
- 參數綁定: Struts2 靠屬性+OGNL(耦合高),SpringMVC 靠靈活的方法參數綁定注解(解耦好)。
- 攔截器: Struts2 的攔截器棧是核心流程;SpringMVC 的攔截器是流程中的鉤子。
- 視圖: Struts2 強綁定 OGNL+值棧;SpringMVC 標準解耦 ViewResolver + EL/模板。
- 配置: Struts2 重度 XML;SpringMVC 擁抱 Java 配置 + 注解。
- 生態 & 未來: SpringMVC + Spring Boot 是 絕對主流和趨勢;Struts2 逐漸成為 “上古” 技術(維護老項目才會接觸)。
幽默收尾:
面試時如果被問到,可以笑著說:“這就像問現在出門是騎馬(Struts2)還是開車(SpringMVC)。雖然馬兒也曾風光無限,但時代變了,老司機們都開 SpringMVC 這輛 ‘Spring Boot 超跑’ 了!當然,如果貴司馬廄里(老系統)還有幾匹 Struts2 的千里馬需要照顧,我也略懂馴馬術(維護經驗)😉。”
記住這些核心點,結合生動的類比,面試官想不給你加分都難!加油!