---
URL: "/zh-CN/blog/2026-04/SpringBoot-Restful.html"
LLMS_URL: "/zh-CN/blog/2026-04/SpringBoot-Restful.md"
lastUpdated: true
commentabled: true
recommended: true
title: "SpringBoot 接口路径规范"
description: "SpringBoot 接口路径规范"
date:

pageClass: "blog-page-class"
cover: "/covers/springboot.svg"
---

---
lastUpdated: true
commentabled: true
recommended: true
title: SpringBoot 接口路径规范
description: SpringBoot 接口路径规范
date: 2026-04-17 10:45:00 
pageClass: blog-page-class
cover: /covers/springboot.svg
---

彻底搞懂 `@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";
    }
}
```

🔹 这里最终的访问路径是：

`/admin/order/add`

你的理解是完全正确的：类上的 `/admin/order` 和方法上的 `/add` 组成完整路径。

## ✅ 二、Mapping 注解参数详解 ##

以 `@GetMapping` 为例（`PostMapping`、`PutMapping`、`DeleteMapping` 都类似），它有几个常用参数：

### 1️⃣ value（或 path） ###

- 表示当前方法相对于类上 `@RequestMapping` 的子路径。
- 可以是字符串或字符串数组。
- `value` 和 `path` 是同义别名，任选其一即可。

例：

```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`

同一路径根据请求参数不同来走不同处理逻辑

#### ✅ 背景 ####

在正常情况下，如果你有两个方法，它们的路径和请求方法都一样，比如都是：

```bash
GET /search
```

那么 Spring 会认为这是“路由冲突”：它不知道到底该走哪个方法，会抛出类似 `Ambiguous mapping. Cannot map 'xxxController' method` 的异常。

#### ✅ 但是通过 `params` 区分 ####

你可以在 `@GetMapping` 的 `params` 参数中 *指定请求必须携带哪些参数才能匹配到*这个方法，从而在同一路径下用不同的参数值区分不同方法。

#### ✅ 你的例子 ####

```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 请求：

```bash
GET /api/search?type=quick
```

Spring 会检查：

- URL 匹配 `/search`；
- params 中有 `type=quick`；

所以只会匹配到：

```java
public String quickSearch()
```

响应是 *"Quick search result"*。

##### ✅ 情况 2：`/api/search?type=advanced` #####

发送 GET 请求：

```bash
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=quick` 且 `sort=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) { ... }
}
```

## ✅ 四、几点易错点 ##

✅ 方法路径前不要随意加或漏掉斜杠：

- `/add` 和 `add` 效果相同，但最好统一加 `/`。

✅ 类上 `@RequestMapping` 的路径不要加尾部 `/`：

- 推荐 `/admin/order` 而不是 `/admin/order/`，避免和方法路径拼接时产生双斜杠。

✅ 不要把方法上路径写成绝对路径（以 `/` 开头和不以 `/` 开头都可以，但不要搞混）：

- `/add` 和 `add` 都能正常拼接，但统一风格更好。

> 在 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` → 删除
