服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|JavaScript|易语言|R语言|

服务器之家 - 编程语言 - Java教程 - Feign接口方法返回值设置方式

Feign接口方法返回值设置方式

2021-09-29 11:58CoderYin Java教程

这篇文章主要介绍了Feign接口方法返回值设置方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

一、介绍

随着微服务的广泛应用,越来越多的企业都会使用微服务进行项目开发,在各个服务之间需要通过feign来进行通信,所以在feign调用接口中方法会接受其他服务接口不同类型返回值

二、返回值设置

1、依据被调用服务接口设置相同返回类型

介绍:微服务A接口getUser 返回List<User>类型,微服务B通过feign调用方法也返回相同的结果类型。

特点:返回类型一一对应,在调用时不需要进行转化直接拿来就可以用。

缺点:扩展性不好,维护性不加。

解释:在目前springboot开发中,接口一般都会返回json类型数据(也就是使用@restController或者使用@ResponseBody注解修饰),就算是对象或者对象集合也是一样的,或者其他自己封装的返回对象。如果有许多不同的返回对象,当这些返回对象在A服务做了修改相应的在B服务的feign接口处也要做修改,相当麻烦且不符合java面向接口编程思想。

2、全部设置为String

介绍:微服务A接口只要被@restController或者使用@ResponseBody注解修饰我统统在微服务Bfeign接口使用String来进行接受。

特点:通过String来接受返回参数,格式一致。

缺点:后面调用需要转换。

