RestTemplate集合的URI模板语法吗?

时间:2019-06-25 09:09:36

标签: java spring uri resttemplate

我有一个带有方法的Spring Boot 2服务

@RequestMapping(path = "/usable/search")
public List<Provider> findUsable(
    @RequestParam(name = "country-id", required = false) Integer countryId,
    @RequestParam(name = "network-ids[]", required = false) List<Integer> networkIds,
    @RequestParam(name = "usages[]") Set<Usage> usages)

我想从另一个Spring Boot服务中调用该服务。为此我

HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
val response =
    restTemplate.exchange(
        "http://castor-v2/providers/usable/search?network-ids[]={0}&usages[]={1}",
        HttpMethod.GET,
        new HttpEntity<Long>(httpHeaders),
        new ParameterizedTypeReference<List<Provider>>() {},
        Collections.singletonList(networkId),
        Collections.singleton(Usage.MESSAGE_DELIVERY));

这会生成一个类似search?network-ids[]=[428]&usages[]=[MESSAGE_DELIVERY]的http请求,该请求是错误的(服务器用org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'java.util.List'; nested exception is java.lang.NumberFormatException: For input string: "[573]"轰炸了);正确的应该是search?network-ids[]=77371&usages[]=MESSAGE_DELIVERY

很可能URI模板错误。应该如何与Java集合一起使用?

更新:我创建了一个没有括号的新api端点,并按照@vatsal的建议使用了UriComponentsBuilder

3 个答案:

答案 0 :(得分:1)

您不能将对象作为请求参数传递。请求参数是String到String的多值映射。如果您想将用法作为字符串传递,则可以创建这样的方法

@RequestMapping(path = "/usable/search")
public List<Provider> findUsable(
    @RequestParam(name = "country-id", required = false) Integer countryId,
    @RequestParam(name = "networkIds", required = false) List<Integer> networkIds,
    @RequestParam(name = "usages") Set<String> usages)

致电此服务

http://castor-v2/providers/usable/search?networkIds=0&networkIds=1&usages=usages1&usages=usages2

答案 1 :(得分:1)

它可能会将singletonList转换为字符串。其中将包括块括号。 因此,您可以预先将列表转换为字符串,也可以创建自己的列表实现,该实现具有to字符串方法,该方法将值转换为逗号分隔的列表。

答案 2 :(得分:1)

要轻松操纵URL /路径/参数/等,可以使用Spring的UriComponentsBuilder类。手动连接字符串比较干净,它会为您处理URL编码:

使用RestTemplate进行此操作的简单代码如下:

HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_JSON);

String url = "http://castor-v2/providers/usable/search";
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url)
            .queryParam("country-id", countryId)
            .queryParam("network-ids[]", networkId)
            .queryParam("usages[]", Usage.MESSAGE_DELIVERY);

HttpEntity<?> entity = new HttpEntity<>(httpHeaders);

HttpEntity<String> response = restTemplate.exchange(
            builder.toUriString(),
            HttpMethod.GET,
            entity,
            String.class);

这应该可以解决您的查询。另外,请确保将“用法”作为字符串传递。如果您仍要继续使用Usage作为对象,则可以使用RequestBody代替RequestParam并将其作为Body传递给POST调用。