Feign远程调用传递对象参数并返回自定义分页数据的过程解析

 更新时间:2022年3月17日 16:58  点击:724 作者:RyanJJ_

Feign介绍

Feign是Netflix公司开源的轻量级rest客户端,使用Feign可以非常方便的实现Http 客户端。Spring Cloud引入Feign并且集成了Ribbon实现客户端负载均衡调用。

Feign测试

1.在yml文件里面增加了配置信息

feign:
  httpclient:
    enabled: true

2.在客户端pom.xml文件中引入的依赖(消费者端)

<!-- 配置feign 发送请求使用 httpclient,而不是java原生 -->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
        </dependency>
       
 <!-- 此处不使用Apache HttpClient 的httpclient依赖,一定要使用下面这个依赖,因为我们要返回的是POJO类-->
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-httpclient</artifactId>
            <version>10.1.0</version>
        </dependency>

此处注意

此处依赖为什么使用io.github.openfeign的httpclient,而不使用Apache 的HttpClient替换Feign原生httpclient。

看了很多文章,都是说引用这个依赖:

<!-- 使用Apache HttpClient替换Feign原生httpclient-->
<!--        <dependency>-->
<!--            <groupId>com.netflix.feign</groupId>-->
<!--            <artifactId>feign-httpclient</artifactId>-->
<!--            <version>8.16.1</version>-->
<!--        </dependency>-->

但是不知道哪里的问题,在获取返回结果时一直报错:

Caused by: java.lang.NoSuchMethodError: feign.Response.create(ILjava/lang/String;Ljava/util/Map;Lfeign/Response$Body;)Lfeign/Response;

查看源码得知,openfeign在接受返回值时调用的不是httpclient的feign-core包的代码而是调用的本身的feign-core的代码,而本身的feign-core包中的Response类没有create方法。两个feign-core包中的Retryer接口不一致导致的,openfeign的feign-core版本为10.1.0 httpclient的版本为8.16.1。

找了半天问题,最后就把httpclient的依赖换成代码块中的依赖就OK了。

3.服务调用端接口为

此处使用POST请求,第6步有解释。

@Slf4j
@RequestMapping("/list")
@RestController
public class WebQueryListController {   
    
    @Autowired
    private TourismListService listService;
   
    @PostMapping("/ad/allByQuery")
    public ApiResult<Page<TourismAd>> allByQuery(@RequestBody TourismAdQuery adQuery){
        ApiResult<Page<TourismAd>>  pageApiResult =  listService.selectAllAdByQuery(adQuery);
        return pageApiResult;
    }

我的TourismAdQuery类继承了Page类(似乎没有影响)

@Data
public class TourismAdQuery extends  Page<TourismAd> {
 
    /**
     * 标题
     */
    private String title;
     。。。。。。。
}

4.服务调用端Service代码

此处@PostMapping地址为服务端提供的api接口地址

@FeignClient(name = "fisher-back-service", fallback = TourismListFallback.class, configuration = FeignConfig.class)
public interface TourismListService {
 
    /**
     * 分页查询广告根据查询条件
     * @param adQuery
     * @return
     */
   @PostMapping(value = "/ad/get/allByQuery")
    ApiResult<Page<TourismAd>> selectAllAdByQuery(TourismAdQuery adQuery);

5.服务调用端Fallback为

@Slf4j
@Service
public class TourismListFallback implements TourismListService {
 
    /**
     * 分页查询广告根据查询条件
     *
     * @param adQuery
     * @return
     */
    @Override
    public ApiResult<Page<TourismAd>> selectAllAdByQuery(TourismAdQuery adQuery) {
        log.error("调用 selectAllAdByQuery 方法异常,参数:{}", adQuery);
        return null;
    }

6.服务提供端代码为

此处传进来的参数是一个POJO类,如果不使用@RequestBody注解 的话,feign远程调用时参数是无法被接收到的。

虽然获取数据时,大多数使用 Get请求方法,但是GET方法无法接收@RequestBody参数体。

所以只好改GET请求为POST请求。

@RestController
@RequestMapping("/ad")
public class TourismAdController extends BaseController<TourismAdService, TourismAd, Integer> {
 
    @Autowired
    private TourismAdService adService;
 
