深入理解 Spring MVC Controller —— 请求参数获取

简介: 前言接上篇《深入理解 Spring MVC Controller —— 请求映射》,上篇主要介绍了处理器方法及请求映射的定义。有了处理器方法 Spring MVC 就可以对请求进行处理,有了请求映射 Spring MVC 就能知道哪些请求应该由哪些处理器方法来处理。

前言


接上篇《深入理解 Spring MVC Controller —— 请求映射》,上篇主要介绍了处理器方法及请求映射的定义。有了处理器方法 Spring MVC 就可以对请求进行处理,有了请求映射 Spring MVC 就能知道哪些请求应该由哪些处理器方法来处理。


Spring MVC 中对请求进行处理,除了定义处理器方法以及请求映射,我们还需要关心的一个问题是如何接收请求有关的参数,因为不同的参数往往伴随着不同的业务逻辑。


由于请求参数获取的内容较多,这篇我们先来了解 Spring MVC 常见的参数获取方式,下篇我们再深入分析并实战如何利用请求参数优雅获取登录用户信息。


前方高能预警:作为基础内容,本篇篇幅略长,可先收藏等有时间再查阅。


请求参数获取


传统的 Java Web 项目,我们通常通过 HttpServletRequest 来获取请求相关的参数。Spring MVC 简化了请求参数的获取方式,直接将请求参数定义为处理器方法参数即可。


当处理器方法被 Spring MVC 调用时,Spring MVC 会尝试根据请求上下文信息解析出给定类型的方法参数值,并自动进行类型转换和参数校验,因此方法参数还可以定义为除字符串类型的其他类型。默认情况下处理器方法中可以定义的请求参数如下。


表单参数


表单参数可能是在 Spring MVC 中使用最频繁的请求参数之一了。


Http 协议中的表单大概可以分为两类,一类是 application/x-www-from-urlencoded,请求中只能携带字符串形式的参数值,另一类是 multipart/form-data,请求中除了携带字符串形式的参数值还可以携带文件。


Spring MVC 对字符串参数值和文件参数值有不同的处理方式。


表单单个普通参数获取


@RequestParam 注解指定请求参数

对于表单的单个普通参数获取,可以直接在处理器方法参数上添加 @RequestParam 注解并指定参数名,接收的是 GET 请求方式查询字符串上的参数或 POST 请求方式表单上的某一个参数。


Spring MVC 并未限制 @RequestParam 标注的处理器方法参数的类型,只要内部支持类型转换即可,方法参数类型通常来说为简单类型。简单类型包括基本类型及其包装类型、Enum、CharSequence、Number、Date、Temporal、URI、URL、Locale、Class 类型。


示例代码如下。

    @PostMapping("/login")
    public Result<LoginBO> login(@RequestParam("username") String username, @RequestParam("password") String password) {
        return Result.ok(userService.login(username, password));
    }

示例代码提供了登录功能,并获取了用户名和密码。


如果 JDK 版本在 1.8 以上使用 javac 编译时还可以添加 -parameters 参数,这样 @RequestParam 可以省略参数名,Spring MVC 会根据方法参数名获取参数值。


注意:如果想使用 Map 作为方法类型接收单个参数值,@RequestParam 必须指定参数名,否则 Map 方法参数接收的是所有的表单参数。


简单类型直接接收请求参数


类型为简单类型的处理器方法参数可以直接接收表单中的单个参数,方法参数名就是接收的参数名,注意此时方法参数上不能存在 @RequestParam 注解及 @RequestPart 注解。


表单单个文件参数获取

@RequestPart 指定文件参数

如果想要接收用户上传的文件,可以将 Multipart 相关类型直接定义为处理器方法参数的类型,然后使用 @RequestPart 指定请求参数名。


Multipart 相关的参数类型如下:


MultipartFile、Collection、List、MultipartFile[] 类型参数。

Part、Collection、List、Part[] 类型参数。

