转自:https://www.baeldung.com/java-feign-file-upload
1. 概述 在本教程中,我们将演示如何使用 Open Feign 上传文件。 Feign 是微服务开发者通过 REST API 以声明方式与其他微服务进行通信的强大工具。
2. 前置条件 假设为文件上传开了一个 RESTful Web 服务,下面给出了详细信息:
1 POST http://localhost:8081/upload-file
因此,为了解释通过 Feign
客户端上传文件,我们将调用暴露的 Web 服务 API,如下所示:
1 2 3 4 @PostMapping(value = "/upload-file") public String handleFileUpload (@RequestPart(value = "file") MultipartFile file) { }
3. 依赖 为了支持文件上传的 application/x-www-form-urlencoded
和 multipart/form-data
编码类型,我们需要 feign-core
、feign-form
和 feign-form-spring
模块。
因此,我们将以下依赖项添加到 Maven:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <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 >
我们也可以使用内部有 feign-core
的 spring-cloud-starter-openfeign
:
1 2 3 4 5 <dependency > <groupId > org.springframework.cloud</groupId > <artifactId > spring-cloud-starter-openfeign</artifactId > <version > 3.1.0</version > </dependency >
4. 配置 让我们将@EnableFeignClients
添加到我们的主类中:
1 2 3 4 5 6 7 @SpringBootApplication @EnableFeignClients public class ExampleApplication { public static void main (String[] args) { SpringApplication.run(ExampleApplication.class, args); } }
@EnableFeignClients
注解允许对声明为 Feign 客户端的接口进行组件扫描。
5. 通过Feign客户端上传文件 5.1. 通过带注解的客户端 让我们为带注解的 @FeignClient
类创建所需的编码器:
1 2 3 4 5 6 7 8 9 10 11 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
对其进行注解。 我们还将添加名称和配置属性及其对应的值:
1 2 3 4 5 @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
将如下所示:
1 @FeignClient(name = "file", url = "http://localhost:8081", fallback = UploadFallback.class, configuration = FeignSupportConfig.class)
最后,我们可以直接从服务层调用 FeignSupportConfig
:
1 2 3 public String uploadFile (MultipartFile file) { return client.fileUpload(file); }
5.2. 通过 Feign.builder
在某些情况下,我们的 Feign Clients 需要自定义,并且在上面描述的注解方式满足不了我们自定义需求。 在这种情况下,我们使用 Feign.builder()
API 创建客户端。
让我们构建一个代理接口,其中包含针对文件上传的 REST API 的文件上传方法:
1 2 3 4 5 public interface UploadResource { @RequestLine("POST /upload-file") @Headers("Content-Type: multipart/form-data") Response uploadFile (@Param("file") MultipartFile file) ; }
注解@RequestLine
定义了API 的HTTP 方法和相对资源路径,@Headers
指定了Content-Type
等请求头。
现在,让我们在代理接口中调用指定的方法。 我们将从我们的服务类中执行此操作:
1 2 3 4 5 6 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 Service-based URL。
6. 验证 让我们创建一个测试来验证带有注解的客户端的文件上传:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 @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()
上传的文件:
1 2 3 4 5 @Test public void whenFeignBuilder_thenFileUploadSuccess () throws IOException { Assert.assertTrue(uploadService.uploadFileWithManualClient(multipartFile)); }
7. 结论 在本文中,我们展示了如何使用 OpenFeign 实现多部分文件上传,以及将其用在简单应用程序中的各种方法。
我们还看到了如何配置 Feign 客户端或使用 Feign.Builder()
来执行相同的操作。
像往常一样,本教程中使用的所有代码示例都可以在 GitHub 上找到。