RestTemplate:如何同时发送URL和查询参数

80

我正在尝试在URL中传递路径参数和查询参数,但是我遇到了奇怪的错误。以下是代码:

    String url = "http://test.com/Services/rest/{id}/Identifier"
    Map<String, String> params = new HashMap<String, String>();
    params.put("id", "1234");
    UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(url)
                                        .queryParam("name", "myName");
    String uriBuilder = builder.build().encode().toUriString();
    restTemplate.exchange(uriBuilder , HttpMethod.PUT, requestEntity,
                    class_p, params);

我的网址变成了 http://test.com/Services/rest/%7Bid%7D/Identifier?name=myName,该怎么办才能使其正常工作?我希望得到的是 http://test.com/Services/rest/{id}/Identifier?name=myName ,这样参数就会将id添加到url中。

7个回答

186

我会使用UriComponentsBuilder中的buildAndExpand来传递所有类型的URI参数。

例如:

String url = "http://test.com/solarSystem/planets/{planet}/moons/{moon}";

// URI (URL) parameters
Map<String, String> urlParams = new HashMap<>();
urlParams.put("planet", "Mars");
urlParams.put("moon", "Phobos");

// Query parameters
UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(url)
        // Add query parameter
        .queryParam("firstName", "Mark")
        .queryParam("lastName", "Watney");

System.out.println(builder.buildAndExpand(urlParams).toUri());
/**
 * Console output:
 * http://test.com/solarSystem/planets/Mars/moons/Phobos?firstName=Mark&lastName=Watney
 */

restTemplate.exchange(builder.buildAndExpand(urlParams).toUri() , HttpMethod.PUT,
        requestEntity, class_p);

/**
 * Log entry:
 * org.springframework.web.client.RestTemplate Created PUT request for "http://test.com/solarSystem/planets/Mars/moons/Phobos?firstName=Mark&lastName=Watney"
 */

2
但是在Spring 3中没有“UriComponentsBuilder”类。是否有Spring 3的替代解决方案? - Gnaniyar Zubair
1
您是指 urlParams.put("planet", "Mars"); 吗?您的 URL 模板中有 {planet} - Shannon
@Shannon 没错,谢谢你注意到了这个打字错误。现在已经修复了。 - Michal Foksa
没问题,谢谢! - Sankalpa Wijewickrama

22

Michal Foksa的答案存在一个问题,就是它首先添加查询参数,然后才扩展路径变量。如果查询参数包含括号,例如{foobar},这将导致异常。

安全的方法是先扩展路径变量,然后再添加查询参数:

String url = "http://test.com/Services/rest/{id}/Identifier";
Map<String, String> params = new HashMap<String, String>();
params.put("id", "1234");
URI uri = UriComponentsBuilder.fromUriString(url)
        .buildAndExpand(params)
        .toUri();
uri = UriComponentsBuilder
        .fromUri(uri)
        .queryParam("name", "myName")
        .build()
        .toUri();
restTemplate.exchange(uri , HttpMethod.PUT, requestEntity, class_p);

6
使用参数映射的TestRestTemplate.exchange函数的单行代码。
restTemplate.exchange("/someUrl?id={id}", HttpMethod.GET, reqEntity, respType, ["id": id])

像这样初始化的参数映射是一个Groovy初始化器*


3
你尝试过使用路径变量吗?这里的示例演示了查询参数,而问题是关于路径参数的。 - SUMIT

3
String url = "http://test.com/Services/rest/{id}/Identifier";
Map<String, String> params = new HashMap<String, String>();
params.put("id", "1234");
URI uri = UriComponentsBuilder.fromUriString(url)
        .buildAndExpand(params)
        .toUri();
uri = UriComponentsBuilder
        .fromUri(uri)
        .queryParam("name", "myName")
        .build()
        .toUri();
restTemplate.exchange(uri , HttpMethod.PUT, requestEntity, class_p);

安全的方式是先扩展路径变量,然后再添加查询参数:

对我而言,这导致了重复编码,例如,空格被解码为 %2520(空格 -> %20 -> %25)。

我通过以下方法解决了这个问题:

String url = "http://test.com/Services/rest/{id}/Identifier";
Map<String, String> params = new HashMap<String, String>();
params.put("id", "1234");
UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUriString(url);
uriComponentsBuilder.uriVariables(params);
Uri uri = uriComponentsBuilder.queryParam("name", "myName");
        .build()
        .toUri();
restTemplate.exchange(uri , HttpMethod.PUT, requestEntity, class_p);

基本上,我正在使用uriComponentsBuilder.uriVariables(params);添加路径参数。文档说:

相对于UriComponents.expand(Map)或buildAndExpand(Map),当您需要提供URI变量但尚未构建UriComponents实例时,或者在预先扩展一些共享的默认值(例如主机和端口)时,此方法非常有用。...

来源:https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/util/UriComponentsBuilder.html#uriVariables-java.util.Map-

0
以下是可运行的代码,我在制作查询参数时必须传递两个对应位置的值。
String queryParam = "Key=Project_{ProdjectCode}_IN_{AccountCode}"

Map<String, String> queryParamMap = new HashMap<>();
queryParamMap.put("ProjectCode","Project1");
queryParamMap.put("AccountCode","Account1");

UriComponents builder = UriComponentsBuilder.fromHttpUrl("http://myservice.com/accountsDetails").query(queryParam).buildAndExpand(queryParamMap);

restTemplate.exchange(builder.toUriString(), HttpMethod.GET,httpEntity,MyResponse.class);

以上代码将向以下URL发起GET请求: http://myservice.com/accountsDetails?Key=Project_Project1_IN_Account1

0

0

一个简单的方法是:

String url = "http://test.com/Services/rest/{id}/Identifier"

UriComponents uriComponents = UriComponentsBuilder.fromUriString(url).build();
uriComponents = uriComponents.expand(Collections.singletonMap("id", "1234"));

然后添加查询参数。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接