一、Spring MVC 核心定位与优势
-
MVC架构的Spring实现
-
Model:封装业务数据(POJO/Service层),通过
Model
对象传递到视图。 -
View:支持JSP、Thymeleaf等模板引擎,负责数据渲染。
-
Controller:使用
@Controller
注解处理请求,解耦业务逻辑与视图。
-
-
核心优势
-
松耦合设计:组件(如
ViewResolver
)可独立替换,从JSP切换至Thymeleaf仅需配置改动。 -
注解驱动开发:
@GetMapping
等注解减少50%+XML配置,提升开发效率。 -
无缝整合Spring生态:轻松集成事务管理(
@Transactional
)、安全框架(Spring Security)。
-
二、核心组件与协作机制
1. 核心组件职责
组件 | 作用 | 实现类示例 |
---|---|---|
DispatcherServlet | 前端控制器,接收所有HTTP请求并协调流程 | 默认配置于web.xml |
HandlerMapping | 映射URL到Controller方法(如解析@RequestMapping ) | RequestMappingHandlerMapping |
HandlerAdapter | 适配器模式调用Controller方法,处理参数绑定 | RequestMappingHandlerAdapter |
ViewResolver | 将逻辑视图名解析为物理视图(如/WEB-INF/views/home.jsp ) | InternalResourceViewResolver |
HandlerExceptionResolver | 统一处理控制器层异常 | ExceptionHandlerExceptionResolver |
2. 组件协作流程
-
用户发起HTTP请求 →
DispatcherServlet
拦截请求。 -
HandlerMapping
根据URL查找匹配的Controller方法 → 返回执行链(含拦截器)。 -
HandlerAdapter
执行Controller方法 → 调用Service层业务逻辑。 -
Controller返回
ModelAndView
(含数据模型+视图名) →ViewResolver
解析视图。 -
视图渲染HTML → 响应客户端。
三、工作流程详解(含拦截器机制)
以GET /users/{id}
请求为例:
-
拦截器预处理:
-
preHandle()
:权限校验/日志记录(若返回false
则中断流程)。
-
-
Controller处理:
@GetMapping("/users/{id}") public String getUser(@PathVariable Long id, Model model) { User user = userService.findById(id); // 调用Service层 model.addAttribute("user", user); // 数据存入Model return "userDetail"; // 逻辑视图名 }
-
拦截器后处理:
-
postHandle()
:修改模型数据(视图渲染前)。 -
afterCompletion()
:资源清理(无论成功/异常均执行)。
-
四、关键注解全解析
注解类型 | 常用注解 | 作用 | 示例 |
---|---|---|---|
控制器声明 | @Controller | 定义控制器类 | @Controller public class UserCtrl |
@RestController | 复合注解(@Controller +@ResponseBody ) | 直接返回JSON | |
请求映射 | @RequestMapping | 类/方法级URL映射 | @RequestMapping("/api") |
@GetMapping | 限定GET请求 | @GetMapping("/{id}") | |
参数处理 | @RequestParam | 获取查询参数 | ?name=Tom → @RequestParam String name |
@PathVariable | 获取路径参数 | /users/1 → @PathVariable Long id | |
@RequestBody | 解析JSON请求体到对象 | @RequestBody User user | |
数据响应 | @ResponseBody | 方法返回值直接写入响应体 | 返回JSON/XML |
数据校验 | @Valid | 参数校验(配合JSR-303) | @Valid @RequestBody User user |
五、配置方式对比(XML vs 注解 vs Spring Boot)
配置方式 | 特点 | 示例 |
---|---|---|
XML配置 | 传统方式,显式定义Bean和映射关系 | xml <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/views/" /> </bean> |
注解驱动 | 零XML配置,通过@EnableWebMvc 开启 | @Configuration @EnableWebMvc public class WebConfig implements WebMvcConfigurer |
Spring Boot自动配置 | 内嵌Tomcat + 默认视图解析器,开箱即用 | spring-boot-starter-web 依赖自动配置DispatcherServlet |
六、常见问题与最佳实践
-
控制器线程安全问题
-
问题:Controller默认单例,成员变量并发访问会导致数据错乱。
-
解决:避免使用实例变量,改用局部变量或
ThreadLocal
。
-
-
拦截器 vs 过滤器
特性 拦截器(Interceptor) 过滤器(Filter) 作用范围 Controller方法前后 Servlet请求前后(DispatcherServlet之前) 依赖容器 Spring容器 Servlet容器 访问对象 可获取 HandlerMethod
仅 ServletRequest/Response
-
性能优化建议
-
使用
execution()
代替annotation()
切点:编译期优化,减少运行时开销。 -
避免在频繁调用的方法上使用复杂AOP。
-
七、实战:Spring Boot整合Spring MVC
-
项目初始化
<!-- pom.xml --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <!-- 含Spring MVC --> </dependency>
-
Controller示例(返回JSON)
@RestController public class UserApiController { @GetMapping("/api/users/{id}") public ResponseEntity<User> getUser(@PathVariable Long id) { User user = userService.getUser(id); return ResponseEntity.ok(user); // 直接返回JSON } }
-
自定义视图解析器
@Configuration public class WebConfig implements WebMvcConfigurer { @Bean public ViewResolver viewResolver() { InternalResourceViewResolver resolver = new InternalResourceViewResolver(); resolver.setPrefix("/WEB-INF/views/"); resolver.setSuffix(".jsp"); return resolver; } }
Spring MVC vs Spring Boot:
Spring MVC:Web框架,解决请求处理与视图渲染。
Spring Boot:快速开发脚手架,通过自动配置简化Spring MVC部署