   @ApiOperation(value = "分页查询广告根据查询条件", notes = "分页查询广告根据查询条件", httpMethod = "POST")
    @PostMapping("/get/allByQuery")
    public ApiResult<Page<TourismAd>> allByQuery(@RequestBody TourismAdQuery adQuery){
        return adService.selectAllByQuery(adQuery);
    }

7.测试

调用接口http://localhost:9009/list/ad/allByQuery 传递json格式参数即可:

{
  "address": "",
  "title": "广告位1",
  "size": 6
}

成功分页获取数据 自定义的返回类型数据:

{
  "data": {
    "records": [
      {
        "id": 1,
        "title": "广告位1",
        "description": "招商",
        "sort": 0,
        "datetime": "2019-09-26 17:46:50",
        "updatetime": "2019-09-26 17:46:50",
        "peopleid": 0,
        "display": 0,
        "content": "04004",
        "file": "444//44.jpg",
        "leaseperson": "找找",
        "address": "杭州市",
        "idcard": "1154465656656",
        "phone": "131654799"
      }
    ],
    "total": 1,
    "size": 6,
    "current": 1,
    "searchCount": true,
    "pages": 1
  },
  "code": 200,
  "message": "分页获取成功"
}

Feign调用分页接口报错:Method has too many Body parameters

接口定义:

@ApiOperation(value = "分页查询会话")
@PostMapping(Routes.SESSIONS_QUERY)
JsonResult<Pagination<SessionInfo>> querySessions(@RequestBody @Valid SessionsQo qo,
@PageableDefault(size = 20, sort = "id", direction = Sort.Direction.DESC) Pageable pageable);

服务消费方调用报错:

Method has too many Body parameters: public abstract com.xingren.common.data.JsonResult com.xingren.xxx.yyy.contract.api.controller.ISessionController.querySessions(com.xingren.xxx.yyy.contract.qo.SessionsQo,org.springframework.data.domain.Pageable)

解决方法

通过搜索、调研,目前有三种解决方法:

1、将分页属性直接通过入参传递,接口定义如下:

@ApiOperation(value = "分页查询会话")
@PostMapping(Routes.SESSIONS_QUERY)
JsonResult<Pagination<SessionInfo>> querySessions(@RequestBody @Valid SessionsQo qo,
@RequestParam("page") Integer page, @RequestParam("size") Integer size, @RequestParam("sort") Sort sort);

2、将分页对象冗余在Qo中(通过继承实现):

@Data
@NoArgsConstructor
@ApiModel(value = "查询会话")
public class SessionsQo extends PageableParam {
@ApiParam(value = "会话id列表")
private List<Long> sessionIdIn = Lists.newArrayList();
...
}

3、通过注解传递(参考:Issue):

服务提供方定义注解:

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface PageableParam {
}

服务提供方定义接口:

@ApiOperation(value = "分页查询会话")
@PostMapping(Routes.SESSIONS_QUERY)
JsonResult<Pagination<SessionInfo>> querySessions(@RequestBody @Valid SessionsQo qo,
@PageableParam @SpringQueryMap Pageable pageable);

服务消费方定义processor:

@Bean
public PageableParamProcessor pageableParamProcessor() {
    return new PageableParamProcessor();
}
 
public static class PageableParamProcessor implements AnnotatedParameterProcessor { 
    private static final Class<PageableParam> ANNOTATION = PageableParam.class;
 
    @Override
    public Class<? extends Annotation> getAnnotationType() {
        return ANNOTATION;
    }
 
    @Override
    public boolean processArgument(AnnotatedParameterContext context, Annotation annotation, Method method) {
        int parameterIndex = context.getParameterIndex();
        MethodMetadata data = context.getMethodMetadata();
        data.queryMapIndex(parameterIndex);
        return true;
    } 
}

服务消费方自定义PageableUtil:

public class PageableUtil extends PageRequest implements Map<String, Object> { 
    public static final String PAGE = "page";
    public static final String SIZE = "size";
    public static final String SORT = "sort";
 
    @Delegate
    protected Map<String, Object> delegate = Maps.newHashMap(); 
    public PageableUtil(int page, int size, Sort sort) {
        super(page, size, sort);
        delegate.put(PAGE, page);
        delegate.put(SIZE, size);
        if (Objects.nonNull(sort)) {
            delegate.put(SORT, sort.toString().replace(": ", ","));
        }
    }
 