代码介绍:

  1. // 微服务A controller 已经使用@restController修饰
  2. @PostMapping(value="/getAllQuestionBank",produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
  3. public List<QuestionBankDto> getAllQuestionBank(){
  4. return baseinfoQuestionMange.getAllQuestionBank();
  5. }
  6.  
  7. // 微服务B feign接口 使用String进行接受
  8. @PostMapping(value="/baseinfo/getAllQuestionBank")
  9. String getAllQuestionBank();
  10.  
  11. // 微服务B 当需要调用feign信息时需要强转成List<QuestionBankDto>格式
  12.  
  13. // 调用微服务获取题库章节信息,该处强制使用try catch进行包裹
  14. String questionBankInfo = baseInfoApi.getAllQuestionBank();
  15. List<QuestionBankDto> mysqlQuestionBank = objectMapper.readValue(questionBankInfo,new TypeReference<ArrayList<QuestionBankDto>>(){});

Feign接口方法返回值设置方式

只要你导入一下springboot依赖,它默认就给你导入了Jackson jar包

Feign接口方法返回值设置方式

注意事项:使用该方式时需要将ObjectMapper配置到bean容器中。

Feign接口方法返回值设置方式

3、总结

项目不同,需求不同,两种方式没有谁对谁错之分,依据自己项目需求进行选择。

Feign 使用这几天遇到的一些问题

事情的起因要从我打算调用下paas模块服务开始

Feign 现在教程很多,然后引入下pom

  1. <dependency>
  2. <groupId>org.springframework.cloud</groupId>
  3. <artifactId>spring-cloud-starter-openfeign</artifactId>
  4. </dependency>

自己定义下接口

  1. @FeignClient(name = "weixinTokenClient", url = "https://qyapi.weixin.qq.com/cgi-bin")
  2. public interface IWeiXinTokenClient {
  3. /**
  4. * 获取应用的token
  5. * @param corpid
  6. * @param corpsecret
  7. * @return
  8. */
  9. @RequestMapping(value = "/gettoken", method = RequestMethod.GET)
  10. WeiXinTokenResultModel getToken(@RequestParam String corpid, @RequestParam String corpsecret);
  11. }

写个test类测试下,完美返回,因为自己写过类似的项目,可以看下lemur-http,原理大体一致,想了想还是简单的.但是后面的问题就出来

1. nacos 配置拿不到服务

原因是:nacos注册服务只注册了lemur-admin和lemur-paas这种服务级别的服务,获取服务地址需要用lemur-admin服务,但是在admin调用paas接口的时候

  1. @FeignClient(value = "paasUserFacade", contextId = "lemur-paas", path = "/im/user")
  2. public interface IPaasUserFacade extends IBaseController<PaasUserRequestModel> {
  3. }

@FeignClient注解不论是value,name,contextId ,serviceId全都是当做了name,所以在获取nacos地址的地方都是用paasUserFacade去匹配的,根本无法拿到,最终一直跟了N遍代码,也没有找打解决办法,自己还是改了源码FeignClientFactoryBean,在注册bean的地方还是使用value ,并且不用contextId 注册别名,意义不大,还重名,把contextId 当做服务Id,feign是通过target来做地址解析的,所以只要把target的url地址改为lemur-paas/im/user就可以了

  1. <T> T getTarget() {
  2. FeignContext context = this.applicationContext.getBean(FeignContext.class);
  3. Feign.Builder builder = feign(context);
  4. if (!StringUtils.hasText(this.url)) {
  5. if (StringUtils.hasText(this.contextId) && !this.name.startsWith("http")){
  6. this.url = "http://" + this.contextId;
  7. }else if (StringUtils.hasText(this.contextId)){
  8. this.url = this.contextId;
  9. } else if (!this.name.startsWith("http")) {
  10. this.url = "http://" + this.name;
  11. }
  12. else {
  13. this.url = this.name;
  14. }
  15. this.url += cleanPath();
  16. return (T) loadBalance(builder, context,
  17. new HardCodedTarget<>(this.type, this.name, this.url));
  18. }
  19. if (StringUtils.hasText(this.url) && !this.url.startsWith("http")) {
  20. this.url = "http://" + this.url;
  21. }
  22. String url = this.url + cleanPath();
  23. Client client = getOptional(context, Client.class);
  24. if (client != null) {
  25. if (client instanceof LoadBalancerFeignClient) {
  26. // not load balancing because we have a url,
  27. // but ribbon is on the classpath, so unwrap
  28. client = ((LoadBalancerFeignClient) client).getDelegate();
  29. }
  30. builder.client(client);
  31. }
  32. Targeter targeter = get(context, Targeter.class);
  33. return (T) targeter.target(this, builder, context,
  34. new HardCodedTarget<>(this.type, this.name, url));
  35. }

改完源码之后,算是可以互相调用了

2.fastjson 不支持abstract class ,关键是不报错,直接返回null

因为风铃统一返回的都是Response对象,加泛型,结果怎么调用返回的都是null,看看被调用的服务是有收到请求并返回的,这个只能是客户端的问题了,一开始以为是泛型解析的问题,跟踪了整个调用解析链条

  1. ReflectiveFeign.invoke->
  2. SynchronousMethodHandler.invoke->
  3. executeAndDecode->decode(解析对象)->
  4. ResponseEntityDecoder.decode->
  5. SpringDecoder.decode->
  6. HttpMessageConverterExtractor.extractData(返回泛型)->
  7. FastJsonHttpMessageConverter(真正的解析器).read(type,clazz,inputMessage)->
  8. parseObject(is)

然后发现什么,fastjson无法实例化对象,我去你也报个错啊,把abstract去掉,就正常返回了

3.spring gateway 不支持web

spring gateway 因为使用webflux写的,不是web容器所以不能引入web,在引入feign的时候要把web去掉,不然起不来

  1. <dependency>
  2. <groupId>org.springframework.cloud</groupId>
  3. <artifactId>spring-cloud-starter-openfeign</artifactId>
  4. <exclusions>
  5. <exclusion>
  6. <artifactId>spring-boot-starter-web</artifactId>
  7. <groupId>org.springframework.boot</groupId>
  8. </exclusion>
  9. </exclusions>
  10. </dependency>

同时spring gateway 也不支持读取配置文件,同理原因,像j2cache的文件配置方式就读取不到

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

原文链接:https://blog.csdn.net/CoderYin/article/details/90754547

延伸 · 阅读

精彩推荐