Appearance
Spring Boot 中的 @RequestParam 注解详解 🚀
什么是 @RequestParam?
@RequestParam
是 Spring MVC 中用于绑定 HTTP 请求参数的核心注解。它能够将 URL 查询参数或表单数据自动映射到控制器方法的参数上,让我们轻松获取客户端传递的数据。
NOTE
@RequestParam
主要用于处理两种类型的请求参数:
- 查询参数:如
GET /pets?petId=123
中的petId=123
- 表单数据:如
POST
请求中的表单字段
为什么需要 @RequestParam?🤔
解决的核心痛点
在没有 @RequestParam
之前,开发者需要手动从 HttpServletRequest
中获取参数:
kotlin
@GetMapping("/pets")
fun getPet(request: HttpServletRequest): String {
// 手动获取参数,容易出错
val petIdStr = request.getParameter("petId")
if (petIdStr == null) {
throw IllegalArgumentException("petId is required")
}
val petId = try {
petIdStr.toInt()
} catch (e: NumberFormatException) {
throw IllegalArgumentException("petId must be a number")
}
// 业务逻辑...
return "petForm"
}
kotlin
@GetMapping("/pets")
fun getPet(@RequestParam("petId") petId: Int): String {
// Spring 自动处理参数获取、类型转换和验证
// 直接使用 petId,无需手动处理
return "petForm"
}
设计哲学
@RequestParam
体现了 Spring 框架的核心设计理念:
- 约定优于配置:默认行为满足大多数场景
- 声明式编程:通过注解声明意图,框架处理细节
- 类型安全:自动类型转换,减少运行时错误
基础用法示例 📝
1. 简单参数绑定
kotlin
@RestController
@RequestMapping("/api/pets")
class PetController {
@GetMapping
fun getPet(@RequestParam("petId") petId: Int): ResponseEntity<Pet> {
// Spring 自动将字符串 "123" 转换为 Int 类型
val pet = petService.findById(petId)
return ResponseEntity.ok(pet)
}
}
请求示例:GET /api/pets?petId=123
2. 可选参数处理
kotlin
@GetMapping("/search")
fun searchPets(
@RequestParam(value = "name", required = false) name: String?,
@RequestParam(value = "age", required = false) age: Int?
): List<Pet> {
return petService.search(name, age)
}
kotlin
@GetMapping("/search")
fun searchPets(
@RequestParam(value = "name", defaultValue = "") name: String,
@RequestParam(value = "page", defaultValue = "0") page: Int,
@RequestParam(value = "size", defaultValue = "10") size: Int
): Page<Pet> {
return petService.findAll(PageRequest.of(page, size))
}
TIP
使用 defaultValue
比 required = false
更安全,因为它避免了空值处理的复杂性。
3. 多值参数处理
kotlin
@GetMapping("/filter")
fun filterPets(
@RequestParam("tags") tags: List<String>,
@RequestParam("ages") ages: IntArray
): List<Pet> {
// 处理多个相同名称的参数
// 请求: /filter?tags=cute&tags=friendly&ages=1&ages=2&ages=3
return petService.filterByTagsAndAges(tags, ages)
}
请求示例:GET /api/pets/filter?tags=cute&tags=friendly&ages=1&ages=2&ages=3
高级用法 🔥
1. 获取所有请求参数
kotlin
@PostMapping("/process")
fun processForm(
@RequestParam params: MultiValueMap<String, String>
): ResponseEntity<String> {
// 获取所有请求参数,包括重复的参数名
params.forEach { (key, values) ->
println("参数 $key: $values")
}
// 处理特定参数
val name = params.getFirst("name")
val hobbies = params["hobbies"] // 获取所有 hobby 值
return ResponseEntity.ok("处理完成")
}
2. 表单数据处理
kotlin
@PostMapping("/pets", consumes = [MediaType.APPLICATION_FORM_URLENCODED_VALUE])
fun createPet(
@RequestParam("name") name: String,
@RequestParam("age") age: Int,
@RequestParam("breed") breed: String,
@RequestParam(value = "description", required = false) description: String?
): ResponseEntity<Pet> {
val pet = Pet(name = name, age = age, breed = breed, description = description)
val savedPet = petService.save(pet)
return ResponseEntity.status(HttpStatus.CREATED).body(savedPet)
}
3. 复杂参数映射
点击查看复杂表单处理示例
kotlin
@RestController
@RequestMapping("/api/orders")
class OrderController {
@PostMapping("/create")
fun createOrder(
@RequestParam("customerId") customerId: Long,
@RequestParam("items") itemIds: List<Long>,
@RequestParam("quantities") quantities: List<Int>,
@RequestParam(value = "couponCode", required = false) couponCode: String?,
@RequestParam(value = "notes", defaultValue = "") notes: String,
@RequestParam("deliveryDate")
@DateTimeFormat(pattern = "yyyy-MM-dd") deliveryDate: LocalDate
): ResponseEntity<Order> {
// 验证参数
if (itemIds.size != quantities.size) {
throw IllegalArgumentException("商品数量与数量列表长度不匹配")
}
// 构建订单项
val orderItems = itemIds.zip(quantities) { itemId, quantity ->
OrderItem(itemId = itemId, quantity = quantity)
}
// 创建订单
val order = Order(
customerId = customerId,
items = orderItems,
couponCode = couponCode,
notes = notes,
deliveryDate = deliveryDate
)
val savedOrder = orderService.create(order)
return ResponseEntity.status(HttpStatus.CREATED).body(savedOrder)
}
}
类型转换与验证 ⚡
自动类型转换
Spring 支持多种类型的自动转换:
kotlin
@GetMapping("/demo")
fun typeConversionDemo(
@RequestParam("id") id: Long, // String → Long
@RequestParam("active") active: Boolean, // String → Boolean
@RequestParam("price") price: BigDecimal, // String → BigDecimal
@RequestParam("tags") tags: Set<String>, // String[] → Set<String>
@RequestParam("date")
@DateTimeFormat(pattern = "yyyy-MM-dd") date: LocalDate // String → LocalDate
): Map<String, Any> {
return mapOf(
"id" to id,
"active" to active,
"price" to price,
"tags" to tags,
"date" to date
)
}
参数验证
结合 Bean Validation 进行参数验证:
kotlin
@GetMapping("/validate")
fun validateParams(
@RequestParam("email")
@Email(message = "邮箱格式不正确") email: String,
@RequestParam("age")
@Min(value = 0, message = "年龄不能小于0")
@Max(value = 150, message = "年龄不能大于150") age: Int,
@RequestParam("phone")
@Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确") phone: String
): ResponseEntity<String> {
return ResponseEntity.ok("验证通过")
}
最佳实践 ✅
1. 参数命名规范
kotlin
// ✅ 推荐:使用有意义的参数名
@GetMapping("/search")
fun searchUsers(
@RequestParam("keyword") searchKeyword: String,
@RequestParam("page") pageNumber: Int = 0,
@RequestParam("size") pageSize: Int = 20
): Page<User>
// ❌ 不推荐:参数名不明确
@GetMapping("/search")
fun searchUsers(
@RequestParam("q") q: String,
@RequestParam("p") p: Int,
@RequestParam("s") s: Int
): Page<User>
2. 合理设置默认值
kotlin
@GetMapping("/products")
fun getProducts(
@RequestParam(value = "category", defaultValue = "all") category: String,
@RequestParam(value = "sortBy", defaultValue = "name") sortBy: String,
@RequestParam(value = "order", defaultValue = "asc") order: String,
@RequestParam(value = "page", defaultValue = "0") page: Int,
@RequestParam(value = "size", defaultValue = "10") size: Int
): Page<Product> {
// 业务逻辑
}
3. 错误处理
kotlin
@ControllerAdvice
class GlobalExceptionHandler {
@ExceptionHandler(MissingServletRequestParameterException::class)
fun handleMissingParam(ex: MissingServletRequestParameterException): ResponseEntity<ErrorResponse> {
val error = ErrorResponse(
code = "MISSING_PARAMETER",
message = "缺少必需参数: ${ex.parameterName}",
timestamp = LocalDateTime.now()
)
return ResponseEntity.badRequest().body(error)
}
@ExceptionHandler(MethodArgumentTypeMismatchException::class)
fun handleTypeMismatch(ex: MethodArgumentTypeMismatchException): ResponseEntity<ErrorResponse> {
val error = ErrorResponse(
code = "TYPE_MISMATCH",
message = "参数 ${ex.name} 类型错误,期望: ${ex.requiredType?.simpleName}",
timestamp = LocalDateTime.now()
)
return ResponseEntity.badRequest().body(error)
}
}
常见陷阱与注意事项 ⚠️
1. 参数名不匹配
WARNING
当 @RequestParam
的 value
与实际请求参数名不匹配时,会抛出异常。
kotlin
// 请求: GET /api/users?userId=123
@GetMapping("/users")
fun getUser(@RequestParam("id") userId: Long)
// 错误:请求参数是 userId,但注解中写的是 id
正确做法:
kotlin
@GetMapping("/users")
fun getUser(@RequestParam("userId") userId: Long)
2. 类型转换失败
kotlin
// 请求: GET /api/products?price=abc
@GetMapping("/products")
fun getProducts(@RequestParam("price") price: Double) {
// 会抛出 MethodArgumentTypeMismatchException
}
TIP
建议使用自定义转换器或在全局异常处理器中处理类型转换异常。
3. 数组参数的空值处理
kotlin
@GetMapping("/filter")
fun filterItems(@RequestParam("tags") tags: List<String>) {
// 如果请求中没有 tags 参数,会抛出异常
// 解决方案:设置 required = false 或 defaultValue
}
总结 🎯
@RequestParam
是 Spring MVC 中处理请求参数的强大工具,它:
- 简化开发:自动处理参数绑定和类型转换
- 提高安全性:减少手动参数处理的错误
- 增强可读性:声明式的参数定义更清晰
- 支持灵活配置:可选参数、默认值、多值处理等
IMPORTANT
掌握 @RequestParam
的正确使用方法,能够让你的 Spring Boot 应用更加健壮和易维护。记住要合理设置默认值、处理异常情况,并遵循良好的命名规范。
通过本文的学习,相信你已经对 @RequestParam
有了深入的理解。在实际项目中,结合业务需求灵活运用这些知识,你将能够构建出更加优雅和可靠的 Web 应用! 🚀