解决
如果我们遇到的问题相同,那你看完这段代码就可以知道解决方法。
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/user")
public class UserController {
@GetMapping(path = {"/{userId}", "/"})
public void user(@PathVariable(value = "userId", required = false) String uid) {
if (uid == null) {
uid = "默认的id值";
}
String id = uid; // 获取到值
// do something.
}
}
核心的两步:
@RequestMapping
注解的path
属性值可以是字符串数组,即多个URL模式。
@PathVariable
注解的required
属性表示该路由变量是否是必须的,需要设置为false
。
Intro
首先,依赖详情:org.springframework.spring-web:5.3.4
注解路径:org.springframework.web.bind.annotation.PathVariable
其次:HTTP 客户端向服务端传递参数的4种方式 SpringMVC的对应接收方式
设计RESTful风格的API如下
get /api/user/{userId}
get /api/user/1001
表示获取id为1001的用户信息
get /api/user/1003
表示获取id为1003的用户信息
get /api/user/1004
表示获取id为1004的用户信息
如果接口的调用方(前段/或其他消费端)未传入userId,能否在服务的提供段设置默认值?即:
get /api/user
后台会获取一个默认的用户信息(如id为1000的用户信息)
可以。
解决
- V1
@RequestMapping(path = "/api/user/{userId}")
public void user(@PathVariable(value = "userId") String uid) {
String id = uid; // 获取到值
// do something.
}
V1的缺点是: 只能处理 /api/user/xxx
这样的请求,而对于/api/user
这样的请求,他根本不处理(非己之责)
- V2
@RequestMapping(path = {"/api/user/{userId}", "/api/user"})
public void user(@PathVariable(value = "userId", required = false) String uid) {
if (uid == null) {
uid = "默认的id值";
}
String id = uid; // 获取到值
// do something.
}
首先,@RequestMapping
注解的path
属性是这样定义的:
@AliasFor("value")
String[] path() default {};
即可以设置请求映射规则为对多个path值进行拦截处理。
只改path还不够。
还需要修改@PathVariable
的required
属性为false
。
这样即使不传入这个路由变量。也可以被该方法拦截。
- V3
通常,在Controller类上使用注解@RequestMapping
指定基本路径,
而对于该控制器中的具体方法,可以使用以下几种指定了请求方法的、带有请求映射功能的注解去标记。
@PostMapping 增
@DeleteMapping 删
@PutMapping 改
@GetMapping 查
@PatchMapping 部分字段修改
修改后:
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/user")
public class UserController {
@GetMapping(path = {"/{userId}", "/"})
public void user(@PathVariable(value = "userId", required = false) String uid) {
if (uid == null) {
uid = "默认的id值";
}
String id = uid; // 获取到值
// do something.
}
}
这样,当请求格式为get /api/user/xxx
或/api/user
时,都会进入该方法,执行一套逻辑。
相当于设置了路由变量{userId}
的默认值。
思考
对处于路由路径path末端的路由单节路由变量可设置默认值,
那么对于路由路径path中,中间部分的某节路由变量,能否也设置默认值?
@RequestMapping(path = {"/api/user/{userId}/profile", "/api/user/profile"})
public void profile(@PathVariable(value = "userId", required = false) String uid) {
System.out.println("拿到的路由变量:" + uid);
if (uid == null) {
uid = "默认的id值";
}
String id = uid;
}
经测试可以。
get /api/user/id2002/profile
可以返回userId为id2002的用户profile。
get /api/user/profile
也可以返回一个userId为所设置默认值的用户profile。
源码
package org.springframework.web.bind.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
/**
* Annotation which indicates that a method parameter should be bound to a URI template
* variable. Supported for {@link RequestMapping} annotated handler methods.
*
* <p>If the method parameter is {@link java.util.Map Map<String, String>}
* then the map is populated with all path variable names and values.
*
* @author Arjen Poutsma
* @author Juergen Hoeller
* @since 3.0
* @see RequestMapping
* @see org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
*/
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PathVariable {
/**
* Alias for {@link #name}.
*/
@AliasFor("name")
String value() default "";
/**
* The name of the path variable to bind to.
* @since 4.3.3
*/
@AliasFor("value")
String name() default "";
/**
* Whether the path variable is required.
* <p>Defaults to {@code true}, leading to an exception being thrown if the path
* variable is missing in the incoming request. Switch this to {@code false} if
* you prefer a {@code null} or Java 8 {@code java.util.Optional} in this case.
* e.g. on a {@code ModelAttribute} method which serves for different requests.
* @since 4.3.3
*/
boolean required() default true;
}
可以看到@PathVariable
注解有三个属性值,其中name
和value
互为同义词/别名。
required
就是我们利用到的属性。