接口路径规范

彻底搞懂 @GetMapping@PostMapping@PutMapping@DeleteMapping 等注解中路径参数的含义,以及它们和类上 @RequestMapping 的配合方式。

✅ 一、Mapping 注解和访问路径的关系

在 Spring Boot 的控制器中:

  • 类上的 @RequestMapping 定义了该类中所有接口的 公共前缀
  • 方法上的 @GetMapping@PostMapping 定义了该方法的 子路径
  • 最终接口访问地址 = 类上路径 + 方法上路径。

✅ 你的示例

java 复制代码
@RestController
@RequestMapping("/admin/order")  // 类级别公共前缀
public class OrderController {

    @GetMapping("/add")          // 方法级别路径
    public String addOrder() {
        return "add order";
    }
}

🔹 这里最终的访问路径是:

pgsql 复制代码
/admin/order/add

你的理解是完全正确的:类上的 /admin/order 和方法上的 /add 组成完整路径。


✅ 二、Mapping 注解参数详解

@GetMapping 为例(PostMappingPutMappingDeleteMapping 都类似),它有几个常用参数:

1️⃣ value(或 path

  • 表示当前方法相对于类上 @RequestMapping 的子路径。
  • 可以是字符串或字符串数组。
  • valuepath 是同义别名,任选其一即可。

例:

java 复制代码
@GetMapping("/list")
@GetMapping(path="/list")

以上两种写法完全等价。


2️⃣ params

  • 指定 必须带上哪些请求参数 才能匹配此方法。
  • 常用于区分同一路径下根据参数不同选择不同方法。

例:

java 复制代码
@GetMapping(value="/search", params="type=quick")
public String quickSearch() { ... }

@GetMapping(value="/search", params="type=advanced")
public String advancedSearch() { ... }

🔹 /search?type=quick 会匹配到 quickSearch

🔹 /search?type=advanced 会匹配到 advancedSearch


同一路径根据请求参数不同来走不同处理逻辑

✅ 背景

在正常情况下,如果你有两个方法,它们的路径和请求方法都一样,比如都是:

sql 复制代码
GET /search

那么 Spring 会认为这是"路由冲突":它不知道到底该走哪个方法,会抛出类似

pgsql 复制代码
Ambiguous mapping. Cannot map 'xxxController' method

的异常。


✅ 但是通过 params 区分

你可以在 @GetMappingparams 参数中 指定请求必须携带哪些参数才能匹配到这个方法,从而在同一路径下用不同的参数值区分不同方法。


✅ 你的例子

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

    @GetMapping(value="/search", params="type=quick")
    public String quickSearch() {
        return "Quick search result";
    }

    @GetMapping(value="/search", params="type=advanced")
    public String advancedSearch() {
        return "Advanced search result";
    }
}

🔹 这里有两种情况:

情况 1:/api/search?type=quick

  • 发送 GET 请求:

    pgsql 复制代码
    GET /api/search?type=quick
  • Spring 会检查:

    • URL 匹配 /search
    • params 中有 type=quick
  • 所以只会匹配到:

    java 复制代码
    public String quickSearch()
  • 响应是 "Quick search result"。

情况 2:/api/search?type=advanced

  • 发送 GET 请求:

    pgsql 复制代码
    GET /api/search?type=advanced
  • URL 依然是 /search,但参数变成了 type=advanced

  • 所以只会匹配到:

    java 复制代码
    public String advancedSearch()
  • 响应是 "Advanced search result"。


✅ 这个 params 是什么意思?

@GetMapping 中:

java 复制代码
@GetMapping(value="/search", params="type=quick")

这里的 params="type=quick" 表示:

  • 这个方法只会匹配请求中带有参数 type,并且其值必须等于 quick 的请求。

✅ 使用场景

为什么要这样做?

🔹 如果你要做 同一路径,但不同搜索类型 的接口,比如搜索可以按:

  • type=quick → 快速搜索
  • type=advanced → 高级搜索

而你又想让它们都用 /search 这个统一 URL(不想搞 /quickSearch/advancedSearch 两个接口),这时就非常适合用 params


✅ 注意

  • 如果没有带指定参数,或者参数值不符合任何一个方法定义的条件,Spring 会返回 404。

  • 你可以在 params 中同时指定多个参数,比如:

    java 复制代码
    @GetMapping(value="/search", params={"type=quick", "sort=asc"})

    表示请求中必须同时满足 type=quicksort=asc


✅ 小结

✔️ 通过 params 你可以:

  • 在同一个路径下,用不同的参数组合区分不同的接口处理方法;
  • 避免在 URL 路径上区分不同功能,让 API 更加 RESTful。

✅ 一句话总结:

params="type=quick" 表示只有 当 GET 请求 /search 携带参数 type=quick 时,Spring 才会将请求路由到对应方法。

3️⃣ headers

  • 指定必须带上哪些请求头才能匹配此方法。
  • 用得不多,适合对 header 严格要求的接口。

例:

java 复制代码
@GetMapping(value="/secure", headers="X-API-KEY=mykey")
public String secureApi() { ... }

4️⃣ produces

  • 指定返回的内容类型(响应类型)必须满足客户端的 Accept 头,否则不匹配。
  • 适合一个接口同时支持多种返回格式。

例:

java 复制代码
@GetMapping(value="/data", produces="application/json")
public Data getJsonData() { ... }

@GetMapping(value="/data", produces="application/xml")
public Data getXmlData() { ... }

