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() {
...
}
}
相关阅读推荐: