@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 等派生注解,是最清晰、最常用的写法。

相关推荐
付威202330 分钟前
target 目录越来越大,Rust 项目该怎么清理
后端
技录局41 分钟前
Kafka 深度原理分析:从消息流到分布式日志
后端
大数据技术派1 小时前
我用AI写代码,做了3个小玩意儿
后端·微信小程序
yeccheng1 小时前
MySQL 索引超详解:从底层 B+ 树到面试高频考点
java·开发语言·jvm·mysql·面试
这个昵称不容易1 小时前
SpringBoot 读书笔记共享平台部署实战:97 个 Java 文件 / 113 个接口 / 10 张表
java·springboot·毕设
爱上咖啡香2 小时前
我给 Laravel AI 写了个千问驱动,文本、语音、图像、视频全打通
后端
杨文说AI与数字化2 小时前
票种表重构复盘:把填数字改成规则可执行版本
后端
回家路上绕了弯2 小时前
什么是 Agent as a Service?把 AI Agent 变成可调用的服务
后端
金銀銅鐵3 小时前
一个 Java 文件实现《孫子兵法·始計篇》中英对照阅读器
java·后端·ai编程
DevOpenClub4 小时前
高考教育信息问答 API:会话参数、资料引用与流式响应
java·数据库·高考