PathVariable
本章是 Spring MVC RESTful URL 设计的核心。在 RESTful 架构中,资源通过 URL 路径直接定位,如
/employees/1001表示 ID 为 1001 的员工。@PathVariable的作用就是将 URL 路径中的模板变量绑定到 Controller 方法的参数上。理解@PathVariable,就掌握了 RESTful 风格 URL 的参数提取机制。
定义与作用
@PathVariable 是 Spring MVC 提供的方法参数级注解,它的职责可以用一句话概括:将 URL 路径中的模板变量(占位符)绑定到 Controller 方法的形参上,实现 RESTful 风格的资源定位。
在 RESTful 设计中,URL 是资源的地址,不是操作的地址:
- 传统风格:
/getEmployee?id=1001(URL 描述操作,参数描述目标) - RESTful 风格:
/employees/1001(URL 直接定位资源)
@PathVariable 让 Spring MVC 能够解析第二种风格的 URL。
核心原理
URL 模板变量解析过程
图解:
- HandlerMapping 匹配 URL 模式
/employees/{id}与实际路径/employees/1001 - 提取路径变量
id=1001(字符串形式) - HandlerAdapter 调用方法时,根据
@PathVariable的声明,将字符串转换为方法参数类型(Long) - 类型转换失败时(如
/employees/abc),抛出MethodArgumentTypeMismatchException,最终返回 400 Bad Request
@PathVariable 与 @RequestParam 的对比
适用位置与常用属性
@PathVariable 标注在方法参数上,有以下属性:
| 属性 | 类型 | 作用 | 示例 |
|---|---|---|---|
value / name | String | 指定路径变量名(与形参名不一致时使用) | @PathVariable("id") Long employeeId |
required | boolean | 是否必须(默认 true) | @PathVariable(required = false) Long id |
@PathVariable vs @RequestParam 对比表
| 对比维度 | @PathVariable | @RequestParam |
|---|---|---|
| 参数位置 | URL 路径中 | URL 查询字符串中 |
| URL 示例 | /employees/1001 | /employees?id=1001 |
| 风格 | RESTful | 传统 |
| 是否必填 | 是(路径必须有值) | 可配置(默认必填) |
| 支持多个值 | 否(一个占位符一个值) | 是(?id=1&id=2) |
| 适合场景 | 资源标识符 | 查询条件、过滤参数 |
| 正则限定 | 支持({id:\d+}) | 不支持 |
完整示例
场景
飞翔科技的员工管理系统采用 RESTful 设计。架构师白歌要求所有资源定位都使用路径变量风格,如 /employees/1001、/departments/2001。
控制器代码
package com.feixiang.web;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/employees")
public class EmployeeController {
// 容器已注入该 Bean,本教程不展开 Service 实现
@Autowired
private EmployeeService employeeService;
// 基础用法:单个路径变量
@GetMapping("/{id}")
public Employee getById(@PathVariable Long id) {
return employeeService.findById(id);
}
// 显式指定变量名(形参名与占位符不一致)
@GetMapping("/{id}/manager")
public Employee getManager(@PathVariable("id") Long employeeId) {
return employeeService.findManager(employeeId);
}
// 多个路径变量
@GetMapping("/{id}/projects/{projectId}")
public Project getEmployeeProject(
@PathVariable Long id,
@PathVariable Long projectId) {
return employeeService.findProject(id, projectId);
}
// 正则限定:只匹配数字 ID
@GetMapping("/{id:\d+}")
public Employee getByNumericId(@PathVariable Long id) {
return employeeService.findById(id);
}
// 组合路径变量和查询参数
@GetMapping("/{id}/tasks")
public List<Task> getTasks(
@PathVariable Long id,
@RequestParam(required = false) String status) {
return employeeService.findTasks(id, status);
}
}
HTTP 请求示例 1:单个路径变量
curl -X GET http://localhost:8080/employees/1001 \
-H "Accept: application/json"
实际响应:
{
"id": 1001,
"name": "张伟",
"department": "技术部",
"position": "高级工程师"
}
分析:
- URL
/employees/1001匹配@GetMapping("/{id}") - 路径变量
id=1001被提取并转换为Long - 如果访问
/employees/abc,类型转换失败,返回 400 Bad Request
HTTP 请求示例 2:多个路径变量 + 查询参数
curl -X GET "http://localhost:8080/employees/1001/tasks?status=进行中" \
-H "Accept: application/json"
实际响应:
[
{
"taskId": 5001,
"title": "API 接口开发",
"status": "进行中",
"deadline": "2024-07-01"
},
{
"taskId": 5002,
"title": "单元测试编写",
"status": "进行中",
"deadline": "2024-06-30"
}
]
分析:
1001是路径变量(@PathVariable),标识资源status=进行中是查询参数(@RequestParam),标识过滤条件- RESTful 设计原则:资源标识符放路径,查询条件放查询字符串
- 这种混合使用是实际项目中最常见的模式
易错场景与面试考点
误区一:路径变量名与占位符不一致
错误写法:
@GetMapping("/{employeeId}")
public Employee getById(@PathVariable Long id) {
// 编译错误!占位符是 employeeId,参数名是 id
return employeeService.findById(id);
}
纠正:如果方法参数名与 URL 占位符名不一致,必须显式指定 value:
@GetMapping("/{employeeId}")
public Employee getById(@PathVariable("employeeId") Long id) {
return employeeService.findById(id);
}
注意:如果编译时保留了参数名(Java 8+ 加 -parameters 编译选项,或 IDE 默认开启),Spring 可以自动匹配。但生产环境建议显式指定,避免编译优化导致参数名丢失。
误区二:用 @PathVariable 做可选参数
错误写法:
@GetMapping("/{id}")
public Employee getById(@PathVariable(required = false) Long id) {
if (id == null) {
return employeeService.findDefault();
}
return employeeService.findById(id);
}
纠正:@PathVariable(required = false) 虽然语法上可行,但 RESTful 设计上路径变量应该是必填的。可选参数应该使用 @RequestParam 或设计不同的 URL 模式:
// 方案一:分开设计
@GetMapping("/default")
public Employee getDefault() {
return employeeService.findDefault();
}
@GetMapping("/{id}")
public Employee getById(@PathVariable Long id) {
return employeeService.findById(id);
}
// 方案二:使用查询参数
@GetMapping
public Employee getById(@RequestParam(required = false) Long id) {
if (id == null) {
return employeeService.findDefault();
}
return employeeService.findById(id);
}
面试高频:@PathVariable 与 @RequestParam 的区别
标准回答:
@PathVariable绑定 URL 路径中的模板变量,如/employees/1001中的1001,用于 RESTful 资源定位@RequestParam绑定 URL 查询字符串中的参数,如/employees?id=1001中的1001,用于查询条件@PathVariable通常必填(路径必须有值),@RequestParam可配置是否必填@PathVariable支持正则限定({id:\d+}),@RequestParam不支持- RESTful 设计中,资源标识符用
@PathVariable,过滤/排序/分页参数用@RequestParam
小结
@PathVariable 是 Spring MVC 实现 RESTful URL 的核心注解,它将 URL 路径中的模板变量绑定到方法参数,使 URL 可以直接定位资源。它是 RESTful 风格与传统风格的分水岭,与 @RequestParam 形成互补:资源标识符走路径,查询条件走查询字符串。
本章与全局的关系:本章讲解了 RESTful URL 的参数绑定机制。至此,第 2 章"控制器与请求映射"的核心注解(@Controller、@RestController、@RequestMapping、@GetMapping、@PostMapping、@PutMapping、@DeleteMapping、@PathVariable)已全部讲解完毕。后续章节将深入讲解请求参数获取、响应数据与视图解析、RESTful API 与消息转换等主题。