Call Rest Api by FeignClient
之前写过一篇使用Feign.builder()
来发送 HTTP 请求的博客,对应的接口注解使用的是@RequestLine
而不是常用的@RequestMapping
。
@RequestLine
是 feign-core 包提供的注解,@RequestMapping
、@PostMapping
、@GetMapping
等是 spring-web 包提供的注解,两个使用方法不大一样。
1. 添加依赖
添加 spring-cloud-starter-openfeign 和 feign-httpclient 依赖。
其中 feign-httpclient 是为了将默认的客户端feign.Client.Default
替换为HttpClient
。
<!-- 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 。
feign:
httpclient:
enabled: true
3. 添加 FeignClient 服务
代码示例如下。
其中@FeignClient
的 name 属性指定了客户端的名称(后面配置打印日志时会用到),可以在配置文件中通过这个属性对特定的服务指定配置。
另外 url 属性中使用 SpEL(Spring Expression Language) 以指定默认值的同时,还可以通过配置文件来修改这个值(修改后需要重启服务才会生效)。
这里是 GET 方法的示例,这种写法会导致参数太多,但又没有查到比较好的使用对象来传递 GET 参数的方法,建议参数过多时还是使用 POST 方法。
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 所在的包名。
可以像下面的示例一样,通过单独的类来配置,也可以在启动类上添加这个注解来配置。
/**
* 用户数据服务配置
*
* @author jiajia
*/
@Component
@EnableFeignClients(basePackages = { "me.liujiajia.user.service" })
public class UserDataServiceConfiguration {
}
5. 测试
如果需要自动化测试的,可以参考如下代码。
首先要添加 spring-boot-starter-test 依赖。
<!-- 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 可以参考之前的一篇博客。
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 。
feign:
client:
config:
userDataService:
logger-level: full
logging:
level:
com.client.client: DEBUG