    public PageableUtil(int page, int size) {
        super(page, size);
        delegate.put(PAGE, page);
        delegate.put(SIZE, size);
    } 
}

定义PageableUtil原因:主要是因为Feign对QueryMap类型参数的序列化和反序列化的言七墨方式与Sort.Order的不兼容,导致排序失效。

服务消费方调用方式:

SessionsQo qo = SessionsQo.builder().sessionIdIn(Collections.singletonList(20L)).build();
JsonResult<Pagination<SessionInfo>> pageInfo = sessionContract.querySessions(qo, new PageableUtil(0, 5, new Sort(Sort.Direction.DESC,

以上为个人经验,希望能给大家一个参考,也希望大家多多支持猪先飞。

原文出处:https://blog.csdn.net/qq_36068521/article/details/102565751

[!--infotagslink--]

相关文章

  • 基于springcloud异步线程池、高并发请求feign的解决方案

    这篇文章主要介绍了基于springcloud异步线程池、高并发请求feign的解决方案,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-02-25
  • php KindEditor文章内分页的实例方法

    我们这里介绍php与KindEditor编辑器使用时如何利用KindEditor编辑器的分页功能实现文章内容分页,KindEditor编辑器在我们点击分页时会插入代码,我们只要以它为分切符,就...2016-11-25
  • 自己动手写的jquery分页控件(非常简单实用)

    最近接了一个项目,其中有需求要用到jquery分页控件,上网也找到了需要分页控件,各种写法各种用法,都是很复杂,最终决定自己动手写一个jquery分页控件,全当是练练手了。写的不好,还请见谅,本分页控件在chrome测试过,其他的兼容性...2015-10-30
  • 解决Feign切换client到okhttp无法生效的坑(出现原因说明)

    这篇文章主要介绍了解决Feign切换client到okhttp无法生效的坑(出现原因说明),具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-02-25
  • 完美解决SpringCloud-OpenFeign使用okhttp替换不生效问题

    这篇文章主要介绍了完美解决SpringCloud-OpenFeign使用okhttp替换不生效问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-02-25
  • jquery实现的伪分页效果代码

    本文实例讲述了jquery实现的伪分页效果代码。分享给大家供大家参考,具体如下:这里介绍的jquery伪分页效果,在火狐下表现完美,IE全系列下有些问题,引入了jQuery1.7.2插件,代码里有丰富的注释,相信对学习jQuery有不小的帮助,期...2015-10-30
  • vue.js 表格分页ajax 异步加载数据

    Vue.js通过简洁的API提供高效的数据绑定和灵活的组件系统.这篇文章主要介绍了vue.js 表格分页ajax 异步加载数据的相关资料,需要的朋友可以参考下...2016-10-20
  • Springboot如何使用mybatis实现拦截SQL分页

    这篇文章主要介绍了Springboot使用mybatis实现拦截SQL分页,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-06-19
  • PHP 一个完整的分页类(附源码)

    在php中要实现分页比起asp中要简单很多了,我们核心就是直接获取当前页面然后判断每页多少再到数据库中利用limit就可以实现分页查询了,下面我来详细介绍分页类实现程序...2016-11-25
  • jquery实现的伪分页效果代码

    本文实例讲述了jquery实现的伪分页效果代码。分享给大家供大家参考,具体如下:这里介绍的jquery伪分页效果,在火狐下表现完美,IE全系列下有些问题,引入了jQuery1.7.2插件,代码里有丰富的注释,相信对学习jQuery有不小的帮助,期...2015-10-30
  • 如何解决springcloud feign 首次调用100%失败的问题

    这篇文章主要介绍了如何解决springcloud feign 首次调用100%失败的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-06-23
  • Feign接口方法返回值设置方式

    这篇文章主要介绍了Feign接口方法返回值设置方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-07-08
  • AngularJS实现分页显示数据库信息

    这篇文章主要为大家详细介绍了AngularJS实现分页显示数据库信息效果的相关资料,感兴趣的小伙伴们可以参考一下...2016-07-06
  • 基于jquery实现表格无刷新分页

    这篇文章主要介绍了基于jquery实现表格无刷新分页,功能实现了前端排序功能,增加了前端搜索功能,感兴趣的小伙伴们可以参考一下...2016-01-08
  • vue实现页面打印自动分页的两种方法

    这篇文章主要为大家详细介绍了vue实现页面打印自动分页的两种方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-09-29
  • 使用Feign消费服务时POST/GET请求方式详解

    这篇文章主要介绍了使用Feign消费服务时POST/GET请求方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-06-25
  • C# DataTable分页处理实例代码

    有时候我们从数据库获取的数据量太大,而我们不需要一次性显示那么多的时候,我们就要对数据进行分页处理了,让每页显示不同的数据。...2020-06-25
  • 解决Feign获取异常信息的处理方案

    这篇文章主要介绍了解决Feign获取异常信息的处理方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-08-27
  • 解决SpringCloud Feign传对象参数调用失败的问题

    这篇文章主要介绍了解决SpringCloud Feign传对象参数调用失败的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-06-24
  • 原生js实现分页效果

    这篇文章主要为大家详细介绍了原生js实现分页效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-09-24