Feign遠(yuǎn)程調(diào)用傳遞對(duì)象參數(shù)并返回自定義分頁(yè)數(shù)據(jù)的過(guò)程解析
Feign介紹
Feign是Netflix公司開(kāi)源的輕量級(jí)rest客戶端,使用Feign可以非常方便的實(shí)現(xiàn)Http 客戶端。Spring Cloud引入Feign并且集成了Ribbon實(shí)現(xiàn)客戶端負(fù)載均衡調(diào)用。
Feign測(cè)試
1.在yml文件里面增加了配置信息
feign: ? httpclient: ? ? enabled: true
2.在客戶端pom.xml文件中引入的依賴(消費(fèi)者端)
<!-- 配置feign 發(fā)送請(qǐng)求使用 httpclient,而不是java原生 --> ? ? ? ? <dependency> ? ? ? ? ? ? <groupId>org.apache.httpcomponents</groupId> ? ? ? ? ? ? <artifactId>httpclient</artifactId> ? ? ? ? </dependency> ? ? ? ? ?<!-- 此處不使用Apache HttpClient 的httpclient依賴,一定要使用下面這個(gè)依賴,因?yàn)槲覀円祷氐氖荘OJO類(lèi)--> ? ? ? ? <dependency> ? ? ? ? ? ? <groupId>io.github.openfeign</groupId> ? ? ? ? ? ? <artifactId>feign-httpclient</artifactId> ? ? ? ? ? ? <version>10.1.0</version> ? ? ? ? </dependency>
此處注意
此處依賴為什么使用io.github.openfeign的httpclient,而不使用Apache 的HttpClient替換Feign原生httpclient。
看了很多文章,都是說(shuō)引用這個(gè)依賴:
<!-- 使用Apache HttpClient替換Feign原生httpclient--> <!-- ? ? ? ?<dependency>--> <!-- ? ? ? ? ? ?<groupId>com.netflix.feign</groupId>--> <!-- ? ? ? ? ? ?<artifactId>feign-httpclient</artifactId>--> <!-- ? ? ? ? ? ?<version>8.16.1</version>--> <!-- ? ? ? ?</dependency>-->
但是不知道哪里的問(wèn)題,在獲取返回結(jié)果時(shí)一直報(bào)錯(cuò):
Caused by: java.lang.NoSuchMethodError: feign.Response.create(ILjava/lang/String;Ljava/util/Map;Lfeign/Response$Body;)Lfeign/Response;
查看源碼得知,openfeign在接受返回值時(shí)調(diào)用的不是httpclient的feign-core包的代碼而是調(diào)用的本身的feign-core的代碼,而本身的feign-core包中的Response類(lèi)沒(méi)有create方法。兩個(gè)feign-core包中的Retryer接口不一致導(dǎo)致的,openfeign的feign-core版本為10.1.0 httpclient的版本為8.16.1。
找了半天問(wèn)題,最后就把httpclient的依賴換成代碼塊中的依賴就OK了。
3.服務(wù)調(diào)用端接口為
此處使用POST請(qǐng)求,第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類(lèi)繼承了Page類(lèi)(似乎沒(méi)有影響)
@Data public class TourismAdQuery extends ?Page<TourismAd> { ? ? ? /** ? ? ?* 標(biāo)題 ? ? ?*/ ? ? private String title; ? ? ?。。。。。。。 }
4.服務(wù)調(diào)用端Service代碼
此處@PostMapping地址為服務(wù)端提供的api接口地址
@FeignClient(name = "fisher-back-service", fallback = TourismListFallback.class, configuration = FeignConfig.class) public interface TourismListService { ? ? ? /** ? ? ?* 分頁(yè)查詢廣告根據(jù)查詢條件 ? ? ?* @param adQuery ? ? ?* @return ? ? ?*/ ? ?@PostMapping(value = "/ad/get/allByQuery") ? ? ApiResult<Page<TourismAd>> selectAllAdByQuery(TourismAdQuery adQuery);
5.服務(wù)調(diào)用端Fallback為
@Slf4j @Service public class TourismListFallback implements TourismListService { ? ? ? /** ? ? ?* 分頁(yè)查詢廣告根據(jù)查詢條件 ? ? ?* ? ? ?* @param adQuery ? ? ?* @return ? ? ?*/ ? ? @Override ? ? public ApiResult<Page<TourismAd>> selectAllAdByQuery(TourismAdQuery adQuery) { ? ? ? ? log.error("調(diào)用 selectAllAdByQuery 方法異常,參數(shù):{}", adQuery); ? ? ? ? return null; ? ? }
6.服務(wù)提供端代碼為
此處傳進(jìn)來(lái)的參數(shù)是一個(gè)POJO類(lèi),如果不使用@RequestBody注解 的話,feign遠(yuǎn)程調(diào)用時(shí)參數(shù)是無(wú)法被接收到的。
雖然獲取數(shù)據(jù)時(shí),大多數(shù)使用 Get請(qǐng)求方法,但是GET方法無(wú)法接收@RequestBody參數(shù)體。
所以只好改GET請(qǐng)求為POST請(qǐng)求。
@RestController @RequestMapping("/ad") public class TourismAdController extends BaseController<TourismAdService, TourismAd, Integer> { ? ? ? @Autowired ? ? private TourismAdService adService; ? ? ?@ApiOperation(value = "分頁(yè)查詢廣告根據(jù)查詢條件", notes = "分頁(yè)查詢廣告根據(jù)查詢條件", httpMethod = "POST") ? ? @PostMapping("/get/allByQuery") ? ? public ApiResult<Page<TourismAd>> allByQuery(@RequestBody TourismAdQuery adQuery){ ? ? ? ? return adService.selectAllByQuery(adQuery); ? ? }
7.測(cè)試
調(diào)用接口http://localhost:9009/list/ad/allByQuery 傳遞json格式參數(shù)即可:
{ ? "address": "", ? "title": "廣告位1", ? "size": 6 }
成功分頁(yè)獲取數(shù)據(jù) 自定義的返回類(lèi)型數(shù)據(jù):
{ ? "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": "分頁(yè)獲取成功" }
Feign調(diào)用分頁(yè)接口報(bào)錯(cuò):Method has too many Body parameters
接口定義:
@ApiOperation(value = "分頁(yè)查詢會(huì)話") @PostMapping(Routes.SESSIONS_QUERY) JsonResult<Pagination<SessionInfo>> querySessions(@RequestBody @Valid SessionsQo qo, @PageableDefault(size = 20, sort = "id", direction = Sort.Direction.DESC) Pageable pageable);
服務(wù)消費(fèi)方調(diào)用報(bào)錯(cuò):
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)
解決方法
通過(guò)搜索、調(diào)研,目前有三種解決方法:
1、將分頁(yè)屬性直接通過(guò)入?yún)鬟f,接口定義如下:
@ApiOperation(value = "分頁(yè)查詢會(huì)話") @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、將分頁(yè)對(duì)象冗余在Qo中(通過(guò)繼承實(shí)現(xiàn)):
@Data @NoArgsConstructor @ApiModel(value = "查詢會(huì)話") public class SessionsQo extends PageableParam { @ApiParam(value = "會(huì)話id列表") private List<Long> sessionIdIn = Lists.newArrayList(); ... }
3、通過(guò)注解傳遞(參考:Issue):
服務(wù)提供方定義注解:
@Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface PageableParam { }
服務(wù)提供方定義接口:
@ApiOperation(value = "分頁(yè)查詢會(huì)話") @PostMapping(Routes.SESSIONS_QUERY) JsonResult<Pagination<SessionInfo>> querySessions(@RequestBody @Valid SessionsQo qo, @PageableParam @SpringQueryMap Pageable pageable);
服務(wù)消費(fèi)方定義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; } }
服務(wù)消費(fèi)方自定義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原因:主要是因?yàn)镕eign對(duì)QueryMap類(lèi)型參數(shù)的序列化和反序列化的言七墨方式與Sort.Order的不兼容,導(dǎo)致排序失效。
服務(wù)消費(fèi)方調(diào)用方式:
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,
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- feign遠(yuǎn)程調(diào)用無(wú)法傳遞對(duì)象屬性405的問(wèn)題
- Feign遠(yuǎn)程調(diào)用參數(shù)里面內(nèi)容丟失的解決方案
- Feign遠(yuǎn)程調(diào)用Multipartfile參數(shù)處理
- 使用Feign遠(yuǎn)程調(diào)用時(shí),序列化對(duì)象失敗的解決
- spring cloud feign實(shí)現(xiàn)遠(yuǎn)程調(diào)用服務(wù)傳輸文件的方法
- 解決在微服務(wù)環(huán)境下遠(yuǎn)程調(diào)用feign和異步線程存在請(qǐng)求數(shù)據(jù)丟失問(wèn)題
相關(guān)文章
解決?IDEA?Maven?項(xiàng)目中"Could?not?find?artifact"?
這篇文章主要介紹了解決IDEA Maven項(xiàng)目中Could not?find?artifact問(wèn)題的常見(jiàn)情況和解決方案,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-07-07關(guān)于SpingMVC的<context:component-scan>包掃描踩坑記錄
這篇文章主要介紹了關(guān)于SpingMVC的<context:component-scan>包掃描踩坑記錄,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03springboot?vue接口測(cè)試HutoolUtil?TreeUtil處理樹(shù)形結(jié)構(gòu)
這篇文章主要介紹了springboot?vue接口測(cè)試HutoolUtil?TreeUtil處理樹(shù)形結(jié)構(gòu),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05教你開(kāi)發(fā)腳手架集成Spring?Boot?Actuator監(jiān)控的詳細(xì)過(guò)程
這篇文章主要介紹了開(kāi)發(fā)腳手架集成Spring?Boot?Actuator監(jiān)控的詳細(xì)過(guò)程,集成包括引入依賴配置文件及訪問(wèn)驗(yàn)證的相關(guān)知識(shí),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-05-05SpringCloud使用Feign實(shí)現(xiàn)遠(yuǎn)程調(diào)用的使用示例
Feign是一個(gè)基于注解的HTTP客戶端庫(kù),它允許您將HTTP請(qǐng)求轉(zhuǎn)換為聲明式的Java接口,本文主要介紹了SpringCloud使用Feign實(shí)現(xiàn)遠(yuǎn)程調(diào)用的使用示例,感興趣的可以了解一下2023-09-09Maven中的dependencyManagement 實(shí)例詳解
dependencyManagement的中文意思就是依賴關(guān)系管理,它就是為了能通更好統(tǒng)一管理項(xiàng)目的版本號(hào)和各種jar版本號(hào),可以更加方便升級(jí),解決包沖突問(wèn)題,這篇文章主要介紹了Maven中的dependencyManagement 實(shí)例詳解,需要的朋友可以參考下2024-02-02Java+swing+Mysql實(shí)現(xiàn)商品銷(xiāo)售管理系統(tǒng)
基礎(chǔ)扎不扎實(shí)只有在實(shí)戰(zhàn)中才能顯現(xiàn),本篇文章手把手帶你用Java+swing+Mysql實(shí)現(xiàn)商品銷(xiāo)售管理系統(tǒng),大家可以在過(guò)程中查缺補(bǔ)漏,提升水平2022-01-01java中以DES的方式實(shí)現(xiàn)對(duì)稱加密并提供密鑰的實(shí)例
這篇文章主要介紹了java中以DES的方式實(shí)現(xiàn)對(duì)稱加密并提供密鑰的實(shí)例的相關(guān)資料,這里提供實(shí)例幫助大家學(xué)習(xí)理解這部分知識(shí),需要的朋友可以參考下2017-08-08