<!-- # Call Rest Api by FeignClient --> <!-- call-rest-api-by-feign-client --> 之前写过[一篇使用`Feign.builder()`来发送HTTP请求的博客][1],对应的接口注解使用的是`@RequestLine`而不是常用的`@RequestMapping`。 `@RequestLine`是 *feign-core* 包提供的注解,`@RequestMapping`、`@PostMapping`、`@GetMapping`等是 *spring-web* 包提供的注解,两个使用方法不大一样。 ## 1. 添加依赖 添加 *spring-cloud-starter-openfeign* 和 *feign-httpclient* 依赖。 其中 *feign-httpclient* 是为了将默认的客户端`feign.Client.Default`替换为`HttpClient`。 ```xml <!-- Feign --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> <version>2.2.8.RELEASE</version> </dependency> <dependency> <groupId>io.github.openfeign</groupId> <artifactId>feign-httpclient</artifactId> <version>11.6</version> </dependency> ``` ## 2. 启用 HttpClient 在 *application.yml* 或 *bootstrap.yml* 中添加如下配置以启用 *HttpClient* 。 ```yaml feign: httpclient: enabled: true ``` ## 3. 添加 FeignClient 服务 代码示例如下。 其中`@FeignClient`的 *name* 属性指定了客户端的名称(后面配置打印日志时会用到),可以在配置文件中通过这个属性对特定的服务指定配置。 另外 *url* 属性中使用 *SpEL(Spring Expression Language)* 以指定默认值的同时,还可以通过配置文件来修改这个值(修改后需要重启服务才会生效)。 这里是 *GET* 方法的示例,这种写法会导致参数太多,但又没有查到比较好的使用对象来传递 *GET* 参数的方法,建议参数过多时还是使用 *POST* 方法。 ```java import org.springframework.cloud.openfeign.FeignClient; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; /** * 用户数据服务 * * @author jiajia */ @FeignClient(name = "userDataService", url = "${user-data-server.domain:" + AdDataConstants.AD_DATA_DOMAIN + "}") public interface UserDataService { /** * 推送用户数据 * * @param uid * @param appId * @param imei * @param oaid * @param mac * @param androidId * @param ip * @param ua * @param createTime * @return */ @GetMapping(value = "api/app/user", consumes = MediaType.APPLICATION_JSON_VALUE) UserDataPublicResponse pushUserData( @RequestParam("id") String id, @RequestParam("app_id") String appId, @RequestParam("imei") String imei, @RequestParam("oaid") String oaid, @RequestParam("mac") String mac, @RequestParam("android_id") String androidId, @RequestParam("ip") String ip, @RequestParam("ua") String ua, @RequestParam("create_time") String createTime ); } ``` ## 4. 启用 FeignClient 通过`@EnableFeignClients`的 *basePackages* 属性指定需要扫描的 *FeignClient* 所在的包名。 可以像下面的示例一样,通过单独的类来配置,也可以在启动类上添加这个注解来配置。 ```java /** * 用户数据服务配置 * * @author jiajia */ @Component @EnableFeignClients(basePackages = { "me.liujiajia.user.service" }) public class UserDataServiceConfiguration { } ``` ## 5. 测试 如果需要自动化测试的,可以参考如下代码。 首先要添加 *spring-boot-starter-test* 依赖。 ```xml <!-- Test --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <version>2.2.13.RELEASE</version> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> ``` 添加测试类,通过`@SpringBootTest`已加载各种配置,通过`@Test`注解标记测试方法。关于自动化测试的 Mock 可以参考[之前的一篇博客][6]。 ```java import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @Slf4j @SpringBootTest public class UserDataServiceTest { @Autowired private UserDataService userDataService; @Test public void should_success_when_push_user_data() { UserDataPublicResponse response = userDataService.pushUserData( "1", "a_app_id", "869659051398480", "97e7ff3f-e5f3-d1b8-ccfc-f79bbeaf4841", "20:00:00:00:00:00", "873541edf36da917", "127.0.0.1", "Mozilla/5.0 (iPhone; CPU iPhone OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 SP-engine/2.30.0 main%2F1.0 baiduboxapp/12.14.5.10 (Baidu; P2 14.6) NABar/1.0 themeUA=Theme/default", "2021-10-20 12:00:00" ); Assertions.assertNotNull(response); Assertions.assertEquals(response.getCode(), 0); Assertions.assertEquals(response.getMessage(), "ok"); } } ``` ## 6. 打印请求的日志 默认是不打印HTTP请求的具体信息的,如需要可以通过添加如下配置来启用。 - *userDataService* 为`@FeignClient`注解中 *name* 属性指定的客户端名称; - *logger-level* 的值见`feign.Logger.Level`枚举,可选值有 *NONE*、*BASIC*、*HEADERS* 和 *FULL* ; - *logging.level* 中指定的是`Client`类的包名,日志级别的常用值值有 *ERROR*、*WARN*、*INFO*、*DEBUG* 和 *TRACE* 。 ```yaml feign: client: config: userDataService: logger-level: full logging: level: com.client.client: DEBUG ``` [1]:https://www.liujiajia.me/2021/7/10/call-rest-api-by-feign (Call Rest Api by Feign) [2]:https://blog.csdn.net/cuiyaoqiang/article/details/81215483 (feignclient发送get请求,传递参数为对象。) [3]:https://spring.io/projects/spring-cloud-openfeign (Spring Cloud OpenFeign) [4]:https://blog.csdn.net/odeng888/article/details/81101914 (怎样配置Feign使用HttpClient) [5]:https://blog.csdn.net/qq_15199097/article/details/90075245 (https://blog.csdn.net/qq_15199097/article/details/90075245) [6]:https://www.liujiajia.me/2021/4/27/junit5-mockmvc-mockito (JUnit5 & MockMvc & Mockito) Loading... 版权声明:本文为博主「佳佳」的原创文章,遵循 CC 4.0 BY-NC-SA 版权协议,转载请附上原文出处链接及本声明。 原文链接:https://www.liujiajia.me/2021/10/22/call-rest-api-by-feign-client 提交