Spring MVC @RequestParam 注解怎么用?如何处理可选参数和默认值?

@RequestParam 注解的作用

@RequestParam 注解用于将 HTTP 请求中的请求参数(Query Parameters 或 Form Data)绑定到 Controller 方法的参数上。

  • Query Parameters : 出现在 URL 中 ? 之后的部分,格式为 key=value,多个参数用 & 分隔(例如:/search?query=spring&page=1)。
  • Form Data : 当浏览器提交 HTML 表单时,表单字段的值会作为请求参数发送。一般出现在 POST 请求中,Content-Typeapplication/x-www-form-urlencodedmultipart/form-data

基本用法

最简单的用法是,如果方法参数名与请求参数名相同 ,可以直接在方法参数前加上 @RequestParam 注解。Spring 会自动进行绑定和类型转换。

java 复制代码
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class SearchController {

    // 处理 /search?query=someValue
    @GetMapping("/search")
    @ResponseBody
    public String searchByQuery(@RequestParam String query) {
        // 此时 'query' 参数的值会被自动赋给方法参数 'query'
        return "Searching for: " + query;
    }

    // 处理 /data?id=123
    @GetMapping("/data")
    @ResponseBody
    public String getDataById(@RequestParam int id) {
        // Spring 会自动将请求参数 "123" (String) 转换为 int 类型
        return "Fetching data for ID: " + id;
    }
}

注意 : 虽然在某些情况下,如果方法参数名和请求参数名完全一致,并且编译时保留了参数名信息(例如使用 Maven 或 Gradle 的特定配置),可以省略 @RequestParam 注解,但强烈建议始终显式使用 @RequestParam,以提高代码的可读性和明确性,并避免因编译配置变化导致的问题。

@RequestParam 的属性

@RequestParam 提供了一些属性来定制绑定行为:

  1. name (或 value):

    • 指定要绑定的请求参数的名称。当方法参数名与请求参数名不同时,必须使用此属性。
    • namevalue 是同义词。
    • 示例:@RequestParam(name = "user_id") Long userId 会将名为 user_id 的请求参数绑定到 userId 方法参数上。
  2. required:

    • 指定该参数是否必须存在于请求中。
    • 类型:boolean
    • 默认值:true 。如果 required=true,但请求中没有该参数,Spring MVC 会抛出 MissingServletRequestParameterException 异常,导致 HTTP 400 (Bad Request) 响应。
    • 如果参数是可选的,需要设置为 required = false
  3. defaultValue:

    • 当请求中没有 提供该参数,或者参数值为空字符串时,为其提供一个默认值。
    • 类型:String。Spring 会尝试将这个字符串默认值转换为方法参数的目标类型。
    • 注意 : 使用 defaultValue 隐含了 required = false 的行为。即使你没有显式设置 required = false,只要提供了 defaultValue,该参数就不再是必需的。如果参数不存在,就会使用默认值,而不会抛出异常。
    • 如果参数存在但无法转换为目标类型(例如,请求 id=abc 但方法参数是 int),或者 defaultValue 无法转换为目标类型,会抛出类型转换异常。

处理可选参数和默认值

这是 @RequestParam 非常常见的用法:

场景 1:参数可选,如果不存在则为 null (对于对象类型) 或引发错误 (对于基本类型)

java 复制代码
@GetMapping("/optional")
@ResponseBody
public String optionalParam(
        @RequestParam(name = "lang", required = false) String language, // 可选,不存在时 language 为 null
        @RequestParam(name = "count", required = false) Integer count) { // 可选,不存在时 count 为 null

    String langMessage = (language != null) ? "Language: " + language : "Language not specified";
    String countMessage = (count != null) ? "Count: " + count : "Count not specified";

    return langMessage + ", " + countMessage;
}
// 请求 /optional -> "Language not specified, Count not specified"
// 请求 /optional?lang=en -> "Language: en, Count not specified"
// 请求 /optional?count=5 -> "Language not specified, Count: 5"
// 请求 /optional?lang=fr&count=10 -> "Language: fr, Count: 10"

注意 : 如果可选参数是基本类型(如 int, boolean),并且你设置了 required=false 但没有 defaultValue,当请求中缺少该参数时,会尝试将 null 赋给基本类型,这将导致错误。因此,对于可选的基本类型参数,通常建议使用包装类型(Integer, Boolean)或提供 defaultValue

场景 2:参数可选,如果不存在则使用默认值

