Spring Boot - 控制器请求映射
# Spring Boot 控制器请求映射
笔记
因为需要多个 URL 能同时映射进入一个方法(一个 RequstMapping
),所以学习了 Spring Boot 的 Controller 映射请求方式
# 1. @RequestMapping 基础概念
Spring 4.3 版本引入了一系列注解,包括 @GetMapping
、@PostMapping
、@PutMapping
、@DeleteMapping
、@PatchMapping
等,用于简化HTTP请求方法的映射工作,并更好地表达被注解方法的语义。
这些注解根据命名约定可以看出,每个注解都负责处理特定的HTTP请求方法类型:
@GetMapping
专门处理GET请求@PostMapping
专门处理POST请求- 等等
@RequestMapping
注解可以应用在两个层级:
- 控制器类级别 - 定义共同的路径前缀
- 方法级别 - 定义具体的请求路径
/**
* 示例控制器
* 类级别的@RequestMapping定义路径前缀为/home
*/
@RestController
@RequestMapping("/home") // 定义基础路径前缀
public class IndexController {
/**
* 处理根路径请求
* 完整请求路径: hostname:port/home/
*/
@RequestMapping("/")
String get() {
return "Hello from get";
}
/**
* 处理index路径请求
* 完整请求路径: hostname:port/home/index/
*/
@RequestMapping("/index")
String index() {
return "Hello from index";
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
请求映射的执行流程:
- 首先匹配类级别的
@RequestMapping
- 然后进入类内部,匹配方法级别的
@RequestMapping
- 两级路径组合形成完整的请求路径
# 2. URL 映射配置方式
# 2.1 映射单个URL
// 以下两种方式效果相同
@RequestMapping("/users")
@RequestMapping(value = "/users")
2
3
# 2.2 映射多个URL
// 以下两种方式效果相同
@RequestMapping({"/users", "/members"})
@RequestMapping(value = {"/users", "/members"})
2
3
# 2.3 路径斜杠说明
路径开头是否添加斜杠("/")都可以,但建议统一添加以保持一致性。例如:
@RequestMapping("")
与@RequestMapping("/")
效果相同,都表示根路径- 使用
/
开头可以使路径更加明确,避免混淆
# 3. 五种URL映射方式
@RequestMapping
提供了五种不同的映射方式,以满足各种需求:
# 3.1 标准映射
标准URL映射是最直接、最简单的映射方式。
/**
* 标准映射示例
* 映射到单个确定的URL
*/
@RequestMapping("/hello")
/**
* 多个确定URL的标准映射
* 同时处理两个不同的URL
*/
@RequestMapping({"/hello", "/world/test"})
2
3
4
5
6
7
8
9
10
11
# 3.2 Ant风格映射
Ant风格使用通配符来灵活匹配URL。三种通配符的含义:
?
: 匹配当前目录下的任何单个字符*
: 匹配当前目录下的任意数量字符(包括0个)**
: 匹配任意数量的目录(包括0个)
解释: 当前目录指的是由两个 /
分隔的部分,例如 /xx/
中的 xx
是一个目录。
/**
* 匹配 /a/hello/, /b/hello/, /c/hello/ 等
* ? 只匹配单个字符
*/
@RequestMapping("/?/hello/")
/**
* 匹配 /any/hello, /anything/hello 等
* * 可匹配任意字符
*/
@RequestMapping("/*/hello")
/**
* 匹配 /hello, /any/hello, /any/path/hello 等
* ** 可匹配包括0个在内的任意级目录
*/
@RequestMapping("/**/hello")
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 3.3 占位符映射
通过 {}
定义路径变量,实现动态URL的处理。
/**
* 用户信息查询接口
* {userId}是路径变量,将自动映射到方法参数中
*/
@RequestMapping("/user/{userId}/show")
public User show(@PathVariable("userId") Long userId) {
// 根据userId查询用户
User user = userService.getById(userId);
return user;
}
2
3
4
5
6
7
8
9
10
特别说明:
- 当URL中的占位符值为纯数字时,可以根据需要选择接收类型(Long、Integer、String等)
@PathVariable("参数名")
不能简写为@PathVariable
,必须指定参数名
# 3.4 请求方法限制
限制接口只能通过特定的HTTP方法访问。
/**
* 只接受POST方法的请求
*/
@RequestMapping(value="/hello", method=RequestMethod.POST)
/**
* 同时接受GET和POST方法的请求
*/
@RequestMapping(value="/hello", method={RequestMethod.GET, RequestMethod.POST})
2
3
4
5
6
7
8
9
# 3.5 请求参数限制
通过params属性限制请求参数。
/**
* 以下示例要求请求必须包含userId参数
*/
@RequestMapping(value="/user", params="userId")
/**
* 以下示例要求请求不能包含userId参数
*/
@RequestMapping(value="/user", params="!userId")
/**
* 以下示例要求请求必须包含userId参数且值不能为1
*/
@RequestMapping(value="/user", params="userId!=1")
/**
* 以下示例要求请求必须同时包含userId和userName两个参数
*/
@RequestMapping(value="/user", params={"userId", "userName"})
/**
* 以下示例要求请求必须包含userId和userName参数,
* 且userId值必须为1,userName值不能为2
*/
@RequestMapping(value="/user", params={"userId=1", "userName!=2"})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 4. 处理多个URL映射到同一方法
可以将多个不同的请求路径映射到同一个处理方法,增强代码复用性。
/**
* 多URL映射示例
* 以下URL均会映射到该方法:
* - localhost:8080/home
* - localhost:8080/home/
* - localhost:8080/home/page
* - localhost:8080/home/pageabc (通配符匹配)
* - localhost:8080/home/view/ (目录通配符匹配)
* - localhost:8080/home/view/view
* - 任何以/msg结尾的路径,如/home/a/b/msg
*/
@RestController
@RequestMapping("/home")
public class IndexController {
@RequestMapping(value = {"", "/page", "page*", "view/*", "**/msg"})
String indexMultipleMapping() {
return "Hello from index multiple mapping.";
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
此示例中,各种URL模式说明:
""
- 匹配基础路径/home
"/page"
- 匹配/home/page
"page*"
- 匹配所有以page开头的路径,如/home/pageabc
"view/*"
- 匹配 view目录下的任何路径,如/home/view/anything
"**/msg"
- 匹配任何以msg结尾的路径,无论目录层级多深
# 5. 处理请求内容类型与响应格式
通过produces
和consumes
属性控制请求和响应的媒体类型。
/**
* 媒体类型控制示例控制器
*/
@RestController
@RequestMapping("/home")
public class IndexController {
/**
* 指定响应类型为JSON
* 方法将只处理Accept头为application/JSON的请求
*/
@RequestMapping(value = "/prod", produces = {"application/JSON"})
@ResponseBody
String getProduces() {
return "Produces attribute";
}
/**
* 指定接收的请求体类型
* 方法将只处理Content-Type为application/JSON或application/XML的请求
*/
@RequestMapping(value = "/cons", consumes = {"application/JSON", "application/XML"})
String getConsumes() {
return "Consumes attribute";
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
说明:
produces
- 指定响应的内容类型,对应HTTP响应的Content-Typeconsumes
- 指定接收的请求内容类型,对应HTTP请求的Content-Type- 这些属性可以限制请求的匹配范围,实现更精确的API控制
# 6. 处理HTTP请求头
利用headers
属性根据请求头内容筛选请求。
/**
* 请求头控制示例
*/
@RestController
@RequestMapping("/home")
public class IndexController {
/**
* 只处理Content-Type为text/plain的请求
*/
@RequestMapping(value = "/head", headers = {"content-type=text/plain"})
String post() {
return "Mapping applied along with headers";
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
多请求头处理示例:
/**
* 处理多种内容类型的请求头
* 同时接受Content-Type为text/plain或text/html的请求
*/
@RestController
@RequestMapping("/home")
public class IndexController {
@RequestMapping(value = "/head", headers = {"content-type=text/plain", "content-type=text/html"})
String post() {
return "Mapping applied along with headers";
}
}
2
3
4
5
6
7
8
9
10
11
12
# 7. 处理请求参数的高级用法
使用params
元素可以让同一个URL路径根据不同的请求参数匹配到不同的处理方法。
/**
* 基于请求参数值的路由控制
*/
@RestController
@RequestMapping("/home")
public class IndexController {
/**
* 处理personId=10的请求
* 例如: /home/fetch?personId=10
*/
@RequestMapping(value = "/fetch", params = {"personId=10"})
String getParams(@RequestParam("personId") String id) {
return "Fetched parameter using params attribute = " + id;
}
/**
* 处理personId=20的请求
* 例如: /home/fetch?personId=20
*/
@RequestMapping(value = "/fetch", params = {"personId=20"})
String getParamsDifferent(@RequestParam("personId") String id) {
return "Fetched parameter using params attribute = " + id;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
实际应用说明:
- 同一URL路径
/home/fetch
可以根据参数值不同映射到不同的处理方法 - 当访问
/home/fetch?personId=10
时,会执行getParams()
方法 - 当访问
/home/fetch?personId=20
时,会执行getParamsDifferent()
方法 - 这种方式可以实现基于参数值的复杂路由逻辑
# 8. 处理动态URI与正则表达式匹配
结合@PathVariable
注解处理动态URI,还可以使用正则表达式进行路径匹配。
/**
* 动态URI与正则表达式匹配示例
*/
@RestController
@RequestMapping("/home")
public class IndexController {
/**
* 处理动态id路径参数
* 例如: /home/fetch/123
*/
@RequestMapping(value = "/fetch/{id}", method = RequestMethod.GET)
String getDynamicUriValue(@PathVariable String id) {
System.out.println("ID is " + id); // 日志输出获取的ID值
return "Dynamic URI parameter fetched";
}
/**
* 使用正则表达式限制路径参数格式
* id必须是小写字母,name可以是任意字符
* 例如: /home/fetch/abc/shirt
*/
@RequestMapping(value = "/fetch/{id:[a-z]+}/{name}", method = RequestMethod.GET)
String getDynamicUriValueRegex(@PathVariable("name") String name) {
System.out.println("Name is " + name); // 日志输出获取的name值
return "Dynamic URI parameter fetched using regex";
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
重要区别说明:
@PathVariable
用于从URI路径中提取变量值@RequestParam
用于从查询参数中提取值- 正则表达式
{id:[a-z]+}
限制了id参数只能包含小写字母 - 当访问
/home/fetch/10/shirt
时会抛出异常,因为10
不符合[a-z]+
正则表达式
# 9. 默认请求处理方法
在控制器中可以定义一个默认处理方法,处理向基础URI发起的请求。
/**
* 默认处理方法示例
*/
@RestController
@RequestMapping("/home")
public class IndexController {
/**
* 默认处理方法,没有指定具体路径
* 处理对/home的请求
*/
@RequestMapping()
String defaultMethod() { // 方法名修正为有效的Java标识符
return "This is a default method for the class";
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
说明:
- 当
@RequestMapping
没有指定任何值时,它会处理控制器基础路径的请求 - 上例中,向
/home
发起的请求将由defaultMethod()
方法处理 - 这种方式可以为API提供默认的行为或响应
# 10. 请求映射简化注解
Spring 4.3引入了一系列组合注解,简化了请求映射的配置。这些注解是@RequestMapping
的特定变体:
@GetMapping
- 等价于@RequestMapping(method = RequestMethod.GET)
@PostMapping
- 等价于@RequestMapping(method = RequestMethod.POST)
@PutMapping
- 等价于@RequestMapping(method = RequestMethod.PUT)
@DeleteMapping
- 等价于@RequestMapping(method = RequestMethod.DELETE)
@PatchMapping
- 等价于@RequestMapping(method = RequestMethod.PATCH)
/**
* 组合注解实战示例
*/
@RestController
@RequestMapping("/home")
public class IndexController {
/**
* GET请求处理 - 获取人员列表
*/
@GetMapping("/person")
public @ResponseBody ResponseEntity<String> getPerson() {
return new ResponseEntity<String>("Response from GET", HttpStatus.OK);
}
/**
* GET请求处理 - 获取特定ID的人员
*/
@GetMapping("/person/{id}")
public @ResponseBody ResponseEntity<String> getPersonById(@PathVariable String id) {
return new ResponseEntity<String>("Response from GET with id " + id, HttpStatus.OK);
}
/**
* POST请求处理 - 创建人员
*/
@PostMapping("/person")
public @ResponseBody ResponseEntity<String> postPerson() {
return new ResponseEntity<String>("Response from POST method", HttpStatus.OK);
}
/**
* PUT请求处理 - 更新人员
*/
@PutMapping("/person")
public @ResponseBody ResponseEntity<String> putPerson() {
return new ResponseEntity<String>("Response from PUT method", HttpStatus.OK);
}
/**
* DELETE请求处理 - 删除人员
*/
@DeleteMapping("/person")
public @ResponseBody ResponseEntity<String> deletePerson() {
return new ResponseEntity<String>("Response from DELETE method", HttpStatus.OK);
}
/**
* PATCH请求处理 - 部分更新人员
*/
@PatchMapping("/person")
public @ResponseBody ResponseEntity<String> patchPerson() {
return new ResponseEntity<String>("Response from PATCH method", HttpStatus.OK);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
使用组合注解的优势:
- 代码更简洁、更具可读性
- 明确表达了处理方法的意图和HTTP方法语义
- 减少了应用程序的配置元数据
- 符合RESTful API设计规范和最佳实践
# 11. 请求参数接收
针对不同的请求方式如何接收参数,请参考 Spring Boot - 请求参数接收 专题文档。