Весна RestTemplate GET з параметрами


266

Я повинен здійснити RESTдзвінок, який включає в себе власні заголовки та параметри запиту. Я встановлюю свої HttpEntityлише заголовки (без корпусу), і я використовую такий RestTemplate.exchange()спосіб:

HttpHeaders headers = new HttpHeaders();
headers.set("Accept", "application/json");

Map<String, String> params = new HashMap<String, String>();
params.put("msisdn", msisdn);
params.put("email", email);
params.put("clientVersion", clientVersion);
params.put("clientType", clientType);
params.put("issuerName", issuerName);
params.put("applicationName", applicationName);

HttpEntity entity = new HttpEntity(headers);

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

Це не вдається в кінцевому підсумку, dispatcher servletоскільки неможливо вирішити запит для обробника. Налагодивши це, схоже, параметри запиту не надсилаються.

Коли я здійснюю обмін з POSTвикористанням тіла запиту, і немає параметрів запиту, він працює чудово.

Хтось має ідеї?

Відповіді:


480

Щоб легко маніпулювати URL-адресами / шлях / парами / тощо, ви можете використовувати клас UriComponentsBuilder Spring . Чистіше те, що вручну об'єднувати рядки, і він піклується про кодування URL-адрес для вас:

HttpHeaders headers = new HttpHeaders();
headers.set("Accept", MediaType.APPLICATION_JSON_VALUE);

UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url)
        .queryParam("msisdn", msisdn)
        .queryParam("email", email)
        .queryParam("clientVersion", clientVersion)
        .queryParam("clientType", clientType)
        .queryParam("issuerName", issuerName)
        .queryParam("applicationName", applicationName);

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

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

10
Чудова порада. Просто змінено exchangeна getForEntity: restTemplate.getForEntity(builder.build().encode().toUri(), String.class);для простоти.
Фернандо М. Пінхайро

12
@ FernandoM.Pinheiro: Ви маєте рацію, але якщо ви очікуєте загального типу у відповіді, тоді вам потрібно скористатися exchangeта вказати ParameterizedTypeReference. Приклад можна додатково спростити, замінивши builder.build().encode().toUri()на builder.toUriString().
mirzmaster

@Christophe L Чи можете ви показати, як я можу отримувати ці параметри рядка на стороні сервера ??
KJEjava48

3
Існує ярлик, щоб отримати URI: просто зателефонуйтеbuilder.toUriString()
Майкл Піефель

Весняні документи для UriComponentsBuilder . Посібник, що пояснює різні випадки використання UriComponentsBuilder
Chacko Mathew

179

UriVariables також розширено в рядку запиту. Наприклад, наступний виклик розширить значення для облікового запису та імені:

restTemplate.exchange("http://my-rest-url.org/rest/account/{account}?name={name}",
    HttpMethod.GET,
    httpEntity,
    clazz,
    "my-account",
    "my-name"
);

тож фактична URL-адреса запиту буде

http://my-rest-url.org/rest/account/my-account?name=my-name

Подивіться на HierarchicalUriComponents.expandInternal (UriTemplateVariables) для отримання більш детальної інформації. Версія весни 3.1.3.


Спасибі - Дуже просте рішення
Angshuman Agarwal

2
І при створенні екземпляра RestTemplate ви можете вказати, як ці параметри запиту будуть розширюватися, вказавши DefaultUriTemplateHandler (до весни 5) або DefaultUriBuilderFactory (Весна 5+). Це корисно, коли ви хочете кодувати додаткові символи, такі як!, (,) Тощо.
Стівен Рудольф

У моїй URL-адресі є 10+ параметрів, будь-який спосіб досягти того ж з об’єктом / картою замість перерахування кожної змінної? Я не можу використовувати UriComponentsBuilderжодне, оскільки це спричиняє генерування різної метрики для кожного запиту зMicrometer
Doug

@Doug - RestTemplateмає паралельні методи вказівки або позиційного масиву значень ( Object... uriVariables), або карти названих значень ( Map<String, ?> uriVariables). Звуки як версія карти є те , що ви хочете: restTemplate.exchange(url, HttpMethod.GET, httpEntity, clazz, urlVariablesMap).
М. Джастін

