1、概览 {#1概览}
本文将带你了解 Spring 中 @PathVariable
注解的作用和用法。
简单地说,@PathVariable
注解可用于处理请求 URI 映射中的模板变量,并将其绑定到 Controller 方法参数。
2、示例映射 {#2示例映射}
@PathVariable
注解的一个简单用例是用于标识具有 ID 的实体的端点:
@GetMapping("/api/employees/{id}")
@ResponseBody
public String getEmployeesById(@PathVariable String id) {
return "ID: " + id;
}
在本例中,使用 @PathVariable
注解来提取 URI 的模板部分,该部分由变量 {id}
表示。
调用示例如下:
http://localhost:8080/api/employees/111
----
ID: 111
3、指定 PATH (路径)变量名 {#3指定-path-路径变量名}
在上一个示例中,由于方法参数和路径变量的名称相同,可以不用主动设置模板路径变量的名称。
如果路径变量名不同,可以在 @PathVariable
注解的参数中指定:
@GetMapping("/api/employeeswithvariable/{id}")
@ResponseBody
public String getEmployeesByIdWithVariableName(@PathVariable("id") String employeeId) {
return "ID: " + employeeId;
}
测试如下:
http://localhost:8080/api/employeeswithvariable/1
----
ID: 1
为了清晰起见,还可以将路径变量名定义为 @PathVariable(value="id")
,而不是 PathVariable("id")
。
4、单个请求中的多个路径变量 {#4单个请求中的多个路径变量}
根据情况,可以在请求 URI 中为 Controller 方法设置多个路径变量,而 Controller 方法也有多个方法参数:
@GetMapping("/api/employees/{id}/{name}")
@ResponseBody
public String getEmployeesByIdAndName(@PathVariable String id, @PathVariable String name) {
return "ID: " + id + ", name: " + name;
}
测试:
http://localhost:8080/api/employees/1/bar
----
ID: 1, name: bar
还可以使用 java.util.Map<String, String>
类型的方法参数来处理多个 @PathVariable
参数:
@GetMapping("/api/employeeswithmapvariable/{id}/{name}")
@ResponseBody
public String getEmployeesByIdAndNameWithMapVariable(@PathVariable Map<String, String> pathVarsMap) {
String id = pathVarsMap.get("id");
String name = pathVarsMap.get("name");
if (id != null && name != null) {
return "ID: " + id + ", name: " + name;
} else {
return "Missing Parameters";
}
}
测试如下:
http://localhost:8080/api/employees/1/bar
----
ID: 1, name: bar
然而,在处理包含点(.
)字符的路径变量字符串时,处理多个 @PathVariable
参数时有一个小坑需要注意,细节参阅 这里。
5、可选择的路径变量 {#5可选择的路径变量}
在 Spring 中,默认情况下,使用 @PathVariable
注解的方法参数是必需的。
@GetMapping(value = { "/api/employeeswithrequired", "/api/employeeswithrequired/{id}" })
@ResponseBody
public String getEmployeesByIdWithRequired(@PathVariable String id) {
return "ID: " + id;
}
咋一看,上述 Controller 应该可以处理 /api/employeeswithrequired
和 /api/employeeswithrequired/1
请求。但是,由于 @PathVariables
所注解的方法参数默认为必选参数,因此它无法处理 /api/employeeswithrequired
请求:
http://localhost:8080/api/employeeswithrequired
----
{"timestamp":"2020-07-08T02:20:07.349+00:00","status":404,"error":"Not Found","message":"","path":"/api/employeeswithrequired"}
http://localhost:8080/api/employeeswithrequired/1
----
ID: 111
有两种不同的方法来处理这个问题。
5.1、设置 required 属性为 false {#51设置-required-属性为-false}
可以将 @PathVariable
的 required
属性设置为 false
,使其成为可选属性。这样,就可以处理带路径变量和不带路径变量的 URI 了:
@GetMapping(value = { "/api/employeeswithrequiredfalse", "/api/employeeswithrequiredfalse/{id}" })
@ResponseBody
public String getEmployeesByIdWithRequiredFalse(@PathVariable(required = false) String id) {
if (id != null) {
return "ID: " + id;
} else {
return "ID missing";
}
}
http://localhost:8080/api/employeeswithrequiredfalse
----
ID missing
5.2、使用 java.util.Optional {#52使用-javautiloptional}
从 Spring 4.1 开始,还可以使用 java.util.Optional<T>
(在 Java 8+ 中可用)来处理非必须的路径变量:
@GetMapping(value = { "/api/employeeswithoptional", "/api/employeeswithoptional/{id}" })
@ResponseBody
public String getEmployeesByIdWithOptional(@PathVariable Optional<String> id) {
if (id.isPresent()) {
return "ID: " + id.get();
} else {
return "ID missing";
}
}
现在,如果不在请求中指定路径变量 id
,就会得到默认响应:
http://localhost:8080/api/employeeswithoptional
----
ID missing
5.3、使用 Map<String, String>
类型的方法参数 {#53使用-mapstring-string-类型的方法参数}
如前所述,可以使用 java.util.Map
类型的单个方法参数来处理请求 URI 中的所有路径变量。
还可以使用这种策略来处理可选路径变量的情况:
@GetMapping(value = { "/api/employeeswithmap/{id}", "/api/employeeswithmap" })
@ResponseBody
public String getEmployeesByIdWithMap(@PathVariable Map<String, String> pathVarsMap) {
String id = pathVarsMap.get("id");
if (id != null) {
return "ID: " + id;
} else {
return "ID missing";
}
}
6、@PathVariable 默认值 {#6pathvariable-默认值}
在默认情况下,没有提供为使用 @PathVariable
注解的方法参数定义默认值的机制。然而,可以使用上面介绍的相同策略来满足 @PathVariable
的默认值情况,只需在路径变量上检查 null
值即可。
例如,可以使用 java.util.Optional<String>
来识别路径变量是否为 null
。如果是 null
值,就可以使用默认值来响应请求:
@GetMapping(value = { "/api/defaultemployeeswithoptional", "/api/defaultemployeeswithoptional/{id}" })
@ResponseBody
public String getDefaultEmployeesByIdWithOptional(@PathVariable Optional<String> id) {
if (id.isPresent()) {
return "ID: " + id.get();
} else {
return "ID: Default Employee";
}
}
7、总结 {#7总结}
本文介绍了如何使用 Spring 的 @PathVariable
注解来处理 URI 中的路径变量,以及如何处理可选参数和参数默认值的问题。
Ref:https://www.baeldung.com/spring-pathvariable