Изменить запрос Spring MVC, чтобы перечислить привязку параметров, чтобы они не разделялись запятыми

Я отправляю names из простой веб-формы:

<form action = "test" method = "GET">
  <select name = "names" multiple = "true">
    <option>Doe, Jane</option>
    <option>Doe, John</option>
  </select>
  <input type = "submit"/>
</form>

names привязан к List в контроллере:

@GetMapping("/test")
public String test(@RequestParam List<String> names, Model m) {
  System.out.println(names.size());
  System.out.println(names);
  return "test";
}

Но поскольку значения моего имени содержат запятую (,), Spring анализирует то, что должно быть одним значением имени, на две строки.

Запрос GET для /test?names=Doe, John (удаление кодировки URL запятой от , до %2C для удобочитаемости) приводит к появлению списка, содержащего два значения String, Doe и John, а не одно значение Doe, John, как мне бы хотелось.

Однако при отправке нескольких значений, таких как: /test?names=Doe, Jane&names=Doe, John, все работает должным образом. В этом случае у меня есть список с двумя элементами: Doe, Jane и Doe, John.

Один из обходных путей — просто всегда отправлять пустое значение names в форму, включая:

<input type = "hidden" name = "names"/>

А затем удалить пустое значение из списка. Но я бы не хотел этого делать.

Как я могу настроить Spring MVC, чтобы НЕ анализировать строковые значения с использованием запятой, а вместо этого ожидать, что значения атрибутов списка будут просто повторяться, как ?name=Jon&name=Sue&name=Bob?

Я использую Spring Boot 2.3.2. Спасибо!

0
0
467
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Преобразование, кажется, происходит в:

org.springframework.core.convert.support.StringToCollectionConverter

который должен быть конвертером по умолчанию, зарегистрированным фреймворком.

Вы можете использовать метод @InitBinder в контроллере или Controller Advice для регистрации конвертеров, однако я не уверен, как вы переопределяете или отключаете этот преобразователь по умолчанию.

Тогда проще всего вернуться к доступу к параметру непосредственно из HttpServletRequest:

 @Controller
public class TestController {

    @RequestMapping("/test")
    public String test(@RequestParam("names") List<String> names, HttpServletRequest request) {
        
        //1
        System.out.println(request.getParameterValues("names").length);
        System.out.println(Arrays.toString(request.getParameterValues("names")));
        
        //2
        System.out.println(names.size());
        System.out.println(names);

        return null;
    }
}

После дополнительных экспериментов вы можете отключить вызов фреймворка StringToCollectionConverter в Spring Boot, явно удалив преобразование из String.class в Collection.class из GenericConversionService:

@Autowired
void conversionService(GenericConversionService genericConversionService) {
  List<String> names = genericConversionService.convert("Ed, Al", List.class);
  System.out.println(names.size()); // 2

  genericConversionService.removeConvertible(String.class, Collection.class);

  names = genericConversionService.convert("Ed, Al", List.class);
  System.out.println(names.size()); // 1

}

Другие вопросы по теме