Spring Data Rest与Spring Feign查询参数列表不兼容问题及解决办法
场景重现
Feign客户端代码:
@GetMapping("/api/cars/search/findCarsByIdIn") CollectionModel<Cars> getCars( @RequestParam("carIds") Collection<Integer> carIds);
该代码生成的请求URL为:http://car-service/api/cars/search/findCarsByIdIn?carIds=33&carIds=46
但Spring Data Rest期望的参数格式是逗号分隔的单个参数,即:http://car-service/api/cars/search/findCarsByIdIn?carIds=33,46
此时Spring Data REST抛出类型转换错误:
class java.lang.String cannot be cast to class java.lang.Integer
(java.lang.String and java.lang.Integer are in module java.base of
loader 'bootstrap')
解决方案
方案1:调整Feign客户端,生成逗号分隔的参数
Feign默认会把集合参数拆分为多个同名参数,可通过以下方式修改参数序列化逻辑:
方式A:手动转换为逗号分隔字符串传递
修改Feign接口定义,直接接收字符串类型参数:
@GetMapping("/api/cars/search/findCarsByIdIn") CollectionModel<Cars> getCars(@RequestParam("carIds") String carIds);
调用时将集合转为逗号分隔的字符串:
String carIdsStr = carIds.stream() .map(String::valueOf) .collect(Collectors.joining(",")); feignClient.getCars(carIdsStr);
方式B:配置Feign全局集合格式化器
在Spring Cloud环境下,通过自定义FeignFormatterRegistrar统一处理集合参数的序列化:
@Component public class FeignCollectionFormatterRegistrar implements FeignFormatterRegistrar { @Override public void registerFormatters(FormatterRegistry registry) { registry.addFormatterForType(Collection.class, new Formatter<Collection<?>>() { @Override public String print(Collection<?> collection, Locale locale) { return collection.stream() .map(Object::toString) .collect(Collectors.joining(",")); } @Override public Collection<?> parse(String text, Locale locale) throws ParseException { return Arrays.asList(text.split(",")); } }); } }
配置后Feign会自动将集合序列化为逗号分隔的字符串参数,无需修改原有接口定义。
方案2:调整Spring Data Rest,支持多参数格式
如果不想修改Feign客户端,可通过自定义配置让Spring Data Rest支持多参数形式的集合解析:
@Configuration public class RestConfig implements RepositoryRestConfigurer { @Override public void configureConversionService(ConfigurableConversionService conversionService) { // 添加转换器,将多参数的字符串数组转为Integer集合 conversionService.addConverter(new Converter<String[], Collection<Integer>>() { @Override public Collection<Integer> convert(String[] source) { return Arrays.stream(source) .map(Integer::valueOf) .collect(Collectors.toList()); } }); } }
配置后Spring Data Rest就能正确解析?carIds=33&carIds=46格式的参数,避免类型转换错误。
内容的提问来源于stack exchange,提问作者James