示例代码如下。

    @PostMapping("/upload")
    public Result<UploadBO> upload(@RequestPart("file") MultipartFile file) {
        return Result.ok(fileService.upload(file));
    }


Multipart 相关类型直接接收文件参数


除了使用 @RequestPart 注解指定参数名,还可以直接将 Multipart 相关类型直接定义为处理器方法参数,方法参数名就是请求参数名,注意此时方法参数上不能携带 @RequestParam 注解及 @RequestPart 注解。


所有表单参数获取


如果想要一次性获取所有的请求参数,而不是根据请求参数名获取,可以将处理器方法参数定义为 Map 或 MultiValueMap,然后使用 @RequestParam 注解标注方法参数,此时 @RequestParam 不能指定参数名。


具体可以使用的泛型类型如下。


MultiValueMap、MultiValueMap、MultiValueMap

Map、Map、Map

由于泛型的值只能为 String、MultipartFile、Part,因此普通表单参数和文件表单参数需要分别接收。


示例代码如下。


    @PostMapping("/upload")
    public Result<UploadBO> upload(@RequestParam Map<String, MultipartFile> files, @RequestParam Map<String, String> extra) {
        return null;
    }


可选请求参数


如果认为方法参数表示的表单请求参数是可选的,可以将 @RequestParamrequired 属性值指定为 false,表示该参数是可选的,除此之外还可以用 Optional 类型接收请求参数。示例代码如下。


    @PostMapping("/login")
    public Result<LoginBO> login(@RequestParam(value = "username", required = false) String username, @RequestParam("password") Optional<String> password) {
        return Result.ok(userService.login(username, password));
    }


请求头参数


Spring MVC 中,如果想要获取请求头中的单个参数值,可以使用 @RequestHeader 指定请求头,并标注在处理器方法参数上。与 @RequestParam 注解类似,请求头的名称也可以省略,此时将方法参数作为请求头的名称。示例代码如下。


    @PostMapping("/upload")
    public Result<UploadBO> upload(@RequestHeader("token") String token) {
        return null;
    }


如果想要一次性获取所有的请求头,可以使用 Map 类型作为处理器方法参数,Map 的 key 和 value 都为 String 类型,此时 @RequestHeader 注解不必指定请求头,示例代码如下。


    @PostMapping("/upload")
    public Result<UploadBO> upload(@RequestHeader Map<String, String> header1,@RequestHeader MultiValueMap<String, String> header2) {
        return null;
    }


默认情况 @RequestHeader 表示的请求头必须存在,如果是可选的,可以设置 @RequestHeader(required = false) 或使用 Optional 类型接收请求头。


Cookie 参数


请求头中可能包含多个 cookie 信息,如果直接获取 Cookie 请求头的值然后再解析会比较麻烦。


Spring MVC 支持使用 String 类型或 Cookie 类型作为处理器方法参数类型来接收 Cookie信息,在方法参数上添加 @CookieValue 注解指定 Cookie 的名称即可。


如果省略 Cookie 名称则方法参数名作为 Cookie 名称。示例代码如下。


    @PostMapping("/upload")
    public Result<UploadBO> upload(@CookieValue("username") String username, @CookieValue Cookie password) {
        return null;
    }


默认情况 @CookieValue 表示的 Cookie 必须存在,如果是可选的,可以设置 @CookieValue(required = false) 或使用 Optional 类型接收 Cookie。


路径变量


路径变量常用于 RESTFUL 风格的接口中,路径的值可以作为一个参数值,此时我们需要在映射路径中指定路径变量的名称,然后使用处理器方法参数接收。处理器方法参数上添加 @PathVariable 注解指定路径变量名即可,同样变量名也可以忽略,此时方法参数名作为路径变量名。示例代码如下。


    @GetMapping("/user/{userId}")
    public Result<?> getUser(@PathVariable("userId") String userId) {
        return null;
    }