5️⃣ consumes

  • 指定接口能接收的请求体内容类型(Content-Type),常用于 POST/PUT。

例:

java 复制代码
@PostMapping(value="/upload", consumes="application/json")
public String uploadJson(@RequestBody MyData data) { ... }

✅ 三、几个 Mapping 注解的区别

  • @RequestMapping

    • 通用注解,可通过 method= RequestMethod.GET/POST/... 指定请求方法。
    • 可以同时用于类或方法上。
    • 更灵活,但更繁琐。
  • @GetMapping

    • 相当于 @RequestMapping(method=RequestMethod.GET) 的简化版本。
    • 只处理 GET 请求,其他 @XxxMapping 类似。
  • @PostMapping

    • 简化处理 POST 请求。
  • @PutMapping

    • 简化处理 PUT 请求。
  • @DeleteMapping

    • 简化处理 DELETE 请求。

✅ 例子:全部组合演示

java 复制代码
@RestController
@RequestMapping("/api/v1/users")  // 公共前缀:/api/v1/users
public class UserController {

    @GetMapping("/{id}")          // GET /api/v1/users/123
    public String getUser(@PathVariable Long id) { ... }

    @PostMapping                  // POST /api/v1/users
    public String createUser() { ... }

    @PutMapping("/{id}")          // PUT /api/v1/users/123
    public String updateUser(@PathVariable Long id) { ... }

    @DeleteMapping("/{id}")       // DELETE /api/v1/users/123
    public String deleteUser(@PathVariable Long id) { ... }
}

✅ 四、几点易错点

✅ 方法路径前不要随意加或漏掉斜杠:

  • /addadd 效果相同,但最好统一加 /

✅ 类上 @RequestMapping 的路径不要加尾部 /

  • 推荐 /admin/order 而不是 /admin/order/,避免和方法路径拼接时产生双斜杠。

✅ 不要把方法上路径写成绝对路径(以 / 开头和不以 / 开头都可以,但不要搞混):

  • /addadd 都能正常拼接,但统一风格更好。

🔹 在 REST 风格中, "动作"通过请求方法来区分,而不是靠路径来区分。


✅ 关键点:URL + HTTP 方法共同决定唯一接口

比如:

  • PUT /api/v1/users/123 → 表示对 id=123 的用户进行更新。
  • DELETE /api/v1/users/123 → 表示对 id=123 的用户进行删除。

虽然路径完全一致(/api/v1/users/123),但是:

  • 客户端 在发起请求时,指定了不同的 HTTP 方法(PUT 或 DELETE);
  • Spring Boot 会根据方法注解 @PutMapping / @DeleteMapping 中内置的请求方法去匹配不同的处理函数;
  • 所以对于同一路径,Spring 会根据请求的方法(Method)路由到正确的处理器。

✅ 在 Java Spring 中是怎么匹配的?

Spring 底层机制:

  • @PutMapping("/{id}") 本质等价于:

    java 复制代码
    @RequestMapping(value="/{id}", method=RequestMethod.PUT)
  • @DeleteMapping("/{id}") 等价于:

    java 复制代码
    @RequestMapping(value="/{id}", method=RequestMethod.DELETE)
  • Spring DispatcherServlet 根据:

    • 请求的 URL
    • 请求的 HTTP Method
      这两个条件匹配 Controller 方法。

✅ 调用示例

你通过不同方式发送不同方法的请求:

🔹 修改用户(PUT):

bash 复制代码
curl -X PUT http://localhost:8080/api/v1/users/123 \
     -H "Content-Type: application/json" \
     -d '{"name":"newname"}'

🔹 删除用户(DELETE):

bash 复制代码
curl -X DELETE http://localhost:8080/api/v1/users/123
  • 两次请求的 URL 完全一样;
  • 但第一次是 PUT 方法 → 匹配 @PutMapping
  • 第二次是 DELETE 方法 → 匹配 @DeleteMapping

✅ 这就是 RESTful API 的核心思想:

  • URL 表示 资源的位置

  • HTTP 方法表示 对资源的动作

    • GET → 查询
    • POST → 新增
    • PUT → 更新
    • PATCH → 部分更新
    • DELETE → 删除
相关推荐
寻求出路的程序媛12 分钟前
分布式 & 高性能 & 高可用 体系、学习重点、面试点
分布式·后端·面试·性能优化
掘金者阿豪22 分钟前
Let‘s Encrypt 证书到底会不会自动续期?从一次服务器迁移后的证书排查说起
后端
Zane199428 分钟前
手写"判断key存不存在"的模板代码太烦?一文讲透 collections 四件套
后端·python
joinwell5229 分钟前
Agent 中断后,原任务如何安全接管?从恢复标记到效果事实
人工智能·后端·架构
sp4241 分钟前
羽量级的 Java Bean 实体校验器
后端
魔兽大山哥1 小时前
【NL2SQL 实战 07】LIMIT 不是小事:默认 100 行背后的产品判断
后端
qq_339191141 小时前
go cpu占比高排查,cpu100%排查,go pprof cpu命令
开发语言·后端·golang
笃行3501 小时前
异构数据同步如何真正做到“数据无忧“?——解读 KFS 的全周期一致性校验与修复能力
后端
云边有个稻草人1 小时前
异构数据同步如何保证数据不出错:KFS全周期校验与修复实践
后端
JaguarJack1 小时前
现在就值得尝试的 5 个 Laravel 新包
后端·php·laravel·服务端