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.