Spring RestTemplate GET với các tham số


267

Tôi phải thực hiện một RESTcuộc gọi bao gồm các tiêu đề tùy chỉnh và các tham số truy vấn. Tôi đặt HttpEntitychỉ với các tiêu đề (không có phần thân) và tôi sử dụng RestTemplate.exchange()phương pháp như sau:

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

Điều này không thành công ở cuối máy khách với việc dispatcher servletkhông thể giải quyết yêu cầu cho người xử lý. Sau khi gỡ lỗi, có vẻ như các tham số yêu cầu không được gửi.

Khi tôi thực hiện trao đổi với POSTviệc sử dụng phần thân yêu cầu và không có tham số truy vấn nào, nó sẽ hoạt động tốt.

Có ai có ý tưởng nào?

Câu trả lời:


481

Để dễ dàng thao tác URL / đường dẫn / params / v.v., bạn có thể sử dụng lớp UriComponentsBuilder của Spring . Nó sạch hơn mà nối các chuỗi theo cách thủ công và nó sẽ chăm sóc mã hóa URL cho bạn:

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
Mẹo tuyệt vời. Chỉ cần thay đổi exchangethành getForEntity: restTemplate.getForEntity(builder.build().encode().toUri(), String.class);cho đơn giản.
Fernando M. Pinheiro

12
@ FernandoM.Pinheiro: Bạn đúng, nhưng nếu bạn đang mong đợi một loại chung trong phản hồi, thì bạn cần sử dụng exchangevà cung cấp a ParameterizedTypeReference. Ví dụ có thể được đơn giản hóa hơn nữa, thay thế builder.build().encode().toUri()bằng builder.toUriString().
mirzmaster

@Christophe L Bạn có thể hiển thị làm thế nào tôi có thể nhận được các tham số chuỗi này ở phía máy chủ không ??
KJEjava48

3
Có một lối tắt để nhận URI: chỉ cần gọibuilder.toUriString()
Michael Piefel

Tài liệu mùa xuân cho UriComponentsBuilder . Hướng dẫn giải thích các trường hợp sử dụng khác nhau của UriComponentsBuilder
Chacko Mathew

180

Các uriVariabled cũng được mở rộng trong chuỗi truy vấn. Ví dụ: cuộc gọi sau sẽ mở rộng giá trị cho cả hai, tài khoản và tên:

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

vì vậy url yêu cầu thực tế sẽ là

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

Hãy xem HVELicalUriComponents.ExandI Internalal (UriTemplateVariables) để biết thêm chi tiết. Phiên bản của mùa xuân là 3.1.3.


Cảm ơn - Giải pháp rất đơn giản
Angshuman Agarwal

2
Và khi tạo phiên bản RestTemplate, bạn có thể chỉ định cách các giá trị tham số truy vấn đó sẽ được mở rộng bằng cách chỉ định DefaultUriTemplateHandler (trước Spring 5) hoặc DefaultUriBuilderFactory (Spring 5+). Điều này hữu ích khi bạn muốn mã hóa các ký tự bổ sung như !, (,), V.v.
Stephen Rudolph

URL của tôi có hơn 10 tham số, có cách nào để đạt được điều tương tự với một đối tượng / bản đồ thay vì liệt kê mọi biến không? Tôi không thể sử dụng UriComponentsBuildervì nó khiến nó tạo ra một số liệu khác nhau cho mỗi yêu cầu vớiMicrometer
Doug

@Doug - RestTemplatecó các phương thức song song để chỉ định một mảng vị trí của các giá trị ( Object... uriVariables) hoặc bản đồ của các giá trị được đặt tên ( Map<String, ?> uriVariables). Âm thanh như phiên bản bản đồ là những gì bạn muốn : restTemplate.exchange(url, HttpMethod.GET, httpEntity, clazz, urlVariablesMap).
M. Justin

42

