Feign框架對於檔案上傳訊息體格式並沒有做原生支援,需要整合模組feign-form來實現。
獨立使用Feign
新增模組依賴:
<!-- Feign框架核心 -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-core</artifactId>
<version>11.1</version>
</dependency>
<!-- 支援表單格式,檔案上傳格式 -->
<dependency>
<groupId>io.github.openfeign.form</groupId>
<artifactId>feign-form</artifactId>
<version>3.8.0</version>
</dependency>
<!-- 檔案操作工具類 -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
上傳檔案
定義介面:
public interface FileUploadAPI {
// 上傳檔案:引數為單個檔案物件
@RequestLine("POST /test/upload/single")
@Headers("Content-Type: multipart/form-data")
String upload(@Param("file") File file);
// 上傳檔案:引數文多個檔案物件
@RequestLine("POST /test/upload/batch")
@Headers("Content-Type: multipart/form-data")
String upload(@Param("files") File[] files);
// 上傳檔案:引數文多個檔案物件
@RequestLine("POST /test/upload/batch")
@Headers("Content-Type: multipart/form-data")
String upload(@Param("files") List<File> files);
// 上傳檔案:引數為檔案位元組陣列(這種方式在服務端無法獲取檔名,不要使用)
@RequestLine("POST /test/upload/single")
@Headers("Content-Type: multipart/form-data")
String upload(@Param("file") byte[] bytes);
// 上傳檔案:引數為FormData物件
@RequestLine("POST /test/upload/single")
@Headers("Content-Type: multipart/form-data")
String upload(@Param("file") FormData photo);
// 上傳檔案:引數為POJO物件
@RequestLine("POST /test/upload/single")
@Headers("Content-Type: multipart/form-data")
String upload(@Param("file") MyFile myFile);
class MyFile {
@FormProperty("is_public")
Boolean isPublic;
File file;
public Boolean getPublic() {
return isPublic;
}
public void setPublic(Boolean aPublic) {
isPublic = aPublic;
}
public File getFile() {
return file;
}
public void setFile(File file) {
this.file = file;
}
}
}
呼叫介面:
FileAPI fileAPI = Feign.builder()
.encoder(new FormEncoder()) // 必須明確設定請求引數編碼器
.logger(new Slf4jLogger())
.logLevel(Logger.Level.FULL)
.target(FileAPI.class, "http://localhost:8080");
File file1 = new File("C:\\Users\\xxx\\Downloads\\test1.jpg");
File file2 = new File("C:\\Users\\xxx\\Downloads\\test2.jpg");
// 上傳檔案1:引數為檔案物件
fileAPI.upload(file1);
// 上傳檔案2:引數為位元組陣列(注意:在服務端無法獲取到檔名)
byte[] bytes = FileUtils.readFileToByteArray(file1);
fileAPI.upload(bytes);
// 上傳檔案3:引數為FormData物件
byte[] bytes = FileUtils.readFileToByteArray(file1);
FormData formData = new FormData("image/jpg", "test1.jpg", bytes);
String result = fileAPI.upload(formData);
// 上傳檔案4:引數為POJO物件
FileAPI.MyFile myFile = new FileAPI.MyFile();
myFile.setPublic(true);
myFile.setFile(file1);
fileAPI.upload(myFile);
// 上傳檔案:引數為多個檔案
fileAPI.upload(new File[]{file1, file2});
fileAPI.upload(Arrays.asList(new File[]{file1, file2}));
下載檔案
定義介面:
public interface FileDownloadAPI {
// 下載檔案
@RequestLine("GET /test/download/file")
Response download(@QueryMap Map<String, Object> queryMap);
}
呼叫介面:
// 下載檔案時返回值為Response物件,不需要設定解碼器
FileAPI fileAPI = Feign.builder()
.logger(new Slf4jLogger())
.logLevel(Logger.Level.FULL)
.target(FileAPI.class, "http://localhost:8080");
String fileName = "test.jpg";
Map<String, Object> queryMap = new HashMap<>();
queryMap.put("fileName", fileName);
Response response = fileAPI.download(queryMap);
if (response.status() == 200) {
File downloadFile = new File("D:\\Downloads\\", fileName);
FileUtils.copyInputStreamToFile(response.body().asInputStream(), downloadFile);
}
使用Spring Cloud Feign
在Spring框架中使用Feign實現檔案上傳時需要依賴feign-form
和feign-form-spring
,這2個模組已經在“Spring Cloud Feign”中自帶了,只需要新增spring-cloud-starter-openfeign
依賴即可。
<!-- 整合Spring和Feign,包含了模組feign-form和feign-form-spring -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>3.0.2</version>
</dependency>
<!-- 檔案操作工具類 -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
上傳檔案
定義介面及配置:
@FeignClient(value = "FileAPI", url = "http://localhost:8080", configuration = FileUploadAPI.FileUploadAPIConfiguration.class)
public interface FileUploadAPI {
/**
* 上傳單個檔案
* @param file
* @return
*/
@RequestMapping(value = "/test/upload/single", method = RequestMethod.POST, headers = "Content-Type=multipart/form-data")
String upload(@RequestPart("file") MultipartFile file);
/**
* 上傳多個檔案
* @param files
* @return
*/
@RequestMapping(value = "/test/upload/batch", method = RequestMethod.POST, headers = "Content-Type=multipart/form-data")
String upload(@RequestPart("files") List<MultipartFile> files);
class FileUploadAPIConfiguration {
@Autowired
private ObjectFactory<HttpMessageConverters> messageConverters;
@Bean
public Encoder feignEncoder () {
return new SpringFormEncoder(new SpringEncoder(messageConverters));
}
@Bean
public Logger feignLogger() {
return new Slf4jLogger();
}
@Bean
public Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
}
}
呼叫介面:
// 上傳單個檔案
File file = new File("C:\\Users\\xxx\\Downloads\\test1.jpg");
FileInputStream fis = new FileInputStream(file);
MockMultipartFile mockMultipartFile = new MockMultipartFile("file", file.getName(), "image/jpg", fis);
this.fileUploadAPI.upload(mockMultipartFile);
fis.close();
// 上傳多個檔案
File file1 = new File("C:\\Users\\xxx\\Downloads\\test1.jpg");
File file2 = new File("C:\\Users\\xxx\\Downloads\\test2.jpg");
FileInputStream fis1 = new FileInputStream(file1);
FileInputStream fis2 = new FileInputStream(file2);
MockMultipartFile f1 = new MockMultipartFile("files", file1.getName(), "image/jpg", fis1);
MockMultipartFile f2 = new MockMultipartFile("files", file2.getName(), "image/jpg", fis2);
this.fileUploadAPI.upload(Arrays.asList(new MockMultipartFile[]{f1, f2}));
fis1.close();
fis2.close();
下載檔案
定義介面:
@FeignClient(value = "FileDownloadAPI", url = "http://localhost:8080", configuration = FileDownloadAPI.FileDownloadAPIConfiguration.class)
public interface FileDownloadAPI {
/**
* 下載檔案
* @param fileName 檔名
* @return
*/
@RequestMapping(value = "/test/download/file", method = RequestMethod.GET)
Response download(@RequestParam("fileName") String fileName);
// 下載檔案時返回值為Response物件,不需要設定解碼器
class FileDownloadAPIConfiguration {
@Bean
public Logger feignLogger() {
return new Slf4jLogger();
}
@Bean
public Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
}
}
呼叫介面:
String fileName = "test.jpg";
Response response = this.fileDownloadAPI.download(fileName);
File destFile = new File("D:\\Downloads\\", fileName);
// 使用org.apache.commons.io.FileUtils工具類將輸入流中的內容轉存到檔案
FileUtils.copyInputStreamToFile(response.body().asInputStream(), destFile);
總結
1.Feign框架需要整合模組feign-form才能支援檔案上傳的訊息體格式。
2.不論是獨立使用Feign,還是使用Spring Cloud Feign,下載檔案時的返回值都必須為feign.Response
型別。