關(guān)于Feign接口單文件上傳务甥,比較簡單窒悔,和普通的 SpringMVC 幾乎是一樣的,對應(yīng)好參數(shù)和配置信息即可。
多文件上傳卻是個頭疼的問題(和自己的水平有關(guān)吧)藤乙。
瀏覽了幾篇博客猜揪,雖然有代碼可以參考,但是并不詳細(xì)坛梁。那么請看下面史上最細(xì)致的Feign多文件上傳總結(jié)(自吹自擂一下)而姐,最細(xì)致談不上,可以讓你真正解決問題划咐。
如果你遇到了下面的這個錯誤提示:
Caused by: org.apache.commons.fileupload.FileUploadException: the request was rejected because no multipart boundary was found
或者
The current request is not a multipart request
恭喜你來對地方了拴念!
有人說第二個錯誤“就是傳輸?shù)奈募?shù)據(jù)為空了,比較簡單”褐缠,真的簡單么政鼠?當(dāng)你什么都寫了,參數(shù)也有文件了队魏,但是調(diào)用Feign的時(shí)候就是報(bào)這個錯誤公般,這才是最頭疼的問題,明明看著可以器躏,其實(shí)就是不行俐载,鬧心不?
開始解說
環(huán)境版本
Spring-boot版本:
2.2.0.RELEASE
SpringCloud版本:
Hoxton.M3
JDK版本:
1.8
接口提供方
接口提供方不需要特殊處理登失,看一下實(shí)力代碼遏佣,按照示例代碼寫就可以:
@RequestMapping(value = "/upload/batch" , method = RequestMethod.POST , consumes = MediaType.MULTIPART_FORM_DATA_VALUE )
public ResponseData upload( @NotNull( message = "文件業(yè)務(wù)類型不能為空") @RequestParam("type") Integer type ,
@NotNull( message = "用戶id不能為空") @RequestParam("userId") Long userId ,
@RequestParam("images") MultipartFile[] images ) {
List<UserImageResVO> imageResVos = fileOpService.uploadImages( userId, type, images);
return ResponseData.success( imageResVos ) ;
}
注意的地方就是 @RequestMapping上 加上:
consumes = MediaType.MULTIPART_FORM_DATA_VALUE
這里的 文件參數(shù) MultipartFile[] images 注解使用的是:
@RequestParam("images")
之所以在這里提一下,因?yàn)樵诮涌谙M(fèi)方使用的不是這個(多文件)揽浙。
接口消費(fèi)方
引入依賴
<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>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
這是Feign為支持文件上傳提供的依賴状婶,你可以在 這里 選擇不同的版本。
SpringForm編碼器
import feign.RequestTemplate;
import feign.codec.EncodeException;
import feign.codec.Encoder;
import feign.form.MultipartFormContentProcessor;
import feign.form.spring.SpringFormEncoder;
import feign.form.spring.SpringManyMultipartFilesWriter;
import feign.form.spring.SpringSingleMultipartFileWriter;
import org.springframework.web.multipart.MultipartFile;
import java.lang.reflect.Type;
import java.util.Collections;
import java.util.Map;
import static feign.form.ContentType.MULTIPART;
/**
* @description 處理多個文件上傳 編碼器
*
* @author Songxudong
* @date 2019/11/14 4:25 下午
*/
public class SpringMultipartEncoder extends SpringFormEncoder {
public SpringMultipartEncoder(Encoder delegate) {
super(delegate);
MultipartFormContentProcessor processor = (MultipartFormContentProcessor) getContentProcessor(MULTIPART);
processor.addWriter(new SpringSingleMultipartFileWriter());
processor.addWriter(new SpringManyMultipartFilesWriter());
}
@Override
public void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException {
if (bodyType != null && bodyType.equals(MultipartFile[].class)) {
MultipartFile[] file = (MultipartFile[]) object;
if(file != null) {
Map data = Collections.singletonMap(file.length == 0 ? "" : file[0].getName(), object);
super.encode(data, MAP_STRING_WILDCARD, template);
return;
}
}
super.encode(object, bodyType, template);
}
}
之所以需要提供這樣一個編碼器馅巷,是因?yàn)樵诔绦騼?nèi)部調(diào)用Feign接口已經(jīng)不是表單環(huán)境了膛虫,需要重新對文件內(nèi)容進(jìn)行編碼操作。
開篇的第一個錯誤和這個就有關(guān)系钓猬,說“boundary(分割線)”找不到稍刀,就是因?yàn)椴皇潜韱翁峤唬韱翁峤坏脑挸ú埽紩嬖诜指罹€(對post請求了解的都應(yīng)該知道)账月。
Feign多文件支持配置
import com.system.consumer.sys.spring.SpringMultipartEncoder;
import feign.codec.Encoder;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.cloud.openfeign.support.SpringEncoder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @description feign-SpringMVC 多文件上傳配置
*
* @author Songxudong
* @date 2019/11/14 1:52 下午
*/
@Configuration
public class FeignMultipartSupportConfig {
@Autowired
private ObjectFactory<HttpMessageConverters> messageConverters;
@Bean
public Encoder feignEncoder() {
return new SpringMultipartEncoder(new SpringEncoder(messageConverters));
}
}
這個配置下面對在注入的Feign接口提供中使用。
在消費(fèi)方對服務(wù)接口進(jìn)行配置
@FeignClient( name = "medical-resource-provider" , configuration = FeignMultipartSupportConfig.class )
public interface IMedicalResourceService {
/** 文件批量上傳 */
@PostMapping(value = "/file/upload/batch" , consumes = MediaType.MULTIPART_FORM_DATA_VALUE )
ResponseData upload( @RequestParam("type") Integer type , @RequestParam("userId") Long userId ,
@RequestPart("images") MultipartFile[] images ) ;
}
【注意:】
1)@RequestMapping中使用 consumes = MediaType.MULTIPART_FORM_DATA_VALUE
2)文件參數(shù)注解使用 @RequestPart澳迫,而不是 @RequestParam
3)將 FeignMultipartSupportConfig 配置加上
對于注意 2)局齿,如果還是使用 @RequestParam 的話,就會出現(xiàn)開篇的第一個錯誤橄登;
consumes = MediaType.MULTIPART_FORM_DATA_VALUE 這個設(shè)置抓歼,如果在調(diào)用接口的定義上不實(shí)用就會出現(xiàn)開篇的第二個錯誤讥此,原因還是因?yàn)椋@里的調(diào)用不是表單環(huán)境了谣妻,需要我們手動告訴接口萄喳,我們的請求是Multipart類型的。在SpringMVC接口中拌禾,我們不需要配置也可以取胎,因?yàn)闀詣訑y帶對應(yīng)的信息。
好啦湃窍,以上就是對Feign多文件上傳問題的解決過程闻蛀,按照以上過程,是沒有問題的您市。
希望可以幫到大家觉痛。