Ít nhất là từ mùa xuân 3, thay vì sử dụng UriComponentsBuilderđể xây dựng các URL (đó là một chút dài dòng), nhiều trong những RestTemplatephương pháp chấp nhận giữ chỗ trong đường dẫn cho các thông số (không chỉ exchange).

Từ tài liệu:

Nhiều RestTemplatephương thức chấp nhận một mẫu URI và các biến mẫu URI, dưới dạng Stringvararg hoặc as Map<String,String>.

Ví dụ với một Stringvararg:

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

Hoặc với một 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);

Tham khảo: https://docs.spring.io/spring/docs/civerse/spring-framework-reference/integration.html#rest-resttemplate-uri

Nếu bạn nhìn vào javadoc cho RestTemplatevà tìm kiếm cho "URI Template", bạn có thể xem những phương pháp bạn có thể sử dụng placeholders với.


35

OK, vì vậy tôi là một thằng ngốc và tôi nhầm lẫn các tham số truy vấn với các tham số url. Tôi đã hy vọng sẽ có một cách tốt hơn để điền vào các tham số truy vấn của mình thay vì một Chuỗi kết nối xấu xí nhưng chúng ta đang ở đó. Nó chỉ đơn giản là một trường hợp xây dựng URL với các tham số chính xác. Nếu bạn vượt qua nó dưới dạng Chuỗi mùa xuân cũng sẽ đảm nhiệm việc mã hóa cho bạn.


Nó đã làm việc cho bạn ? tôi đã làm theo cách tiếp cận tương tự của việc sử dụng UriComponentsBuilder nhưng, tại URL mục tiêu, khi tôi thực hiện một request.getAttribution (), tôi nhận được null.
yathirigan

47
Tôi thực sự không hiểu tại sao câu trả lời này có dấu xanh.
Pradeep

7
bởi vì anh ấy là OP
Kalpesh Soni

Vậy giải pháp của bạn là gì? Cảm ơn!
Raymond Chen

18

Tôi đã thử một cái gì đó tương tự, và ví dụ RoboSpice đã giúp tôi giải quyết nó :

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: Xây dựng URI động bằng cách sử dụng UriComponents (tham số yêu cầu và biến URI)


6

Chuyển đổi bản đồ băm thành một chuỗi các tham số truy vấn:

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

Tôi có cách tiếp cận khác, bạn có thể đồng ý hoặc không nhưng tôi muốn kiểm soát từ tệp .properations thay vì mã Java được biên dịch

Bên trong tập tin application.properIES

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

Mã Java ở đây, bạn có thể viết if hoặc chuyển điều kiện để tìm hiểu xem URL điểm cuối trong tệp .properations có @PathVariable (chứa {}) hoặc @RequestParam (yourURL? Key = value) v.v ... sau đó gọi phương thức cho phù hợp .. theo cách đó năng động và không cần mã thay đổi trong một cửa hàng trong tương lai ...

Tôi đang cố gắng đưa ra nhiều ý tưởng hơn mã thực tế ở đây ... hãy thử viết phương thức chung cho mỗi @RequestParam và @PathVariable, v.v ... sau đó gọi cho phù hợp khi cầ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

Trong Spring Web 4.3.6 tôi cũng thấy

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

Điều đó có nghĩa là bạn không phải tạo ra một bản đồ xấu xí

Vì vậy, nếu bạn có url này

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

Bạn có thể làm

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

hoặc là

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

Nếu bạn vượt qua các thông số không tham số cho RestTemplate, bạn sẽ có một Số liệu cho tất cả mọi người một URL khác nhau mà bạn vượt qua, xem xét các tham số. Bạn muốn sử dụng các url tham số:

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

thay vì

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

Trường hợp thứ hai là những gì bạn nhận được bằng cách sử dụng lớp UriComponentsBuilder.

Một cách để thực hiện hành vi đầu tiên là như sau:

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

Nếu url của bạn là http://localhost:8080/context path?msisdn={msisdn}&email={email}

sau đó

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

hoạt động cho phương pháp trao đổi resttemplate như mô tả của bạn

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.