42

Оскільки принаймні Spring 3, замість того , щоб використовувати UriComponentsBuilderдля створення URL (який трохи багатослівний), багато з RestTemplateметодів приймають наповнювачі в шляху для параметрів (не тільки exchange).

З документації:

Багато RestTemplateметодів приймає змінні шаблону URI та шаблону URI або як Stringvararg, або як Map<String,String>.

Наприклад, з Stringvararg:

restTemplate.getForObject(
   "http://example.com/hotels/{hotel}/rooms/{room}", String.class, "42", "21");

Або з Map<String, String>:

Map<String, String> vars = new HashMap<>();
vars.put("hotel", "42");
vars.put("room", "21");

restTemplate.getForObject("http://example.com/hotels/{hotel}/rooms/{room}", 
    String.class, vars);

Довідка: https://docs.spring.io/spring/docs/current/spring-framework-reference/integration.html#rest-resttemplate-uri

Якщо ви подивіться на JavaDoc для RestTemplateі пошуку «URI шаблону», ви можете побачити , які методи можна використовувати наповнювачі.


35

Гаразд, тому я ідіот, і я плутаю параметри запиту з параметрами URL. Я якось сподівався, що буде приємніший спосіб заповнити мої параметри запиту, а не потворна об'єднана рядок, але ми є. Це просто випадок побудови URL-адреси з правильними параметрами. Якщо ви передасте його як String Spring, також подбайте про кодування для вас.


це працювало для вас? я дотримувався того ж підходу, що використовував UriComponentsBuilder, але за цільовою URL-адресою, коли я роблю request.getAttribute (), я отримую нульове значення.
yathirigan

47
Я серйозно не розумію, чому ця відповідь має зелений галочок.
Pradeep

7
бо він ОП
Калпеш Соні

То яке ваше рішення? Дякую!
Реймонд Чен

18

Я намагався щось подібне, і приклад RoboSpice допоміг мені це розробити :

HttpHeaders headers = new HttpHeaders();
headers.set("Accept", "application/json");

HttpEntity<String> request = new HttpEntity<>(input, createHeader());

String url = "http://awesomesite.org";
Uri.Builder uriBuilder = Uri.parse(url).buildUpon();
uriBuilder.appendQueryParameter(key, value);
uriBuilder.appendQueryParameter(key, value);
...

String url = uriBuilder.build().toString();

HttpEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, request , String.class);

15
    String uri = http://my-rest-url.org/rest/account/{account};

    Map<String, String> uriParam = new HashMap<>();
    uriParam.put("account", "my_account");

    UriComponents builder = UriComponentsBuilder.fromHttpUrl(uri)
                .queryParam("pageSize","2")
                        .queryParam("page","0")
                        .queryParam("name","my_name").build();

    HttpEntity<String> requestEntity = new HttpEntity<>(null, getHeaders());

    ResponseEntity<String> strResponse = restTemplate.exchange(builder.toUriString(),HttpMethod.GET, requestEntity,
                        String.class,uriParam);

    //final URL: http://my-rest-url.org/rest/account/my_account?pageSize=2&page=0&name=my_name

RestTemplate: Створіть динамічний URI за допомогою UriComponents (змінна URI та параметри запиту)


6

Перетворення хеш-карти в рядок параметрів запиту:

Map<String, String> params = new HashMap<>();
params.put("msisdn", msisdn);
params.put("email", email);
params.put("clientVersion", clientVersion);
params.put("clientType", clientType);
params.put("issuerName", issuerName);
params.put("applicationName", applicationName);

UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url);
for (Map.Entry<String, String> entry : params.entrySet()) {
    builder.queryParam(entry.getKey(), entry.getValue());
}

HttpHeaders headers = new HttpHeaders();
headers.set("Accept", "application/json");

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

3

Я приймаю різний підхід, ви можете погодитися чи ні, але я хочу контролювати файл .properties замість компільованого коду Java

