매개 변수가있는 Spring RestTemplate GET


266

REST사용자 지정 헤더와 쿼리 매개 변수가 포함 된 호출을 해야합니다 . 내 설정 HttpEntity단지 헤더 (NO 몸)으로, 그리고 내가 사용하는 RestTemplate.exchange()다음과 같은 방법 :

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

이는 클라이언트 측 dispatcher servlet에서 요청을 처리기로 처리 할 수 ​​없어 실패 합니다. 디버깅 한 후 요청 매개 변수가 전송되지 않는 것 같습니다.

POST요청 본문을 사용하고 쿼리 매개 변수를 사용 하지 않고 교환을 수행하면 정상적으로 작동합니다.

누구든지 아이디어가 있습니까?

답변:


480

URL / 경로 / 매개 변수 등을 쉽게 조작하기 위해 Spring의 UriComponentsBuilder 클래스를 사용할 수 있습니다 . 문자열을 수동으로 연결하는 것이 더 깨끗하고 URL 인코딩을 처리합니다.

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
좋은 팁. 그냥 변경 exchangegetForEntity: restTemplate.getForEntity(builder.build().encode().toUri(), String.class);단순화를 위해.
페르난도 M. 핀 헤이로

12
@ FernandoM.Pinheiro : 맞습니다. 그러나 응답에 제네릭 형식이 필요한 경우을 사용 exchange하고 제공해야합니다 ParameterizedTypeReference. 그러나로 대체 builder.build().encode().toUri()하여 예제를 더 단순화 할 수 있습니다 builder.toUriString().
mirzmaster

@Christophe L 서버 측에서 이러한 문자열 매개 변수를 어떻게받을 수 있습니까?
KJEjava48

3
바로 가기builder.toUriString()
Michael Piefel

UriComponentsBuilder 용 스프링 문서 . 다양한 사용 사례를 설명하는 가이드 UriComponentsBuilder을
Chacko 매튜에게

179

uriVariables도 쿼리 문자열에서 확장됩니다. 예를 들어 다음 호출은 계정 및 이름 모두에 대한 값을 확장합니다.

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

실제 요청 URL은

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

자세한 내용은 HierarchicalUriComponents.expandInternal (UriTemplateVariables)을 참조하십시오. Spring의 버전은 3.1.3입니다.


감사합니다 - 아주 간단한 해결책
Angshuman 아가 왈

2
RestTemplate 인스턴스를 작성할 때 DefaultUriTemplateHandler (Spring 5 이전) 또는 DefaultUriBuilderFactory (Spring 5+)를 지정하여 해당 쿼리 매개 변수 값을 확장하는 방법을 지정할 수 있습니다. 이것은!, (,) 등과 같은 추가 문자를 인코딩 할 때 유용합니다.
Stephen Rudolph

내 URL에는 10 개 이상의 매개 변수가 있습니다. 모든 변수를 나열하는 대신 객체 / 맵으로 동일한 결과를 얻을 수 있습니까? UriComponentsBuilder각 요청에 대해 다른 측정 항목을 생성하기 때문에 둘 중 하나를 사용할 수 없습니다.Micrometer
Doug

@Doug — RestTemplate위치 값 배열 ( Object... uriVariables) 또는 명명 된 값 맵 ( ) 을 지정하는 병렬 방법이 있습니다 Map<String, ?> uriVariables. 지도 버전과 같은 소리는 원하는 것 restTemplate.exchange(url, HttpMethod.GET, httpEntity, clazz, urlVariablesMap)입니다.
M. 저스틴

42

적어도 봄 3 있기 때문에, 대신에 사용하는 UriComponentsBuilder(조금 자세한 임) URL을 구축, 많은RestTemplate방법은 매개 변수 (단지의 경로에 자리를 수락 exchange).

설명서에서 :

많은 RestTemplate메소드가 URI 템플리트 및 URI 템플리트 변수를 Stringvararg 또는 Map<String,String> .

예를 들어 Stringvararg 를 사용하면

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

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

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

JavaDoc 을 보고 RestTemplate"URI 템플리트"를 검색하면 플레이스 홀더를 사용할 수있는 메소드를 확인할 수 있습니다.


35

좋아, 나는 바보이고 쿼리 매개 변수를 url 매개 변수와 혼동하고 있습니다. 추악한 연결 문자열 대신 쿼리 매개 변수를 채우는 더 좋은 방법이 있기를 바랐지만 거기에 있습니다. 올바른 매개 변수를 사용하여 URL을 작성하는 경우입니다. String Spring으로 전달하면 인코딩이 처리됩니다.


그것은 당신을 위해 일했습니까? UriComponentsBuilder를 사용하는 것과 동일한 접근 방식을 따르지만 대상 URL에서 request.getAttribute ()를 수행하면 null이 발생합니다.
yathirigan

47
나는 왜이 대답에 녹색 진드기가 있는지 이해하지 못합니다.
Pradeep

7
그가 OP이기 때문에
Kalpesh Soni

그래서 당신의 해결책은 무엇입니까? 감사!
Raymond Chen

18

나는 비슷한 것을 시도 하고 있었고 RoboSpice 예제는 그것을 해결하는 데 도움이되었습니다 .

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 (URI 변수 및 요청 매개 변수)를 사용하여 동적 URI 빌드


6

해시 맵을 쿼리 매개 변수 문자열로 변환

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

다른 접근 방식을 취하고 동의 할 수도 있지만 컴파일 된 Java 코드 대신 .properties 파일에서 제어하고 싶습니다.

내부 application.properties 파일

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

Java 코드가 여기에 있으면 if 또는 switch 조건을 작성하여 .properties 파일의 엔드 포인트 URL에 @PathVariable ({} 포함) 또는 @RequestParam (yourURL? key = value) 등이 있는지 확인한 다음 그에 따라 메소드를 호출하십시오. 그런 식으로 역동적이고 미래의 원 스톱 상점에서 코드 변경을 할 필요가 없습니다 ...

여기에 실제 코드보다 더 많은 아이디어를 제공하려고합니다 ... @ RequestParam 및 @PathVariable 등에 대해 각각 일반적인 메소드를 작성하고 필요할 때 적절하게 호출하십시오.

  @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에서 나는 또한 본다.

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

따라서 추악한지도를 만들 필요가 없습니다.

이 URL이 있다면

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

당신은 할 수 있습니다

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

또는

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에 대해 매개 변수화되지 않은 매개 변수를 전달하면 매개 변수를 고려하여 전달하는 하나의 다른 URL에 대해 모두 하나의 지표가 있습니다. 매개 변수화 된 URL을 사용하고 싶습니다.

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

대신에

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

두 번째 경우는 UriComponentsBuilder 클래스를 사용하여 얻는 것입니다.

첫 번째 동작을 구현하는 한 가지 방법은 다음과 같습니다.

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이 http://localhost:8080/context path?msisdn={msisdn}&email={email}

그때

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

당신이 설명한대로 resttemplate 교환 방법에 작동합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.