Использование RestTemplate весной. Исключение - недостаточно переменных для расширения

Я пытаюсь получить доступ к содержимому API, и мне нужно отправить URL с помощью RestTemplate.

String url1 = "http://api.example.com/Search?key=52ddafbe3ee659bad97fcce7c53592916a6bfd73&term=&limit=100&sort={\"price\":\"desc\"}";

OutputPage page = restTemplate.getForObject(url1, OutputPage .class);

Но я получаю следующую ошибку.

Exception in thread "main" java.lang.IllegalArgumentException: Not enough variable values available to expand '"price"'
at org.springframework.web.util.UriComponents$VarArgsTemplateVariables.getValue(UriComponents.java:284)
at org.springframework.web.util.UriComponents.expandUriComponent(UriComponents.java:220)
at org.springframework.web.util.HierarchicalUriComponents.expandInternal(HierarchicalUriComponents.java:317)
at org.springframework.web.util.HierarchicalUriComponents.expandInternal(HierarchicalUriComponents.java:46)
at org.springframework.web.util.UriComponents.expand(UriComponents.java:162)
at org.springframework.web.util.UriTemplate.expand(UriTemplate.java:119)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:501)
at org.springframework.web.client.RestTemplate.getForObject(RestTemplate.java:239)
at hello.Application.main(Application.java:26)

Если я уберу критерии сортировки, он будет работать правильно. Мне нужно проанализировать JSON, используя критерии сортировки. Любая помощь будет высоко ценится.

Спасибо

4 ответа

Решение

Коренная причина в том, что RestTemplate считает фигурные скобки {...} в указанном URL-адресе в качестве заполнителя для переменных URI и пытается заменить их на основе их имени. Например

{pageSize}

будет пытаться получить переменную URI с именем pageSize, Эти переменные URI указаны с некоторыми другими перегруженными getForObject методы. Вы не предоставили ничего, но ваш URL ожидает, так что метод выдает исключение.

Одним из решений является сделать String объект, содержащий значение

String sort = "{\"price\":\"desc\"}";

и укажите реальную переменную URI в вашем URL

String url1 = "http://api.example.com/Search?key=52ddafbe3ee659bad97fcce7c53592916a6bfd73&term=&limit=100&sort={sort}";

Вы бы назвали свой getForObject() вот так

OutputPage page = restTemplate.getForObject(url1, OutputPage.class, sort);

Я настоятельно рекомендую вам не отправлять JSON в параметре запроса GET-запроса, а отправлять его в теле запроса POST.

Если решение, предложенное Sotirios Delimanolis, немного сложно реализовать в сценарии, и если строка URI, содержащая фигурные скобки и другие символы, гарантированно верна, может быть проще передать закодированную строку URI методу RestTemplate который поражает ReST сервер.

Строка URI может быть построена с использованием UriComponentsBuilder.build (), закодирована с использованием UriComponents.encode() и отправлена ​​с использованием RestTemplate.exchange() следующим образом:

public ResponseEntity<Object> requestRestServer()
{
    HttpEntity<?> entity = new HttpEntity<>(requestHeaders);
    UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(rawValidUrl)
            .queryParams(
                    (LinkedMultiValueMap<String, String>) allRequestParams);
    UriComponents uriComponents = builder.build().encode();
    ResponseEntity<Object> responseEntity = restTemplate.exchange(uriComponents.toUri(), HttpMethod.GET,
            entity, String.class);
    return responseEntity;
}

Построение, кодирование и извлечение URI были отделены для ясности в приведенном выше фрагменте кода.

Вы можете URL кодировать значения параметров:

String url1 = "http://api.example.com/Search?key=52ddafbe3ee659bad97fcce7c53592916a6bfd73&term=&limit=100&sort=";

org.apache.commons.codec.net.URLCodec codec = new org.apache.commons.codec.net.URLCodec();
url1 = url1 + codec.encode("{\"price\":\"desc\"}");
OutputPage page = restTemplate.getForObject(url1, OutputPage.class);

Вы можете установить конкретный UriTemplateHandler в своем restTemplate. Этот обработчик просто проигнорирует uriVariables:

UriTemplateHandler skipVariablePlaceHolderUriTemplateHandler = new UriTemplateHandler() {
    @Override
    public URI expand(String uriTemplate, Object... uriVariables) {
        return retrieveURI(uriTemplate);
    }

    @Override
    public URI expand(String uriTemplate, Map<String, ?> uriVariables) {
        return retrieveURI(uriTemplate);
    }

    private URI retrieveURI(String uriTemplate) {
        return UriComponentsBuilder.fromUriString(uriTemplate).build().toUri();
    }
};

restTemplate.setUriTemplateHandler(skipVariablePlaceHolderUriTemplateHandler);

Вы можете просто добавить переменную в Url и передать значение для переменной в методе restTemplate.postForObject.

String url1 = "http://api.example.com/Search? 
key=52ddafbe3ee659bad97fcce7c53592916a6bfd73&term=&limit=100&sort={data}";
String data="{\"price\":\"desc\"}";
OutputPage page = restTemplate.getForObject(url1, OutputPage.class, data);

Вы можете закодировать URL-адрес перед использованием RestTemplate

URLEncoder.encode(data, StandardCharsets.UTF_8.toString());
Другие вопросы по тегам