Spring REST - 有没有办法覆盖 Spring 用来将查询参数分隔成值列表的字符?

Spring REST - Is there a way to override the character Spring uses to separate a query parameter into a list of values?

我正在使用 Spring 编写 REST API,并且有某些客户无法或不会改变他们调用我的服务的方式。

通常在发送带有值列表的查询参数时,您只需用逗号分隔参数,Spring 将完成其余的工作 curl http://host.com/api/endpoint?listParam=1,2,3

和控制器

@GetMapping("/api/endpoint")
public ResponseEntity endpoint(@RequestParam("listParam" List<String> listParam){
    // Here, listParam is populated with 1,2,3
}

不幸的是,我的客户将传递带有横线 | 分隔符的列表,根本不可能让他们更改它。
示例: curl http://host.com/api/endpoint?listParam=1%7C2%7C3%7C

我仍然想使用 Spring 将这些调用分解成列表,这样我就不必用手动 String.split() 调用使我的代码混乱。

我已经尝试过的:
找到了@InitBinder注解,写了下面的

@InitBinder
public void initBinder(WebDataBinder dataBinder){
    dataBinder.registerCustomEditor(String[].class, new StringArrayPropertyEditor("|"));
}

但是,此代码似乎从未被调用(使用断点观察)并且使用横线作为分隔符的请求失败并显示 400 BAD REQUEST。

如有任何建议,将不胜感激,谢谢!

404 由于 URL 编码问题即将到来。

你需要编码 | 然后它会起作用,但它会产生另一个问题,参数不会被拆分。

要解决此问题,您需要创建一个可以将 String 转换为 Collection 的自定义转换。对于自定义转换,您可以检查StringToCollectionConverter class。进行自定义转换后,您可以注册该服务,在任何配置中 classes 添加以下功能


  @Autowired
  void conversionService(GenericConversionService genericConversionService) {
    genericConversionService.addConverter(myStringToCollectionConvert());
  }

  @Bean
  public MyStringToCollectionConvert myStringToCollectionConvert() {
    return new MyStringToCollectionConvert();
  }

在此 MyStringToCollectionConvert 中 class 将解析 String 并转换为字符串集合。

我接受了 Sonus21 的回答,因为他的建议让我找到了一个有效的例子,但我的解决方案并不完全是他的。

class StringToCollectionConverter 对我来说确实存在,但它无法访问,我无法以任何方式使用它。但是,在查看它实现的接口 (ConditionalGenericConverter) 并使用 Spring 转换器搜索更多示例时,我最终确定了以下解决方案。

我问题中的listParam其实是指一组Enum值。我做的第一件事是重写我的控制器以实际使用枚举值而不是原始整数。

@GetMapping("/api/endpoint")
public ResponseEntity endpoint(@RequestParam("listParam" List<EnumClass> listParam){
    // ...
}

接下来我写了一个Spring Custom Converter (Baeldung Doc)

public class CustomStringToEnumClassListConverter implements Converter<String, List<EnumClass>> {

    @Override
    public List<EnumClass> convert(String str) {
        return Stream.of(
                str.split("\|")) // Here is where we manually delimit the incoming string with bars instead of commas
                .map(i -> EnumClass.intToValue(Integer.parseInt(i))) // intToValue is a method I wrote to get the actual Enum for a given int
                .collect(Collectors.toList());
    }
}

最后,我写了一个 Config Bean 并用 Spring 注册了这个自定义转换器:

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addFormatters(FormatterRegistry registry){
        registry.addConverter(new CustomStringToEnumClassListConverter());
    }
}

所有这些都完成后,Spring 会自动用 EnumClass 个对象填充 listParam 列表。