Spring Web MVC 1.3. Annotated Controllers


https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-ann-controller

1.3.1. Declaration

您可以通过在Servlet的WebApplicationContext中使用标准Spring bean定义来定义controller bean

@Controller原型允许自动检测,与Spring的通用支持一致,它可以检测类路径中的@Component类,并为它们自动注册bean定义。它还充当带注释类的原型,指示其作为web组件的角色。

要启用自动检测此类@Controller bean,可以将组件扫描添加到Java配置中,如下例所示:

@Configuration
@ComponentScan("org.example.web")
public class WebConfig {

    // ...
}

AOP Proxies

在某些情况下,您可能需要在运行时使用AOP代理来装饰控制器。一个例子是,如果您选择在控制器上直接使用@Transactional注释。在这种情况下,特别是对于控制器,我们建议使用基于类的代理。这通常是控制器的默认选择。

1.3.2. Request Mapping

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

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

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

URI patterns

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

  • PathPattern?—?与URL路径匹配的预解析模式也预解析为PathContainer。该解决方案专为web使用而设计,可以有效地处理编码和路径参数,并进行高效匹配。
  • AntPathMatcher?—?根据字符串路径匹配字符串模式。这是Spring配置中用于选择类路径、文件系统和其他位置上的资源的原始解决方案。它的效率较低,而且字符串路径输入对于有效处理URL的编码和其他问题是一个挑战。

 一些示例模式(patterns):

  • "/resources/ima?e.png" - match one character in a path segment
  • "/resources/*.png" - match zero or more characters in a path segment
  • "/resources/**" - match multiple path segments
  • "/projects/{project}/versions" - match a path segment and capture it as a variable
  • "/projects/{project:[a-z]+}/versions" - match and capture a variable with a regex

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

@GetMapping("/owners/{ownerId}/pets/{petId}")
public Pet findPet(@PathVariable Long ownerId, @PathVariable Long petId) {
    // ...
}

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

@Controller
@RequestMapping("/owners/{ownerId}")
public class OwnerController {

    @GetMapping("/pets/{petId}")
    public Pet findPet(@PathVariable Long ownerId, @PathVariable Long petId) {
        // ...
    }
}

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

您可以显式地命名URI变量(例如@PathVariable("customId")),但如果名称相同,并且您的代码是使用调试信息或Java 8上的-parameters编译器标志编译的,则可以省略该细节。

Parameters, headers

可以根据请求参数条件缩小请求映射范围。您可以测试是否存在请求参数(myParam)、是否没有(!myParam)或是否存在特定值(myParam=myValue)。以下示例显示了如何测试特定值:

@GetMapping(path = "/pets/{petId}", params = "myParam=myValue") 
public void findPet(@PathVariable String petId) {
    // ...
}

您也可以将其用于请求头条件,如下例所示:

@GetMapping(path = "/pets", headers = "myHeader=myValue") 
public void findPet(@PathVariable String petId) {
    // ...
}

1.3.3. Handler Methods

@RequestMapping处理程序方法具有灵活的签名,可以从一系列受支持的控制器方法参数和返回值中进行选择。

Method Arguments

下表描述了受支持的控制器方法参数。

Type Conversion

一些表示基于字符串的请求输入的带注释控制器方法参数(例如@RequestParam、@RequestHeader、@PathVariable、@MatrixVariable和@CookieValue)如果被声明为字符串以外的内容,则可能需要进行类型转换。

在这种情况下,类型转换会根据配置的转换器自动应用。默认情况下,支持简单类型(int、long、Date等)。您可以通过WebDataBinder(请参阅DataBinder或通过向FormattingConversionService注册格式化程序来自定义类型转换。请参见Spring字段格式

类型转换中的一个实际问题是空字符串源值的处理。如果由于类型转换而变为null,则此类值将被视为缺失。对于Long、UUID和其他目标类型,情况可能就是这样。如果希望允许注入null,可以在参数注释上使用required标志,或者将参数声明为@Nullable

Matrix Variables

RFC 3986讨论了路径段中的名称-值对(name-value pairs)。在Spring MVC中,我们根据Tim Berners Lee的“旧帖子”将它们称为“矩阵变量”,但它们也可以称为URI路径参数。

@RequestParam

可以使用@RequestParam注释将Servlet请求参数(即查询参数或表单数据)绑定到控制器中的方法参数

默认情况下,使用此注释的方法参数是必需的,但您可以通过将@RequestParam注释的required标志设置为false或或使用java.util.Optional声明参数来指定方法参数是可选的。

如果目标方法参数类型不是字符串,则会自动应用类型转换。参见类型转换。

将参数类型声明为数组或列表可以解析同一参数名的多个参数值。

如果@RequestParam注释被声明为MapMultiValueMap,且注释中未指定参数名称,则会使用每个给定参数名称的请求参数值填充该映射

注意@RequestParam的使用是可选的(例如,设置其属性)。默认情况下,任何简单值类型(由BeanUtils#isSimpleProperty确定)且未由任何其他参数解析程序解析的参数都会被视为使用@RequestParam注释

@ModelAttribute

您可以在方法参数上使用@ModelAttribute注释来访问模型中的属性,如果不存在属性,也可以将其实例化model属性还覆盖了HTTP Servlet请求参数的值,这些参数的名称与字段名称匹配。这被称为数据绑定,它使您不必解析和转换单个查询参数和表单字段。以下示例显示了如何执行此操作:

@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@ModelAttribute Pet pet) {
    // method logic...
}

上述Pet实例的来源如下:详见原文

请注意,使用@ModelAttribute是可选的(例如,设置其属性)。默认情况下,任何不是简单值类型(由BeanUtils#isSimpleProperty确定)且未由任何其他参数解析程序解析的参数都将被视为使用@ModelAttribute注释

1.3.5. DataBinder

@Controller或@ControllerAdvice类可以使用@InitBinder方法初始化WebDataBinder实例,而这些方法反过来可以:

  • Bind request parameters (that is, form or query data) to a model object.
  • Convert String-based request values (such as request parameters, path variables, headers, cookies, and others) to the target type of controller method arguments.
  • 在呈现HTML表单时,将模型对象值格式化为字符串值。

@InitBinder方法可以注册特定于控制器的java.beans.PropertyEditorSpring转换器格式化组件。此外,可以使用MVC config在全局共享的FormattingConversionService中注册转换器和格式化程序类型。

@InitBinder方法支持许多与@RequestMapping方法相同的参数,但@ModelAttribute(命令对象)参数除外。通常,它们是用WebDataBinder参数(用于注册)和void返回值声明的。下面的列表显示了一个示例:

@Controller
public class FormController {

    @InitBinder 
    public void initBinder(WebDataBinder binder) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        dateFormat.setLenient(false);
        binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
    }

    // ...
}

或者,当您通过共享FormattingConversionService使用基于格式化程序的设置时,您可以重复使用相同的方法并注册特定于控制器的格式化程序实现,如下例所示:

@Controller
public class FormController {

    @InitBinder 
    protected void initBinder(WebDataBinder binder) {
        binder.addCustomFormatter(new DateFormatter("yyyy-MM-dd"));
    }

    // ...
}