SpringCloud OpenFeign 參數(shù)傳遞和響應(yīng)處理的詳細(xì)步驟
一、OpenFeign 參數(shù)傳遞和響應(yīng)處理
1.1、feign 客戶端參數(shù)傳遞
1.1.1、零散類型參數(shù)傳遞
OpenFeign 對零散類型參數(shù)傳遞有以下限制
- querystring 方式傳遞參數(shù)(例如 "/user?name=cyk" ):在 openfeign 接口聲明中必須要給參數(shù)加入 @RequestParam 注解/
- restful 路徑傳參(例如 "/user/{id}/{name}" ):在 openfeign 接口聲明中必須要給參數(shù)加入注解 @PathVariable 注解.
為什么 openfeign 要這樣區(qū)分呢?
因為 openfeign 是 偽HttpClient 對象,我們在遠(yuǎn)程調(diào)用他的客戶端提供的接口時,并不知道你到底是路徑傳參還是問號傳參,因此需要通過注解的方式來指明傳參方式(就像 Spring Web 一樣,只不過 Spring Web 中如果沒指明傳參類型,底層會按默認(rèn)方式走,而 openfeign 則沒有).
1. 例如 querystring 方式傳參
a)遠(yuǎn)程調(diào)用方
@RestController @RequestMapping("/user") public class UserController { @Autowired private ProductClient productClient; @GetMapping("/test1") public String test1(Long id) { String info = productClient.getInfo(id); System.out.println(info); return "user ok! \n" + info; } }
b)服務(wù)提供方
@RestController @RequestMapping("/product") public class ProductController { @GetMapping("/get_info") public String getInfo(Long id) { return "product ok! id=" + id; } }
c)feign 客戶端
@FeignClient(value = "product", configuration = LoadBalancerClientConfiguration.class) public interface ProductClient { @GetMapping("/product/get_info") String getInfo(@RequestParam("id") Long id); }
d)測試結(jié)果:
2. 例如路徑方式傳參
a)遠(yuǎn)程調(diào)用方
@RestController @RequestMapping("/user") public class UserController { @Autowired private ProductClient productClient; @GetMapping("/test2") public String test2(String name) { String info = productClient.getName(name); System.out.println(info); return "user ok! \n" + info; } }
b)服務(wù)提供方
@RestController @RequestMapping("/product") public class ProductController { @GetMapping("/{name}") public String getName(@PathVariable("name") String name) { return "product ok! name=" + name; } }
c)feign 客戶端
@FeignClient(value = "product", configuration = LoadBalancerClientConfiguration.class) public interface ProductClient { @GetMapping("/product/{name}") String getName(@PathVariable("name") String name); }
d)測試結(jié)果:
擴(kuò)展:restful 和 問號傳參的區(qū)別
RESTful 風(fēng)格是一種基于 HTTP 協(xié)議的 API 設(shè)計風(fēng)格,它通過使用不同的 HTTP 方法(GET、POST、PUT、DELETE 等)和不同的 URL 來表示不同的操作和資源。RESTful 風(fēng)格的優(yōu)點包括:
- 清晰、簡潔的 URL 設(shè)計:RESTful 風(fēng)格的 URL 通常比較簡潔,易于理解和記憶,能夠清晰地表達(dá)出資源的結(jié)構(gòu)和操作。
- 良好的可擴(kuò)展性:RESTful 風(fēng)格的設(shè)計允許你在原有的 API 上添加新的資源和方法,而不會對原有的 API 造成影響。
- 支持緩存:RESTful 風(fēng)格的 API 可以利用 HTTP 緩存機(jī)制,提高 API 的響應(yīng)速度和性能。
- 跨平臺、跨語言:RESTful 風(fēng)格的 API 可以被不同的平臺和語言調(diào)用,具有很好的兼容性和可集成性。
問號傳參風(fēng)格是一種通過在 URL 中使用問號傳參的方式來傳遞參數(shù)的 API 設(shè)計風(fēng)格。它的優(yōu)點包括:
- 動態(tài)參數(shù)傳遞:問號傳參風(fēng)格允許你在 URL 中直接傳遞參數(shù),可以方便地實現(xiàn)動態(tài)參數(shù)的傳遞。
- 支持復(fù)雜參數(shù)類型:問號傳參風(fēng)格可以支持復(fù)雜的數(shù)據(jù)類型,例如對象、數(shù)組等,能夠更好地滿足復(fù)雜參數(shù)傳遞的需求。
- 易于開發(fā)和實現(xiàn):問號傳參風(fēng)格的 API 開發(fā)起來相對簡單,容易實現(xiàn)和調(diào)試。
總的來說,如果你需要設(shè)計一個簡單的 API,并且對性能和擴(kuò)展性要求不高,問號傳參風(fēng)格可能是一個不錯的選擇。而如果你需要設(shè)計一個復(fù)雜的 API,需要支持緩存、擴(kuò)展性、跨平臺和跨語言等要求,那么 RESTful 風(fēng)格可能更適合你的需求。
1.1.2、對象參數(shù)傳遞
對象參數(shù)傳遞方式有兩種,一種是 form 表單提交,另一種是 application/json 方式(推薦),這里主要講第二種方式(實際開發(fā)中用的).
openfeign 接口要求對象傳參必須要使用 @RequestBody 注解指明類型.
原因:這就像是我們給后端傳遞一個 json 格式數(shù)據(jù)類型,然后后端使用 一個對象接收參數(shù),并通過 @RequestBody 指明他是 json 格式.
注意:openfeign 中對象傳參只能使用 POST,并且也符合使用習(xí)慣,最主要是因為 GET 請求傳對象會報錯 Method Not Allowed.
1. 對象參數(shù)傳遞案例
a)遠(yuǎn)程調(diào)用方
@RestController @RequestMapping("/user") public class UserController { @Autowired private ProductClient productClient; @GetMapping("/test3") public String test3(@RequestBody User user) { user.setUsername(user.getUsername()); user.setPassword(user.getPassword()); String userinfo = productClient.getUser(user); return "user ok! \n" + userinfo; } }
b)服務(wù)提供方
@RestController @RequestMapping("/product") public class ProductController { @PostMapping("/get_user") public String getUser(@RequestBody User user) { return "product ok! " + user.toString(); } }
c)feign 客戶端
@FeignClient(value = "product", configuration = LoadBalancerClientConfiguration.class) public interface ProductClient { //注意:openfeign 中對象傳參只能使用 POST,并且也符合使用習(xí)慣 //GET 請求傳對象會報錯: Method Not Allowed @PostMapping("/product/get_user") String getUser(@RequestBody User user); }
d)測試結(jié)果:
1.1.3、數(shù)組參數(shù)傳遞
數(shù)組參數(shù)傳遞要求在 feign 客戶端接口使用 @RequestParam 注解指明參數(shù)類型.
原因:數(shù)組參數(shù)傳遞,實際上就是 querystring 方式傳參,例如 " /user/?name=123&name=456&name=789 ",其中 name 就是數(shù)組.
1. 數(shù)組傳參案例
a)遠(yuǎn)程調(diào)用方
@RestController @RequestMapping("/user") public class UserController { @Autowired private ProductClient productClient; @GetMapping("/test4") public String test4(String[] arr) { String result = productClient.getArr(arr); return "user ok! \n" + result; } }
b)服務(wù)提供方
@RestController @RequestMapping("/product") public class ProductController { @GetMapping("/get_arr") public String getArr(@RequestParam("arr") String[] arr) { return "product ok!" + Arrays.toString(arr); } }
c)feign 客戶端
@FeignClient(value = "product", configuration = LoadBalancerClientConfiguration.class) public interface ProductClient { @GetMapping("/product/get_arr") String getArr(@RequestParam("arr") String[] arr); }
d)測試結(jié)果
1.1.4、集合類型的參數(shù)傳遞(了解)
spring mvc 不能直接接收集合類型參數(shù)(例如 List)!如果一定要接收,需要將集合類型參數(shù)放入對象中,然后使用對象的方式傳遞.
例如如下:
@Data public class User { private String username; private String password; private List<String> arr; }
這里就不演示了,因為 使用方式 以及 注意事項 和對象傳遞參數(shù)一樣.
1.2、feign 客戶端響應(yīng)處理
1.2.1、天坑!
這里我們只需要知道一點就可以,F(xiàn)eign 客戶端不能處理 Object 這種類型的返回格式!無論是對象中包含 Object 類型還是 Map 中存在 Object 類型....... 只要有他,就會出現(xiàn)各種格式問題.
例如,服務(wù)提供方傳入的是一個 Long 類型,但是遠(yuǎn)程調(diào)用方接收到參數(shù)之后就變成了 Integer 類型(這里的處理,和 RabbitMQ 消息發(fā)送后的格式轉(zhuǎn)化一個尿性),強轉(zhuǎn)就會報以下錯誤:
ChatGPT 給出了以下解釋:
這是因為 OpenFeign 在默認(rèn)情況下會自動將對象和 Map 對象轉(zhuǎn)換成 JSON 格式。它使用了 Jackson 作為默認(rèn)的序列化/反序列化庫。當(dāng)你在使用 OpenFeign 進(jìn)行遠(yuǎn)程調(diào)用時,返回的對象會被自動轉(zhuǎn)換成 JSON 格式。
然而,需要注意的是,OpenFeign 只能處理簡單的 Java 對象和 Map 對象,對于復(fù)雜的 Java 對象或包含特殊類型的對象,可能無法自動進(jìn)行正確的序列化和反序列化。在這種情況下,你可能需要自定義序列化/反序列化方式,或者使用其他序列化庫來替代默認(rèn)的 Jackson。
1.2.2、解決辦法
只要服務(wù)提供方的返回值類型涉及到 Object 、對象、Map 這些復(fù)雜類型,都可以在 Feign 客戶端使用 String 類型作為接口返回值類型(因為 openfeign 會自動轉(zhuǎn)換為 json 格式),遠(yuǎn)程調(diào)用方接收到響應(yīng)之后,就可以使用 ObjectMapper.readValue() 反序列化成我們所需要的對象即可.
案例一
a)遠(yuǎn)程調(diào)用方
@RestController @RequestMapping("/user") public class UserController { @Autowired private ProductClient productClient; @Autowired private ObjectMapper objectMapper; @SneakyThrows @GetMapping("/test6") public String test6() { String data = productClient.getData(); Long finalData = objectMapper.readValue(data, Long.class); return "user ok!" + finalData; } }
b)服務(wù)提供方
@RestController @RequestMapping("/product") public class ProductController { @GetMapping("/get_data") public Object getData() { return 100L; } }
c)feign 客戶端
@FeignClient(value = "product", configuration = LoadBalancerClientConfiguration.class) public interface ProductClient { @GetMapping("/product/get_data") String getData(); }
測試結(jié)果:
案例二(復(fù)雜數(shù)據(jù)類型)
a)Feign 客戶端接口響應(yīng)類型
@Data public class User { private String username; private String password; private List<String> arr; }
b)遠(yuǎn)程調(diào)用方
@RestController @RequestMapping("/user") public class UserController { @Autowired private ProductClient productClient; @Autowired private ObjectMapper objectMapper; @GetMapping("/test5") public String test5() throws JsonProcessingException { User user = new User(); user.setUsername("cyk"); user.setPassword("1111"); List<String> arrayList = new ArrayList<>(); arrayList.add("aaa"); arrayList.add("bbb"); user.setArr(arrayList); String userList = productClient.getUserList(user); User user2 = objectMapper.readValue(userList, User.class); System.out.println(user2); return "user ok! \n" + userList; } }
c)服務(wù)提供方
@RestController @RequestMapping("/product") public class ProductController { @PostMapping("/get_user_list") public User getUserList(@RequestBody User user) { return user; } }
d)feign 客戶端
@FeignClient(value = "product", configuration = LoadBalancerClientConfiguration.class) public interface ProductClient { @PostMapping("/product/get_user_list") String getUserList(@RequestBody User user); }
測試結(jié)果:
到此這篇關(guān)于SpringCloud OpenFeign 參數(shù)傳遞和響應(yīng)處理的文章就介紹到這了,更多相關(guān)SpringCloud OpenFeign 參數(shù)傳遞內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java中ConcurrentHashMap是如何實現(xiàn)線程安全
ConcurrentHashMap是一個哈希表,支持檢索的全并發(fā)和更新的高預(yù)期并發(fā)。本文主要介紹了Java中ConcurrentHashMap是如何實現(xiàn)線程安全,感興趣的可以了解一下2021-11-11Mybatis如何按順序查詢出對應(yīng)的數(shù)據(jù)字段
這篇文章主要介紹了Mybatis如何按順序查詢出對應(yīng)的數(shù)據(jù)字段,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-01-01Spring?Boot+RabbitMQ?通過fanout模式實現(xiàn)消息接收功能(支持消費者多實例部署)
這篇文章主要介紹了Spring?Boot+RabbitMQ?通過fanout模式實現(xiàn)消息接收(支持消費者多實例部署),本文通過案例場景分析給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-03-03Spring Boot 整合 TKMybatis 二次簡化持久層代碼的實現(xiàn)
這篇文章主要介紹了Spring Boot 整合 TKMybatis 二次簡化持久層代碼的實現(xiàn),本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-01-01Spring cloud alibaba之Ribbon負(fù)載均衡實現(xiàn)方案
Spring cloud Ribbon是基于Netflix Ribbon實現(xiàn)的一套客戶端的負(fù)載均衡工具,Ribbon客戶端提供一系列完善的配置,如超時、重試等,Ribbon也可以實現(xiàn)自己的負(fù)載均衡算法,感興趣的朋友跟隨小編一起看看吧2021-07-07