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 的千里马需要照顾,我也略懂驯马术(维护经验)😉。”
记住这些核心点,结合生动的类比,面试官想不给你加分都难!加油!