Appearance
Spring MVC 详解
Spring MVC 是 Spring 框架的 Web 模块,基于 MVC 设计模式,通过 DispatcherServlet 作为前端控制器统一调度请求。
一、MVC 架构
MVC 三层角色:
Model(模型):
数据 + 业务逻辑
Service + Dao + Entity
View(视图):
展示层
JSP / Thymeleaf / JSON(前后端分离)
Controller(控制器):
请求入口,协调 Model 和 View
@Controller / @RestController二、DispatcherServlet 核心架构
Spring MVC 请求处理流程:
客户端请求
│
▼
┌─────────────────────────────────────────────────────────────┐
│ ① DispatcherServlet(前端控制器) │
│ 所有请求的入口,统一分发 │
└──────────────────────┬──────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ ② HandlerMapping(处理器映射器) │
│ 根据 URL 找到对应的 Controller 和方法 │
│ RequestMappingHandlerMapping → 解析 @RequestMapping │
└──────────────────────┬──────────────────────────────────────┘
│ 返回 HandlerExecutionChain
│ (包含 Handler + 拦截器列表)
▼
┌─────────────────────────────────────────────────────────────┐
│ ③ HandlerAdapter(处理器适配器) │
│ 调用 Controller 方法,处理参数绑定、返回值 │
│ RequestMappingHandlerAdapter → 处理 @RequestMapping 方法 │
└──────────────────────┬──────────────────────────────────────┘
│ 返回 ModelAndView
▼
┌─────────────────────────────────────────────────────────────┐
│ ④ ViewResolver(视图解析器) │
│ 将逻辑视图名解析为实际视图(JSP / Thymeleaf 模板) │
│ 前后端分离项目:直接返回 JSON,不经过 ViewResolver │
└──────────────────────┬──────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ ⑤ View(视图渲染) │
│ 渲染 HTML 返回给客户端 │
│ 前后端分离:HttpMessageConverter 将对象转为 JSON │
└─────────────────────────────────────────────────────────────┘三、核心组件详解
3.1 HandlerMapping
java
// 根据 URL 匹配 Controller
// RequestMappingHandlerMapping 是默认实现,解析 @RequestMapping 注解
@RestController
@RequestMapping("/api/orders")
public class OrderController {
@GetMapping("/{id}") // 匹配 GET /api/orders/123
public Order getOrder(@PathVariable Long id) { }
@PostMapping // 匹配 POST /api/orders
public Order createOrder(@RequestBody Order order) { }
}3.2 HandlerAdapter
java
// 负责调用 Controller 方法,处理参数绑定、类型转换、数据校验
// RequestMappingHandlerAdapter 是默认实现
// 支持的参数类型(方法参数自动注入):
@GetMapping("/test")
public Result test(
HttpServletRequest request, // Servlet API
HttpServletResponse response,
@RequestParam("name") String name, // 请求参数
@PathVariable("id") Long id, // 路径变量
@RequestBody Order order, // 请求体 JSON
@RequestHeader("token") String token,// 请求头
@CookieValue("sessionId") String sid,// Cookie
Model model // 视图模型
) { }3.3 HttpMessageConverter
java
// 前后端分离项目中,HTTP 消息转换器负责 JSON ↔ 对象转换
// ① 请求体 JSON → 对象(@RequestBody)
// {"name":"iPhone","price":6999} → Order 对象
// 使用:MappingJackson2HttpMessageConverter(Jackson)
// ② 对象 → 响应体 JSON(@ResponseBody / @RestController)
// Order 对象 → {"name":"iPhone","price":6999}
// 使用:MappingJackson2HttpMessageConverter(Jackson)
// 自定义配置
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
// 自定义 JSON 转换器
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(new ObjectMapper().setDateFormat(...));
converters.add(converter);
}
}四、拦截器
java
// 拦截器:在请求到达 Controller 前后执行,类似 AOP 但专用于 Web 层
@Component
public class AuthInterceptor implements HandlerInterceptor {
// ① Controller 执行前
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) {
String token = request.getHeader("Authorization");
if (token == null) {
response.setStatus(401);
return false; // 返回 false 拦截请求,不继续往下走
}
return true; // 返回 true 放行
}
// ② Controller 执行后,视图渲染前
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler, ModelAndView modelAndView) { }
// ③ 视图渲染完成后
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler, Exception ex) { }
}
// 注册拦截器
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private AuthInterceptor authInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authInterceptor)
.addPathPatterns("/api/**") // 拦截的路径
.excludePathPatterns("/api/login"); // 排除的路径
}
}五、拦截器 vs 过滤器
| 维度 | 过滤器(Filter) | 拦截器(Interceptor) |
|---|---|---|
| 归属 | Servlet 规范,Tomcat 管理 | Spring 框架,Spring 容器管理 |
| 执行时机 | 进入 Servlet 之前 | 进入 Controller 之前 |
| 粒度 | 只能获取 request/response | 可以获取 Controller 方法信息 |
| 依赖注入 | 不支持 @Autowired | 支持 @Autowired |
| 生命周期 | 随 Tomcat 启动 | 随 Spring 容器启动 |
请求链路:
请求 → Filter → DispatcherServlet → Interceptor → Controller
Filter 在外层,Interceptor 在内层六、统一异常处理
java
// @ControllerAdvice + @ExceptionHandler 全局异常处理
@RestControllerAdvice
public class GlobalExceptionHandler {
// 处理业务异常
@ExceptionHandler(BusinessException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public Result handleBusinessException(BusinessException e) {
return Result.error(e.getCode(), e.getMessage());
}
// 处理参数校验异常
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public Result handleValidation(MethodArgumentNotValidException e) {
String msg = e.getBindingResult().getFieldErrors().stream()
.map(FieldError::getDefaultMessage)
.collect(Collectors.joining(", "));
return Result.error("400", msg);
}
// 兜底处理
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Result handleException(Exception e) {
log.error("系统异常", e);
return Result.error("500", "系统异常,请联系管理员");
}
}七、面试要点
Q1:Spring MVC 的请求处理流程是怎样的?
请求 → DispatcherServlet → HandlerMapping 找到 Controller → HandlerAdapter 调用 Controller 方法 → 返回 ModelAndView → ViewResolver 解析视图 → 渲染返回。前后端分离项目中,HttpMessageConverter 将返回对象转为 JSON 直接写入响应。
Q2:过滤器和拦截器的区别?
过滤器是 Servlet 规范,在 Tomcat 层面执行,进入 DispatcherServlet 之前;拦截器是 Spring 框架的,在 Controller 执行前后执行,可以获取 Controller 方法信息,支持依赖注入。
Q3:@RestController 和 @Controller 的区别?
@RestController = @Controller + @ResponseBody。@Controller 返回视图名,@RestController 返回 JSON 数据(每个方法自动加 @ResponseBody)。
