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-Type
为application/x-www-form-urlencoded
或multipart/form-data
。
基本用法
最简单的用法是,如果方法参数名与请求参数名相同,可以直接在方法参数前加上 @RequestParam
注解。Spring 会自动进行绑定和类型转换。
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")@ResponseBodypublic String searchByQuery(@RequestParam String query) {// 此时 'query' 参数的值会被自动赋给方法参数 'query'return "Searching for: " + query;}// 处理 /data?id=123@GetMapping("/data")@ResponseBodypublic String getDataById(@RequestParam int id) {// Spring 会自动将请求参数 "123" (String) 转换为 int 类型return "Fetching data for ID: " + id;}
}
注意: 虽然在某些情况下,如果方法参数名和请求参数名完全一致,并且编译时保留了参数名信息(例如使用 Maven 或 Gradle 的特定配置),可以省略 @RequestParam
注解,但强烈建议始终显式使用 @RequestParam
,以提高代码的可读性和明确性,并避免因编译配置变化导致的问题。
@RequestParam
的属性
@RequestParam
提供了一些属性来定制绑定行为:
-
name
(或value
):- 指定要绑定的请求参数的名称。当方法参数名与请求参数名不同时,必须使用此属性。
name
和value
是同义词。- 示例:
@RequestParam(name = "user_id") Long userId
会将名为user_id
的请求参数绑定到userId
方法参数上。
-
required
:- 指定该参数是否必须存在于请求中。
- 类型:
boolean
。 - 默认值:
true
。如果required=true
,但请求中没有该参数,Spring MVC 会抛出MissingServletRequestParameterException
异常,导致 HTTP 400 (Bad Request) 响应。 - 如果参数是可选的,需要设置为
required = false
。
-
defaultValue
:- 当请求中没有提供该参数,或者参数值为空字符串时,为其提供一个默认值。
- 类型:
String
。Spring 会尝试将这个字符串默认值转换为方法参数的目标类型。 - 注意: 使用
defaultValue
隐含了required = false
的行为。即使你没有显式设置required = false
,只要提供了defaultValue
,该参数就不再是必需的。如果参数不存在,就会使用默认值,而不会抛出异常。 - 如果参数存在但无法转换为目标类型(例如,请求
id=abc
但方法参数是int
),或者defaultValue
无法转换为目标类型,会抛出类型转换异常。
处理可选参数和默认值
这是 @RequestParam
非常常见的用法:
场景 1:参数可选,如果不存在则为 null
(对于对象类型) 或引发错误 (对于基本类型)
@GetMapping("/optional")
@ResponseBody
public String optionalParam(@RequestParam(name = "lang", required = false) String language, // 可选,不存在时 language 为 null@RequestParam(name = "count", required = false) Integer count) { // 可选,不存在时 count 为 nullString 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:参数可选,如果不存在则使用默认值
@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) { // 可选,默认为 10String 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
或数组类型。
@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=springreturn "Fetching items with tags: " + Arrays.toString(tags);
}
绑定所有请求参数到 Map
如果你想获取所有请求参数,可以将 @RequestParam
应用于 Map<String, String>
或 MultiValueMap<String, String>
。
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)绑定到方法参数。- 使用
name
或value
属性指定请求参数名(如果与方法参数名不同)。 - 使用
required = false
使参数变为可选(不存在时,对象类型为null
,基本类型需小心或用包装类/defaultValue
)。 - 使用
defaultValue = "value"
为可选参数提供默认值(参数不存在或为空时生效,隐含required=false
)。 - 可以将多值参数绑定到
List
或数组。 - 可以将所有参数绑定到
Map
或MultiValueMap
。 - Spring 自动进行类型转换,如果转换失败会报错。