Spring Cloud中FeignClient實(shí)現(xiàn)文件上傳功能
項(xiàng)目概況:Spring Cloud搭的微服務(wù),使用了eureka,F(xiàn)eignClient,現(xiàn)在遇到FeignClient調(diào)用接口時(shí)不支持上傳文件,
百度到兩種方案,一種是使用feign-form和feign-form-spring庫(kù)來(lái)做,源碼地址。
具體的使用方法是加入maven依賴
<dependency> <groupId>io.github.openfeign.form</groupId> <artifactId>feign-form-spring</artifactId> <version>3.2.2</version> </dependency> <dependency> <groupId>io.github.openfeign.form</groupId> <artifactId>feign-form</artifactId> <version>3.2.2</version> </dependency>
注入SpringFormEncoder類
@Bean
@Primary
@Scope("prototype")
public Encoder multipartFormEncoder() {
return new SpringFormEncoder();
}
FeignClient接口里方法參數(shù)是文件類型的要用@RequestPart注解,且要設(shè)置ContentType為multipart/form-data
@ResponseBody
@RequestMapping(value = "/ctstestcase/updateTestCase", method = {RequestMethod.POST}, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
Map<String, Object> updateTestCase(@RequestParam("testcaseId") String testcaseId,
@RequestParam("name") String name, @RequestParam("assignId") String assignId,
@RequestParam("areaId") String areaId, @RequestParam("state") Integer state,
@RequestParam("iterationId") String iterationId,@RequestParam("priority") Integer priority,
@RequestParam("moduleId") String moduleId, @RequestParam("executionType") Integer executionType,
@RequestParam("summary") String summary, @RequestParam("tcsteps") String tcsteps,
@RequestParam("relations") String relations,@RequestParam("attachments") String attachments,
@RequestPart("files") MultipartFile[] files);
但遇到一個(gè)問(wèn)題,就是不支持文件數(shù)組類型,我看了源碼,發(fā)現(xiàn)源碼里底層是有對(duì)MultipartFile[]類型的支持的,源碼中有個(gè)類叫SpringManyMultipartFilesWriter,是專門針對(duì)文件數(shù)組類型進(jìn)行操作的,但是配置到項(xiàng)目里的SpringFormEncoder類里卻沒(méi)有對(duì)文件數(shù)組類型的判斷,以致不能支持文件數(shù)組的上傳.。
SpringManyMultipartFilesWriter源碼:
@FieldDefaults(level = PRIVATE, makeFinal = true)
public class SpringManyMultipartFilesWriter extends AbstractWriter {
SpringSingleMultipartFileWriter fileWriter = new SpringSingleMultipartFileWriter();
@Override
public void write (Output output, String boundary, String key, Object value) throws Exception {
if (value instanceof MultipartFile[]) {
val files = (MultipartFile[]) value;
for (val file : files) {
fileWriter.write(output, boundary, key, file);
}
} else if (value instanceof Iterable) {
val iterable = (Iterable<?>) value;
for (val file : iterable) {
fileWriter.write(output, boundary, key, file);
}
}
}
@Override
public boolean isApplicable (Object value) {
if (value == null) {
return false;
}
if (value instanceof MultipartFile[]) {
return true;
}
if (value instanceof Iterable) {
val iterable = (Iterable<?>) value;
val iterator = iterable.iterator();
if (iterator.hasNext() && iterator.next() instanceof MultipartFile) {
return true;
}
}
return false;
}
SpringFormEncoder源碼:
public class SpringFormEncoder extends FormEncoder {
/**
* Constructor with the default Feign's encoder as a delegate.
*/
public SpringFormEncoder () {
this(new Encoder.Default());
}
/**
* Constructor with specified delegate encoder.
*
* @param delegate delegate encoder, if this encoder couldn't encode object.
*/
public SpringFormEncoder (Encoder delegate) {
super(delegate);
val 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.equals(MultipartFile.class)) {
super.encode(object, bodyType, template);
return;
}
val file = (MultipartFile) object;
val data = singletonMap(file.getName(), object);
super.encode(data, MAP_STRING_WILDCARD, template);
}
}
從上面SpringFormEncoder的源碼上可以看到SpringFormEncoder類構(gòu)造時(shí)把SpringManyMultipartFilesWriter實(shí)例添加到了處理器列表里了,但是在encode方法里又只判斷了MultipartFile類型,沒(méi)有判斷數(shù)組類型,這就比較奇怪了,底層有對(duì)數(shù)組的支持但上層卻缺少了相應(yīng)判斷,而且在源碼里的test包里也沒(méi)有對(duì)文件數(shù)組類型的測(cè)試,難道只是encode方法里漏掉了?還是說(shuō)那個(gè)文件數(shù)組的支持有問(wèn)題?所以encode方法里才沒(méi)有加入對(duì)其的判斷?
于是我先試著對(duì)encode方法進(jìn)行擴(kuò)展加入對(duì)文件數(shù)組的判斷,應(yīng)該就可以支持文件數(shù)組的上傳了,于是把SpringFormEncoder類源碼復(fù)制出來(lái)重命名為FeignSpringFormEncoder,源碼如下:
public class FeignSpringFormEncoder extends FormEncoder {
/**
* Constructor with the default Feign's encoder as a delegate.
*/
public FeignSpringFormEncoder() {
this(new Encoder.Default());
}
/**
* Constructor with specified delegate encoder.
*
* @param delegate delegate encoder, if this encoder couldn't encode object.
*/
public FeignSpringFormEncoder(Encoder delegate) {
super(delegate);
val 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.equals(MultipartFile.class)) {
val file = (MultipartFile) object;
val data = singletonMap(file.getName(), object);
super.encode(data, MAP_STRING_WILDCARD, template);
return;
} else if (bodyType.equals(MultipartFile[].class)) {
val file = (MultipartFile[]) object;
if(file != null) {
val data = singletonMap(file.length == 0 ? "" : file[0].getName(), object);
super.encode(data, MAP_STRING_WILDCARD, template);
return;
}
}
super.encode(object, bodyType, template);
}
}
經(jīng)過(guò)測(cè)試,已經(jīng)可以支持文件數(shù)組了,完美解決。
這里再順便說(shuō)一下當(dāng)時(shí)還百度到另一個(gè)解決文件上傳的方案,這個(gè)方案就不細(xì)說(shuō)了,直接上我用到的那個(gè)開(kāi)源代碼的地址
這個(gè)我試過(guò)也是可以解決文件上傳問(wèn)題的,但問(wèn)題是FeignClient不能用SpringMVC的注解,得用Feign自帶的注解,也因此我才擴(kuò)展了第一種方法來(lái)做的文件上傳功能。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot啟動(dòng)類@SpringBootApplication注解背后的秘密
這篇文章主要介紹了SpringBoot啟動(dòng)類@SpringBootApplication注解背后的秘密,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12
jenkins 構(gòu)建項(xiàng)目之 pipeline基礎(chǔ)教程
​pipeline ,簡(jiǎn)單來(lái)說(shuō),就是一套運(yùn)行在 jenkins 上的工作流框架。這篇文章主要介紹了jenkins 構(gòu)建項(xiàng)目之 pipeline基礎(chǔ)教程,需要的朋友可以參考下2020-07-07
Java項(xiàng)目中大批量數(shù)據(jù)查詢導(dǎo)致OOM的解決
本文主要介紹了Java項(xiàng)目中大批量數(shù)據(jù)查詢導(dǎo)致OOM的解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06

