如何使用附加的@RequestBody 在 POST 请求中将 Pageable 传递给 Feign 客户端

Posted

技术标签:

【中文标题】如何使用附加的@RequestBody 在 POST 请求中将 Pageable 传递给 Feign 客户端【英文标题】:How to pass Pageable to Feign Client in POST Request with additional @RequestBody 【发布时间】:2020-11-16 19:13:39 【问题描述】:

我尝试在 Spring 中为我的 REST 服务控制器创建一个 feign 客户端。

@PostMapping("/search")
public Page<MeasureDto> searchMeasures(@RequestBody MeasureDto example, Pageable pageable) 
    ...

客户端如下所示:

@PostMapping("/search")
public Page<MeasureDto> searchMeasures(@RequestHeader("apiKey") String apiKey, @RequestBody MeasureDto example, Pageable pageable);

运行测试时抛出以下异常:

原因:java.lang.IllegalStateException: Method has too many Body parameters: public abstract org.springframework.data.domain.Page com.foo.bar.jobservice.client.MeasureServiceClient.searchMeasures(java.lang.String, com.example.foo.jobservice.client.dto.MeasureDto,org.springframework.data.domain.Pageable)

我已经知道/尝试过的:

github上有一个已关闭的issue:https://github.com/spring-cloud/spring-cloud-netflix/issues/556

应该解决问题的提交问题:

https://github.com/spring-cloud/spring-cloud-openfeign/issues/26

提交:

https://github.com/spring-cloud/spring-cloud-openfeign/commit/6e0e63644ba34193f03c2cd74391cac73b9bfdb4

我的配置:

import feign.codec.Encoder;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.openfeign.support.PageJacksonModule;
import org.springframework.cloud.openfeign.support.PageableSpringEncoder;
import org.springframework.cloud.openfeign.support.SpringEncoder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@EnableFeignClients
@Configuration
public class FeignConfig 

    @Bean
    public PageJacksonModule pageJacksonModule() 
        return new PageJacksonModule();
    

    @Autowired
    private ObjectFactory<HttpMessageConverters> messageConverters;

    @Bean
    public Encoder feignEncoder() 
        return new PageableSpringEncoder(new SpringEncoder(messageConverters));
    

还是不行。

我正在使用什么:

<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.1.RELEASE</version>

<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>2.2.3.RELEASE</version>

我做错了什么?


更新:

我创建了一个可重现的示例:

https://github.com/manuelwaltschek/mre.git

启动客户端服务或调用 spring/spring-cloud-openfeign/375-pageable-not-working/parent/client/src/test/java/com/example/client/HelloServiceClientTest.java

在 github 上打开问题: https://github.com/spring-cloud/spring-cloud-openfeign/issues/375 https://github.com/spring-cloud/spring-cloud-openfeign/issues/385

编辑:基本上我想知道如何将 pageable 传递给 feign 客户端。也许在 url 参数中对其进行编码?

相关问题:how to pass Spring Pageable to FeignClient

【问题讨论】:

github.com/spring-cloud/spring-cloud-openfeign/issues/375 可能 spring 将 @RequestBody MeasureDto 示例和 Pageable pageable 解释为两个不同的 RequestBody 并且它只接受一个。 client 和 feign client 方法应该相同。我认为如果您复制客户端方法并将其传递给假客户端,它将起作用。 @fatmazehragüç 不,它不会工作。 “@RequestHeader”根本不是问题 在 feign 客户端上,也许你应该说@PostMapping("/your-service/search")。类似的东西。 【参考方案1】:

我现在在客户端界面中的 Pageable 参数上使用 org.springframework.cloud.openfeign.SpringQueryMap 注释在查询 url 参数中发送可分页

@PostMapping("/search")
public Page<HelloDto> searchHellos(@RequestHeader("apiKey") String apiKey, 
                                   @RequestBody HelloDto example,
                                   @SpringQueryMap Pageable pageable);

【讨论】:

【参考方案2】:

异常与“过多的 Body 参数”有关,这意味着您只需在 RequestBody 中发送一个对象,在这种特殊情况下,我相信它是 MeasureDto“示例”。您必须以不同方式传递的页面,通常我在类中有一个“页面”整数属性(在您的情况下为 MeasureDTO),或者我将页码作为@RequestParam 发送,就像这样:

@PostMapping("/search")
public Page<MeasureDto> searchMeasures(@RequestBody MeasureDto example, @RequestParam(required = true) Integer page) 
 
 // PageRequest.Of(numberPage, quantityRegisters) will send a Pageable, in this case bellow, number of page + number of records
    measureService.getMeasurePageable(example, PageRequest.of(page, 10)); 
 

尽管如此,如果您正在搜索而不是保存它,请考虑将 GetMapping 与 queryParams 结合使用。

【讨论】:

感谢您的方法,但我无法更改依赖项(控制器)的接口另外我希望客户端和服务具有相同的接口 GetMapping 不是一个选项。我想发送一个带有 Paging 的 RequestBody,因为我正在通过示例搜索 MongoDB 存储库。

以上是关于如何使用附加的@RequestBody 在 POST 请求中将 Pageable 传递给 Feign 客户端的主要内容,如果未能解决你的问题,请参考以下文章

如何将 @RequestBody 与 JSONP 请求一起使用?

如何在@ExceptionHandler(Spring REST)中获取@RequestBody

如何使用 RequestBody 和 PostMapping 在两台服务器之间共享数据?

SpringBoot 实战:在 RequestBody 中优雅的使用枚举参数

检查文件是否存在/将编号附加到名称

Ajax JQuery 到 Spring @RequestBody?我如何传递数据?