Ich muss einen Aufruf von REST
machen, der benutzerdefinierte Header und Abfrageparameter enthält. Ich setze meine HttpEntity
nur mit den Kopfzeilen (ohne Körper) und verwende die RestTemplate.exchange()
-Methode wie folgt:
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);
Dies schlägt auf der Clientseite fehl, da der dispatcher servlet
die Anforderung an einen Handler nicht auflösen kann. Nach dem Debuggen scheinen die Anforderungsparameter nicht gesendet zu werden.
Wenn ich mit einer POST
einen Austausch mit einem Anfragetext und keinen Abfrageparametern durchführe, funktioniert das einwandfrei.
Hat jemand irgendwelche Ideen?
OK, also bin ich ein Idiot und verwechsle Abfrageparameter mit URL-Parametern. Ich hatte irgendwie gehofft, dass es eine schönere Möglichkeit gibt, meine Abfrageparameter zu füllen, als einen hässlichen verketteten String, aber da sind wir. Es ist einfach ein Fall, bei dem die URL mit den richtigen Parametern erstellt wird. Wenn Sie es als String übergeben, übernimmt Spring die Codierung für Sie.
Um URLs/Pfad/Parameter/usw. einfach zu bearbeiten, können Sie die Spring-Klasse UriComponentsBuilder verwenden. Es ist sauberer, dass Zeichenketten manuell verkettet werden, und kümmert sich um die URL-Kodierung für Sie:
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);
Die uriVariables werden auch in der Abfragezeichenfolge erweitert. Mit dem folgenden Aufruf werden beispielsweise Werte für Konto und Name erweitert:
restTemplate.exchange("http://my-rest-url.org/rest/account/{account}?name={name}",
HttpMethod.GET,
httpEntity,
clazz,
"my-account",
"my-name"
);
die tatsächliche Anforderungs-URL wird also sein
http://my-rest-url.org/rest/account/my-account?name=my-name
Weitere Informationen finden Sie unter HierarchicalUriComponents.expandInternal (UriTemplateVariables) .. _. Die Version von Spring ist 3.1.3.
Ich habe etwas Ähnliches versucht, und das RoboSpice-Beispiel hat mir geholfen, es herauszufinden :
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);
Seit mindestens Spring 3 verwenden viele der UriComponentsBuilder
-Methoden anstelle von RestTemplate
zum Erstellen der URL (was ein wenig ausführlich ist) Platzhalter im Pfad für Parameter (nicht nur exchange
).
Aus der Dokumentation:
Viele der
RestTemplate
-Methoden akzeptieren eine URI-Vorlage und einen URI Vorlagenvariablen, entweder alsString
vararg oder alsMap<String,String>
.Zum Beispiel mit einer
String
vararg:restTemplate.getForObject( "http://example.com/hotels/{hotel}/rooms/{room}", String.class, "42", "21");
Oder mit einem
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);
Wenn Sie sich das JavaDoc für RestTemplate
ansehen und nach "URI-Vorlage" suchen, können Sie sehen, mit welchen Methoden Sie Platzhalter verwenden können.
Ich gehe von einem anderen Ansatz aus, Sie können dem zustimmen oder nicht, aber ich möchte die Kontrolle über die .properties-Datei anstelle von kompiliertem Java-Code
endpoint.url = https: // yourHost/resource? requestParam1 = {0} & requestParam2 = {1}
Java-Code geht hier, Sie können schreiben, ob Sie die Bedingung ändern möchten, um herauszufinden, ob die Endpunkt-URL in der .properties-Datei @PathVariable (enthält {}) oder @RequestParam (yourURL? Key = value) usw. enthält. Dann rufen Sie die Methode entsprechend auf. auf diese Weise seine Dynamik und nicht die Notwendigkeit, Änderungen in zukünftigen One-Stop-Shops zu kodieren ...
Ich versuche hier mehr von der Idee als vom tatsächlichen Code zu geben ... versuchen Sie, eine generische Methode für @RequestParam und @PathVariable usw. zu schreiben ... und rufen Sie sie entsprechend auf, wenn sie benötigt wird
@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(); }
Wenn Sie nicht-parametrisierte Parameter für RestTemplate übergeben, haben Sie eine Metrik für jeden einzelnen URL, den Sie übergeben, unter Berücksichtigung der Parameter. Sie möchten parametrisierte URLs verwenden:
http://my-url/action?param1={param1}¶m2={param2}
anstatt
http://my-url/action?param1=XXXX¶m2=YYYY
Im zweiten Fall erhalten Sie die UriComponentsBuilder-Klasse.
Eine Möglichkeit, das erste Verhalten zu implementieren, ist folgende:
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);
}
Eine andere Lösung mit dem riComponentsBuilder (Konvertieren einer vorhandenen HashMap):
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);
In Spring Web 4.3.6 sehe ich auch
public <T> T getForObject(String url, Class<T> responseType, Object... uriVariables)
Das bedeutet, dass Sie keine hässliche Karte erstellen müssen
Wenn Sie also diese URL haben
http://my-url/action?param1={param1}¶m2={param2}
Sie können entweder tun
restTemplate.getForObject(url, Response.class, param1, param2)
oder
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: Dynamische URI mit UriComponents erstellen (URI-Variable und Request-Parameter)