Spring RestTemplate GET参数

Elw*_*ood 227 java rest spring

我必须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);
Run Code Online (Sandbox Code Playgroud)

这在客户端失败,dispatcher servlet无法解析对处理程序的请求.调试它后,看起来似乎没有发送请求参数.

当我POST使用请求正文进行交换而没有查询参数时,它可以正常工作.

有没有人有任何想法?

Chr*_*e L 416

要轻松操作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);
Run Code Online (Sandbox Code Playgroud)

  • 小心!如果你这样做,你将得到双重编码。builder.queryParam("value", "some&amp;value") 将在 builder.toUriString() 期间编码,“some%26value”,然后再次在 'exchange()' 中编码,“some%2526value”。最好改为传递 uriVariables。 (11认同)
  • @ FernandoM.Pinheiro:你是对的,但如果你期望在响应中使用泛型类型,那么你需要使用`exchange`并提供`ParameterizedTypeReference`.这个例子可以进一步简化,用`builder.toUriString()`替换`builder.build().encode().toUri()`. (10认同)
  • 很棒的提示.刚刚将```````改为```getForEntity```:```restTemplate.getForEntity(builder.build().encode().toUri(),String.class);```为简单起见. (8认同)
  • 有一个获取URI的快捷方式:只需调用`builder.toUriString()` (3认同)
  • 正如 @steve 上面所说,如果您按照此答案执行操作,则可能会面临获得双重编码值的风险,包括参数值中是否有空格。如果您使用“.build().toUriString()”而不是简单的“.toUriString()”,则可以修复此问题。这会跳过调用“.encode()”,从而达到目的。请参阅https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/util/UriComponentsBuilder.html#toUriString-- (2认同)

pav*_*vel 156

uriVariables也在查询字符串中展开.例如,以下调用将扩展帐户和名称的值:

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

所以实际的请求网址将是

http://my-rest-url.org/rest/account/my-account?name=my-name
Run Code Online (Sandbox Code Playgroud)

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

  • 哇,从文档来看,这一点都不明显. (23认同)
  • 并且在创建RestTemplate实例时,可以通过指定DefaultUriTemplateHandler(在Spring 5之前)或DefaultUriBuilderFactory(Spring 5+)来指定如何扩展那些查询参数值。当您希望编码其他字符,例如!,(,)等时,此功能很有用。 (2认同)
  • @Doug — `RestTemplate` 具有并行方法,用于指定值的位置数组 (`Object... uriVariables`) 或命名值的映射 (`Map&lt;String, ?&gt; uriVariables`)。听起来地图版本就是您想要的:`restTemplate.exchange(url, HttpMethod.GET, httpEntity, clazz, urlVariablesMap)`。 (2认同)

Elw*_*ood 37

好的,所以我是个白痴,我把查询参数与url参数混淆了.我有点希望有一个更好的方法来填充我的查询参数而不是一个丑陋的连接字符串,但我们有.这只是用正确的参数构建URL的情况.如果你把它传递给一个String Spring也会为你处理编码.

  • 我真的不明白为什么这个答案有绿色勾号. (34认同)
  • 因为他是OP (5认同)

dus*_*ltz 28

由于至少弹簧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");
Run Code Online (Sandbox Code Playgroud)

或者用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/{hotel}", 
    String.class, vars);
Run Code Online (Sandbox Code Playgroud)

参考:https://docs.spring.io/spring/docs/current/spring-framework-reference/integration.html#rest-resttemplate-uri

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


elB*_*ord 17

我尝试了类似的东西,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);
Run Code Online (Sandbox Code Playgroud)


小智 10

    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
Run Code Online (Sandbox Code Playgroud)

RestTemplate:使用UriComponents(URI变量和Request参数)构建动态URI


Ily*_*nko 9

将哈希映射转换为一串查询参数:

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);
Run Code Online (Sandbox Code Playgroud)


Kal*_*oni 7

在 Spring Web 4.3.6 我也看到

public <T> T getForObject(String url, Class<T> responseType, Object... uriVariables)
Run Code Online (Sandbox Code Playgroud)

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

所以如果你有这个网址

http://my-url/action?param1={param1}&param2={param2}
Run Code Online (Sandbox Code Playgroud)

你可以这样做

restTemplate.getForObject(url, Response.class, param1, param2)
Run Code Online (Sandbox Code Playgroud)

或者

restTemplate.getForObject(url, Response.class, param [])
Run Code Online (Sandbox Code Playgroud)


Jav*_*hin 5

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

内部 application.properties 文件

端点.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(); }
Run Code Online (Sandbox Code Playgroud)