Spring RestTemplate OTTIENI con i parametri


268

Devo effettuare una RESTchiamata che includa intestazioni personalizzate e parametri di query. Ho impostato il mio HttpEntitysolo con le intestazioni (senza corpo) e utilizzo il RestTemplate.exchange()metodo come segue:

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

Ciò ha esito negativo sul lato client con l' dispatcher servletimpossibilità di risolvere la richiesta a un gestore. Dopo aver eseguito il debug, sembra che i parametri della richiesta non vengano inviati.

Quando faccio uno scambio con l' POSTutilizzo di un corpo della richiesta e senza parametri di query funziona perfettamente.

Qualcuno ha qualche idea?

Risposte:


481

Per manipolare facilmente URL / percorso / parametri / ecc., Puoi usare la classe UriComponentsBuilder di Spring . È più pulito concatenare manualmente le stringhe e si occupa della codifica URL per te:

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
Ottimo consiglio Appena cambiato exchangein getForEntity: restTemplate.getForEntity(builder.build().encode().toUri(), String.class);per semplicità.
Fernando M. Pinheiro,

12
@ FernandoM.Pinheiro: hai ragione, ma se ti aspetti un tipo generico nella risposta, allora devi usare exchangee fornire un ParameterizedTypeReference. L'esempio può essere ulteriormente semplificato, sostituendolo builder.build().encode().toUri()con builder.toUriString().
mirzmaster,

@Christophe L Puoi mostrare come posso ricevere questi parametri di stringa sul lato server ??
KJEjava48,

3
Esiste una scorciatoia per ottenere l'URI: basta chiamarebuilder.toUriString()
Michael Piefel il

Documenti di primavera per UriComponentsBuilder . Guida che spiega i vari casi d'uso di UriComponentsBuilder
Chacko Mathew

180

Le uriVariabili sono anche espanse nella stringa di query. Ad esempio, la seguente chiamata espande i valori sia di account che di nome:

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

così sarà l'URL della richiesta effettiva

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

Guarda HierarchicalUriComponents.expandInternal (UriTemplateVariables) per maggiori dettagli. La versione di Spring è 3.1.3.


Grazie - Soluzione molto semplice
Angshuman Agarwal,

2
E quando si crea l'istanza RestTemplate, è possibile specificare come verranno espansi i valori di questi parametri di query specificando DefaultUriTemplateHandler (prima della Spring 5) o DefaultUriBuilderFactory (Spring 5+). Ciò è utile quando si desidera codificare caratteri aggiuntivi come!, (,), Ecc.
Stephen Rudolph,

Il mio URL ha oltre 10 parametri, un modo per ottenere lo stesso con un oggetto / mappa invece di elencare ogni variabile? Non posso usare UriComponentsBuilderneanche perché sta causando una metrica diversa per ogni richiesta conMicrometer
Doug

@Doug - RestTemplateha metodi paralleli per specificare una matrice posizionale di valori ( Object... uriVariables) o una mappa di valori nominati ( Map<String, ?> uriVariables). Suoni come la versione della mappa è quello che si vuole: restTemplate.exchange(url, HttpMethod.GET, httpEntity, clazz, urlVariablesMap).
M. Justin,

42

Poiché almeno Spring 3, invece di utilizzare UriComponentsBuilderper creare l'URL (che è un po 'dettagliato), molti dei RestTemplatemetodi accettano segnaposto nel percorso per i parametri (non soloexchange ).

Dalla documentazione:

Molti dei RestTemplatemetodi accettano un modello URI e variabili del modello URI, come Stringvararg o come Map<String,String> .

Ad esempio con un Stringvararg:

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

O con un 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);

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

Se si guarda alla JavaDoc per RestTemplatee cercare "URI Template", è possibile vedere quali metodi è possibile utilizzare i segnaposto con.


35

OK, quindi sono un idiota e confondo i parametri della query con i parametri url. Speravo che ci sarebbe un modo migliore per popolare i miei parametri di query piuttosto che una brutta stringa concatenata, ma ci siamo. È semplicemente il caso di creare l'URL con i parametri corretti. Se lo passi come String Spring si occuperà anche della codifica per te.


Ha funzionato per te ? ho seguito lo stesso approccio dell'utilizzo di UriComponentsBuilder ma, nell'URL di destinazione, quando eseguo request.getAttribute (), ottengo null.
yathirigan,

47
Davvero non capisco perché questa risposta abbia un segno di spunta verde.
Pradeep,

7
perché è l'OP
Kalpesh Soni il

Qual è la tua soluzione? Grazie!
Raymond Chen,

18

Stavo tentando qualcosa di simile e l'esempio di RoboSpice mi ha aiutato a risolverlo :

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: crea URI dinamico usando UriComponents (variabile URI e parametri Request)


6

Conversione di una mappa hash in una stringa di parametri di query:

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

Ho un approccio diverso, potresti essere d'accordo o no, ma voglio controllare dal file .properties invece che dal codice Java compilato

All'interno del file application.properties

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

Il codice Java va qui, puoi scrivere se o cambiare condizione per scoprire se l'URL dell'endpoint nel file .properties ha @PathVariable (contiene {}) o @RequestParam (yourURL? Chiave = valore) ecc ... quindi invoca il metodo di conseguenza .. in questo modo è dinamico e non è necessario modificare il codice nel futuro sportello unico ...

Sto cercando di dare più idea del codice reale qui ... prova a scrivere un metodo generico ciascuno per @RequestParam, @PathVariable ecc ... quindi chiama di conseguenza quando necessario

  @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

In Spring Web 4.3.6 vedo anche

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

Ciò significa che non devi creare una brutta mappa

Quindi se hai questo URL

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

Puoi farlo entrambi

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

o

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

Se passi parametri non parametrizzati per RestTemplate, avrai una metrica per tutti i singoli URL diversi che passi, considerando i parametri. Desideri utilizzare gli URL parametrizzati:

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

invece di

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

Il secondo caso è quello che ottieni usando la classe UriComponentsBuilder.

Un modo per implementare il primo comportamento è il seguente:

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

Se il tuo URL è http://localhost:8080/context path?msisdn={msisdn}&email={email}

poi

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

funziona per il metodo di scambio resttemplate come descritto da te

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.