如何在Spring Boot中通过查询参数传递对象列表?
解决Spring Boot GET请求中通过查询参数传递对象列表的问题
问题原因分析
你尝试的两种方式都无法正常绑定,原因如下:
- JSON字符串格式:
@ModelAttribute默认使用Servlet请求参数绑定机制,不会自动将JSON字符串解析为对象列表,因此这种方式无法直接生效。 - 索引式参数格式:你使用了Lombok的
@Value注解生成不可变DTO,Spring的DataBinder需要正确识别构造器参数名才能完成绑定。如果编译时未保留参数名,Spring无法匹配查询参数与构造器参数,导致列表始终为null。
可行解决方案
方案一:启用参数名保留 + 索引式参数绑定
步骤1:编译时保留参数名
Spring需要获取类构造器的参数名才能完成不可变类的属性绑定,因此需要在编译时开启参数名保留:
- Maven:在
pom.xml中配置maven-compiler-plugin
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <source>1.8</source> <target>1.8</target> <parameters>true</parameters> <!-- 开启参数名保留 --> </configuration> </plugin> </plugins> </build>
- Gradle:在
build.gradle中添加配置
java { compileOptions { parameters = true } }
步骤2:使用正确的索引式查询参数格式
发送请求时使用如下格式的查询参数:
/rss?authors[0].name=张三&authors[0].authorId=1001&authors[1].name=李四&authors[1].authorId=1002&status=ACTIVE
此时Spring会自动将参数绑定到FindRssFeedDto的authors列表中。
方案二:手动解析JSON格式查询参数
如果你更倾向于传递JSON字符串格式的参数,可以通过@RequestParam接收字符串后手动反序列化:
修改Controller与DTO
@RestController @RequiredArgsConstructor class RssFeedController { private final RssFeedFacade rssFacade; private final ObjectMapper objectMapper; @GetMapping(value = "/rss", produces = MediaType.APPLICATION_JSON_VALUE) public RssFeedDto findRssFeed( @RequestParam(required = false) String authors, @RequestParam(required = false) FeedStatus status) throws IOException { List<FindRssFeedDto.Author> authorList = null; if (authors != null) { authorList = objectMapper.readValue(authors, new TypeReference<List<FindRssFeedDto.Author>>() {}); } FindRssFeedDto dto = new FindRssFeedDto(authorList, status); return rssFacade.findRssFeed(dto); } }
此时可以使用如下格式的查询参数发送请求:
/rss?authors=[{"name":"张三","authorId":"1001"},{"name":"李四","authorId":"1002"}]&status=ACTIVE
方案三:不推荐:使用@RequestBody(GET请求非常规用法)
虽然HTTP规范不推荐GET请求携带请求体,但部分客户端支持这种方式。你可以将@ModelAttribute替换为@RequestBody,然后将参数放在请求体中发送JSON格式数据。但这种方式不符合REST规范,不建议使用。
总结
优先选择方案一,它符合HTTP GET请求的参数传递规范,且无需额外的手动解析代码。如果必须使用JSON格式参数,再考虑方案二。不需要自定义全局反序列化器,通过上述配置或代码调整即可解决问题。
内容的提问来源于stack exchange,提问作者KSs
相关产品推荐
相关产品推荐

