Spring RestTemplate GET 带参数
Posted
技术标签:
【中文标题】Spring RestTemplate GET 带参数【英文标题】:Spring RestTemplate GET with parameters 【发布时间】:2012-01-07 23:50:04 【问题描述】:我必须进行包含自定义标头和查询参数的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
进行交换时,它工作得很好。
有人有什么想法吗?
【问题讨论】:
【参考方案1】:要轻松操作 URLs/path/params/等,您可以使用 Spring 的 UriComponentsBuilder 类创建一个带有参数占位符的 URL 模板,然后在 RestOperations.exchange(...)
调用中为这些参数提供值。它比手动连接字符串更干净,它会为您处理 URL 编码:
HttpHeaders headers = new HttpHeaders();
headers.set(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE);
HttpEntity<?> entity = new HttpEntity<>(headers);
String urlTemplate = UriComponentsBuilder.fromHttpUrl(url)
.queryParam("msisdn", "msisdn")
.queryParam("email", "email")
.queryParam("clientVersion", "clientVersion")
.queryParam("clientType", "clientType")
.queryParam("issuerName", "issuerName")
.queryParam("applicationName", "applicationName")
.encode()
.toUriString();
Map<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);
HttpEntity<String> response = restOperations.exchange(
urlTemplate,
HttpMethod.GET,
entity,
String.class,
params
);
【讨论】:
很棒的提示。为简单起见,将exchange
更改为getForEntity
: restTemplate.getForEntity(builder.build().encode().toUri(), String.class);
。
@FernandoM.Pinheiro:您说得对,但如果您希望响应中包含泛型类型,那么您需要使用exchange
并提供ParameterizedTypeReference
。该示例可以进一步简化,将builder.build().encode().toUri()
替换为builder.toUriString()
。
有一个获取URI的快捷方式:调用builder.toUriString()
小心!如果你这样做,你会得到双重编码。 builder.queryParam("value", "some&value") 将在 builder.toUriString(), "some%26value" 期间进行编码,然后在 'exchange()', "some%2526value" 中再次编码。最好传入 uriVariables。
正如@steve 上面所说,如果您按照此答案进行操作,您可能会获得双重编码值,包括您的参数值中有空格。如果您使用.build().toUriString()
而不是简单的.toUriString()
,则可以解决此问题。这会跳过调用.encode()
,这可以解决问题。见docs.spring.io/spring-framework/docs/current/javadoc-api/org/…【参考方案2】:
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。
【讨论】:
谢谢 - 非常简单的解决方案 并且在创建 RestTemplate 实例时,您可以通过指定 DefaultUriTemplateHandler(Spring 5 之前)或 DefaultUriBuilderFactory(Spring 5+)来指定如何扩展这些查询参数值。当您希望编码其他字符(例如 !、(、) 等时,这很有用。 我的 URL 有 10 多个参数,有什么方法可以通过对象/地图实现相同的效果,而不是列出每个变量?我也不能使用UriComponentsBuilder
,因为它会导致它为Micrometer
的每个请求生成不同的指标
@Doug — RestTemplate
具有指定值的位置数组 (Object... uriVariables
) 或命名值的映射 (Map<String, ?> uriVariables
) 的并行方法。听起来地图版本就是您想要的:restTemplate.exchange(url, HttpMethod.GET, httpEntity, clazz, urlVariablesMap)
。
没错!你可以通过调用来检查 URL 结果:restTemplate.getUriTemplateHandler().expand(“/some/some/other”, some, other);见 org.springframework.web.util.UriTemplateHandler【参考方案3】:
至少从 Spring 3 开始,而不是使用 UriComponentsBuilder
来构建 URL(这有点冗长),RestTemplate
中的 许多 方法接受参数路径中的占位符(不是只是exchange
)。
来自文档:
许多
RestTemplate
方法接受URI 模板和URI 模板变量,可以是String
vararg,也可以是Map<String,String>
.例如使用
String
可变参数: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 模板”,您可以看到可以使用占位符的方法。
【讨论】:
【参考方案4】:好的,所以我是个白痴,我将查询参数与 url 参数混淆了。我有点希望有一种更好的方法来填充我的查询参数,而不是一个丑陋的串联字符串,但我们已经有了。这只是使用正确参数构建 URL 的一种情况。如果您将它作为字符串传递,Spring 也会为您处理编码。
【讨论】:
它对你有用吗?我遵循使用 UriComponentsBuilder 的相同方法,但是在目标 URL 处,当我执行 request.getAttribute() 时,我得到 null。 我真的不明白为什么这个答案有绿色勾号。 因为他是OP 那么您的解决方案是什么?谢谢!【参考方案5】: 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】:我正在尝试类似的事情,the RoboSpice example helped me work it out:
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);
【讨论】:
【参考方案7】:将哈希映射转换为查询参数字符串:
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);
【讨论】:
【参考方案8】:在 Spring Web 4.3.6 中我也看到了
public <T> T getForObject(String url, Class<T> responseType, Object... uriVariables)
这意味着您不必创建丑陋的地图
所以如果你有这个网址
http://my-url/action?param1=param1¶m2=param2
你可以这样做
restTemplate.getForObject(url, Response.class, param1, param2)
或
restTemplate.getForObject(url, Response.class, param [])
【讨论】:
【参考方案9】:我采取不同的方法,你可能同意或不同意,但我想从 .properties 文件而不是编译的 Java 代码进行控制
在 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();
【讨论】:
【参考方案10】:如果您为 RestTemplate 传递非参数化参数,则考虑到参数,您将为每个传递的单个不同 URL 提供一个指标。您想使用参数化网址:
http://my-url/action?param1=param1¶m2=param2
而不是
http://my-url/action?param1=XXXX¶m2=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);
【讨论】:
【参考方案11】: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);
【讨论】:
【参考方案12】:我正在提供带有路径参数示例的 RestTemplate GET 方法的代码 sn-p
public ResponseEntity<String> getName(int id)
final String url = "http://localhost:8080/springrestexample/employee/name?id=id";
Map<String, String> params = new HashMap<String, String>();
params.put("id", id);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity request = new HttpEntity(headers);
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, String.class, params);
return response;
【讨论】:
【参考方案13】:如果你的网址是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 交换方法
【讨论】:
以上是关于Spring RestTemplate GET 带参数的主要内容,如果未能解决你的问题,请参考以下文章
springboot中使用restTemplate发送带参数和请求头的post,get请求