默认情况 @PathVariable 表示的路径变量必须存在,如果是可选的,可以设置 @PathVariable(required = false) 或使用 Optional 类型接收路径变量。


矩阵变量


矩阵变量和路径变量类似,变量同样定义在路径中,但是使用较少。可以使用@MatrixVariable 注解标注的处理器方法参数接收矩阵变量,方法参数类型可以为简单类型,也可以为 Map。


Spring 5.2 版本及以下需要手动开启矩阵变量支持,配置如下。


@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        UrlPathHelper urlPathHelper = new UrlPathHelper();
        urlPathHelper.setRemoveSemicolonContent(false);
        configurer.setUrlPathHelper(urlPathHelper);
    }
}


处理器方法参数类型为 Map 的情况,@MatrixVariable 如果指定了 name,则 Map 接收的是单个矩阵变量的值。处理器方法参数获取单个矩阵变量值的示例代码如下。


    @GetMapping("/user{basic}/info")
    public Result<?> getUser(@MatrixVariable(name = "basic") String basic) {
        return Result.ok(basic);
    }


对于请求路径 /user;basic=zhangsan;/info,处理器方法参数 basic 接收到的值为 zhangsan。


处理器方法参数类型为 Map 的情况,@MatrixVariable 如果没有指定 name,可以使用 pathVar 指定请求映射路径中的变量名, 此时 Map 接收的是多个矩阵变量。处理器方法参数获取多个矩阵变量的示例代码如下。


    @GetMapping("/user{basic}/info")
    public Result<?> getUser(@MatrixVariable(pathVar = "basic") Map<String, String> basic) {
        return Result.ok(basic);
    }


对于请求路径 /user;name=zhangsan;age=20/info ,处理器方法参数 basic 接收到的值为 { "name": "zhangsan", "age": "20" }。


默认情况 @MatrixVariable 表示的矩阵变量必须存在,如果是可选的,可以设置 @MatrixVariable(required = false) 或使用 Optional 类型接收矩阵变量。


请求体参数


对于请求体,可以使用 @RequestBody 标注的处理器方法参数接收。示例代码如下。


@Data
public class User {
    private Long id;
    private String name;
}
@RestController
public class UserController {
    @GetMapping("/user/update")
    public Result<?> updateUser(@RequestBody User user) {
        return null;
    }
}


默认情况 @RequestBody 表示的请求头必须存在,如果是可选的,可以设置 @RequestBody(required = false) 或使用 Optional 类型接收请求体。


其他处理器方法参数


除了用于接收请求参数的处理器方法参数,Spring MVC 还支持定义一些其他的处理器方法参数。这里简单做一些介绍。


Request 相关参数


Request 相关参数表示 request 本身或其基本信息。


Spring MVC 支持的与 request 有关的处理器方法参数类型包括:

WebRequest、ServletRequest、MultipartRequest、HttpSession、PushBuilder、Principal、InputStream、Reader、HttpMethod、Locale、TimeZone、ZoneId。

HttpEntity、RequestEntity。

SessionStatus。

除了上面的参数,Spring MVC 还支持获取 request attribute 中的参数,使用 @RequestAttribute 标注处理器方法参数即可,这可以获取过滤器或拦截中使用 ServletRequest#setAttribute 设置的参数。


Response 相关参数


resposne 相关参数表示 response 本身或其基本信息。


Spring MVC 支持的处理器方法参数类型包括: ServletResponse、OutputStream、Writer。


Model 相关参数


Model 是 MVC 中的概念,是 View 使用的数据,在 Spring MVC 中,不同的 View 实现,Spring 可能会将 Model 数据存至不同的地方,对于 JSP 页面来说,Spring MVC 就把 Model 数据存到了 request attribute 中。


Spring MVC 中可以使用 Model 或 Map 类型接收 model 参数,然后将数据存至 model 中即可。示例代码如下。


    @GetMapping("/user/update")
    public Result<?> updateUser(Model model1, Map<String, Object> model2) {
        return null;
    }


