MVC 常用注解大总结与常见坑
学完 21–38 章,注解已经铺了一地。这一章把它们按职责归类做一次总复习,再集中清点最容易踩的坑。
注解全家桶速查
| 分组 | 注解 | 一句话作用 |
|---|---|---|
| 控制器 | @Controller / @RestController | 类声明:控制器 / 控制器+全类响应体 |
| 映射 | @RequestMapping 及 @GetMapping/@PostMapping/@PutMapping/@DeleteMapping/@PatchMapping | 把 HTTP 方法与路径绑定到方法 |
| 参数 | @RequestParam / @PathVariable / @RequestHeader / @CookieValue | 从查询串/路径/头/Cookie 取值 |
| 请求体 | @RequestBody / @RequestPart | 反序列化请求体 / multipart 的某个 part |
| 模型 | @ModelAttribute / @SessionAttributes / @SessionAttribute | 模型属性 / 会话暂存模型 / 读会话 |
| 响应 | @ResponseBody / ResponseEntity / @ResponseStatus | 写响应体 / 状态+头+体 / 固定状态码 |
| 校验 | @Valid / @Validated | 触发 Bean Validation / 支持分组 |
| 异常 | @ExceptionHandler / @ControllerAdvice / @RestControllerAdvice | 局部/全局异常转响应 |
| 跨域 | @CrossOrigin | 放开单个接口的跨域限制 |
常见坑 No.1:String 返回值被当成视图名
在 @Controller 里返回 "OK" 会去解析视图 → 404 或视图解析异常。想返回文本/JSON 必须 @ResponseBody 或用 @RestController。
常见坑 No.2:@RequestParam 依赖参数名推断
不写 value 时按方法形参名匹配,需要 javac -parameters 或调试信息;否则解析失败。结论:显式写全 name,别赌编译开关。
常见坑 No.3:@RequestBody 的幺蛾子
- 一个方法只能有一个 @RequestBody。
- JSON 缺字段对不上 → HttpMessageNotReadableException(400)。
- 想收 JSON 又想收表单字段,别同时用 @RequestBody + @RequestParam 混搭(@RequestBody 独占请求体),改用 DTO + 字段或 @RequestPart。
- LocalDate/LocalDateTime 反序列化:依赖 jackson-datatype-jsr310 并配好格式,默认格式不是你想要的。
常见坑 No.4:BindingResult 必须紧跟被校验参数
@Valid DTO 后面隔了别的参数再接 BindingResult → IllegalStateException(框架要求紧跟,见第 26 章)。
常见坑 No.5:映射歧义与 404/405/406/415
| 现象 | 原因与排查 |
|---|---|
| 启动报 Ambiguous mapping | 两个方法映射到同一 URL+方法 |
| 请求 404 | URL 没匹配:查路径变量、方法注解、前缀 @RequestMapping |
| 方法对但请求方法不对 → 405 | GET 调了 POST 接口 |
| produces 不满足 Accept → 406 | 客户端要的格式你没声明/不能产 |
| consumes 不满足 Content-Type → 415 | 客户端发的内容类型你没收 |
常见坑 No.6:静态资源被控制器「吃掉」
DispatcherServlet 映射 / 后,/css/app.css 若没配资源映射会 404;若控制器写了 @GetMapping("/") 又会抢走静态资源。给静态资源独立前缀(/static/)+ addResourceHandlers 是常规解法(第 32 章)。
常见坑 No.7:@DateTimeFormat 与 JSON 是两套机制
@DateTimeFormat 只作用于表单/参数绑定格式化;JSON 序列化由 Jackson 控制(@JsonFormat/JavaTimeModule)。混用会导致「表单没问题、JSON 报错」。
常见坑 No.8:参数解析顺序与类型错误的表现
方法参数按「参数解析器逐个试」的顺序处理,解析失败多数表现为 400(类型不匹配)而非 500;500 通常意味着解析器内部异常或 NPE,注意区分。多参数时把 @RequestParam 等标注参数与 Model、BindingResult 的位置写规整(BindingResult 规则见坑 No.4),代码可读性也更好。
常见坑 No.9:中文乱码与响应头
字符编码问题大多出在容器/过滤器层(CharacterEncodingFilter 要放在最前),而不是控制器;序列化中文乱码检查 Jackson 的编码与 Content-Type 里的 charset。
常见坑 No.10:异常被吞
在控制器里 try/catch 吞掉异常只返回 null,前端拿到 200 + null 很难排查。让异常抛给 @RestControllerAdvice 统一处理,日志在 advice 里记。
复习建议
对照「注解全家桶」表自查:每个注解能不能说出它写在类上还是方法上、参数上还是返回值上?标注位置的错位(如把 @RequestParam 放类上)是新手报错主因。遇到怪问题先打印 andDo(print()) 看真实请求响应,再对着上面十坑逐个排除。
注解是 Spring MVC 的「语法」,映射、解析、响应、异常四套注解各管一段。写之前先想清楚数据从哪来(参数注解)、结果往哪去(响应注解)、出错谁来接(异常注解),坑自然就绕开了。