1、概览 {#1概览}
Feign 是微服务中通过 REST API 以声明方式与其他微服务通信的强大工具,本文将带你了解如何使用 Open Feign 上传文件。
2、先决条件 {#2先决条件}
假设如下 RESTful Web 服务用于文件上传:
POST http://localhost:8081/upload-file
该 Web 服务端点定义如下:
@PostMapping(value = "/upload-file")
public String handleFileUpload(@RequestPart(value = "file") MultipartFile file) {
// 文件上传逻辑
}
3、依赖 {#3依赖}
为了支持文件上传的 application/x-www-form-urlencoded
和 multipart/form-data
编码类型,需要添加 feign-core
、 feign-form
和 feign-form-spring
模块。
在 Maven 中添加以下依赖:
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-core</artifactId>
<version>10.12</version>
</dependency>
<dependency>
<groupId>io.github.openfeign.form</groupId>
<artifactId>feign-form</artifactId>
<version>3.8.0</version>
</dependency>
<dependency>
<groupId>io.github.openfeign.form</groupId>
<artifactId>feign-form-spring</artifactId>
<version>3.8.0</version>
</dependency>
还可以直接使用 spring-cloud-starter-openfeign
依赖,它已经包含了 feign-core
:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>3.1.0</version>
</dependency>
4、配置 {#4配置}
在 main 类中添加 @EnableFeignClients
:
@SpringBootApplication
@EnableFeignClients
public class ExampleApplication {
public static void main(String[] args) {
SpringApplication.run(ExampleApplication.class, args);
}
}
@EnableFeignClients
注解允许组件扫描声明为 Feign 客户端的接口,并自动生成代理实现。
5、通过 Feign 客户端上传文件 {#5通过-feign-客户端上传文件}
5.1、@FeignClient
注解客户端 {#51feignclient-注解客户端}
为 @FeignClient
注解类创建所需的编码器:
public class FeignSupportConfig {
@Bean
public Encoder multipartFormEncoder() {
return new SpringFormEncoder(new SpringEncoder(new ObjectFactory<HttpMessageConverters>() {
@Override
public HttpMessageConverters getObject() throws BeansException {
return new HttpMessageConverters(new RestTemplate().getMessageConverters());
}
}));
}
}
注意,FeignSupportConfig
不需要使用 @Configuration
注解。
现在,创建一个接口,并用 @FeignClient
对其进行注解,并且添加 name
和 configuration
属性及其相应的值:
@FeignClient(name = "file", url = "http://localhost:8081", configuration = FeignSupportConfig.class)
public interface UploadClient {
@PostMapping(value = "/upload-file", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
String fileUpload(@RequestPart(value = "file") MultipartFile file);
}
UploadClient
指向上述的文件上传 API。
在使用 Hystrix
时,使用 fallback
属性作为备选方案。当上传 API 失败时,会执行此操作。
现在,@FeignClient
看起来像这样:
@FeignClient(name = "file", url = "http://localhost:8081", fallback = UploadFallback.class, configuration = FeignSupportConfig.class)
最后,直接从 Service 层调用 UploadClient
:
public String uploadFile(MultipartFile file) {
return client.fileUpload(file);
}
5.2、Feign.builder {#52feignbuilder}
在某些情况下,Feign 客户端需要定制,而上述注解方式无法实现这一点。在这种情况下,可以使用 Feign.builder()
API 创建客户端。
创建一个代理接口,其中包含一个针对 REST API 的文件上传方法,用于文件上传:
public interface UploadResource {
@RequestLine("POST /upload-file")
@Headers("Content-Type: multipart/form-data")
Response uploadFile(@Param("file") MultipartFile file);
}
注解 @RequestLine
定义了 HTTP 方法和 API 的相对资源路径,而 @Headers
则指定了 Content-Type
等 Header。
现在,从 Service 类中调用代理接口中的指定方法:
public boolean uploadFileWithManualClient(MultipartFile file) {
UploadResource fileUploadResource = Feign.builder().encoder(new SpringFormEncoder())
.target(UploadResource.class, HTTP_FILE_UPLOAD_URL);
Response response = fileUploadResource.uploadFile(file);
return response.status() == 200;
}
如上,使用了 Feign.builder()
工具来构建 UploadResource
代理接口的实例。还使用了 SpringFormEncoder
和基于 RESTful Web 服务的 URL。
6、验证 {#6验证}
创建一个测试,验证注解客户端的文件上传:
@SpringBootTest
public class OpenFeignFileUploadLiveTest {
@Autowired
private UploadService uploadService;
private static String FILE_NAME = "fileupload.txt";
@Test
public void whenAnnotatedFeignClient_thenFileUploadSuccess() {
ClassLoader classloader = Thread.currentThread().getContextClassLoader();
File file = new File(classloader.getResource(FILE_NAME).getFile());
Assert.assertTrue(file.exists());
FileInputStream input = new FileInputStream(file);
MultipartFile multipartFile = new MockMultipartFile("file", file.getName(), "text/plain",
IOUtils.toByteArray(input));
String uploadFile = uploadService.uploadFile(multipartFile);
Assert.assertNotNull(uploadFile);
}
}
现在,创建另一个测试,验证 Feign.Builder()
客户端的文件上传:
@Test
public void whenFeignBuilder_thenFileUploadSuccess() throws IOException {
// 同上
Assert.assertTrue(uploadService.uploadFileWithManualClient(multipartFile));
}
7、总结 {#7总结}
本文介绍了使用 OpenFeign 实现 Multipart 文件上传的两种方式,分别是使用 @FeignClient
注解客户端或使用 Feign.builder()
API 创建的代理客户端。
Ref:https://www.baeldung.com/java-feign-file-upload