Spring RestController中包装类内Set<String>无法拆分逗号分隔RequestParam
问题解决:Spring Boot包装类中Set无法解析逗号分隔参数
问题背景
直接通过@RequestParam接收Set<String>时,以下两种请求方式都能正常将参数拆分为集合元素:
- 逗号分隔形式:
localhost:8080/foo/bar/people?idsType1=QWE,RTY,UIO - 多参数重复形式:
localhost:8080/foo/bar/people?idsType1=QWE&idsType1=RTY&idsType1=UIO
但将Set<String>放入包装类后,逗号分隔的参数会被识别为单个完整元素"QWE,RTY,UIO",仅多参数形式仍能正常拆分。包装类用于整合多个参数并实现自定义复杂校验,环境为SpringBoot 2.2.1-RELEASE、Java 8 openjdk。
原因分析
直接使用@RequestParam时,Spring的RequestParamMethodArgumentResolver会自动处理逗号分隔的字符串,将其拆分为集合元素;而使用包装类时,参数绑定由ServletModelAttributeMethodProcessor处理,默认不会对字符串进行逗号拆分来填充集合。
解决方案
方案1:在Controller中注册自定义PropertyEditor
针对特定字段添加参数转换逻辑,仅对当前Controller生效:
@Controller public class PeopleController { @InitBinder public void initBinder(WebDataBinder binder) { binder.registerCustomEditor(Set.class, "idsType1", new PropertyEditorSupport() { @Override public void setAsText(String text) { if (text == null || text.isEmpty()) { setValue(Collections.emptySet()); return; } Set<String> values = Arrays.stream(text.split(",")) .map(String::trim) .filter(s -> !s.isEmpty()) .collect(Collectors.toSet()); setValue(values); } }); } @ResponseStatus(OK) @GetMapping(value = "/people") public PeopleResponse getPeople(@Valid IdsType1 idsType1) { return service.getPeople(idsType1.getIdsType1()); } }
方案2:全局注册String转Set的Converter
实现Spring的Converter接口并注册为Bean,让所有字符串转Set<String>的场景自动应用该转换:
@Component public class StringToSetConverter implements Converter<String, Set<String>> { @Override public Set<String> convert(String source) { if (source == null || source.isEmpty()) { return Collections.emptySet(); } return Arrays.stream(source.split(",")) .map(String::trim) .filter(s -> !s.isEmpty()) .collect(Collectors.toSet()); } }
方案3:在包装类字段上添加@RequestParam注解
让包装类字段使用@RequestParam的解析逻辑,需配合Controller方法上的@ModelAttribute:
@Value @RequiredArgsConstructor public class IdsType1 { @RequestParam(name = "idsType1") Set<String> idsType1; }
对应的Controller方法:
@ResponseStatus(OK) @GetMapping(value = "/people") public PeopleResponse getPeople(@Valid @ModelAttribute IdsType1 idsType1) { return service.getPeople(idsType1.getIdsType1()); }
内容的提问来源于stack exchange,提问作者Marcin K.
相关产品推荐
相关产品推荐

