从 DTO 填充查询参数

Populate query parameters from DTO

有没有办法让 Spring 从 DTO 自动填充 RestTemplate 查询参数,类似于它自动实例化响应 DTO 的方式?

我想写这样的东西:

RequestDto request = new RequestDto();
request.setFoo("foo");
request.setBar("bar");

ResponseDto response = restTemplate.getForObject(
        "http://example.com/api",
        ResponseDto.class, 
        request
);

而不是:

ResponseDto response = restTemplate.getForObject(
        "http://example.com/api?foo={foo}&bar={bar}",
        ResponseDto.class,
        "foo",
        "bar"
);

因为有很多大型 DTO,需要大量样板代码,必须与任何 DTO 更改保持同步。

Spring 4.3.25

我不认为这是直接可能的。以下内容并未完全使用 DTO,但它确实允许您构建请求而无需手动形成 URL 字符串。您可以使用 Spring 的 UriComponentsBuilder class.

UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl("http://example.com/api")
    .queryParam("foo", "bar")
    // etc. ...
    .queryParam("bar", "foo");

String result = restTemplate.getForObject(builder.toString(), String.class);

您可以遍历 DTO 并按上述方式构建查询。或者没有 DTO,您可以使用 Map<String, String> 并对其进行循环。

Map<String, String> params = new HashMap<>();
params.put("foo", "bar");

UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl("http://example.com/api");
for (Map.Entry<String, String> entry : params.entrySet()) {
    builder.queryParam(entry.getKey(), entry.getValue());
}
String result = restTemplate.getForObject(builder.toString(), String.class);

编辑:

按照下面 crizzis 的建议,您可以使用 Spring Cloud OpenFeign's REST Client (from Feign @QueryMap support):

The OpenFeign @QueryMap annotation provides support for POJOs to be used as GET parameter maps. Unfortunately, the default OpenFeign QueryMap annotation is incompatible with Spring because it lacks a value property.

Spring Cloud OpenFeign provides an equivalent @SpringQueryMap annotation, which is used to annotate a POJO or Map parameter as a query parameter map.

从你问题的例子:

public class RequestDto {
  private string foo;
  private string bar;
}
@FeignClient(name = "client", url = "http://example.com")
public interface FooTemplate {

    @GetMapping(path = "/api")
    String endpoint(@SpringQueryMap RequestDto requestDto);
}

你可以这样做-

UriComponentsBuilder builder = UriComponentsBuilder.fromUriString("http://example.com/api")
        .queryParam("foo", "foo")
        .queryParam("bar", "bar");

ResponseDto response = restTemplate.getForObject(
        builder.buildAndExpand(builder).toUriString(),
        ResponseDto.class);

可以在这里找到更详细的答案-

使用 Feign 怎么样?它允许您像 Spring 控制器一样描述远程端点。这包括对查询参数 DTO 的支持。

查看示例