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?
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.
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);
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.
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);
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 queString
vararg, soit en tant queMap<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);
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.
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é.
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(); }
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}¶m2={param2}
au lieu de
http://my-url/action?param1=XXXX¶m2=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);
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);
}
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);
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}¶m2={param2}
Vous pouvez soit faire
restTemplate.getForObject(url, Response.class, param1, param2)
ou
restTemplate.getForObject(url, Response.class, param [])
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)