363 votes

Spring RestTemplate GET avec des paramètres

Je dois faire un appel REST qui inclut des en-têtes personnalisés et des paramètres de requête. Je définis mon HttpEntity avec juste les en-têtes (pas de corps), et j'utilise la méthode RestTemplate.exchange() comme suit :

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

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

HttpEntity entity = new HttpEntity(headers);

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

Cela échoue au niveau du client avec le servlet de dispatcher incapable de résoudre la requête vers un gestionnaire. Après avoir débogué, il semble que les paramètres de requête ne sont pas envoyés.

Quand je fais un échange avec un POST en utilisant un corps de requête et aucun paramètre de requête, cela fonctionne très bien.

Est-ce que quelqu'un a des idées ?

646voto

Christophe L Points 1813

Pour manipuler facilement les URL / chemins / paramètres, vous pouvez utiliser la classe UriComponentsBuilder de Spring pour créer un modèle d'URL avec des espaces réservés pour les paramètres, puis fournir les valeurs de ces paramètres dans l'appel à RestOperations.exchange(...). C'est plus propre que de concaténer manuellement des chaînes et cela se charge de l'encodage d'URL pour vous :

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

String urlTemplate = UriComponentsBuilder.fromHttpUrl(url)
        .queryParam("msisdn", "{msisdn}")
        .queryParam("email", "{email}")
        .queryParam("clientVersion", "{clientVersion}")
        .queryParam("clientType", "{clientType}")
        .queryParam("issuerName", "{issuerName}")
        .queryParam("applicationName", "{applicationName}")
        .encode()
        .toUriString();

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

HttpEntity response = restOperations.exchange(
        urlTemplate,
        HttpMethod.GET,
        entity,
        String.class,
        params
);

14 votes

Super conseil. Je viens de changer exchange en getForEntity : restTemplate.getForEntity(builder.build().encode().toUri(), String.class); pour plus de simplicité.

13 votes

@FernandoM.Pinheiro: Vous avez raison, mais si vous attendez un type générique dans la réponse, alors vous devez utiliser exchange et fournir un ParameterizedTypeReference. L'exemple peut être encore simplifié en remplaçant builder.build().encode().toUri() par builder.toUriString().

0 votes

@Christophe L Pouvez-vous montrer comment je pourrais recevoir ces paramètres de chaîne du côté serveur?

255voto

pavel Points 1176

Les uriVariables sont également étendues dans la chaîne de requête. Par exemple, l'appel suivant va étendre les valeurs à la fois pour le compte et le nom :

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

donc l'URL de requête réelle sera

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

Consultez HierarchicalUriComponents.expandInternal(UriTemplateVariables) pour plus de détails. Version de Spring est 3.1.3.

0 votes

Merci - Solution très simple

3 votes

Et lors de la création de l'instance RestTemplate, vous pouvez spécifier comment ces valeurs des paramètres de requête seront développées en spécifiant le DefaultUriTemplateHandler (avant Spring 5) ou DefaultUriBuilderFactory (Spring 5+). Cela est utile lorsque vous souhaitez encoder des caractères supplémentaires tels que !, (, ), etc.

0 votes

Mon URL a 10+ paramètres, y a-t-il un moyen d'obtenir le même résultat avec un objet/map au lieu de lister chaque variable? Je ne peux pas utiliser UriComponentsBuilder car cela génère une métrique différente pour chaque requête avec Micrometer

65voto

dustin.schultz Points 165

Depuis au moins Spring 3, au lieu d'utiliser UriComponentsBuilder pour construire l'URL (ce qui est un peu verbeux), beaucoup des méthodes de RestTemplate acceptent des espaces réservés dans le chemin pour les paramètres (pas seulement exchange).

D'après la documentation:

Beaucoup des méthodes de RestTemplate acceptent un modèle URI et des variables de modèle URI, soit en tant que vararg String, soit en tant que Map.

Par exemple avec un vararg String:

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

Ou avec un Map:

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

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

Référence: https://docs.spring.io/spring/docs/current/spring-framework-reference/integration.html#rest-resttemplate-uri

Si vous regardez le JavaDoc de RestTemplate et recherchez "Modèle URI", vous pouvez voir quelles méthodes vous pouvez utiliser avec des espaces réservés.

33voto

Elwood Points 3749

D'accord, donc je suis idiot et je confonds les paramètres de requête avec les paramètres d'URL. J'espérais qu'il y aurait un moyen plus efficace de remplir mes paramètres de requête plutôt qu'avec une chaîne de caractères moche, mais c'est comme ça. Il suffit de construire l'URL avec les bons paramètres. Si vous le transmettez en tant que chaîne de caractères, Spring se chargera également de l'encodage pour vous.

0 votes

Est-ce que cela a fonctionné pour vous ? J'ai suivi la même approche en utilisant UriComponentsBuilder, mais, à l'URL cible, lorsque je fais un request.getAttribute(), je reçois null.

76 votes

Je ne comprends sérieusement pas pourquoi cette réponse a une coche verte.

14 votes

Parce qu'il est le créateur du post

30voto

Kripesh Bista Points 321
    String uri = http://mon-url-de-rest.org/rest/account/{account};

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

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

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

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

    //final URL: http://mon-url-de-rest.org/rest/account/mon_compte?pageSize=2&page=0&name=mon_nom

RestTemplate: Construire une URI dynamique en utilisant UriComponents (variables d'URI et paramètres de requête)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X