我必须进行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做一个交换时,它工作得很好。

有人有什么想法吗?


当前回答

我提供了一个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;
}

其他回答

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。

至少从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”,你可以看到哪些方法可以使用占位符。

为了方便地操作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
);

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

or

restTemplate.getForObject(url, Response.class, param [])

可以对String使用follow代码。

URL_EXAMPLE="http://{domain}/Index.php?Username={user}&password={password}";

String domain = "example.com";
String user = "user";
String password = "password";

String data=this.restTemplate.getForObject(URL_EXAMPLE,String.class,domain,user,password);