<spring-cloud-openfeign.version>2.2.6.RELEASE</spring-cloud-openfeign.version>
对应的SpringBoot
<version>2.3.0.RELEASE</version>
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> <version>${spring-cloud-openfeign.version}</version> <exclusions> <exclusion> <artifactId>archaius-core</artifactId> <groupId>com.netflix.archaius</groupId> </exclusion> </exclusions> </dependency>
如果不在同一个 Module 中,需要添加 MapperScan
@ComponentScan(basePackages = {"com.iron"}) @SpringBootApplication @EnableFeignClients(basePackages = {"com.iron.his"}) @MapperScan(basePackages ={"com.iron.his.mapper"} ) -- 如果两个MapperScan 就需要 classpath: 改成 classpath* public class DefaultApplication { public static void main(String[] args) { SpringApplication.run(VipSoftWebApplication.class, args); } }
日志记录
FeignConfig
package com.vipsoft.dingtalk.config; import feign.Logger; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class FeignConfig { /** * Feign 的详细日志,配合yml使用 *logging: * level: * # feign 日志以什么级别监控哪个接口 * com.vipsoft.ecgreport.sehedule.service: debug * @return */ @Bean Logger.Level fegnLoggerLevel(){ return Logger.Level.FULL; } }
application.yml
server: application: name: VipSoft Dingtalk port: 8080 servlet: context-path: /dingtalk tomcat: basedir: ./logs/ background-processor-delay: 30 redirect-context-root: true uri-encoding: UTF-8 accesslog: enabled: true #为true时,上面的日期格式才有意义,否则就是写在一个文件里了 buffered: true directory: ./logs file-date-format: .yyyy-MM-dd #pattern: '%h %l %u %t "%r" %s %b "%{Referer}i" "%{User-Agent}i" %D ms' pattern: '%t %a %m %U %s %b %D ms' prefix: access_log rename-on-rotate: false request-attributes-enabled: false rotate: true suffix: .log # 因为feign调试日志是debug级别输出,springboot默认的日志级别是info,所以feign的debug日志级别就不会输出 # logging.level=debug这样配置是对所有的日志级别进行配置 # 该场景只需要对feign接口进行debug配置,所以是这样配置logging.level.com.vipsoft.dingtalk.rpc=debug logging: level: # feign 日志以什么级别监控哪个接口 com.vipsoft.dingtalk.rpc: debug dingtalk: rebot-url: https://oapi.dingtalk.com
简单调用
//定义一个拦截器 public class FeignInterceptor implements RequestInterceptor { @Override public void apply(RequestTemplate requestTemplate) { requestTemplate.header("AppId", "AppId"); requestTemplate.header("AppKey", "myuser1"); requestTemplate.header("AppSecret", "mypassword"); } } //接口类 @Component @FeignClient(name = "demo-feign", url = "https://www.fastmock.site/mock/e5738f58a04967320a772f1d69aa4a41/mp/", configuration = FeignInterceptor.class) public interface IFeignTestService { @GetMapping(value = "/GetUser") String getUser(@RequestBody String words); } //调用 @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class FeignTests { Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired private IFeignTestService feignTestService; @Test void searchTest() { String result = feignTestService.getUser("VipSoft"); logger.info(result); } }
OpenFeign 动态URL
//定义一个拦截器 public class FeignInterceptor implements RequestInterceptor { @Override public void apply(RequestTemplate requestTemplate) { requestTemplate.header("AppId", "AppId"); requestTemplate.header("AppKey", "myuser1"); requestTemplate.header("AppSecret", "mypassword"); } } //接口类 @Component @FeignClient(name = "demo-feign", url = "url必须有值,这里随便写,但不能为空", configuration = FeignInterceptor.class) public interface IFeignTestService { @PostMapping("/") String getWebsite(URI uri, @RequestBody String words); } //调用 @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class FeignTests { Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired private IFeignTestService feignTestService; @Test void searchTest() { String ss1 = feignTestService.getWebsite(new URI("https://www.fastmock.site/mock/e5738f58a04967320a772f1d69aa4a41/mp/GetUser"), ""); logger.error(ss1); String ss2 = feignTestService.getWebsite(new URI("https://www.fastmock.site/mock/e5738f58a04967320a772f1d69aa4a41/mp/hospital"), ""); logger.error(ss2); String ss3 = feignTestService.getWebsite(new URI("https://www.fastmock.site/mock/e5738f58a04967320a772f1d69aa4a41/mp/device"), ""); logger.error(ss3); } }
OpenFeign application/x-www-form-urlencoded
@Test void queryOrderTest() { MultiValueMap<String, Object> param = new LinkedMultiValueMap<>(); param.add("msg_type", "GUOGUO_QUERY_SEND_SERVICE_DETAIL"); param.add("logistic_provider_id", "123456"); param.add("data_digest", "def"); param.add("logistics_interface", "abc"); String result = cainiaoService.querySendServiceDetail(param); logger.info(PojoUtil.pojoToJson(param)); logger.info(result); } @Component @FeignClient(name = "feign-cainiao", url = "${cainiao.url}") public interface IFeignCainiaoService { /** * 获取三期API接口 * * @param bodyParam AppId、PageIndex、PageSize * @return */ @PostMapping(headers = {"content-type=application/x-www-form-urlencoded"}) String querySendServiceDetail(@RequestBody MultiValueMap<String, Object> bodyParam); }
OpenFeign 自定义配置
//接口类 @Component @FeignClient(name = "demo-feign", url = "url必须有值,这里随便写,但不能为空", configuration = IFeignTestService.MultipartSupportConfig.class) public interface IFeignTestService { //写接口内部,这样可以高内聚 class MultipartSupportConfig { @Autowired private ObjectFactory<HttpMessageConverters> messageConverters; @Bean public Encoder feignFormEncoder() { return new SpringFormEncoder(new SpringEncoder(messageConverters)); } } @PostMapping("/") String getWebsite(URI uri, @RequestBody String words); }
传 Header、URL 参数
/** * 发送预警信息 * @return */ @PostMapping(value = "/") String sendMessage(@RequestHeader Map<String, Object> headerParam, @RequestBody RobotMessage param); /** * 发送预警信息 * @return */ @PostMapping(value = "/robot/send") String sendMessage(@RequestParam Map<String, Object> headerParam, @RequestBody RobotMessage param);
上传文件
@FeignClient(name = "vipsoft", url = "${api.url}") public interface ICallbackFeignService { /** * 上传文件 * * 注意: 使用openfeign传递参数含有文件类型时必须指定 consumes = MediaType.MULTIPART_FORM_DATA_VALUE* * @return */ @PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) String upload(@RequestPart("file") MultipartFile file); } package com.vipsoft.web; import com.vipsoft.web.rpc.ICallbackFeignService; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.mock.web.MockMultipartFile; import org.springframework.web.multipart.MultipartFile; import java.io.File; import java.io.FileInputStream; @SpringBootTest public class AppCallbackTest { @Autowired ICallbackFeignService appCallbackFeignService; @Test void Upload() throws Exception { File file = new File("D:\\Users\\Desktop\\fanye.mp4"); //这里的第一个参数值 file 是对应上面feign的文件注解中的@RequestPar中的name。一定要对应上 MultipartFile multipartFile = new MockMultipartFile("file", file.getName(), "application/octet-stream;charset=utf-8", new FileInputStream(file)); appCallbackFeignService.upload(multipartFile); } }