我必须进行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);
这在客户端失败,因为调度程序servlet无法将请求解析到处理程序。调试之后,似乎没有发送请求参数。
当我使用请求体和没有查询参数的POST做一个交换时,它工作得很好。
有人有什么想法吗?
uriVariables也在查询字符串中展开。例如,下面的调用将展开account和name的值:
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。
我也尝试过类似的东西,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);
为了方便地操作URL / 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
);
我采取不同的方法,你可能同意或不同意,但我想从.properties文件控制,而不是编译的Java代码
内部应用程序。属性文件
endpoint。url = https://host/resource?
Java代码在这里,你可以写if或切换条件,以找出端点URL在.properties文件中是否有@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(); }
至少从Spring 3开始,许多RestTemplate方法不是使用UriComponentsBuilder来构建URL(这有点啰嗦),而是在参数路径中接受占位符(不仅仅是交换)。
从文档中可以看到:
Many of the RestTemplate methods accepts a URI template and URI
template variables, either as a String vararg, or as
Map<String,String>.
For example with a String vararg:
restTemplate.getForObject(
"http://example.com/hotels/{hotel}/rooms/{room}", String.class, "42", "21");
Or with a 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 for RestTemplate并搜索“URI Template”,你可以看到哪些方法可以使用占位符。
如果您为RestTemplate传递非参数参数,那么考虑到参数,您将为传递的每个不同URL都有一个Metrics。你想要使用参数化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);
在Spring Web 4.3.6中我也看到了
public <T> T getForObject(String url, Class<T> responseType, Object... uriVariables)
这意味着你不必创建一个丑陋的地图
如果你有这个url
http://my-url/action?param1={param1}¶m2={param2}
你可以选择
restTemplate.getForObject(url, Response.class, param1, param2)
or
restTemplate.getForObject(url, Response.class, param [])
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
将哈希映射转换为查询参数字符串:
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);
我提供了一个RestTemplate GET方法的代码片段与路径参数示例
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;
}