一、 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": "分页获取成功"
}