Синтаксис шаблона RestTemplate URI для коллекций? - PullRequest
0 голосов
/ 25 июня 2019

У меня есть служба Spring Boot 2 с методом

@RequestMapping(path = "/usable/search")
public List<Provider> findUsable(
    @RequestParam(name = "country-id", required = false) Integer countryId,
    @RequestParam(name = "network-ids[]", required = false) List<Integer> networkIds,
    @RequestParam(name = "usages[]") Set<Usage> usages)

Я хочу вызвать эту службу из другой службы Spring Boot. Для этого я делаю

HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
val response =
    restTemplate.exchange(
        "http://castor-v2/providers/usable/search?network-ids[]={0}&usages[]={1}",
        HttpMethod.GET,
        new HttpEntity<Long>(httpHeaders),
        new ParameterizedTypeReference<List<Provider>>() {},
        Collections.singletonList(networkId),
        Collections.singleton(Usage.MESSAGE_DELIVERY));

Это генерирует http-запрос, такой как search?network-ids[]=[428]&usages[]=[MESSAGE_DELIVERY], который является неправильным (сервер бомбит с org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'java.util.List'; nested exception is java.lang.NumberFormatException: For input string: "[573]"); правильно будет search?network-ids[]=77371&usages[]=MESSAGE_DELIVERY.

Скорее всего, шаблон URI неправильный. Как следует использовать с коллекциями Java?

Обновление : я создал новую конечную точку API без скобок и использовал UriComponentsBuilder, как предложено @ vatsal.

Ответы [ 3 ]

1 голос
/ 25 июня 2019

Вероятно, он преобразует singletonList в строку. Который будет включать в себя скобки блока. Таким образом, вы можете заранее преобразовать список в строку или создать собственную реализацию списка, в которой есть метод to string, который преобразует значения в список через запятую.

1 голос
/ 25 июня 2019

Чтобы легко манипулировать URL / path / params / и т. Д., Вы можете использовать класс Spring UriComponentsBuilder. Он чище, что вручную объединяет строки и заботится о кодировке URL для вас:

Простой код для этого с помощью RestTemplate будет выглядеть следующим образом:

HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_JSON);

String url = "http://castor-v2/providers/usable/search";
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url)
            .queryParam("country-id", countryId)
            .queryParam("network-ids[]", networkId)
            .queryParam("usages[]", Usage.MESSAGE_DELIVERY);

HttpEntity<?> entity = new HttpEntity<>(httpHeaders);

HttpEntity<String> response = restTemplate.exchange(
            builder.toUriString(),
            HttpMethod.GET,
            entity,
            String.class);

Это должно решить ваш запрос. Также убедитесь, что вы передаете Usage как String. Если вы все еще хотите продолжать использовать Usage в качестве объекта, тогда вместо RequestParam вы можете использовать RequestBody и передать его в качестве Body для вызова POST.

1 голос
/ 25 июня 2019

Вы не можете передать объект в качестве параметра запроса. Параметры запроса представляют собой карту с несколькими значениями String to String. если вы хотите передать Usage как String, вы можете создать метод, подобный этому

@RequestMapping(path = "/usable/search")
public List<Provider> findUsable(
    @RequestParam(name = "country-id", required = false) Integer countryId,
    @RequestParam(name = "networkIds", required = false) List<Integer> networkIds,
    @RequestParam(name = "usages") Set<String> usages)

Для вызова этой услуги

http://castor-v2/providers/usable/search?networkIds=0&networkIds=1&usages=usages1&usages=usages2
...