Spring RestTemplate DAPATKAN dengan parameter

267

Saya harus melakukan RESTpanggilan yang menyertakan tajuk khusus dan parameter kueri. Saya mengatur saya HttpEntityhanya dengan header (tanpa badan), dan saya menggunakan RestTemplate.exchange()metode sebagai berikut:

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

Ini gagal di ujung klien dengan dispatcher servletketidakmampuan untuk menyelesaikan permintaan ke penangan. Setelah melakukan debug, sepertinya parameter permintaan tidak dikirim.

Ketika saya melakukan pertukaran dengan POSTmenggunakan tubuh permintaan dan tidak ada parameter permintaan itu berfungsi dengan baik.

Adakah yang punya ide?

Elwood
sumber

Jawaban:

481

Untuk memanipulasi URL / path / params / dll dengan mudah, Anda dapat menggunakan kelas UriComponentsBuilder Spring . Lebih bersih bahwa merangkai string secara manual dan menangani pengodean URL untuk Anda:

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);
Christophe L.
sumber
10
Tip yang bagus. Baru saja diubah exchangemenjadi getForEntity: restTemplate.getForEntity(builder.build().encode().toUri(), String.class);untuk kesederhanaan.
Fernando M. Pinheiro
12
@ FernandoM.Pinheiro: Anda benar, tetapi jika Anda mengharapkan tipe generik dalam respons, maka Anda perlu menggunakan exchangedan menyediakan a ParameterizedTypeReference. Contohnya dapat disederhanakan, diganti builder.build().encode().toUri()dengan builder.toUriString().
mirzmaster
@ Christophe L Bisakah Anda menunjukkan bagaimana saya bisa menerima parameter string ini di sisi server ??
KJEjava48
3
Ada jalan pintas untuk mendapatkan URI: panggil sajabuilder.toUriString()
Michael Piefel
Spring docs untuk UriComponentsBuilder . Panduan menjelaskan berbagai kasus penggunaan UriComponentsBuilder
Chacko Mathew
180

Variabel uriVariabel juga diperluas dalam string kueri. Misalnya, panggilan berikut akan memperluas nilai untuk akun dan nama:

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

jadi url permintaan yang sebenarnya adalah

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

Lihatlah HierarchicalUriComponents.expandInternal (UriTemplateVariables) untuk lebih jelasnya. Versi Spring adalah 3.1.3.

pavel
sumber
Terima kasih - solusi yang sangat sederhana
Angshuman Agarwal
2
Dan ketika membuat instance RestTemplate, Anda dapat menentukan bagaimana nilai parameter kueri akan diperluas dengan menentukan DefaultUriTemplateHandler (sebelum Musim Semi 5) atau DefaultUriBuilderFactory (Musim 5+). Ini berguna ketika Anda ingin menyandikan karakter tambahan seperti!, (,), Dll.
Stephen Rudolph
URL saya memiliki 10+ parameter, cara apa pun untuk mencapai hal yang sama dengan objek / peta alih-alih mencantumkan setiap variabel? Saya tidak dapat menggunakan apa pun UriComponentsBuilderkarena menyebabkannya menghasilkan metrik yang berbeda untuk setiap permintaan denganMicrometer
Doug
@ Doug - RestTemplatememiliki metode paralel untuk menentukan array nilai posisi ( Object... uriVariables) atau peta nilai yang ditentukan ( Map<String, ?> uriVariables). Suara seperti versi peta adalah apa yang Anda inginkan: restTemplate.exchange(url, HttpMethod.GET, httpEntity, clazz, urlVariablesMap).
M. Justin
42

Setidaknya sejak musim semi 3, alih-alih menggunakan UriComponentsBuilderuntuk membangun URL (yang sedikit verbose), banyak dari RestTemplatemetode menerima placeholder di jalan untuk parameter (bukan hanya exchange).

Dari dokumentasi:

Banyak RestTemplatemetode yang menerima templat URI dan variabel templat URI, baik sebagai Stringvararg, atau sebagai Map<String,String>.

Misalnya dengan Stringvararg:

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

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

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

Jika Anda melihat JavaDoc untuk RestTemplatedan mencari "Templat URI", Anda bisa melihat metode mana yang bisa Anda gunakan dengan placeholder.

dustin.schultz
sumber
35

OK, jadi saya menjadi idiot dan saya membingungkan parameter kueri dengan parameter url. Saya agak berharap akan ada cara yang lebih baik untuk mengisi parameter kueri saya daripada String yang digabungkan tetapi ada kita. Ini hanya kasus membangun URL dengan parameter yang benar. Jika Anda meneruskannya sebagai String Spring juga akan mengurus pengodean untuk Anda.

Elwood
sumber
apakah itu bekerja untukmu? saya mengikuti pendekatan yang sama menggunakan UriComponentsBuilder tetapi, pada URL target, ketika saya melakukan request.getAttribute (), saya mendapatkan nol.
yathirigan
47
Saya benar-benar tidak mengerti mengapa jawaban ini memiliki tanda centang hijau.
Pradeep
7
karena dia adalah OP
Kalpesh Soni
Jadi apa solusinya? Terima kasih!
Raymond Chen
18

Saya mencoba sesuatu yang serupa, dan contoh RoboSpice membantu saya mengatasinya :

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);
elBradford
sumber
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: Bangun URI dinamis menggunakan UriComponents (variabel URI dan parameter Permintaan)

Kripesh Bista
sumber
6

Mengonversi peta hash ke serangkaian parameter kueri:

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);
Ilya Lysenko
sumber
3

Saya mengambil pendekatan yang berbeda, Anda mungkin setuju atau tidak, tetapi saya ingin mengontrol dari file .properties daripada mengkompilasi kode Java

Di dalam file application.properties

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

Kode Java ada di sini, Anda dapat menulis jika atau beralih kondisi untuk mengetahui apakah URL titik akhir dalam file .properties memiliki @PathVariable (berisi {}) atau @RequestParam (yourURL? Key = value) dll ... lalu gunakan metode yang sesuai .. ... dengan cara itu dinamis dan tidak perlu mengubah kode di one stop shop di masa depan ...

Saya mencoba memberikan lebih banyak ide daripada kode aktual di sini ... coba tulis metode generik masing-masing untuk @RequestParam, dan @PathVariable dll ... lalu panggil yang sesuai ketika dibutuhkan

  @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(); }
Java_Fire_Within
sumber
3

Di Spring Web 4.3.6 saya juga melihat

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

Itu berarti Anda tidak perlu membuat peta yang jelek

Jadi, jika Anda memiliki url ini

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

Anda bisa melakukannya

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

atau

restTemplate.getForObject(url, Response.class, param [])
Kalpesh Soni
sumber
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);
    }
Neeraj Gahlawat
sumber
2

Jika Anda melewati param non-parametrized untuk RestTemplate, Anda akan memiliki satu Metrik untuk semua orang satu URL berbeda yang Anda lewati, dengan mempertimbangkan parameter. Anda ingin menggunakan url yang parametrized:

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

dari pada

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

Kasus kedua adalah apa yang Anda dapatkan dengan menggunakan kelas UriComponentsBuilder.

Salah satu cara untuk menerapkan perilaku pertama adalah sebagai berikut:

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);
Dalton
sumber
0

Jika url Anda http://localhost:8080/context path?msisdn={msisdn}&email={email}

kemudian

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

bekerja untuk metode pertukaran resttemplate seperti yang dijelaskan oleh Anda

tidak diketahui
sumber