Spring MVC学习—基于注解的Controller控制器的配置全解一万字
Posted L-Java
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring MVC学习—基于注解的Controller控制器的配置全解一万字相关的知识,希望对你有一定的参考价值。
基于最新Spring 5.x,详细介绍了Spring MVC的基于注解的Controller控制器的配置全解,
包括基于注解的Controller控制器的声明、Request Mapping请求映射的规则、基于@RequestMapping的处理器方法的参数、返回值的配置等
。
此前我们介绍了Spring MVC的核心组件和请求执行流程,现在我们来学习Spring MVC的基于注解的Controller控制器的配置全解,包括基于注解的Controller控制器的声明、Request Mapping请求映射的规则、基于@RequestMapping的处理器方法的参数、返回值的配置等
。
Spring MVC 提供了基于注解的编程模型,@Controller和@RestController
组件内部可以使用注解来表示请求映射、请求输入、异常处理等功能。注解提供了方法级别的Controller实现,从而不必扩展基类或实现特定的接口,减少了代码量、优化了项目结构!
一个常见的基于注解定义的控制器案例如下:
@Controller
public class HelloController {
@GetMapping("/hello")
public String handle(Model model) {
model.addAttribute("message", "Hello World!");
return "index.jsp";
}
}
该方法接受Model参数并以String的形式返回逻辑视图名称,但是还存在许多其他可配置的选项,下面我们会一一介绍!
Spring MVC学习 系列文章
Spring MVC学习(1)—MVC的介绍以及Spring MVC的入门案例
Spring MVC学习(2)—Spring MVC中容器的层次结构以及父子容器的概念
Spring MVC学习(3)—Spring MVC中的核心组件以及请求的执行流程
Spring MVC学习(4)—ViewSolvsolver视图解析器的详细介绍与使用案例
Spring MVC学习(5)—基于注解的Controller控制器的配置全解【一万字】
Spring MVC学习(6)—Spring数据类型转换机制全解【一万字】
Spring MVC学习(7)—Validation基于注解的声明式数据校验机制全解【一万字】
Spring MVC学习(8)—HandlerInterceptor处理器拦截器机制全解
Spring MVC学习(9)—项目统一异常处理机制详解与使用案例
Spring MVC学习(10)—文件上传配置、DispatcherServlet的路径配置、请求和响应内容编码
Spring MVC学习(11)—跨域的介绍以及使用CORS解决跨域问题
文章目录
- Spring MVC学习 系列文章
- 1 控制器的声明
- 2 Request Mapping请求映射配置
- 3 Handler Methods处理器方法
- 4 Controller Advice
1 控制器的声明
我们可以通过在 Servlet 的WebApplicationContext中使用标准Spring bean 的定义方式来定义Controller控制器bean。
@Controller注解采用@Component作为元注解,支持@ComponentScan和<context:component-scan/>
的组件扫描,同时@Controller注解还会指示标注的类被作为 Web 组件的角色,如果采用@Service、@Component等其他组件扫描注解,那么内部的方法级别的控制器不会生效!
@RestController 是一个组合注解,它组合使用了 @Controller 和 @ResponseBody元注解,指示其类中的每种方法都继承了类级别的@ResponseBody注解,因此返回的数据将直接写入response响应正文中,而不会使用ViewSolvsolver和View进行视图模版解析和渲染。
注意,如果需要写入response响应正文中是JSON数据并且能自动将返回的对象格式化为JSON,那么还需要JSON转换的依赖:
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson
-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
</dependency>
1.1 AOP 代理
Controller控制器中支持AOP 代理,例如在类上添加@Transactional进行事务控制,但这需要Spring MVC的配置文件定义了事务的支持!
由于Controller控制器中的方法一般都不是从接口中继承的,因此建议使用基于类的动态代理,但是如果Controller实现了除了容器回调接口(例如InitializingBean、DisposableBean、Closeable、AutoCloseable接口以及Aware接口包括其子接口)、标志性接口、内部接口的的其他合理接口,那么为了让控制机方法的AOP配置生效,可能需要显式配置基于类的代理,通常是配置<tx:annotation-driven proxy-target-class="true"/>
或者@EnableTransactionManagement(proxyTargetClass = true)
。
2 Request Mapping请求映射配置
我们可以使用注解@RequestMapping将请求映射到不同的控制器方法。它具有各种属性,可按 URL、HTTP 方法、请求参数、请求头和媒体类型匹配。可以在类级别使用它来表示共享映射,也可以在方法级别使用它来缩小到特定的终结点映射。
更常见的还有用于筛选特定HTTP方法的@RequestMapping变体:@GetMapping、@PostMapping、@PutMapping、@DeleteMapping、@PatchMapping。
上面的这些基于特定HTTP方法的注解是一种组合注解,在RESTFUL风格的项目中,大多数的控制器方法都应该映射到特定的HTTP请求方法,因此更多的使用这些特性化的注解,而不是使用@RequestMapping,后者默认情况下与所有类型的HTTP方法匹配。但是,在类级别仍可以使用@RequestMapping来表示共享映射。
下面示例要求具体HTTP请求方法的方法级映射:
@RestController
@RequestMapping("/persons")
class PersonController {
/**
* 查询的方法,采用get请求
*/
@GetMapping("/{id}")
public Person get(@PathVariable Long id) {
// ...
}
/**
* 插入的方法,采用post请求
*/
@PostMapping
public void add(@RequestBody Person person) {
// ...
}
/**
* 更新的方法,采用put请求
*/
@PutMapping
public void update(@RequestBody Person person) {
// ...
}
/**
* 删除的方法,采用delete请求
*/
@DeleteMapping("/{id}")
public void delete(@PathVariable Long id) {
// ...
}
}
2.1 URI 模式
我们可以使用 global模式和通配符来映射请求,简单的说,请求的URL路径支持模式匹配!Spring MVC 使用 PathMatcher 协定和来自spring-core的 AntPathMatcher 实现进行 URI 路径匹配。
下面是Pattern以及对应的匹配规则:
Pattern | Description | Example |
? | 匹配一个字符 | "/pages/t?st.html" 匹配 "/pages/test.html" 和"/pages/t3st.html" |
* | 匹配路径段中的零个或多个字符 | "/resources/.png" 匹配 "/resources/file.png"。"/projects/*/versions" 匹配 "/projects/spring/versions" 不匹配 "/projects/spring/boot/versions" |
** | 匹配零个或多个路径段,直到路径结束 | "/resources/**" 匹配 "/resources/file.png" 和 "/resources/images/file.png" |
{name} | 匹配路径段,并捕获它作为名为"name"的控制器方法的参数变量的值 | "/projects/{project}/versions" 匹配" /projects/spring/versions" 和 captures project=spring |
{name:[a-z]+} | 匹配满足"[a-z]+"正则表达式的路径段,并捕获它作为名为"name"的控制器方法的参数变量的值 | "/projects/{project:[a-z]+}/versions" 匹配"/projects/spring/versions" 不匹配 "/projects/spring1/versions" |
2.1.1 @PathVariable
捕获的 URI 中的变量可以通过@PathVariable注解注入到方法参数中进行访问,默认情况下参数名和URI中的变量名一致,如下例所示,
@GetMapping("/owners/{ownerId}/pets/{petId}")
public Pet findPet(@PathVariable Long ownerId, @PathVariable Long petId) {
// ...
}
实际上参数名和URI中的变量名不一致也可以,此时需要在@PathVariable注解中指明使用的变量:
@GetMapping("/owners/{ownerId}")
public void findPet(@PathVariable("ownerId") Long id) {
// ...
}
我们可以同时在类和方法级别中声明 URI 变量并使用,如下例所示:
@Controller
@RequestMapping("/owners/{ownerId}")
public class OwnerController {
@GetMapping("/pets/{petId}")
public Pet findPet(@PathVariable Long ownerId, @PathVariable Long petId) {
// ...
}
}
URI变量将自动转换为参数相应的类型,如果不能转换将引发TypeMismatchException异常。默认情况下支持简单类型(int、long、Date 等),您可以注册对任何其他数据类型的支持,可以通过 WebDataBinder(DataBinder)或通过FormattingConversionService注册格式器Formatters来自定义类型转换规则。
2.1.2 正则表达式
语法[varName:regex]
声明带有正则表达式的URI变量,在一个路径段中,可以多次使用该语法。例如,以下方法可以提取URI路径段中的名称、版本和文件扩展名:
@RestController
public class RegexController {
@GetMapping("/{name:[a-z-]+}-{version:\\\\d\\\\.\\\\d\\\\.\\\\d}{ext:\\\\.[a-z]+}")
public void handle(@PathVariable String name, @PathVariable String version, @PathVariable String ext) {
System.out.println(name);
System.out.println(version);
System.out.println(ext);
}
}
访问/spring-web-3.0.5.jar,将会得到:
2.1.3 占位符
URI路径模式还可以支持嵌入${…}占位符,这些占位符在启动时通过PropertyPlaceHolderConfigurer针对本地、系统system、环境environment和其他属性源中的属性来解析。因此我们可以使用它根据某些外部配置对基本 URL 进行参数化。
URI配置文件UriPlaceholder.properties(需要加载到容器中)如下,:
uri1=tx
uri2=xt
uri3=xxx
Controller如下:
@RestController
@RequestMapping("/${uri1}")
class PlaceholderController {
@GetMapping("/${uri2}/{${uri3}}/{id}")
public void handle(@PathVariable Long id, @PathVariable String xxx) {
System.out.println(id);
System.out.println(xxx);
}
}
访问/tx/xt/aaa/111,结果如下:
2.1.4 后缀匹配
默认情况下,Spring MVC支持“.*”的后缀匹配,比如映射到 /person 的控制器也隐式映射到/person.*。这样的好处是,可以通过文件扩展名用于来表示请求的内容类型(content type)以用于响应(而不是使用Accept请求头) - 例如/person.pdf,/person.xml等。
但是后来文件扩展名的使用已经以各种方式证明是有问题的。使用 URI 变量、路径参数和 URI 编码时,可能会导致歧义,还可能引起RFD攻击,目前AcceptHeader是首选的内容协商判定依据。
如果要完全禁用文件扩展名匹配,必须设置以下两项:
PathMatchConfigurer.setUseSuffixPatternMatch(false)。
ContentNegotiationConfigurer.preferredPathExtension(false)。
2.2 匹配Content-Type
我们可以根据请求的Content-Type(客户端发送的实体数据类型)
缩小请求映射范围,如下案例:
@PostMapping(path = "/pets", consumes = "application/json")
public void addPet(@RequestBody Pet pet) {
// ...
}
consumes
属性是一个String数组,可以传递一个或多个media type媒体类型字符串,其中至少一个与请求的Content-Type匹配!
此外,consumes支持否定表达式
,例如!text/plain表示除text/plain之外的任何Content-Type。
同理,我们可以在类级别
声明共享的consumes属性。但是,与大多数其他请求映射属性不同,在类级别使用时,方法级使用该同名属性将会重写,而不是扩展类级声明,简单的说就是如果方法上也有consumes属性,那么就不会采用、合并类级别上的consumes属性。
在设置consumes的媒体类型值的时候,可以使用MediaType类,该类为常用媒体类型(如APPLICATION_JSON_VALUE
和APPLICATION_XML_VALUE
)提供了可使用的字符串常量。
2.3 匹配Accept
我们可以根据请求的Accept(客户端希望接受的数据类型)
缩小请求映射范围,如下案例:
@GetMapping(path = "/pets/{petId}", produces = "application/json")
@ResponseBody
public Pet getPet(@PathVariable String petId) {
// ...
}
produces
属性是一个String数组,可以传递一个或多个media type媒体类型字符串,其中至少一个与请求的Accept匹配!
此外,produces支持否定表达式
,例如!text/plain表示除text/plain之外的任何Accept。
同理,我们可以在类级别
声明共享的produces属性。但是,与大多数其他请求映射属性不同,在类级别使用时,方法级使用该同名属性将会重写,而不是扩展类级声明,简单的说就是如果方法上也有produces属性,那么就不会采用、合并类级别上的produces属性。
在设置produces的媒体类型值的时候,可以使用MediaType类,该类为常用媒体类型(如APPLICATION_JSON_VALUE
和APPLICATION_XML_VALUE
)提供了可使用的字符串常量。
2.4 匹配参数
我们可以根据请求参数条件缩小请求映射范围。可以测试存在请求参数(myParam)、缺少请求参数(!myParam)或特定值(myParam=myValue)是否存在。
下面的示例演示如何测试特定参数值:
@GetMapping(path = "/pets/{petId}", params = "myParam=myValue")
public void findPet(@PathVariable String petId) {
// ...
}
上面的案例中,除了URL路径必须匹配之外,还必须存在myParam参数并且值等于myValue,请求才会映射到该控制器方法!
2.5 匹配请求头
我们可以根据请求头缩小请求映射范围。可以测试存在请求头(myHeader)、缺少请求头(! myHeader)或特定值(myHeader=myValue)是否存在。
下面的示例演示如何测试特定请求头值:
@GetMapping(path = "/pets", headers = "myHeader=myValue")
public void findPet(@PathVariable String petId) {
// ...
}
上面的案例中,除了URL路径必须匹配之外,还必须存在myHeader请求头并且值等于myValue,请求才会映射到该控制器方法!
由于Content-Type和Accept都是请求头参数,因此它们也可以使用headers属性匹配,但是最好还是使用consumes和produces属性。
2.6 HTTP HEAD、OPTIONS方法
@GetMapping和@RequestMapping(method=RequestMethod.GET)透明的支持HTTP HEAD 方法进行请求映射,控制器方法不需要更改。response中的Content-Length头将会设置为将要写入的字节数而无需实际写入响应。也就是说,HTTP HEAD 请求的处理就像是 HTTP GET 一样,只是,不写入响应正文,而是计算响应字节数并设置Content-Length标头。HEAD请求一般用来测试超链接的有效性,可用性和最近修改。
对于HTTP OPTIONS请求,默认情况下将对应的控制器注解中的method属性(表示支持的HTTP 方法)的值设置为“Allow”响应头的值,其中RequestMethod.GET支持GET,HEAD,OPTIONS方法,其他的类型则支持本类型方法和OPTIONS方法,也可以通过response手动设置“Allow”头信息!
对于没有HTTP方法声明的@RequestMapping,Allow头将被设置为GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS。但是,控制器方法应始终声明支持的HTTP方法(例如通过使用HTTP方法特定的变体:@GetMapping,@PostMapping等)。
2.7 组合注解
Spring MVC支持使用组合注解进行请求映射。这些注解本身使用@RequestMapping作为元注解,并且旨在以更狭窄,更具体的用途重新声明请求映射规则!
@GetMapping、@PostMapping、@PutMapping、@DeleteMapping、@DeleteMapping 和 @PatchMapping是组合注解的实例。提供这些特性化注解的原因是,在RESTful风格的开发规范中,大多数控制器方法应该映射到特定的 HTTP 方法,以表达特定的操作,而不是使用@RequestMapping,因为默认情况下它匹配所有 HTTP 方法。
以@GetMapping为例,可以看到,其内部采用了@RequestMapping注解作为元注解,并且限制了请求方法为RequestMethod.GET,即仅支持GET,HEAD,OPTIONS请求。
3 Handler Methods处理器方法
基于@RequestMapping的处理器方法具有灵活的方法签名,可以从一系列受支持的控制器方法参数和返回值中选择所需要开发方式!
3.1 方法参数
方法支持JDK 8 的 java.util.Optional作为方法参数,并可以结合具有required属性的注解(例如@RequestParam、@RequestHeader ),采用Optional包装的参数等效于required=false。
下表描述了受支持的控制器方法参数和注解,任何参数都不支持Reactive相关类型。
控制器方法参数 | 说明 |
---|---|
WebRequest, NativeWebRequest | 用于对请求参数、请求(request)和会话(session)属性的通用访问,而无需直接使用 Servlet API。 |
javax.servlet.ServletRequest, javax.servlet.ServletResponse | 请求和响应,可以指定特性的类型,比如HttpServletRequest、MultipartHttpServletRequest |
javax.servlet.http.HttpSession | session,如果使用了该参数,那么永远不会为null。请注意,session访问不是线程安全的。如果允许多个请求同时访问session,请考虑将RequestMappingHandlerAdapter实例的synchronizeOnSession标志设置为 true。 |
javax.servlet.http.PushBuilder | Servlet 4.0 的PushBuilder用于实现服务器资源推送。如果客户端不支持 HTTP/2 ,则注入的 PushBuilder 实例可能为 null。 |
java.security.Principal | 当前经过身份验证的用户 – 如果已知,可能是特定的Principal实现类。 |
HttpMethod | 当前请求的 HTTP 方法。 |
java.util.Locale | 当前请求的区域设置,由可用的LocaleResolver区域解析器确定。 |
java.util.TimeZone, java.time.ZoneId | 与当前请求关联的时区,由LocaleContextResolver确定。 |
java.io.InputStream, java.io.Reader | 原始请求体,通过 Servlet API 获取的。 |
java.io.OutputStream, java.io.Writer | 原始响应体,通过 Servlet API 获取的。 |
@PathVariable | 用于访问 URI 模版变量,在前面的请求映射部分就讲过了。 |
@MatrixVariable | 用于访问 URI 路径段中的name-value键值对。 |
@RequestParam | 用于访问 Servlet 请求参数,支持多部分文件参数类型,参数值将自动转换为声明的方法参数类型。注意,对于简单类型的参数,可以不使用@RequestParam注解! |
@RequestHeader | 用于访问请求头中的信息。请求头的值将自动转换为声明的方法参数类型。 |
@CookieValue | 用于访问 Cookie。Cookie值将转换为声明的方法参数类型。 |
@RequestBody | 用于访问 HTTP 请求正文(请求体)。正文内容转换为声明的方法参数类型,通过使用HttpMessageConverter来实现转换,比较重要。 |
HttpEntity | 用于访问请求头和正文。正文类型使用HttpMessageConverter转换。 |
@RequestPart | 用于访问multipart/form-data多部分请求中的一个部分,使用HttpMessageConverter转换类型。对于解析同时上传多中数据的请求的解析方便 |
java.util.Map, org.springframework.ui.Model, org.springframework.ui.ModelMap | 用于访问、设置model参数,model中的数据将可能用于视图渲染。 |
RedirectAttributes | 指定用于重定向时的属性。一个专门用于重定向之后还能带参数跳转的的工具类。 |
@ModelAttribute | 用于访问模型中的现有属性(如果不存在,则进行实例化),并应用数据绑定和验证。 |
Errors, BindingResult | 用于访问来自命令对象(即@ ModelAttribute参数)的数据验证和数据绑定中的错误或来自@RequestBody或@RequestPart参数的验证中的错误。必须在经过验证的方法参数后声明一个Errors或BindingResult参数。 |
SessionStatus + class-level @SessionAttributes | SessionStatus#setComplete方法可以触发通过类级注解@SessionAttributes存储的session属性的清理,但是不会清理真正session中的属性。 |
UriComponentsBuilder | 用于构建相对于当前请求的host,port,scheme,context path以及servletmapping的URL。 |
@SessionAttribute | 用于访问已经存储的session域中的会话属性。 |
@RequestAttribute | 用于访问已创建的、预先存在的request域中的属性 |
任何其他参数 | 如果方法参数不与此表中任何上面的类型匹配,并且它是一种简单类型(由 BeanUtils#isSimpleProperty确定),则它是作为一个@RequestParam,并且requir=false。否则,它将作为一个@ModelAttribute。 |
3.2 返回值
下表描述了受支持的控制器方法返回值以及注解,所有返回值都支持Reactive类型。
控制器方法返回值 | 说明 |
---|---|
@ResponseBody | 返回值将通过 HttpMessageConverter进行转换,并写入响应。 |
HttpEntity, ResponseEntity | 返回值用于指定完整的响应(包括HTTP状态码、头部信息以及响应体),响应体将通过HttpMessageConverter实例转换并写入响应。 |
HttpHeaders | 用于返回具有相应头且无响应正文的响应。 |
String | 一个视图名称,将通过ViewResolver来解析,并与模型数据一起使用(可以与@ModelAttribute方法结合,或者通过设置Model参数来配置模型数据)。 |
View | 一个视图实例,与模型数据一起使用(可以与@ModelAttribute方法结合,或者通过设置Model参数来配置模型数据)。 |
java.util.Map, org.springframework.ui.Model | 配置要添加到模型中的数据,视图名称则通过请求RequestToViewNameTranslator隐式的确定。 |
@ModelAttribute | 配置要添加到模型中的数据,视图名称则通过请求RequestToViewNameTranslator隐式的确定。 |
ModelAndView | 要使用的视图和模型属性,以及(可选)响应状态。 |
void | 如果具有void返回类型(或null返回值)的方法也具有ServletResponse、OutputStream参数或@ResponseStatus注解,则认为该方法已经完全处理了响应。如果没有上面的条件,那么指示没有响应正文,或者选择默认的视图名! |
DeferredResult | 用于从异步线程返回任何上述类型的返回值,用于支持异步请求。 |
Callable | 在Spring MVC 管理的线程中异步生成上述任何返回值,用于支持异步请求。 |
ListenableFuture, java.util.concurrent.CompletionStage, java.util.concurrent.CompletableFuture | DeferredResult的便捷替代方案。 |
ResponseBodyEmitter, SseEmitter | 使用HttpMessageConverter实现异步发出对象流写入到响应中,也可以作为ResponseEntity的响应体。用于实现SSE–server send event,是一种服务端推送的技术。 |
StreamingResponseBody | 以异步方式写入响应输出流,也可以作为ResponseEntity的响应体。 |
Reactive 类型 – Reactor、RxJava 或其他ReactiveAdapterRegistry | DeferredResult的替代方法,其中包含收集到List的多值流(例如Flux,Observable)。 |
任何其他返回值 | 如果返回值与上述任何条件不匹配,并且不是简单类型(由 BeanUtils#isSimpleProperty 确定),并且返回值是字符串或 void,它们都被视为视图名称(通过RequestToViewNameTranslator进行默认视图名称选择)。简单类型的值仍无法解析。 |
3.3 Matrix Variables
根据URI规范RFC 3986,请求URL的路径段中支持键值对。 Spring MVC根据Tim Berners-Lee的一篇旧文章将这些键值对称为“矩阵变量(matrix variables)”,但是它们也可以被称为URI路径参数。
矩阵变量可以出现在任何路径段中,每个变量用分号分隔,多个值用逗号分隔(例如,/cars;color=red,green;year=2012)。也可以通过重复的变量名称指定多个值(例如,color=red;color=green;color=blue)。
如果 URL 预期包含矩阵变量,则控制器方法的请求映射必须使用 URI 变量来屏蔽该矩阵变量内容,并确保请求可以独立于矩阵变量的顺序和存在成功匹配。
我们首先需要启用矩阵变量的使用。在JavaConfig配置中,您需要设置一个 UrlPathHelper bean,并设置removeSemicolonContent=false。在 MVC的XML 命名空间中,可以设置<mvc:annotation-driven enable-matrix-variables="true"/>
。
下面示例如何简单的使用矩阵变量:
@GetMapping("/matrix/{id}")
public void handle(@PathVariable String id, @MatrixVariable int q, @MatrixVariable int r) {
System.out.println(id);
System.out.println(q);
System.out.println(r);
//…………
}
访问/matrix/11;q=22;r=33,得到如下结果:
11
22
33
鉴于所有路径段可能都包含矩阵变量,并且不同的路径段中可能具有同名的矩阵变量,有时可能需要消除矩阵变量预期到底位于哪个路径变量中的歧义。
我们可以通过@MatrixVariable 的name和pathvar属性
来区分,name表示矩阵变量名,pathVar表示当前矩阵变量所在的URI路径变量名!
@GetMapping("/matrix/{path1}/{path2}")
public void handle(@PathVariable int path1, @PathVariable int path2,
@MatrixVariable(name = "q", pathVar = "path1") int q1,
@MatrixVariable(name = "q", pathVar = "path2") int q2) {
System.out.println(path1);
System.out.println(path2);
System.out.println(q1);
System.out.println(q2);
//…………
}
访问/matrix/11;q=22/33;q=44,结果如下:
11
33
22
44
矩阵变量如果不存在,默认将会抛出异常,当然可以通过required
属性定义为可选变量以及通过defaultValue指定默认值,如下例所示:
@GetMapping("/matrix/req/{id}")
public void handle(@MatrixVariable(required = false, defaultValue = "110") int q) {
System.out.println(q);
//…………
}
访问/matrix/req/11,结果如下:
110
若要获取所有矩阵变量,可以使用MultiValueMap
,如下例所示:
@GetMapping("/matrix/all/{all1}/{all2}")
public void handle(@MatrixVariable MultiValueMap<String, String> allmatrixVars,
@MatrixVariable(pathVar = "all1") MultiValueMap<String, String> all1MatrixVars,
@MatrixVariable(pathVar = "all2") MultiValueMap<String, String> all2MatrixVars
) {
System.out.println(allmatrixVars);
System.out.println(all1MatrixVars);
System.out.println(all2MatrixVars);
//…………
}
访问/matrix/all/11;q=22;r=33/44;q=55;s=66,结果如下:
{q=[22, 55], r=[33], s=[66]}
{q=[22], r=[33]}
{q=[55], s=[66]}
3.4 @RequestParam
我们可以使用@RequestParam注解将 Servlet 请求参数(即查询参数或表单数据)绑定到控制器方法参数上。如果目标方法参数类型不是String,则自动应用类型转换。
@RequestParam 注解的name或者value属性表示绑定的请求参数名称,如果不设置,那么默认查找和变量名同名的请求参数,如下所示:
@RestController
public class RequestParamController {
@GetMapping("/requestParam1")
public void handle(@RequestParam String str) {
System.out.println(str);
//…………
}
}
访问/requestParam1?str=test,结果如下:
test
默认情况下,使用此注解标注的方法参数是必需的,如果没有对应的变量,将抛出异常,但可以通过将@RequestParam 注解的required
标志设置为 false 或使用Java8的java.util.Optional
包装原始参数类型来指定方法参数是可选的。
@GetMapping("/requestParam2")
public void handle2(@RequestParam Optional<String> str) {
//是否存在该参数
System.out.println(str.isPresent());
//如果存在该参数,那么输出
str.ifPresent(System.out::println);
//…………
Spring MVC注解版本--初识--12