java 复制代码
@GetMapping("/paged-search")
@ResponseBody
public String pagedSearch(
        @RequestParam(name = "q", required = false) String query, // 可选,默认为 null
        @RequestParam(name = "page", defaultValue = "1") int pageNumber, // 可选,默认为 1
        @RequestParam(name = "size", defaultValue = "10") int pageSize) { // 可选,默认为 10

    String queryInfo = (query != null) ? query : "all items";
    return String.format("Searching for '%s', Page: %d, Size: %d", queryInfo, pageNumber, pageSize);
}
// 请求 /paged-search -> "Searching for 'all items', Page: 1, Size: 10"
// 请求 /paged-search?q=spring -> "Searching for 'spring', Page: 1, Size: 10"
// 请求 /paged-search?page=3&size=20 -> "Searching for 'all items', Page: 3, Size: 20"
// 请求 /paged-search?q=java&page=2 -> "Searching for 'java', Page: 2, Size: 10"

最佳实践 :

即使 defaultValue 隐含了 required=false,也建议同时显式设置 required=false,这样代码意图更清晰:
@RequestParam(name = "page", required = false, defaultValue = "1") int pageNumber

处理多值参数

如果一个请求参数可能出现多次(例如 /items?id=1&id=2&id=3),你可以将方法参数声明为 List 或数组类型。

java 复制代码
@GetMapping("/items")
@ResponseBody
public String getItemsByIds(@RequestParam(name = "id") List<Long> ids) {
    // ids 会包含 [1, 2, 3]
    return "Fetching items with IDs: " + ids;
}

@GetMapping("/tags")
@ResponseBody
public String getItemsByTags(@RequestParam(name = "tag", required = false) String[] tags) {
    if (tags == null || tags.length == 0) {
        return "No tags specified.";
    }
    // tags 会包含 ["java", "spring"] 如果请求是 /tags?tag=java&tag=spring
    return "Fetching items with tags: " + Arrays.toString(tags);
}

绑定所有请求参数到 Map

如果你想获取所有请求参数,可以将 @RequestParam 应用于 Map<String, String>MultiValueMap<String, String>

java 复制代码
import org.springframework.util.MultiValueMap;
import java.util.Map;

// ...

@GetMapping("/allParams")
@ResponseBody
public String getAllParams(@RequestParam Map<String, String> allParams) {
    // allParams 包含所有请求参数的 key-value 对
    // 如果一个 key 有多个值,Map 只会保留其中一个(行为可能依赖具体实现)
    return "Received params: " + allParams.toString();
}

@GetMapping("/multiParams")
@ResponseBody
public String getAllMultiParams(@RequestParam MultiValueMap<String, String> allParams) {
    // MultiValueMap 可以处理一个 key 对应多个值的情况
    // 例如 /multiParams?name=a&name=b&type=x -> allParams 包含 {"name": ["a", "b"], "type": ["x"]}
    return "Received multi-value params: " + allParams.toString();
}

总结

  • @RequestParam 用于将请求参数(Query Params, Form Data)绑定到方法参数。
  • 使用 namevalue 属性指定请求参数名(如果与方法参数名不同)。
  • 使用 required = false 使参数变为可选(不存在时,对象类型为 null,基本类型需小心或用包装类/defaultValue)。
  • 使用 defaultValue = "value" 为可选参数提供默认值(参数不存在或为空时生效,隐含 required=false)。
  • 可以将多值参数绑定到 List 或数组。
  • 可以将所有参数绑定到 MapMultiValueMap
  • Spring 自动进行类型转换,如果转换失败会报错。
相关推荐
南客先生1 分钟前
音视频项目在微服务领域的趋势场景题深度解析
java·微服务·面试·性能优化·音视频·高并发
xcLeigh1 小时前
HTML5好看的水果蔬菜在线商城网站源码系列模板8
java·前端·html5
Alsn861 小时前
11.Spring Boot 3.1.5 中使用 SpringDoc OpenAPI(替代 Swagger)生成 API 文档
java·spring boot·后端
liyongjun63161 小时前
Java List分页工具
java·后端
猎人everest2 小时前
Spring Boot集成Spring Cloud 2024(不使用Feign)
java·spring boot·spring cloud
茂桑2 小时前
日常开发小Tips:后端返回带颜色的字段给前端
java·状态模式
佩奇的技术笔记2 小时前
Java学习手册:Spring 中常用的注解
java·spring
一键三联啊2 小时前
GC的查看
java·jvm·python
howard20053 小时前
项目三 - 任务2:创建笔记本电脑类(一爹多叔)
java·接口·继承·抽象类
药尘师3 小时前
低版的spring boot 1.X接入knife4j
java·spring boot·后端