文章
Spring MVC 学习笔记:请求处理与参数绑定
牛耕田
暂存笔记,持续补充中。Spring MVC 是 Spring Boot Web 的底层骨架,理解它才能用好
@RestController。
一、核心组件与请求链路
Spring MVC 是典型的前端控制器模式,所有请求都先到达 DispatcherServlet,再由它分发给具体组件。
浏览器 → DispatcherServlet → HandlerMapping → HandlerAdapter
→ Handler(Controller) → ViewResolver → View → 响应
| 组件 | 职责 |
|---|---|
DispatcherServlet |
前端控制器,统一调度入口 |
HandlerMapping |
根据 URL 找到处理器(映射不等于处理器本身) |
HandlerAdapter |
适配不同类型的处理器(注解式 / 传统接口式) |
HandlerExceptionResolver |
统一异常处理 |
ViewResolver |
将逻辑视图名解析为具体 View |
MultipartResolver |
文件上传解析 |
LocaleResolver / ThemeResolver |
国际化 / 主题 |
一次请求的完整流程:
DispatcherServlet收到请求,通过HandlerMapping得到HandlerExecutionChain(含拦截器链)。- 依次执行
preHandle。 - 由
HandlerAdapter调用Handler(即 Controller 方法)。 - 返回
ModelAndView,postHandle执行。 ViewResolver解析视图并渲染。afterCompletion执行。
RESTful 场景:使用
@ResponseBody(或@RestController)时,返回的是HttpMessageConverter序列化后的 JSON,不经过 ViewResolver。
二、请求映射
@RestController
@RequestMapping("/api/users")
public class UserController {
@GetMapping("/{id}") // 路径变量
public User get(@PathVariable Long id) { ... }
@PostMapping // 提交
public User create(@RequestBody User user) { ... }
@PutMapping("/{id}") // 全量更新
public User update(@PathVariable Long id, @RequestBody User user) { ... }
@DeleteMapping("/{id}") // 删除
public void delete(@PathVariable Long id) { ... }
}
- 组合注解:
@GetMapping=@RequestMapping(method = RequestMethod.GET)。 - 路径匹配:支持
*(单层)、**(多层);Spring 6 默认改用PathPatternParser,性能优于旧的AntPathMatcher。 - 多条件限定:可用
params、headers、consumes、produces做更细粒度的映射。
三、参数绑定(高频考点)
| 场景 | 注解 | 说明 |
|---|---|---|
查询字符串 ?a=1 |
@RequestParam |
required=false 可设为可选 |
路径变量 /user/{id} |
@PathVariable |
用 {id} 占位 |
| 请求体 JSON | @RequestBody |
由 HttpMessageConverter 反序列化 |
| 表单对象 | 无注解(POJO) | 按字段名自动绑定 |
| 请求头 | @RequestHeader |
|
| Cookie | @CookieValue |
|
| 文件 | @RequestPart / MultipartFile |
@PostMapping("/search")
public PageResult<User> search(
@RequestParam(defaultValue = "1") int page,
@RequestParam(defaultValue = "10") int size,
@RequestParam(required = false) String keyword,
@RequestHeader("Authorization") String token) {
...
}
常见坑:application/json 请求体只能用 @RequestBody,用 @RequestParam 收不到;反之表单提交也不能用 @RequestBody。
四、返回值处理
@ResponseBody/@RestController:返回值经HttpMessageConverter转 JSON。- 返回
ResponseEntity<T>:可自定义状态码与响应头。
@GetMapping("/{id}")
public ResponseEntity<User> get(@PathVariable Long id) {
User u = service.findById(id);
return u == null ? ResponseEntity.notFound().build()
: ResponseEntity.ok(u);
}
五、全局异常处理
用 @RestControllerAdvice + @ExceptionHandler 统一收口,避免每个方法写 try-catch。
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(BizException.class)
public Result<Void> handleBiz(BizException e) {
return Result.fail(e.getCode(), e.getMessage());
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public Result<Void> handleValid(MethodArgumentNotValidException e) {
String msg = e.getBindingResult().getFieldError().getDefaultMessage();
return Result.fail(400, msg);
}
@ExceptionHandler(Exception.class)
public Result<Void> handleOther(Exception e) {
log.error("系统异常", e);
return Result.fail(500, "系统繁忙,请稍后再试");
}
}
注意:
@ExceptionHandler(Exception.class)兜底时不要把堆栈信息返回给前端,否则会泄露内部实现细节。
六、参数校验
引入 spring-boot-starter-validation 后即可使用 Jakarta Bean Validation 注解。
public class UserCreateDTO {
@NotBlank(message = "用户名不能为空")
@Size(min = 3, max = 20, message = "用户名长度需在 3~20 之间")
private String username;
@Email(message = "邮箱格式不正确")
private String email;
}
@PostMapping
public Result<Void> create(@Validated @RequestBody UserCreateDTO dto) { ... }
@Valid(JSR-303 标准)与@Validated(Spring 扩展,支持分组校验)二选一。- 嵌套对象校验需在字段上加
@Valid才会级联生效。
七、拦截器 vs 过滤器
| 维度 | Filter(Servlet 规范) | Interceptor(Spring MVC) |
|---|---|---|
| 作用范围 | 所有请求(含静态资源) | 仅 DispatcherServlet 处理的请求 |
| 能否拿到 Bean | 不易(容器外) | 可以(Spring 容器内) |
| 能否拿到 Handler | 否 | 可以 |
| 典型用途 | 编码、跨域、日志埋点 | 登录校验、权限、限流 |
public class AuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest req, HttpServletResponse resp, Object handler) {
if (req.getHeader("Token") == null) {
resp.setStatus(401);
return false; // 返回 false 即中断
}
return true;
}
}
顺序:
Filter → preHandle → Controller → postHandle → afterCompletion。
八、小结
- Spring MVC = DispatcherServlet + 九大组件,核心是「映射 → 适配 → 执行 → 渲染」。
- 参数绑定靠注解区分来源,JSON 用
@RequestBody,表单/查询用@RequestParam。 - 生产环境必备三件套:全局异常处理 + 参数校验 + 登录拦截器。