Spring RestTemplate GET z parametrami


266

Muszę wykonać RESTpołączenie, które zawiera niestandardowe nagłówki i parametry zapytania. Ustawiam HttpEntitytylko z nagłówkami (bez treści) i używam RestTemplate.exchange()metody w następujący sposób:

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);

Nie udaje się to po stronie klienta, dispatcher servletponieważ nie można rozwiązać żądania do programu obsługi. Po debugowaniu wygląda na to, że parametry żądania nie są wysyłane.

Kiedy dokonuję wymiany za POSTpomocą treści żądania i bez parametrów zapytania, działa to dobrze.

Czy ktoś ma jakieś pomysły?

Odpowiedzi:


480

Aby łatwo manipulować adresami URL / ścieżką / parametrami / itp., Możesz użyć klasy UriComponentsBuilder firmy Spring . Jest czystszy, że ręcznie łączy ciągi i dba o kodowanie adresu URL dla Ciebie:

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
Świetna wskazówka. Właśnie zmieniono exchangena getForEntity: restTemplate.getForEntity(builder.build().encode().toUri(), String.class);dla uproszczenia.
Fernando M. Pinheiro

12
@ FernandoM.Pinheiro: Masz rację, ale jeśli oczekujesz ogólnego rodzaju odpowiedzi, musisz użyć exchangei podać ParameterizedTypeReference. Przykład można jednak jeszcze uprościć, zastępując builder.build().encode().toUri()go builder.toUriString().
mirzmaster,

@Christophe L Czy możesz pokazać, w jaki sposób mogę otrzymać te parametry ciągu po stronie serwera?
KJEjava48

3
Istnieje skrót do uzyskania identyfikatora URI: wystarczy zadzwonićbuilder.toUriString()
Michael Piefel

Wiosenne dokumenty dla UriComponentsBuilder . Przewodnik wyjaśniający różne przypadki użycia UriComponentsBuilder
Chacko Mathew

179

Zmienne uriVariables są również rozwijane w ciągu zapytania. Na przykład następujące wywołanie rozszerzy wartości zarówno konta, jak i nazwy:

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

więc rzeczywisty adres URL żądania będzie

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

Spójrz na HierarchicalUriComponents.expandInternal (UriTemplateVariables), aby uzyskać więcej informacji. Wersja Spring to 3.1.3.


Dzięki - Bardzo proste rozwiązanie
Angshuman Agarwal

2
Podczas tworzenia instancji RestTemplate można określić, w jaki sposób wartości parametrów zapytania będą rozszerzane, określając DefaultUriTemplateHandler (przed Spring 5) lub DefaultUriBuilderFactory (Spring 5+). Jest to przydatne, gdy chcesz zakodować dodatkowe znaki, takie jak!, (,) Itp.
Stephen Rudolph

Mój adres URL ma ponad 10 parametrów, czy jest jakiś sposób, aby osiągnąć to samo z obiektem / mapą zamiast listy każdej zmiennej? Nie mogę również użyć UriComponentsBuilder, ponieważ powoduje to generowanie innej metryki dla każdego żądania zMicrometer
Doug

@Doug - RestTemplatema równoległe metody określania albo tablicy pozycyjnej wartości ( Object... uriVariables), albo mapy nazwanych wartości ( Map<String, ?> uriVariables). Brzmi jak wersja mapy jest to, co chcesz: restTemplate.exchange(url, HttpMethod.GET, httpEntity, clazz, urlVariablesMap).
M. Justin,

42

Co najmniej od wiosny 3, zamiast używać UriComponentsBuilderdo budowania URL (co jest nieco rozwlekły), wiele z RestTemplatemetod zaakceptować zastępcze w ścieżce dla parametrów (nie tylko exchange).

Z dokumentacji:

Wiele RestTemplatemetod akceptuje szablon URI i zmienne szablonu URI, jako Stringvararg lub as Map<String,String>.

Na przykład z Stringvararg:

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

Lub z 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);

Odniesienie: https://docs.spring.io/spring/docs/current/spring-framework-reference/integration.html#rest-resttemplate-uri

Jeśli spojrzeć na JavaDoc dla RestTemplatei wyszukać „URI Szablon”, można zobaczyć, jakie metody można korzystać z zastępczych.


35

OK, więc jestem idiotą i mylę parametry zapytania z parametrami adresu URL. Miałem trochę nadziei, że będzie lepszy sposób na wypełnienie moich parametrów zapytania niż brzydki połączony ciąg, ale tak jest. Jest to po prostu przypadek zbudowania adresu URL z poprawnymi parametrami. Jeśli przekażesz go jako String String, zajmie się także kodowaniem.


czy to zadziałało dla ciebie? zastosowałem to samo podejście, używając UriComponentsBuilder, ale pod docelowym adresem URL, gdy wykonuję request.getAttribute (), otrzymuję wartość null.
yathirigan

47
Naprawdę nie rozumiem, dlaczego ta odpowiedź ma zielony tyk.
Pradeep

7
ponieważ on jest OP
Kalpesh Soni

Więc jakie jest twoje rozwiązanie? Dzięki!
Raymond Chen

18

Próbowałem czegoś podobnego, a przykład RoboSpice pomógł mi to wypracować :

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: Zbuduj dynamiczny URI przy użyciu UriComponents (zmienna URI i parametry żądania)


6

Konwersja mapy skrótu na ciąg parametrów zapytania:

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

Mam inne podejście, możesz się zgodzić lub nie, ale chcę kontrolować z pliku .properties zamiast skompilowanego kodu Java

Wewnątrz pliku application.properties

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

Tutaj jest kod Java, możesz napisać if lub zmienić warunek, aby dowiedzieć się, czy adres URL punktu końcowego w pliku .properties ma @PathVariable (zawiera {}) lub @RequestParam (twójURL? Klucz = wartość) itp., A następnie odpowiednio wywołaj metodę .. , w ten sposób jego dynamika i nie trzeba zmieniać kodu w przyszłości one stop shop ...

Próbuję podać więcej pomysłów niż rzeczywisty kod tutaj ... spróbuj napisać metodę ogólną dla @RequestParam i @PathVariable itp. ... a następnie odpowiednio zadzwoń, gdy zajdzie taka potrzeba

  @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

W Spring Web 4.3.6 również widzę

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

Oznacza to, że nie musisz tworzyć brzydkiej mapy

Więc jeśli masz ten adres URL

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

Możesz albo

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

lub

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

Jeśli przekażesz parametry nie sparametryzowane dla RestTemplate, będziesz mieć jedną Metrykę dla każdego z osobna podając inny adres URL, biorąc pod uwagę parametry. Chcesz użyć sparametryzowanych adresów URL:

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

zamiast

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

Drugi przypadek to to, co otrzymujesz za pomocą klasy UriComponentsBuilder.

Jednym ze sposobów wdrożenia pierwszego zachowania jest:

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

Jeśli masz adres URL http://localhost:8080/context path?msisdn={msisdn}&email={email}

następnie

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

działa w przypadku metody wymiany szablonów zgodnie z opisem użytkownika

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.