web-dev-qa-db-fra.com

Spring RestTemplate GET avec paramètres

Je dois effectuer un appel REST qui inclut des en-têtes personnalisés et des paramètres de requête. Je règle ma 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<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);

Cela échoue à la fin du client, le dispatcher servlet n'étant pas en mesure de résoudre la demande à un gestionnaire. Après l'avoir débogué, il semble que les paramètres de la demande ne soient 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.

Quelqu'un a-t-il une idée?

173
Elwood

OK, alors je suis un idiot et je confonds les paramètres de requête avec les paramètres d'URL. J'espérais un peu qu'il y aurait un moyen plus agréable de renseigner mes paramètres de requête plutôt qu'une chaîne encombrante concaténée, mais c'est le cas. Il s’agit simplement de construire l’URL avec les paramètres corrects. Si vous le transmettez sous forme de chaîne, Spring s'occupera également de l'encodage pour vous.

33
Elwood

Pour manipuler facilement les URL/chemin/paramètres/etc., vous pouvez utiliser la classe UriComponentsBuilder de Spring. C'est plus propre que concaténer manuellement les chaînes et il s'occupe de l'encodage de l'URL pour vous:

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);
334
Christophe L

Les variables uriVariables sont également développées dans la chaîne de requête. Par exemple, l'appel suivant développera des valeurs pour le compte et le nom:

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

donc l'URL de demande réelle sera

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

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

113
pavel

Je tentais quelque chose de similaire, et l'exemple de RoboSpice m'a aidé à résoudre le problème :

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

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

De la documentation:

La plupart des méthodes RestTemplate acceptent un modèle d'URI et un URI les variables de modèle, soit en tant que String vararg, soit en tant que Map<String,String>.

Par exemple, avec un String vararg:

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

Ou avec 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/{hotel}", 
    String.class, vars);

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

Si vous consultez JavaDoc pour RestTemplate et recherchez "Modèle d'URI", vous pouvez voir les méthodes avec lesquelles vous pouvez utiliser des espaces réservés.

10
dustin.schultz

Je prends une approche différente, vous pouvez être d'accord ou pas, mais je veux contrôler depuis un fichier .properties au lieu d'un code Java compilé.

Dans le fichier application.properties

endpoint.url = https: // votre hôte/ressource? requestParam1 = {0} & requestParam2 = {1}

Le code Java va ici, vous pouvez écrire si ou changez la condition pour savoir si l'URL du noeud final dans le fichier .properties a @PathVariable (contient {}) ou @RequestParam (yourURL? Clé = valeur), etc. de cette façon sa dynamique et pas besoin de changer de code à l'avenir one stop shop ... 

J'essaie de donner plus d'idée que le code réel ici ... essayez d'écrire une méthode générique chacune pour @RequestParam, et @PathVariable etc ... puis appelez en conséquence si nécessaire 

  @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
Java_Fire_Within

Si vous transmettez des paramètres non paramétrés pour RestTemplate, vous aurez une métrique pour tout le monde, une seule URL différente que vous transmettez, en fonction des paramètres. Vous souhaitez utiliser des URL paramétrées:

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

au lieu de

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

Le deuxième cas est ce que vous obtenez en utilisant la classe UriComponentsBuilder.

Une façon d'implémenter le premier comportement est la suivante:

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);
2
Dalton
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);
    }
0
Neeraj Gahlawat

Une autre solution avec le riComponentsBuilder (conversion d’un HashMap existant):

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

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

 HttpEntity entity = new HttpEntity(headers);

 UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url);
 for (Map.Entry<String, String> entry : params.entrySet()) {
     builder.queryParam(entry.getKey(), entry.getValue());
 }
 HttpEntity<String> response = restTemplate.exchange(builder.toUriString(), HttpMethod.GET, entity, String.class);
0
Ilya Lysenko

Au printemps Web 4.3.6, je vois aussi

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

Cela signifie que vous n'avez pas à créer une carte laide

Donc, si vous avez cette URL

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

Vous pouvez soit faire

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

ou

restTemplate.getForObject(url, Response.class, param [])
0
Kalpesh Soni
    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: Construire un URI dynamique à l'aide de UriComponents (variable URI et paramètres de requête)

0
Kripesh Bista