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

网友投稿 674 2022-08-19


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

目录Feign介绍Feign测试1.在yml文件里面增加了配置信息2.在客户端pom.xml文件中引入的依赖(消费者端)3.服务调用端接口为4.服务调用端Service代码5.服务调用端Fallback为6.服务提供端代码为7.测试Feign调用分页接口报错:MethodhastoomanyBodyparameters解决方法

Feign介绍

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

Feign测试

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

feign:

httpclient:

enabled: true

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

org.apache.httpcomponents

httpclient

io.github.openfeign

feign-httpclient

10.1.0

此处注意

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

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

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

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> allByQuery(@RequestBody TourismAdQuery adQuery){

ApiResult> pageApiResult = listService.selectAllAdByQuery(adQuery);

return pageApiResult;

}

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

@Data

public class TourismAdQuery extends Page {

/**

* 标题

*/

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> selectAllAdByQuery(TourismAdQuery adQuery);

5.服务调用端Fallback为

@Slf4j

@Service

public class TourismListFallback implements TourismListService {

/**

* 分页查询广告根据查询条件

*

* @param adQuery

* @return

*/

@Override

public ApiResult> 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 {

@Autowired

private TourismAdService adService;

@ApiOperation(value = "分页查询广告根据查询条件", notes = "分页查询广告根据查询条件", httpMethod = "POST")

@PostMapping("/get/allByQuery")

public ApiResult> 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> 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> 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 sessionIdIn = Lists.newArrayList();

...

}

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

服务提供方定义注解:

@Target(ElementType.PARAMETER)

@Retention(RetentionPolicy.RUNTIME)

public @interface PageableParam {

}

服务提供方定义接口:

@ApiOperation(value = "分页查询会话")

@PostMapping(Routes.SESSIONS_QUERY)

JsonResult> querySessions(@RequestBody @Valid SessionsQo qo,

@PageableParam @SpringQueryMap Pageable pageable);

服务消费方定义processor:

@Bean

public PageableParamProcessor pageableParamProcessor() {

return new PageableParamProcessor();

}

public static class PageableParamProcessor implements AnnotatedParameterProcessor {

private statiSReiBihIUdc final Class 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 {

public static final String PAGE = "page";

public static final String SIZE = "size";

public static final String SORT = "sort";

@Delegate

protected Map 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> pageInfo = sessionContract.querySessions(qo, new PageableUtil(0, 5, new Sort(Sort.Direction.DESC,


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Java实现二叉树的示例代码(递归&迭代)
下一篇:详解Java中二叉树的基础概念(递归&迭代)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~