1. 背景
java.lang.IllegalStateException: No primary or single unique constructor found for interface java.util.List
@DeleteMapping
@ApiOperation("删除菜品")
public Result delete(List<Long> ids){
log.info("删除菜品:{}",ids);
return Result.success();
}
2. 原因分析
- 当不加
@RequestParam
时,Spring 默认尝试将请求体或者 URL 中的参数绑定到控制器方法的参数上。 - 对于简单的参数类型(如
String
、int
),Spring 可以通过默认的方式进行匹配。但对于复杂的类型(如List<Long>
),Spring 需要明确知道这些参数是从哪里来的,即是通过查询参数(URL 的?ids=1,2,3
)还是表单参数发送的。 List<Long>
是一个集合类型,Spring 无法自动推断其映射方式,所以会抛出类似No primary or single unique constructor found for interface java.util.List
的异常。这是因为它不知道如何从请求中提取List<Long>
类型的数据。
3. 使用 @RequestParam
的原因
-
当你加上
@RequestParam
后,明确告诉了 Spring 这些参数是通过请求的查询参数(URL 中的参数)传递的,因此 Spring 可以按照指定的规则去解析 URL 参数,并将其绑定到List<Long>
。例如:当客户端发送一个 URL 请求:
DELETE /admin/common/delete?ids=1,2,3
Spring 看到 @RequestParam List<Long> ids
,就知道要把 ids
参数的值 "1,2,3" 解析成一个 List<Long>
,并注入到 delete
方法中。
4. 为什么 @RequestParam
可以省略
- 对于简单的参数类型(如
String
、int
),如果方法参数的名称和 URL 中的查询参数名称匹配,Spring 可以自动完成映射,所以在这些情况下,@RequestParam
可以省略。 - 但对于集合类型或复杂对象,
@RequestParam
不能省略,必须显式告诉 Spring 该如何处理这些请求参数。
5. 总结
在这种情况下,@RequestParam
是必需的,因为 List<Long>
类型无法通过 Spring 的默认机制自动解析。而加上 @RequestParam
后,Spring 明确知道从 URL 查询参数中解析 ids
,从而避免了绑定失败的问题。