最近經(jīng)常有人問Spring Cloud Feign如何上傳文件。有團(tuán)隊(duì)的新成員,也有其他公司的兄弟。本文簡單做個(gè)總結(jié)——
早期的Spring Cloud中,F(xiàn)eign本身是沒有上傳文件的能力的(1年之前),要想實(shí)現(xiàn)這一點(diǎn),需要自己去編寫Encoder 去實(shí)現(xiàn)上傳。現(xiàn)在我們幸福了很多。因?yàn)镕eign官方提供了子項(xiàng)目feign-form ,其中實(shí)現(xiàn)了上傳所需的 Encoder 。
注:筆者測試的版本是Edgware.RELEASE。Camden、Dalston同樣適應(yīng)本文所述。
加依賴
1
2
3
4
5
6
7
8
9
10
|
< dependency > < groupId >io.github.openfeign.form</ groupId > < artifactId >feign-form</ artifactId > < version >3.0.3</ version > </ dependency > < dependency > < groupId >io.github.openfeign.form</ groupId > < artifactId >feign-form-spring</ artifactId > < version >3.0.3</ version > </ dependency > |
編寫Feign Client
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
@FeignClient (name = "ms-content-sample" , configuration = UploadFeignClient.MultipartSupportConfig. class ) public interface UploadFeignClient { @RequestMapping (value = "/upload" , method = RequestMethod.POST, produces = {MediaType.APPLICATION_JSON_UTF8_VALUE}, consumes = MediaType.MULTIPART_FORM_DATA_VALUE) @ResponseBody String handleFileUpload( @RequestPart (value = "file" ) MultipartFile file); class MultipartSupportConfig { @Bean public Encoder feignFormEncoder() { return new SpringFormEncoder(); } } } |
如代碼所示,在這個(gè)Feign Client中,我們引用了配置類MultipartSupportConfig ,在MultipartSupportConfig 中,我們實(shí)例化了SpringFormEncoder 。這樣這個(gè)Feign Client就能夠上傳啦。
注意點(diǎn)
1
2
3
4
|
@RequestMapping (value = "/upload" , method = RequestMethod.POST, produces = {MediaType.APPLICATION_JSON_UTF8_VALUE}, consumes = MediaType.MULTIPART_FORM_DATA_VALUE) 中的produeces 、consumes 不能少; |
接口定義中的注解@RequestPart(value = "file") 不能寫成@RequestParam(value = "file" 。
最好將Hystrix的超時(shí)時(shí)間設(shè)長一點(diǎn),例如5秒,否則可能文件還沒上傳完,Hystrix就超時(shí)了,從而導(dǎo)致客戶端側(cè)的報(bào)錯(cuò)。
SpringCloud中使用Feign的坑
示例如下:
1
2
3
4
5
6
7
8
9
|
@FeignClient ( "service-resource" ) //@RequestMapping("/api/test") public interface TestResourceItg { @RequestMapping (value = "/api/test/raw" , method = RequestMethod.POST, consumes = "application/x-www-form-urlencoded" ) public String raw1( @PathVariable ( "subject" ) String subject, // 標(biāo)題 @RequestParam ( "content" ) String content); // 內(nèi)容 } |
說明:
*使用RequestMapping中的consumes指定生成的請求的Content-Type
*RequestParam指定的參數(shù)會(huì)拼接在URL之后,如: ?name=xxx&age=18
*PathVariable指定的參數(shù)會(huì)放到一個(gè)LinkedHashMap<String, ?>傳入到feign的Encoder中進(jìn)行處理,而在Spring中實(shí)現(xiàn)了該接口的Encoder為SpringEncoder,而該實(shí)現(xiàn)又會(huì)使用Spring中的HttpMessageConverter進(jìn)行請求體的寫入。
坑:
*不要在接口類名上使用RequestMapping,雖然可以使用,但同時(shí)SpringMVC會(huì)把該接口的實(shí)例當(dāng)作Controller開放出去,這個(gè)可以在啟動(dòng)的Mapping日志中查看到
*使用默認(rèn)的SpringEncoder,在不指定consumes時(shí),PathVariable中的參數(shù)會(huì)生成JSON字符串發(fā)送,且默認(rèn)情況下不支持Form表單的生成方式,原因?yàn)?FormHttpMessageConverter只能處理MultiValueMap,而使用PathVariable參數(shù)被放在了HashMap中。默認(rèn)更不支持文件上傳。其實(shí)已經(jīng)有支持處理各種情況的HttpMessageConverter存在。
填坑:
*支持Form表單提交:只需要編寫一個(gè)支持Map的FormHttpMessageConverter即可,內(nèi)部可調(diào)用FormHttpMessageConverter的方法簡化操作。
*支持文件上傳:只需要把要上傳的文件封裝成一個(gè)Resource(該Resource一定要實(shí)現(xiàn)filename接口,這個(gè)是把請求參數(shù)解析成文件的標(biāo)識(shí)),使用默認(rèn)的ResourceHttpMessageConverter處理即可。
*支持處理MultipartFile參數(shù):編寫一個(gè)支持MultipartFile的MultipartFileHttpMessageConverter即可,內(nèi)部可調(diào)用ResourceHttpMessageConverter實(shí)現(xiàn),同時(shí)注意需要將其添加至FormHttpMessageConverter的Parts中,并重寫FormHttpMessageConverter的getFilename方法支持從MultipartFile中獲取filename
*所有的HttpMessageConverter直接以@Bean的方式生成即可,spring會(huì)自動(dòng)識(shí)別添加
完美支持表單和文件上傳:
方案一:
使用附件中的MapFormHttpMessageConverter.java和MultipartFileHttpMessageConverter.java
在Spring中進(jìn)行如下配置即可
1
2
3
4
5
6
7
8
9
10
11
|
@Bean public MapFormHttpMessageConverter mapFormHttpMessageConverter(MultipartFileHttpMessageConverter multipartFileHttpMessageConverter) { MapFormHttpMessageConverter mapFormHttpMessageConverter = new MapFormHttpMessageConverter(); mapFormHttpMessageConverter.addPartConverter(multipartFileHttpMessageConverter); return mapFormHttpMessageConverter; } @Bean public MultipartFileHttpMessageConverter multipartFileHttpMessageConverter() { return new MultipartFileHttpMessageConverter(); } |
方案二:
使用FeignSpringFormEncoder.java
在Spring中配置如下:
1
2
3
4
|
@Bean public Encoder feignEncoder(ObjectFactory<HttpMessageConverters> messageConverters) { return new FeignSpringFormEncoder(messageConverters); } |
推薦使用方案一
方案二為參考https://github.com/pcan/feign-client-test而來,未測
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持服務(wù)器之家。
原文鏈接:http://www.itmuch.com/spring-cloud-sum/spring-cloud-feign-upload/