原文鏈接:使用Feign接口實現文件上傳的解決方案
一般的情況下,後端有個微服務,暴露出一個文件上傳的restful接口給前端,前端調用該接口獲取上傳後的鏈接以及oss key值完成上傳。假設提供restful接口的這個服務叫做A,現在有個微服務B有個本地文件,需要將本地文件調用A文件文件上傳接口上傳到文件服務器,該如何做?
一般情況下,一個文件上傳的restful接口如下所示:
@PostMapping("/upload")
public WrapperResult<UploadResult> uploadFile(@RequestParam("file") MultipartFile multipartFile){
......
}
那對應的Feign接口就如下所示
@PostMapping("/upload")
public WrapperResult<UploadResult> uploadFile(@RequestParam("file") MultipartFile multipartFile);
從直覺上來看,直接調用八成會出問題(笑),通過踩坑,我梳理了下後端調用Feign接口實現文件上傳的改造點
1. 接口修改
一般的文件上傳接口定義:
@PostMapping("/upload")
public WrapperResult<UploadResult> uploadFile(@RequestParam("file") MultipartFile multipartFile){
......
}
在Feign接口暴露出來的情況下,則不能再使用@RequestParam註解,應當使用@RequestPart註解,另外需要指定consumes類型爲表單類型,否則會翻車。
修改後的接口如下
@PostMapping(
value = {"/upload"},
consumes = {"multipart/form-data"}
)
UploadResult uploadFile(@RequestPart("file") @NotNull MultipartFile multipartFile);
這裏注意兩點:
- 使用@RequestPart註解替換掉@RequestParam註解
- 指定consumes類型爲表單類型
2. Encoder修改
在springboot中,一般的Encoder定義如下
@Bean
@Primary
public Encoder feignEncoder() {
HttpMessageConverter jacksonConverter = new MappingJackson2HttpMessageConverter(
JsonUtils.getObjectMapper()
);
ObjectFactory<HttpMessageConverters> objectFactory =
() -> new HttpMessageConverters(jacksonConverter);
return new SpringEncoder(objectFactory);
}
返回了一個SpringEncoder對象,這裏需要返回一個SpringFormEncoder對象以支持Feign接口的表單功能,只需要將new SpringEncoder(objectFactory)修改爲new SpringFormEncoder(new SpringEncoder(objectFactory))即可,修改後的代碼如下
@Bean
@Primary
public Encoder feignEncoder() {
HttpMessageConverter jacksonConverter = new MappingJackson2HttpMessageConverter(
JsonUtils.getObjectMapper()
);
ObjectFactory<HttpMessageConverters> objectFactory =
() -> new HttpMessageConverters(jacksonConverter);
return new SpringFormEncoder(new SpringEncoder(objectFactory));
}
3. 客戶端調用修改
現在Feign接口長這個樣子
@PostMapping(
value = {"/upload"},
consumes = {"multipart/form-data"}
)
UploadResult uploadFile(@RequestPart("file") @NotNull MultipartFile multipartFile);
那我們Feign接口調用的時候就得構造MultipartFile對象,這裏需要引入spring-test的依賴
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
</dependency>
然後代碼這麼寫
FileInputStream fis = null;
try {
Tika tika = new Tika();
String mimeType = tika.detect(file);
fis = new FileInputStream(file);
MockMultipartFile mockMultipartFile = new MockMultipartFile(
"file",
file.getName(),
mimeType,
fis
);
UploadResult uploadResult = ossPublicApi.uploadFile(mockMultipartFile);
}catch(Exception e){
......
}
這裏爲了告知正確的媒體類型,引入了tika,關於tika,參考文章 使用tika獲取文件的實際類型 引入
需要注意以下幾點
- 需要引入spring-test,注意scope默認就行,不能爲provided
- 需要引入tika,告知正確的媒體類型,否則上傳到minio等文件服務器,在瀏覽器中打開圖片、mp4視頻等文件本來應當在瀏覽器打開的文件會變成自動下載
最後,歡飲關注我的博客:一枝梅的博客
END.