在处理器方法执行前,Spring MVC 还会先执行 controller advice bean 和当前 controller 标注了 @ModelAttribute 注解的方法,并将返回值存入 Model 中,由于目前 Model 使用较少,不再加以赘述。


校验相关参数


Spring MVC 中如果想对请求参数进行校验,直接在处理器方法参数上添加 @Validated 注解即可,校验结果则可以定义一个类型为 Errors 的处理器方法参数接收。更多参数校验内容,可以参考我前面文章《Spring 参数校验最佳实践及原理解析》。


这里给出一个简单的示例代码。


@Data
public class User {
    @NotNull(message = "id不能为空")
    private Long id;
    @NotBlank(message = "名称不能为空")
    private String name;
}
@RestController
public class UserController {
    @GetMapping("/user/update")
    public Result<?> updateUser(@RequestBody @Validated User user, Errors errors) {
        if(errors.hasErrors()){
            return Result.fail("参数校验失败");
        }
        return null;
    }
}


表达式参数


Spring MVC 还支持 @Value 标注的注解获取环境变量或属性文件中的属性,可以使用表达式指定默认值或环境变量的名称。示例代码如下。


    @GetMapping("/environment")
    public Result<?> updateUser(@Value("${server.port}") String port) {
        return Result.ok(port);
    }


总结

Spring MVC 处理器方法由于未限制方法签名,因此较为灵活,Spring MVC 默认情况下支持了不同的处理器方法参数类型,有的用于获取请求参数,有的则用于其他功能。


为了支持良好的扩展性,Spring 内部其实是通过组合模式来实现的,Spring 通过 HandlerMethodArgumentResolver 接口解析处理器方法参数,默认的实现及能处理的方法参数我这里做了一个总结,见下图。欢迎留言交流。


27.png

