@RequestMapping 注解详解

@RequestMapping 注解详解

一、概述

@RequestMapping 是 Spring MVC 中最核心的映射注解,用于将 HTTP 请求映射到 Controller 的处理方法上。它既可以标注在类上,也可以标注在方法上。

  • 类级别:定义该 Controller 下所有方法的公共路径前缀。
  • 方法级别:定义具体方法的路径和匹配条件。

两者组合起来构成完整的请求路径。

java 复制代码
@RestController
@RequestMapping("/api/users")
public class UserController {

    @RequestMapping("/list")
    public List<User> list() {
        return userService.list();
    }
}

完整路径是 /api/users/list。

二、核心属性

1. value / path

指定请求路径,两者互为别名。

java 复制代码
@RequestMapping("/user")
@RequestMapping(value = "/user")
@RequestMapping(path = "/user")

三种写法完全等价。

支持多个路径:

java 复制代码
@RequestMapping({"/user", "/member"})
public User getUser() { }

/user 和 /member 都可以访问这个方法。

2. method

指定 HTTP 方法,不写则匹配所有方法。

java 复制代码
@RequestMapping(value = "/user", method = RequestMethod.GET)
@RequestMapping(value = "/user", method = {RequestMethod.GET, RequestMethod.POST})

method 是一个 RequestMethod 枚举数组,可以指定多个。

3. params

指定请求参数的匹配条件,可以要求参数存在、不存在、等于某个值、不等于某个值。

java 复制代码
// 必须携带 type 参数
@RequestMapping(value = "/list", params = "type")

// 必须携带 type=admin
@RequestMapping(value = "/list", params = "type=admin")

// 不能携带 type 参数
@RequestMapping(value = "/list", params = "!type")

// 同时满足多个条件
@RequestMapping(value = "/list", params = {"type=admin", "page"})

4. headers

指定请求头的匹配条件,用法与 params 类似。

java 复制代码
@RequestMapping(value = "/api", headers = "X-API-VERSION=1")
@RequestMapping(value = "/api", headers = "!X-DEBUG")

5. consumes

指定请求的 Content-Type,限制请求体的媒体类型。

java 复制代码
@RequestMapping(value = "/user", method = RequestMethod.POST,
                consumes = "application/json")

表示只接受 Content-Type: application/json 的请求。如果客户端发送的是 application/xml,会返回 415(Unsupported Media Type)。

6. produces

指定响应的 Content-Type,限制返回的媒体类型。

java 复制代码
@RequestMapping(value = "/user", produces = "application/json")

表示只返回 application/json 类型的响应。客户端 Accept 头不匹配时返回 406(Not Acceptable)。

三、派生注解

Spring 4.3 之后提供了一组组合注解,简化常用的 HTTP 方法映射:

注解 等价于
@GetMapping @RequestMapping(method = RequestMethod.GET)
@PostMapping @RequestMapping(method = RequestMethod.POST)
@PutMapping @RequestMapping(method = RequestMethod.PUT)
@DeleteMapping @RequestMapping(method = RequestMethod.DELETE)
@PatchMapping @RequestMapping(method = RequestMethod.PATCH)
java 复制代码
@GetMapping("/user/{id}")
public User getUser(@PathVariable Long id) { }

@PostMapping("/user")
public User createUser(@RequestBody User user) { }

日常开发中优先用这些派生注解,比 @RequestMapping(method = ...) 更简洁。

四、路径匹配规则

1. Ant 风格路径

