【Spring MVC】@RequestMapping 详解
@RequestMapping 注解一共有 8 个属性,常用的有 value 属性、method 属性,其它 6 个属性往往容易被忽视,因此本文将逐一介绍这 8 个属性的作用及用法
示例代码依赖版本如下 Spring Boot:3.0.0-SNAPSHOT Spring MVC:6.0.0-SNAPSHOT server.port=8181
1.源代码
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
@Reflective({ControllerMappingReflectiveProcessor.class})
public @interface RequestMapping {
String name() default "";
@AliasFor("path")
String[] value() default {};
@AliasFor("value")
String[] path() default {};
RequestMethod[] method() default {};
String[] params() default {};
String[] headers() default {};
String[] consumes() default {};
String[] produces() default {};
}以下按照源码中属性的顺序介绍(value 最重要,先介绍 value 属性)
2.value 属性
@GetMapping("/value")
public String demoValue() {
return "value";
}访问 http://127.0.0.1:8181/value 即可执行方法
@GetMapping(value = {"/foo", "/bar"})
public String demoValue() {
return "value";
}访问 http://127.0.0.1:8181/foo 或 http://127.0.0.1:8181/bar 均执行该方法
3.path 属性
作用同 value,path、value 可同时使用(不推荐),但是值必须一致 反例(两者值不相同):
@GetMapping(value = "/path", path = "/path2")
public String demoPath() {
return "path";
}运行报错
Different @AliasFor mirror values for annotation [org.springframework.web.bind.annotation.GetMapping] declared on com.example.springbootssl.controller.TestController.demoPath1(); attribute ‘path’ and its alias ‘value’ are declared with values of [{/path2}] and [{/path}].
4.name 属性
@GetMapping(value = "/name", name = "name属性演示")
public String demoName() {
return "name";
}相当于方法的注释,无实际作用
5.method 属性
用于设置 HTTP 请求方法,如 GET、POST、PUT、DELETE 等,类型为 RequestMethod 枚举类数组
public enum RequestMethod {
GET,
HEAD,
POST,
PUT,
PATCH,
DELETE,
OPTIONS,
TRACE;
private RequestMethod() {
}
}示例代码
@RequestMapping(value = "/method", method = RequestMethod.GET)
public String demoMethod() {
return "method";
}该方法需要通过 GET 请求来调用,在 Spring4.3 后可以使用@GetMapping、@PostMapping 之类的注解简化编码
@GetMapping("/method")
public String demoMethod() {
return "method";
}@RequestMapping 替换成@GetMapping,method 属性直接不用写,两者是等价的,但后者更简洁
也可以让方法同时支持多种请求、如同时支持 GET 和 POST,这种情况就无法使用简化的注解了
@RequestMapping(value = "/method", method = {RequestMethod.GET, RequestMethod.POST})
public String demoMethod() {
return "method";
}6.params 属性
请求参数包含指定的 key 和 value 时,才能执行请求
@GetMapping(value = "/params", params = "par=foo")
public String demoParams(@RequestParam String par) {
System.out.println("par = " + par);
return "params";
}请求参数 par 的值必须为 foo 时才可执行该方法 若访问 http://127.0.0.1:8181/params?par=bar 则 HTTP 状态码为 400,异常信息如下:
Resolved [org.springframework.web.bind.UnsatisfiedServletRequestParameterException: Parameter conditions “par=foo” not met for actual request parameters: par={bar}]
若指定多个参数,则用 String 数组的形式
@GetMapping(value = "/params", params = {"par=foo", "par2=bar"})
public String demoParams(@RequestParam String par, @RequestParam String par2) {
// ...
}必须同时满足条件,即 par=foo,par2=bar 才执行请求
7.headers 属性
和 params 的作用十分相似,请求头包含指定的 key 和 value 时,才能执行请求
@GetMapping(value = "/headers", headers = "X-key=foobar")
public String demoHeaders() {
return "headers";
}此时请求头必须含有 X-key 且值为 foobar 才能执行请求 使用工具手动添加 header 发送请求,调用成功
要注意的是,若不符合条件返回 HTTP 状态码是 404 而不是 400
8.consumes 属性
当请求提交的内容 MIME 类型和 consumes 指定的一致时,才执行方法,否则返回 415 状态码(Unsupported Media Type)
示例代码
@PostMapping(value = "/consumes", consumes = "application/json")
public Map<String, Object> demoConsumes(@RequestBody Map<String, Object> map) {
return map;
}上述代码只有提交内容为 MIME 类型为 application/json 时,才执行方法,也就是说请求头中的 Content-Type 是由客户端决定的,假设为 application/json,但客户端实际传的是 xml 格式的数据,此时由于 consumes 属性为 application/json,两者类型不统一,因此不执行方法

反例(传入数据的 MIME 类型和指定的不一致):
@PostMapping(value = "/consumes", consumes = "application/xml")
public Map<String, Object> demoConsumes(@RequestBody Map<String, Object> map) {
return map;
}这时 body 必须传 xml 格式的才会被处理。故意传 json 格式的数据,将报如下错
此时 HTTP 状态码为 415,也就是 Unsupported Media Type
正确使用:传入 xml 格式的数据 在此之前,需要先搞清楚 Spring
MVC 接收 xml 格式数据的方法,因为大部分都是接收 JSON 格式的 body,直接使用@RequestBody 即可,而 xml 也是使用该注解,但需要额外引入一个依赖,让 Jackson 支持 xml 解析
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
调用成功,传入 xml 数据,返回 json 数据
9.produces 属性
作用是指定响应头中 Content-Type 的值 简单说就是指定返回数据的 MIME 类型,且仅当请求头中的 Accept 包含该指定类型才返回(否则返回
406 状态码 Not Acceptable)
因此,客户端需要什么类型的数据,通过 Accept 请求头就能指定,Accept 为 image/*
,那么服务端就必须返回图片类型的数据,若 Accept 为 * / *,则服务端可以返回任意 MIME 类型的数据了。
@GetMapping(value = "/produces", produces = "application/xml")
public Map<String, Object> demoProduces() {
Map<String, Object> map = new LinkedHashMap<>(3);
map.put("name", "zhangsan");
map.put("sex", "male");
map.put("age", 18);
return map;
}produces 为 application/xml,返回 xml 格式的数据
<Map>
<name>zhangsan</name>
<sex>male</sex>
<age>18</age>
</Map>produces 为 application/json,返回 json 格式的数据
{
"name": "zhangsan",
"sex": "male",
"age": 18
}produces 并非指定什么 MIME 类型,就返回什么 MIME 类型的数据,直接返回传入的 xml 格式数据,而 produces =
“application/pdf”,显然是不合理的,会报以下错误:
No converter for [class …] with preset Content-Type ‘null’]