Spring RestTemplate GET'i parametrelerle


267

RESTÖzel başlıklar ve sorgu parametreleri içeren bir arama yapmak zorunda . HttpEntitySadece üstbilgilerle (gövde yok) ayarladım ve RestTemplate.exchange()yöntemi aşağıdaki gibi kullanıyorum :

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

Bu dispatcher servlet, bir işleyiciye isteği çözümleyememesi ile istemci sonunda başarısız olur . Hata ayıklandıktan sonra, istek parametreleri gönderilmiyor gibi görünüyor.

Ben POSTbir istek gövdesi ve hiçbir sorgu parametreleri kullanarak bir değişim yaptığımda gayet iyi çalışıyor.

Herhangi bir fikri olan var mı?

Yanıtlar:


481

URL'leri / yolu / params / vb. Kolayca değiştirmek için Spring'in UriComponentsBuilder sınıfını kullanabilirsiniz. Dizeleri manuel olarak birleştiren daha temiz ve sizin için URL kodlamasını halleder:

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
Harika bir ipucu. Basitlik exchangeiçin getForEntity: olarak değiştirildi restTemplate.getForEntity(builder.build().encode().toUri(), String.class);.
Fernando

12
@ FernandoM.Pinheiro: Haklısınız, ancak yanıtta genel bir tür bekliyorsanız, kullanmanız exchangeve sağlamanız gerekir ParameterizedTypeReference. Örnek, bundan başka yerine da basitleştirilebilir builder.build().encode().toUri()ile builder.toUriString().
mirzmaster

@Christophe L Sunucu tarafında bu dize parametrelerini nasıl alabileceğimi gösterebilir miyim?
KJEjava48

3
builder.toUriString()
URI'yi


180

UriVariables da sorgu dizesinde genişletilir. Örneğin, aşağıdaki çağrı hem hesap hem de ad için değerleri genişletir:

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

böylece gerçek istek URL'si

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

Daha fazla ayrıntı için HierarchicalUriComponents.expandInternal'a (UriTemplateVariables) bakın. İlkbahar sürümü 3.1.3'tür.


Teşekkürler - Çok basit bir çözüm
Angshuman Agarwal

2
RestTemplate örneği oluştururken, DefaultUriTemplateHandler (İlkbahar 5'ten önce) veya DefaultUriBuilderFactory (İlkbahar 5+) belirterek bu sorgu parametre değerlerinin nasıl genişletileceğini belirtebilirsiniz. !, (,) Vb. Gibi ek karakterleri kodlamak istediğinizde yararlıdır.
Stephen Rudolph

URL'mde 10'dan fazla parametre var, her değişkeni listelemek yerine bir nesne / harita ile aynı şeyi elde etmenin herhangi bir yolu var mı? Ben de UriComponentsBuilderher istek için farklı bir metrik oluşturmak için neden olduğu gibi kullanamıyorumMicrometer
Doug

@Doug - konumsal RestTemplatebir değerler dizisi ( Object... uriVariables) veya adlandırılmış değerlerin ( Map<String, ?> uriVariables) haritasını belirtmek için paralel yöntemlere sahiptir . Harita versiyonu gibi Sesler ne istiyorsun: restTemplate.exchange(url, HttpMethod.GET, httpEntity, clazz, urlVariablesMap).
M. Justin

42

En azından İlkbahar 3'ten beri UriComponentsBuilder, URL'yi (biraz ayrıntılı) oluşturmak için kullanmak yerine , yöntemlerin çoğuRestTemplate parametre yolundaki yer tutucuları kabul eder (sadece değil exchange).

Belgelerden:

RestTemplateYöntemlerin çoğu, bir Stringvararg veya olarak bir URI şablonu ve URI şablonu değişkenlerini kabul eder Map<String,String>.

Örneğin bir Stringvararg ile:

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

Veya aşağıdakilerle 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);

Referans: https://docs.spring.io/spring/docs/current/spring-framework-reference/integration.html#rest-resttemplate-uri

Eğer bakarsak JavaDoc'u için RestTemplateve "URI Şablon" için arama, size olan tutucuları kullanabilirsiniz hangi yöntemleri görebilirsiniz.


35

Tamam, bu yüzden bir salak oluyorum ve sorgu parametrelerini url parametreleriyle karıştırıyorum. Ben çirkin bir bitmiş String yerine benim sorgu parametreleri doldurmak için güzel bir yol olacağını umuyordu ama oradayız. Bu, URL'yi doğru parametrelerle derlemenizdir. Eğer bir String Spring olarak geçerseniz de sizin için kodlama ilgilenir.


senin için çalıştı mı UriComponentsBuilder kullanarak aynı yaklaşımı izledi, ancak hedef URL'de, bir request.getAttribute () yaptığımda null olsun.
yathirigan

47
Bu cevabın neden yeşil kene olduğunu ciddi olarak anlamıyorum.
Pradeep

7
çünkü OP
Kalpesh Soni

Peki çözümünüz nedir? Teşekkürler!
Raymond Chen

18

Benzer bir şey deniyordum ve RoboSpice örneği çalışmama yardımcı oldu :

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: UriComponents kullanarak dinamik URI oluşturun (URI değişkeni ve İstek parametreleri)


6

Bir karma haritanın bir dizi sorgu parametresine dönüştürülmesi:

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

Farklı bir yaklaşım benimsiyorum, kabul edebilir veya etmeyebilirsiniz ama derlenmiş Java kodu yerine .properties dosyasından kontrol etmek istiyorum

Application.properties dosyası içinde

endpoint.url = https: // yourHost / kaynak? requestParam1 = {0} & requestParam2 = {1}

Java kodu buraya gelirse, .properties dosyasındaki uç nokta URL'sinin @PathVariable ({}) veya @RequestParam (yourURL? Anahtar = değer) vb. Bu şekilde dinamik ve gelecekteki bir durak mağazasında değişikliği kodlamaya gerek yok ...

Burada gerçek kod daha fazla fikir vermeye çalışıyorum ... @RequestParam ve @PathVariable vb her biri için genel bir yöntem yazmaya çalışın ... sonra gerektiğinde buna göre arayın

  @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

Spring Web 4.3.6'da ayrıca

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

Bu, çirkin bir harita oluşturmak zorunda olmadığınız anlamına gelir

Yani bu url'ye sahipseniz

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

Ya yapabilirsin

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

veya

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

RestTemplate için parametrelenmemiş parametreler iletirseniz, parametreleri göz önünde bulundurarak, ilettiğiniz herkesin tek tek farklı URL'si için bir Metrikiniz olur. Parametreli URL'leri kullanmak istiyorsunuz:

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

onun yerine

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

İkinci durum UriComponentsBuilder sınıfını kullanarak elde ettiğiniz durumdur.

İlk davranışı uygulamanın bir yolu şudur:

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

URL'niz http://localhost:8080/context path?msisdn={msisdn}&email={email}

sonra

Map<String,Object> queryParams=new HashMap<>();
queryParams.put("msisdn",your value)
queryParams.put("email",your value)

sizin tanımladığınız gibi yeniden biçimlendirme değişim yöntemi için çalışır

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.