深圳幻海软件技术有限公司 欢迎您!

SpringMVC接口定义RequestMapping这些细节你用过吗?

2023-02-28

环境:Spring5.3.25概述你可以使用@RequestMapping注释将请求映射到控制器(controller)方法。它有各种属性,可以根据URL、HTTP方法、请求参数、头和媒体类型进行匹配。你可以在类级别使用它来表示共享映射,或者在方法级别使用它来缩小到特定的端点映射。还有HTTP方法特

环境:Spring5.3.25

概述

你可以使用@RequestMapping注释将请求映射到控制器(controller)方法。它有各种属性,可以根据URL、HTTP方法、请求参数、头和媒体类型进行匹配。你可以在类级别使用它来表示共享映射,或者在方法级别使用它来缩小到特定的端点映射。

还有HTTP方法特定的快捷方式变体@RequestMapping:

  • @GetMapping
  • @PostMapping
  • @PutMapping
  • @DeleteMapping
  • @PatchMapping

提供的快捷方式是自定义注释,因为大多数控制器方法应该映射到特定的HTTP方法,而不是使用@RequestMapping,默认情况下,匹配所有HTTP方法。在类级别上仍然需要@RequestMapping来表示共享映射,统一前缀。

下面的例子有类型级和方法级的映射:​