Всередині application.properties файл

endpoint.url = https: // yourHost / resource? requestParam1 = {0} & requestParam2 = {1}

Тут йде код Java, ви можете написати if або переключити умову, щоб дізнатися, чи є URL-адреса кінцевої точки у .properties файлі @PathVariable (містить {}) або @RequestParam (вашURL? Ключ = значення) тощо ..., а потім викликати метод відповідно. Таким чином, його динамічність і не потрібно змінювати код у майбутньому "зупинці" ...

Я намагаюся дати більше ідеї, ніж фактичного коду тут ... спробуйте написати загальний метод кожен для @RequestParam і @PathVariable тощо ..., то зателефонуйте відповідно, коли потрібно

  @Value("${endpoint.url}")
  private String endpointURL;
  // you can use variable args feature in Java
  public String requestParamMethodNameHere(String value1, String value2) {
    RestTemplate restTemplate = new RestTemplate();
    restTemplate
           .getMessageConverters()
           .add(new MappingJackson2HttpMessageConverter());

    HttpHeaders headers = new HttpHeaders();
    headers.set("Accept", MediaType.APPLICATION_JSON_VALUE);
    HttpEntity<String> entity = new HttpEntity<>(headers);

    try {
      String formatted_URL = MessageFormat.format(endpointURL, value1, value2);
      ResponseEntity<String> response = restTemplate.exchange(
                    formatted_URL ,
                    HttpMethod.GET,
                    entity,
                    String.class);
     return response.getBody();
    } catch (Exception e) { e.printStackTrace(); }

3

У Весна Веб 4.3.6 я також бачу

public <T> T getForObject(String url, Class<T> responseType, Object... uriVariables)

Це означає, що вам не потрібно створювати потворну карту

Тож якщо у вас є ця URL-адреса

http://my-url/action?param1={param1}&param2={param2}

Можна або робити

restTemplate.getForObject(url, Response.class, param1, param2)

або

restTemplate.getForObject(url, Response.class, param [])

2
public static void main(String[] args) {
         HttpHeaders httpHeaders = new HttpHeaders();
         httpHeaders.set("Accept", MediaType.APPLICATION_JSON_VALUE);
         final String url = "https://host:port/contract/{code}";
         Map<String, String> params = new HashMap<String, String>();
         params.put("code", "123456");
         HttpEntity<?> httpEntity  = new HttpEntity<>(httpHeaders); 
         RestTemplate restTemplate  = new RestTemplate();
         restTemplate.exchange(url, HttpMethod.GET, httpEntity,String.class, params);
    }

2

Якщо ви передасте параметризовані парами для RestTemplate, ви матимете одну метрику для кожного окремо взятої різної URL-адреси, враховуючи параметри. Ви хочете використовувати параметризовані URL-адреси:

http://my-url/action?param1={param1}&param2={param2}

замість

http://my-url/action?param1=XXXX&param2=YYYY

Другий випадок - це те, що ви отримуєте, використовуючи клас UriComponentsBuilder.

Одним із способів реалізації першої поведінки є наступний:

Map<String, Object> params = new HashMap<>();
params.put("param1", "XXXX");
params.put("param2", "YYYY");

String url = "http://my-url/action?%s";

String parametrizedArgs = params.keySet().stream().map(k ->
    String.format("%s={%s}", k, k)
).collect(Collectors.joining("&"));

HttpHeaders headers = new HttpHeaders();
headers.set("Accept", MediaType.APPLICATION_JSON_VALUE);
HttpEntity<String> entity = new HttpEntity<>(headers);

restTemplate.exchange(String.format(url, parametrizedArgs), HttpMethod.GET, entity, String.class, params);

0

Якщо ваша URL-адреса http://localhost:8080/context path?msisdn={msisdn}&email={email}

тоді

Map<String,Object> queryParams=new HashMap<>();
queryParams.put("msisdn",your value)
queryParams.put("email",your value)

працює для методу обміну шаблонів решти, як описано Вами

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.