目录
相关文章
|
7月前
|
前端开发 Java 微服务
《深入理解Spring》:Spring、Spring MVC与Spring Boot的深度解析
Spring Framework是Java生态的基石,提供IoC、AOP等核心功能;Spring MVC基于其构建,实现Web层MVC架构;Spring Boot则通过自动配置和内嵌服务器,极大简化了开发与部署。三者层层演进,Spring Boot并非替代,而是对前者的高效封装与增强,适用于微服务与快速开发,而深入理解Spring Framework有助于更好驾驭整体技术栈。
|
前端开发 Java 测试技术
微服务——SpringBoot使用归纳——Spring Boot中的MVC支持——@RequestParam
本文介绍了 `@RequestParam` 注解的使用方法及其与 `@PathVariable` 的区别。`@RequestParam` 用于从请求中获取参数值(如 GET 请求的 URL 参数或 POST 请求的表单数据),而 `@PathVariable` 用于从 URL 模板中提取参数。文章通过示例代码详细说明了 `@RequestParam` 的常用属性,如 `required` 和 `defaultValue`,并展示了如何用实体类封装大量表单参数以简化处理流程。最后,结合 Postman 测试工具验证了接口的功能。
795 0
微服务——SpringBoot使用归纳——Spring Boot中的MVC支持——@RequestParam
|
JSON 前端开发 Java
微服务——SpringBoot使用归纳——Spring Boot中的MVC支持——@RequestBody
`@RequestBody` 是 Spring 框架中的注解,用于将 HTTP 请求体中的 JSON 数据自动映射为 Java 对象。例如,前端通过 POST 请求发送包含 `username` 和 `password` 的 JSON 数据,后端可通过带有 `@RequestBody` 注解的方法参数接收并处理。此注解适用于传递复杂对象的场景,简化了数据解析过程。与表单提交不同,它主要用于接收 JSON 格式的实体数据。
1454 0
|
前端开发 Java 微服务
微服务——SpringBoot使用归纳——Spring Boot中的MVC支持——@PathVariable
`@PathVariable` 是 Spring Boot 中用于从 URL 中提取参数的注解,支持 RESTful 风格接口开发。例如,通过 `@GetMapping(&quot;/user/{id}&quot;)` 可以将 URL 中的 `{id}` 参数自动映射到方法参数中。若参数名不一致,可通过 `@PathVariable(&quot;自定义名&quot;)` 指定绑定关系。此外,还支持多参数占位符,如 `/user/{id}/{name}`,分别映射到方法中的多个参数。运行项目后,访问指定 URL 即可验证参数是否正确接收。
866 0
|
JSON 前端开发 Java
微服务——SpringBoot使用归纳——Spring Boot中的MVC支持——@RequestMapping
@RequestMapping 是 Spring MVC 中用于请求地址映射的注解,可作用于类或方法上。类级别定义控制器父路径,方法级别进一步指定处理逻辑。常用属性包括 value(请求地址)、method(请求类型,如 GET/POST 等,默认 GET)和 produces(返回内容类型)。例如:`@RequestMapping(value = &quot;/test&quot;, produces = &quot;application/json; charset=UTF-8&quot;)`。此外,针对不同请求方式还有简化注解,如 @GetMapping、@PostMapping 等。
783 0
|
JSON 前端开发 Java
微服务——SpringBoot使用归纳——Spring Boot中的MVC支持——@RestController
本文主要介绍 Spring Boot 中 MVC 开发常用的几个注解及其使用方式,包括 `@RestController`、`@RequestMapping`、`@PathVariable`、`@RequestParam` 和 `@RequestBody`。其中重点讲解了 `@RestController` 注解的构成与特点:它是 `@Controller` 和 `@ResponseBody` 的结合体,适用于返回 JSON 数据的场景。文章还指出,在需要模板渲染(如 Thymeleaf)而非前后端分离的情况下,应使用 `@Controller` 而非 `@RestController`
555 0
|
10月前
|
前端开发 Java API
Spring Cloud Gateway Server Web MVC报错“Unsupported transfer encoding: chunked”解决
本文解析了Spring Cloud Gateway中出现“Unsupported transfer encoding: chunked”错误的原因,指出该问题源于Feign依赖的HTTP客户端与服务端的`chunked`传输编码不兼容,并提供了具体的解决方案。通过规范Feign客户端接口的返回类型,可有效避免该异常,提升系统兼容性与稳定性。
698 0
|
10月前
|
SQL Java 数据库连接
Spring、SpringMVC 与 MyBatis 核心知识点解析
我梳理的这些内容,涵盖了 Spring、SpringMVC 和 MyBatis 的核心知识点。 在 Spring 中,我了解到 IOC 是控制反转,把对象控制权交容器;DI 是依赖注入,有三种实现方式。Bean 有五种作用域,单例 bean 的线程安全问题及自动装配方式也清晰了。事务基于数据库和 AOP,有失效场景和七种传播行为。AOP 是面向切面编程,动态代理有 JDK 和 CGLIB 两种。 SpringMVC 的 11 步执行流程我烂熟于心,还有那些常用注解的用法。 MyBatis 里,#{} 和 ${} 的区别很关键,获取主键、处理字段与属性名不匹配的方法也掌握了。多表查询、动态
298 0
|
10月前
|
JSON 前端开发 Java
第05课:Spring Boot中的MVC支持
第05课:Spring Boot中的MVC支持
389 0
|
SQL Java 数据库连接
对Spring、SpringMVC、MyBatis框架的介绍与解释
Spring 框架提供了全面的基础设施支持,Spring MVC 专注于 Web 层的开发,而 MyBatis 则是一个高效的持久层框架。这三个框架结合使用,可以显著提升 Java 企业级应用的开发效率和质量。通过理解它们的核心特性和使用方法,开发者可以更好地构建和维护复杂的应用程序。
872 29

热门文章

最新文章