@RestController
@RequestMapping("/persons")
class PersonController {
  @GetMapping("/{id}")
  public Person getPerson(@PathVariable Long id) {
  // ...
  }
  @PostMapping
  @ResponseStatus(HttpStatus.CREATED)
  public void add(@RequestBody Person person) {
    // ...
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.

URI模式

@RequestMapping方法可以使用URL模式进行映射。有两种选择:

PathPattern - 一个与URL路径匹配的预解析模式,也被预解析为PathContainer。设计为web使用,该解决方案有效地处理编码和路径参数,并有效地匹配。

AntPathMatcher

PathPattern是web应用程序的推荐解决方案,也是Spring WebFlux中的唯一选择。在5.3版本之前,AntPathMatcher是Spring MVC中的唯一选择,并且一直是默认选项。然而,PathPattern可以在MVC配置中启用。

PathPattern支持与AntPathMatcher相同的模式语法。此外,它还支持捕获模式,例如{*spring},用于在路径的末尾匹配0个或多个路径段。PathPattern还限制使用**来匹配多个路径段,这样它只允许在模式的末尾使用。在为给定的请求选择最佳匹配模式时,这消除了许多不明确的情况。完整的模式语法请参考PathPattern和AntPathMatcher。

一些示例模式:

"/resources/ima?e.png" -匹配路径段中的一个字符

"/resources/*.png" -在路径段中匹配零个或多个字符

"/resources/**" -匹配多个路径段

"/projects/{project}/versions" -匹配路径段并将其作为变量捕获

"/projects/{project:[a-z]+}/versions" -用正则表达式匹配并捕获变量

获取的URI变量可以通过@PathVariable访问。例如:

@GetMapping("/owners/{ownerId}/pets/{petId}")
public Pet findPet(@PathVariable Long ownerId, @PathVariable Long petId) {
  // ...
}
  • 1.
  • 2.
  • 3.
  • 4.

你可以在类和方法级别声明URI变量,如下例所示:​

@Controller
// 类级别的应该用的非常少
@RequestMapping("/owners/{ownerId}")
public class OwnerController {
  @GetMapping("/pets/{petId}")
  public Pet findPet(@PathVariable Long ownerId, @PathVariable Long petId) {
    // ...
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.

URI变量会自动转换为适当的类型,或者引发TypeMismatchException异常。默认情况下支持简单类型(int、long、Date等),你也可以注册对任何其他数据类型的支持。请参阅类型转换和DataBinder。

你可以显式地命名URI变量(例如,@PathVariable("customId")),但是如果名称相同,并且你的代码是用调试信息或Java 8上的-parameters(用了该标记方法上的参数名称就被记录下来)编译器标记编译的,则可以省略该细节。

后缀匹配

从5.3开始,默认情况下Spring MVC不再执行.*后缀模式匹配,其中映射到/person的控制器也隐式映射到/person.*。因此,路径扩展不再用于解释响应所请求的内容类型——例如/person.pdf、/person.xml等等。

当浏览器用来发送难以一致解释的Accept头时,以这种方式使用文件扩展名是必要的。目前,这不再是必要的,使用Accept报头应该是首选。

随着时间的推移,文件扩展名的使用在许多方面都被证明是有问题的。当它与URI变量、路径参数和URI编码的使用重叠时,可能会导致歧义。关于基于url的授权和安全性的推理。

要在5.3之前的版本中完全禁用路径扩展的使用,请设置如下:

useSuffixPatternMatching(false),参见PathMatchConfigurer

favorpatheextension(false),参见ContentNegotiationConfigurer

通过“Accept”头以外的方式请求内容类型仍然是有用的,例如在浏览器中输入URL时。路径扩展的安全替代方法是使用查询参数策略。如果必须使用文件扩展名,请考虑通过ContentNegotiationConfigurer的mediaTypes属性将它们限制为显式注册的扩展名列表。

Consumer媒体类型

你可以根据请求的Content-Type缩小请求映射,示例如下:​

// 使用consumes属性按内容类型缩小映射范围
@PostMapping(path = "/pets", consumes = "application/json") 
public void addPet(@RequestBody Pet pet) {
  // ...
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

consume属性还支持否定表达式——例如,!text/plain表示除text/plain以外的任何内容类型。

你可以在类级别声明共享消费属性。然而,与大多数其他请求映射属性不同的是,当在类级使用时,方法级使用属性重写,而不是扩展类级声明。

MediaType为常用的媒体类型提供常量,例如APPLICATION_JSON_VALUE和APPLICATION_XML_VALUE。

Producer媒体类型

你可以根据Accept请求头和控制器方法产生的内容类型列表来缩小请求映射,如下面的例子所示:​

// 使用produces属性按内容类型缩小映射范围。
@GetMapping(path = "/pets/{petId}", produces = "application/json") 
@ResponseBody
public Pet getPet(@PathVariable String petId) {
  // ...
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

媒体类型可以指定字符集。支持非表达式——例如,!text/plain表示除“text/plain”之外的任何内容类型。

你可以在类级别声明一个共享的produces属性。然而,与大多数其他请求映射属性不同的是,当在类级使用时,方法级产生属性重写,而不是扩展类级声明。

请求参数与Header

可以根据请求参数条件缩小请求映射。你可以测试是否有请求参数(myParam),或者是否有特定的值(myParam=myValue)。下面的例子展示了如何测试一个特定的值:​

// 测试myParam是否等于myValue
@GetMapping(path = "/pets/{petId}", params = "myParam=myValue") 
public void findPet(@PathVariable String petId) {
  // ...
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

你也可以使用相同的请求头条件,如下面的例子所示:​

// 测试myHeader是否等于myValue
@GetMapping(path = "/pets", headers = "myHeader=myValue") 
public void findPet(@PathVariable String petId) {
  // ...
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

HTTP请求Method

@GetMapping(和@RequestMapping(method=HttpMethod.GET))对请求映射透明地支持HTTP HEAD。控制器方法不需要改变。应用于javax.servlet.http中的响应包装器。HttpServlet,确保Content-Length头被设置为写入的字节数(而不实际写入响应)。

@GetMapping(和@RequestMapping(method=HttpMethod.GET))隐式映射到并支持HTTP HEAD。处理HTTP HEAD请求时就像处理HTTP GET一样,不同的是,它不是写入正文,而是计算字节数,并设置Content-Length报头。

默认情况下,HTTP OPTIONS是通过将Allow响应头设置为所有具有匹配URL模式的@RequestMapping方法中列出的HTTP方法列表来处理的。

对于没有HTTP方法声明的@RequestMapping,允许头被设置为GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS。控制器方法应该始终声明支持的HTTP方法(例如,通过使用特定于HTTP方法的变量:@GetMapping、@PostMapping和其他)。

你可以显式地将@RequestMapping方法映射到HTTP HEAD和HTTP OPTIONS,但在一般情况下这是不必要的。

自定义注解

Spring MVC支持对请求映射使用组合注释。这些注释本身是用@RequestMapping进行元注释的,并且组合起来重新声明@RequestMapping属性的一个子集(或全部),目的更窄、更具体。

@GetMapping、@PostMapping、@PutMapping、@DeleteMapping和@PatchMapping是组合注释的例子。提供它们的原因是,大多数控制器方法都应该映射到特定的HTTP方法,而不是使用@RequestMapping,默认情况下,它匹配所有HTTP方法。如果需要一个组合注释的示例,请查看它们是如何声明的。

Spring MVC还支持使用自定义请求匹配逻辑的自定义请求映射属性。这是一个更高级的选项,需要子类化RequestMappingHandlerMapping并覆盖getCustomMethodCondition方法,在该方法中你可以检查自定义属性并返回自己的RequestCondition。

显示的注册

你可以以编程方式注册处理程序方法,可以将其用于动态注册或高级情况,例如不同url下相同处理程序的不同实例。下面的例子注册了一个处理器方法:​

@Configuration
public class MyConfig {

  @Autowired
  public void setHandlerMapping(RequestMappingHandlerMapping mapping, UserHandler handler) throws NoSuchMethodException {
    RequestMappingInfo info = RequestMappingInfo.paths("/user/{id}").methods(RequestMethod.GET).build(); 
    // 指定接口处理的方法
    Method method = UserHandler.class.getMethod("getUser", Long.class); 
    mapping.registerMapping(info, handler, method); 
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.

完毕!!!