Spring RestTemplate GET与参数


266

我必须打一个REST电话,其中包括自定义标头和查询参数。我只设置HttpEntity标题(没有正文),并且使用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使用请求正文和无查询参数进行交换时,它工作正常。

有人有什么想法吗?

Answers:


479

为了轻松地操纵URL / path / params /等等,可以使用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
大提示。为了简单起见,仅更改exchangegetForEntityrestTemplate.getForEntity(builder.build().encode().toUri(), String.class);
Fernando M. Pinheiro

12
@ FernandoM.Pinheiro:您是正确的,但是如果您期望响应中包含通用类型,则需要使用exchange并提供一个ParameterizedTypeReference。的例子中虽然可以进一步简化,替换builder.build().encode().toUri()builder.toUriString()
mirzmaster 2015年

@Christophe L您能告诉我如何在服务器端接收这些字符串参数吗?
KJEjava48 '17

3
有一个捷径来获取URI:只需调用builder.toUriString()
迈克尔Piefel


179

uriVariables也将在查询字符串中扩展。例如,以下调用将扩展account和name的值:

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

因此实际的请求网址将是

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

有关更多详细信息,请参见HierarchicalUriComponents.expandInternal(UriTemplateVariables)。Spring的版本是3.1.3。


谢谢-非常简单的解决方案
Angshuman Agarwal,

2
并且在创建RestTemplate实例时,可以通过指定DefaultUriTemplateHandler(在Spring 5之前)或DefaultUriBuilderFactory(Spring 5+)来指定如何扩展那些查询参数值。当你想额外的编码字符,如这是有用的,(,)等!
斯蒂芬·鲁道夫

我的网址有10多个参数,是否可以通过对象/地图来实现相同的目的,而不是列出每个变量?我不能使用UriComponentsBuilder任何一个,因为它导致它为每个请求生成不同的度量标准Micrometer
Doug

@Doug — RestTemplate具有并行方法,用于指定值的位置数组(Object... uriVariables)或命名值的映射(Map<String, ?> uriVariables)。听起来地图版本就是您想要的:restTemplate.exchange(url, HttpMethod.GET, httpEntity, clazz, urlVariablesMap)
M. Justin

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

如果你看的JavaDocRestTemplate,搜索“URI模板”,你可以看到你可以使用的方法有占位符。


35

好的,所以我是个白痴,并且混淆了查询参数和url参数。我有点希望能有一种更好的方法来填充我的查询参数,而不是一个丑陋的串联字符串,但是我们已经有了。这只是使用正确参数构建URL的一种情况。如果您将其作为String传递,Spring还将为您处理编码。


对你有用吗?我遵循使用UriComponentsBuilder的相同方法,但是在目标URL上,当我执行request.getAttribute()时,会得到null。
yathirigan

47
我很不明白为什么这个答案有绿色的勾号。
Pradeep

7
因为他是行动

那么您的解决方案是什么?谢谢!
雷蒙·陈

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变量和Request参数)构建动态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

我采用不同的方法,您可能同意或不同意,但是我想从.properties文件而不是已编译的Java代码进行控制

内部application.properties文件

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

Java代码在这里,您可以编写if或切换条件以查明.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)

这意味着您不必创建丑陋的地图

所以如果你有这个网址

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有一个度量标准。您想使用参数化的网址:

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

如果您的网址是 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交换方法

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.