RequestMapping
RequestMapping
在 AndServer 是扮演的角色非常重要,它可以规定一个 HTTP API 请求路径、请求方法、参数校验、请求头校验、Accept、ContentType 等重要规则。
RequestMapping
的变体有GetMapping
、PostMapping
、PutMapping
、PatchMapping
、DeleteMapping
,GetMapping
表示仅支持GET
请求、PostMapping
表示只支持POST
请求,以此类推,下文将统称为RequestMapping
。
RequestMapping
既可以用在类上,也可以用在方法上。当它仅仅用在类上时没有任何作用,当使用它的类中有方法也使用了它时,相当于把用在类上的RequestMapping
的参数合并在方法的RequestMapping
上。
使用
RequestMapping
注解的方法,其所在的类必须使用Controller注解或者RestController注解才能生效,否则是无意义的。
文本目录:
path 示例
@RestController
public class UserController {
@GetMapping("/user/info")
void info() {
...
}
@PostMapping("/user/register")
void register() {
...
}
}
假设服务器的 IP 地址是192.168.1.11
,监听的端口是8080
,上述示例的访问地址则是:http://192.168.1.11:8080/user/info
和http://192.168.1.11:8080/user/register
。
如上所示,一个Controller
中一般会写多个属于同一个模块的 HTTP API,则每个 HTTP API 的路径都会以/user
开头,这样会显得很麻烦,因此我们可以在类上添加RequestMapping
来简化它:
@RequestMapping("/user")
@RestController
public class UserController {
@GetMapping("/info")
void info() {
...
}
@PostMapping("/register")
void register() {
...
}
}
以上两个示例是等价的。
另外同一个方法可以拥有多个path
:
@RestController
public class UserController {
@PostMapping(path = {"/user/register", "/user/create"})
void register() {
...
}
}
或者:
@RequestMapping("/user")
@RestController
public class UserController {
@PostMapping(path = {"/register", "/create"})
void register() {
...
}
}
如果客户端请求的地址在服务器上不存在,将会抛出
NotFoundException
异常,异常处理请参考ExceptionResolver。
method 示例
除了使用PostMapping
这样明确请求方法的注解之外,还可以使用RequestMapping
指定请求方法,而且可以支持一个 HTTP API 支持多种请求方法:
@RestController
public class UserController {
@RequestMapping(path = "/info"
method = RequestMethod.GET)
void info() {
...
}
@RequestMapping(path = "/register"
method = {RequestMethod.GET, RequestMethod.POST})
void register() {
...
}
}
也可以由方法所在的类来指定它的请求方法是什么:
@RequestMapping(method = RequestMethod.GET)
@RestController
public class UserController {
@RequestMapping(path = "/info")
void info() {
...
}
@RequestMapping(path = "/register")
void register() {
...
}
@DeleteMapping("/delete")
void delete() {
...
}
}
如上示例,前两个方法没有指定请求方法,但是由它们所在的类指定了它们的请求方法是GET
,第三个方法同事支持GET
请求方法和DELETE
请求方法。
如果客户端请求的地址不支持客户端使用的请求方法,将会抛出
MethodNotSupportException
异常,异常处理请参考ExceptionResolver。
param 示例
为了方便展开说明,我们先看一段示例:
@RestController
public class UserController {
@GetMapping(path = "/info", param = "name=123")
void info() {
...
}
}
示例中的代码中param="name=123"
是param
的其中一个语法,param
有四种语法:
key=value
,规定了某 key 必须等于某 value,例如:param = "name=123"
。key!=value
,规定了某 key 必须不等于某 value,例如:param = "name!=123"
。key
,规定了参数中必须有某 key,且值不能为空,例如:param = "name"
。!key
,规定了参数中必须不能由某 key,例如:param = "!name"
。
上述语法是可以混合使用的:
@RestController
public class UserController {
@GetMapping(path = "/info", param = {"name!=123", "password"})
void info() {
...
}
}
上述示例中,param
的含义是不能包含name=123
这一参数键值对,但是必须包含password
参数。
如果客户端的请求违反约束,则会抛出
ParamValidateException
异常,异常处理请参考ExceptionResolver。
header 示例
header
的使用方法和param
完全一致,只是它用来规定请求头,而param
用来规定请求参数。
如果客户端的请求违反约束,则会抛出
HeaderValidateException
异常,异常处理请参考ExceptionResolver。
consume 示例
Consume 单词的字面意思是消耗、消费,在转换到程序中来就是说:你能消费什么?你能处理什么?因此它适合用于校验客户端的Content-Type
头,Contnet-Type 的意思是内容类型,因此consume
的含义就是能消费什么内容了。
consume
的语法有两种:
application/json
,规定了客户端提交的Content-Type
须是 JSON 格式。!applicatioln/xml
,规定了客户端提交的Content-Type
不能是 XML 格式。
同时它支持*
,例如application/*
则支持客户端提交application/json
和application/zip
等类型数据,例如!text/*
则不支持客户端提交text/plain
和text/xml
等类型数据。
示例:
@RestController
public class UserController {
@PostMapping(path = "/info", consume = "application/json")
void info() {
...
}
@PostMapping(path = "/create", consume = {"!text/*", "!application/xml"})
void create() {
...
}
}
上述示例中,第一个方法表示客户端请求时的Content-Type
只能是application/json
,比如客户端是application/json; charset=utf-8
也是允许通过的;第二个示例表示客户端请求时Content-Type
不能是text/plain
、text/xml
和text/css
等,也不能是application/xml
。
如果客户端的请求违反约束,则会抛出
ContentNotSupportedException
异常,异常处理请参考ExceptionResolver。
produce 示例
produce
的语法和consume
完全一致,只是它用来规定客户端的Accept
头,而consume
用来规定客户端的Content-Type
头。
与consume
不同的是,它在服务端不支持*
,但是它支持客户端的*
。因为对于Content-Type
来说,客户端上行或者服务端下行时内容类型都是明确的,因此服务端校验Content-Type
时可以用非明确的值去做包含。而对于Accept
,因为不知道服务端下发的Content-Type
,所以客户端可以用非明确的值做包含,因此客户端的Accept
值有可能是*/*
。
例如,规定客户端能接受 JSON:
@RestController
public class UserController {
@PostMapping(path = "/info", produce = "application/json")
String info() {
...
}
}
上述示例中,如果客户端的Accept
是*/*
或者application/json
就可以校验通过。
例如,规定能接受 JSON 的客户端校验不通过:
@RestController
public class UserController {
@PostMapping(path = "/info", produce = "!application/json")
String info() {
...
}
}
上述示例中,如果客户端的Accept
是*/*
或者application/json
是不能通过校验的。
如果客户端的请求违反约束,则会抛出
ContentNotAcceptableException
异常,异常处理请参考ExceptionResolver。
特别注意,produce
的值会作为服务端响应消息的Content-Type
发送到客户端。
如下所示,produce
不会作为Content-Type
被发送客户端:
@RestController
public class UserController {
@PostMapping(path = "/info", produce = "!application/json")
String info() {
...
}
}
如下所示,produce
会作为Content-Type
被发送客户端:
@RestController
public class UserController {
@PostMapping(path = "/info", produce = "application/json; charset=utf-8")
String info() {
...
}
}
相关阅读推荐: