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

本文详细介绍了如何使用Feign进行微服务间的调用,包括配置、依赖引入及常见问题解决,如HTTP客户端的选择与错误处理。

一、 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 进行远程调用时,参数对象的命名规范往往与项目架构设计、模块划分以及服务间通信的语义清晰性密切相关。以 `biz` 开头的命名方式是一种常见的实践,其背后的原因主要体现在以下几个方面: 1. **业务逻辑隔离与分层设计** 参数对象以 `biz` 为前缀,通常表示该对象属于业务(business)层级,用于承载具体的业务数据和操作意图。这种命名方式有助于在代码中明确区分不同层级的对象,例如与数据库交互的 `dao` 对象、用于页面展示的 `dto` 对象等。通过这种方式,可以增强代码的可读性和可维护性。 2. **服务接口语义化表达** 在微服务架构中,Feign 客户端常用于定义服务间的通信接口。将参数对象命名为 `biz` 开头,可以更清晰地表达该接口所承载的业务含义,表明该参数是面向具体业务场景的输入数据结构。这有助于服务调用方更好地理解接口用途,减少因误解参数含义而导致的错误[^1]。 3. **统一编码风格与团队协作** 在大型项目或多个团队协同开发中,统一的命名规范对于保持代码一致性至关重要。以 `biz` 开头的命名约定可以帮助团队成员快速识别参数对象的作用域和用途,降低沟通成本,提升协作效率。 4. **便于自动化工具识别与处理** 某些项目可能集成了代码生成工具、API 文档生成器或其他自动化系统,这些工具可以通过命名模式自动识别出业务参数对象据此生成相应的文档、校验规则或序列化/反序列化逻辑。 5. **避免命名冲突** 在复杂的系统中,不同模块可能会定义相似功能的参数对象。使用 `biz` 前缀可以在一定程度上避免命名冲突,确保每个对象的命名空间具有唯一性和明确性。 ### 示例代码 以下是一个使用 `biz` 前缀定义的 Feign 调用参数对象示例: ```java public class BizOrderRequest { private String orderId; private String customerName; private BigDecimal amount; // Getters and Setters } ``` 在 Feign 接口中使用该对象作为请求参数: ```java @RequestLine("POST /createOrder") Response createOrder(@Body BizOrderRequest request); ``` 上述示例展示了如何通过命名规范来增强代码的语义表达能力,同时提高接口的可读性。 ---
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值