通配符 含义 示例
? 匹配任意单个字符 /user? 匹配 /user1、/usera
* 匹配任意字符(不跨路径层级) /user/* 匹配 /user/list,不匹配 /user/list/detail
** 匹配任意层级路径 /user/** 匹配 /user/list、/user/list/detail
java 复制代码
@RequestMapping("/user/*")
public User getUser() { }  // 匹配 /user/list、/user/1

@RequestMapping("/user/**")
public User getUser() { }  // 匹配 /user/list、/user/list/detail

2. 路径变量

用 {} 定义路径变量,配合 @PathVariable 获取。

java 复制代码
@GetMapping("/user/{id}")
public User getUser(@PathVariable Long id) { }

访问 /user/1 时,id 为 1。

多个路径变量:

java 复制代码
@GetMapping("/user/{userId}/order/{orderId}")
public Order getOrder(@PathVariable Long userId, 
                      @PathVariable Long orderId) { }

路径变量带正则约束:

java 复制代码
@GetMapping("/user/{id:\\d+}")  // id 只能是数字
public User getUser(@PathVariable Long id) { }

3. 路径匹配中的优先级

当多个映射都能匹配同一个请求时,Spring 会选择最精确的那个:

复制代码
精确路径 > 路径变量 > 通配符
java 复制代码
@GetMapping("/user/list")    // 优先级最高
@GetMapping("/user/{id}")    // 次之
@GetMapping("/user/*")       // 再次
@GetMapping("/user/**")      // 最低

五、类级别与方法级别的组合

java 复制代码
@RestController
@RequestMapping("/api")
public class UserController {

    @GetMapping("/users")
    public List<User> list() { }        // 完整路径:/api/users

    @GetMapping("/users/{id}")
    public User get(@PathVariable Long id) { }  // /api/users/{id}
}

类级别的路径会作为前缀拼接到方法路径前。方法路径可以以 / 开头,也可以不写,效果一样。

六、完整示例

java 复制代码
@RestController
@RequestMapping("/api/users")
public class UserController {

    // GET /api/users
    @GetMapping
    public List<User> list() { }

    // GET /api/users/1
    @GetMapping("/{id}")
    public User getById(@PathVariable Long id) { }

    // GET /api/users/search?name=张三
    @GetMapping(value = "/search", params = "name")
    public List<User> search(@RequestParam String name) { }

    // POST /api/users,只接受 JSON
    @PostMapping(consumes = "application/json")
    public User create(@RequestBody User user) { }

    // PUT /api/users/1
    @PutMapping("/{id}")
    public User update(@PathVariable Long id, @RequestBody User user) { }

    // DELETE /api/users/1
    @DeleteMapping("/{id}")
    public void delete(@PathVariable Long id) { }

    // 只接受 X-API-VERSION=2 的请求,返回 JSON
    @GetMapping(value = "/v2/list", 
                headers = "X-API-VERSION=2",
                produces = "application/json")
    public List<User> listV2() { }
}

七、底层处理机制

@RequestMapping 由 RequestMappingHandlerMapping 处理。容器启动时,它会扫描所有 @Controller 和 @RequestMapping 标注的类和方法,生成 RequestMappingInfo 对象,并注册到映射表中。

RequestMappingInfo 封装了以下条件:

  • 路径模式(PatternsRequestCondition)
  • HTTP 方法(RequestMethodsRequestCondition)
  • 请求参数(ParamsRequestCondition)
  • 请求头(HeadersRequestCondition)
  • 消费媒体类型(ConsumesRequestCondition)
  • 生产媒体类型(ProducesRequestCondition)

请求到达时,DispatcherServlet 调用 RequestMappingHandlerMapping.getHandler(),遍历所有 RequestMappingInfo,找到匹配的那个,返回对应的 HandlerExecutionChain。

匹配时,多个条件必须同时满足。路径、方法、参数、请求头、媒体类型都是"与"的关系。

八、常见问题

1. 路径冲突

两个方法映射了同一个路径和方法:

java 复制代码
@GetMapping("/user")
public User getUser() { }

@GetMapping("/user")
public User getUser2() { }

启动报 Ambiguous mapping。需要修改其中一个的路径或 HTTP 方法。

2. 路径变量和普通路径冲突

java 复制代码
@GetMapping("/user/{id}")
public User getById(@PathVariable String id) { }

@GetMapping("/user/list")
public List<User> list() { }

Spring 会优先匹配精确路径 /user/list,不会冲突。但如果 {id} 用了正则约束,比如 {id:\\d+},/user/list 不会被 {id} 匹配。

3. consumes 导致 415

java 复制代码
@PostMapping(value = "/user", consumes = "application/json")

客户端发送 Content-Type: text/plain 时返回 415。检查请求头是否正确。

4. produces 导致 406

java 复制代码
@GetMapping(value = "/user", produces = "application/json")

客户端 Accept: text/html 时返回 406。要么修改客户端的 Accept 头,要么去掉 produces 限制。

5. 类级别和方法级别路径拼接问题

java 复制代码
@RestController
@RequestMapping("/api/")
public class UserController {

    @GetMapping("/users")
    public List<User> list() { }  // 实际路径:/api/users
}

类级别路径末尾的 / 会被处理,不会产生 //。但建议路径不要带多余斜杠,保持规范。

九、最佳实践

  • 优先使用 @GetMapping、@PostMapping 等派生注解,比 @RequestMapping(method = ...) 更简洁。
  • 类级别用 @RequestMapping 定义模块前缀,方法级别用派生注解定义具体路径。
  • 路径命名用名词复数,如 /users、/orders,符合 RESTful 风格。
  • 需要限制媒体类型时用 consumes 和 produces,避免接口被错误调用。
  • 路径变量用正则约束,如 {id:\\d+},避免非法参数进入方法。
  • 避免两个方法映射完全相同的路径和方法,启动时会报冲突。

十、总结

属性 作用 常用度
value / path 请求路径 ⭐⭐⭐⭐⭐
method HTTP 方法 ⭐⭐⭐⭐⭐
params 请求参数条件 ⭐⭐⭐
headers 请求头条件 ⭐⭐
consumes 请求体媒体类型 ⭐⭐⭐
produces 响应媒体类型 ⭐⭐⭐
派生注解 对应 HTTP 方法
@GetMapping GET
@PostMapping POST
@PutMapping PUT
@DeleteMapping DELETE
@PatchMapping PATCH

@RequestMapping 是 Spring MVC 请求映射的核心。理解它的路径匹配规则、方法限制、参数和媒体类型条件,就能精确控制哪些请求交给哪个方法处理。日常开发中,类级别用 @RequestMapping 定义前缀,方法级别用 @GetMapping 等派生注解,是最清晰、最常用的写法。

相关推荐
骑着蜗牛撵大象3271 小时前
设备监控数据存与查:Spring Boot 接入 TimescaleDB 超表的完整落地
android·spring boot·后端·springboot·时序数据库·es·设备监控
鶴哥只手遮天1 小时前
Spring Boot 4.1.1 深度源码解析-第 15 章 · 条件注解体系:全部 `@ConditionalOnXxx` 的实现原理
java·后端·开源
我的div丢了肿么办1 小时前
go语言安装包详细讲解
后端·go
鶴哥只手遮天1 小时前
Spring Boot 4.1.1 深度源码解析-第 30 章 · 基础设施能力:SSL Bundle、Task 与虚拟线程、Retry
java·后端·开源
IT研究室1 小时前
最新计算机毕业设计选题推荐-基于微信小程序的汉服交易系统-网站-文档指导-Java-springboot
java·微信小程序·课程设计
Zenova EdgeOS1 小时前
Rust TUI 实战:用 ratatui 构建工业边缘终端界面
开发语言·后端·rust·工业网关
imDwAaY1 小时前
Java String 核心原理:一篇讲透字符串常见面试题
后端
imDwAaY1 小时前
API 和 SPI 有什么区别?一篇讲透两者的设计思想
后端
鶴哥只手遮天1 小时前
Spring Boot 4.1.1 深度源码解析-第 26 章 · 指标、观测与链路追踪:Micrometer 与 OpenTelemetry
java·后端·开源