Feign接口实现多文件上传
前言
springBoot版本 2.1.15.RELEASEspringCloud版本 Greenwich.SR6
springCloud 的Feign组件并不支持文件的传输,所以Feign接口文件传输需要在Feign接口中增加依赖。
一、Feign接口实现单文件上传
1.服务提供者(被Feign调用的)
和平常的springboot文件上传接口一样
@RestController
@RequestMapping("/template")
public class FileController {
@Resource
private FileService fileService;
/**
* 增加单个文件
* @param tag 文件标识
* @param file 要上传的文件
* @return 文件上传的结果
*/
@RequestMapping(value="/addFile", method = RequestMethod.POST, consumes = MediaType.MULTIPART_FORM_DATA_VALUE,produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
public Result addFile(@RequestParam("tag") String tag, @RequestPart MultipartFile file){
//文件上传处理
return fileService.addTemplate(tag,file);
}
2.服务消费者
- 1 feign接口增加依赖包
<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>
- 2 feign接口
2.2.1 上传文件配置写在接口内
//info是服务提供者的name
@FeignClient(value = "info/template",configuration = FileClient.MyConfig.class)
public interface FileClient {
/**
* 支持文件上传配置
* 此配置也可以单独写,见下面2.2.2的写法
*/
class MyConfig {
@Bean
public SpringFormEncoder feignFormEncoder() {
return new SpringFormEncoder();
}
}
/**
* 增加单个文件
* @param tag 文件标识
* @param file 要上传的文件
* @return 文件上传的结果
*/
@RequestMapping(value="/addFile", method = RequestMethod.POST, consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
Result addFile(@RequestParam("tag") String tag, @RequestPart MultipartFile file);
- 2.2 上传文件配置单独写
新增feign实现文件上传的配置类
@Configuration
public class FeignMultipartSupportConfig {
@Bean
public Encoder feignFormEncoder() {
return new SpringFormEncoder();
}
}
上传文件配置单独写的feign接口写法
//info是服务提供者的name
@FeignClient(value = "info/template",configuration = FeignMultipartSupportConfig.class)
public interface FileClient {
/**
* 增加单个文件
* @param tag 文件标识
* @param file 要上传的文件
* @return 文件上传的结果
*/
@RequestMapping(value="/addFile", method = RequestMethod.POST, consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
Result addFile(@RequestParam("tag") String tag, @RequestPart MultipartFile file);
- 3 上传文件接口(调用Feign)
@RestController
@RequestMapping("/file")
public class FileFeignController {
@Resource
private FileClient fileClient;
/**
* 增加模板文件
* @param tag模板文件标识
* @param file 要上传的文件
*/
@RequestMapping(value="/addFileByFeign",method = RequestMethod.POST,consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
public Result addFileByFeign(@RequestParam("tag") String tag, @RequestPart MultipartFile file){
return fileClient.addFile(tag,file);
}
二、Feign接口实现多文件上传
1.服务提供者(被Feign调用的)
和平常的springboot文件上传接口一样
@RestController
@RequestMapping("/template")
public class FileController {
@Resource
private FileService fileService;
/** 增加单个文件 ...*/
@{...}
public Result addFile(@RequestParam("tag") String tag, @RequestPart MultipartFile file){...}
/**
* 增加多个文件
* @param tag 文件标识
* @param files 要上传的文件
* @return 文件上传的结果
*/
@RequestMapping(value="/addFiles",method = RequestMethod.POST,consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
public Result addFiles(@RequestParam("tag") String tag, @RequestPart(value = "files") MultipartFile[] files) {
//上传文件处理
return fileService.addFiles(tag,files);
}
2.服务消费者
- 1 feign接口增加依赖包
<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>
- 2 feign接口
2.2.1 重写文件上传配置类
虽然feign-form-spring 3.8.0版本依赖里面有了对上传文件数组的处理,但是处理结果是最后一个文件会覆盖掉前面的文件,所以我们只能上传成功最后一个文件,因此多文件上传时需要重写配置类。
以下是SpringFormEncoder类对于文件数组处理的源码:
public void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException {
HashMap data;
if (bodyType.equals(MultipartFile[].class)) {
MultipartFile[] files = (MultipartFile[])((MultipartFile[])object);
data = new HashMap(files.length, 1.0F);
MultipartFile[] var6 = files;
int var7 = files.length;
for(int var8 = 0; var8 < var7; ++var8) {
MultipartFile file = var6[var8];
data.put(file.getName(), file); //这里最后一个文件会覆盖前面所有的文件
}
super.encode(data, MAP_STRING_WILDCARD, template);
重写配置类,也支持单文件上传 (继承SpringFormEncoder类重写对文件数组处理的方法)
import feign.RequestTemplate;
import feign.codec.EncodeException;
import feign.codec.Encoder;
import feign.form.ContentType;
import feign.form.FormEncoder;
import feign.form.MultipartFormContentProcessor;
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.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* @author nianyu
* 支持多文件上传配置
*/
public class FeignSpringFormEncoder extends FormEncoder {
public FeignSpringFormEncoder() {
this(new Default());
}
public FeignSpringFormEncoder(Encoder delegate) {
super(delegate);
MultipartFormContentProcessor processor = (MultipartFormContentProcessor)this.getContentProcessor(ContentType.MULTIPART);
processor.addFirstWriter(new SpringSingleMultipartFileWriter());
processor.addFirstWriter(new SpringManyMultipartFilesWriter());
}
@Override
public void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException {
HashMap data;
if (bodyType.equals(MultipartFile[].class)) {
MultipartFile[] files = (MultipartFile[])object;
data = new HashMap(files.length, 1.0F);
//这里也可以写别的处理逻辑
if(files != null && files.length >0){
data.put(files[0].getName(), files);
super.encode(data, MAP_STRING_WILDCARD, template);
}else{
super.encode(object, bodyType, template);
}
} else if (bodyType.equals(MultipartFile.class)) {
MultipartFile file = (MultipartFile)object;
Map<String, Object> data1 = Collections.singletonMap(file.getName(), object);
super.encode(data1, MAP_STRING_WILDCARD, template);
} else if (this.isMultipartFileCollection(object)) {
Iterable<?> iterable = (Iterable)object;
data = new HashMap();
Iterator var13 = iterable.iterator();
while(var13.hasNext()) {
Object item = var13.next();
MultipartFile file = (MultipartFile)item;
data.put(file.getName(), file);
}
super.encode(data, MAP_STRING_WILDCARD, template);
} else {
super.encode(object, bodyType, template);
}
}
private boolean isMultipartFileCollection(Object object) {
if (!(object instanceof Iterable)) {
return false;
} else {
Iterable<?> iterable = (Iterable)object;
Iterator<?> iterator = iterable.iterator();
return iterator.hasNext() && iterator.next() instanceof MultipartFile;
}
}
}
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;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Scope;
/**
* @author nianyu
* 支持多文件上传配置
* 将“FeignSpringFormEncoder”作为bean提供给框架,代替“SpringFormEncoder”的“encode()”接口
*/
@Configuration
public class FeignMultipartSupportConfig {
@Autowired
private ObjectFactory<HttpMessageConverters> messageConverters;
@Bean
@Primary
@Scope("prototype")
public Encoder multipartFormEncoder() {
return new FeignSpringFormEncoder(new SpringEncoder(messageConverters));
}
}
- 2.2 feign接口
//info是服务提供者的name
@FeignClient(value = "info/template",configuration = FeignMultipartSupportConfig.class)
public interface FileClient {
/**
* 增加单个文件
* @param tag 文件标识
* @param file 要上传的文件
* @return 文件上传的结果
*/
@RequestMapping(value="/addFile", method = RequestMethod.POST, consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
Result addFile(@RequestParam("tag") String tag, @RequestPart MultipartFile file);
/**
* 增加多个文件
* @param tag 文件标识
* @param file 要上传的文件
* @return 文件上传的结果
*/
@RequestMapping(value="/addFiles", method = RequestMethod.POST, consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
Result addFiles(@RequestParam("tag") String tag, @RequestPart(value = "files") MultipartFile[] files);
- 3 上传文件接口(调用Feign)
@RestController
@RequestMapping("/file")
public class FileFeignController {
@Resource
private FileClient fileClient;
/**
* 增加模板文件
* @param tag模板文件标识
* @param file 要上传的文件
*/
@RequestMapping(value="/addFileByFeign",method = RequestMethod.POST,consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
public Result addFileByFeign(@RequestParam("tag") String tag, @RequestPart MultipartFile file){
return fileClient.addFile(tag,file);
}
/**
* 批量增加模板文件
* @param tag模板文件标识
* @param files 要上传的文件
*/
@RequestMapping(value="/addFilesByFeign",method = RequestMethod.POST,consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
public Result addFilesByFeign(@RequestParam("tag") String tag, @RequestPart(value = "files") MultipartFile[] files){
return fileClient.addFiles(tag,files);
}
本文详细介绍了如何通过Feign接口实现单文件和多文件的上传操作。在单文件上传中,服务提供者和消费者均遵循常规的Spring Boot文件上传方式。在多文件上传部分,由于Feign-form-spring库的限制,需要重写配置类以正确处理文件数组,避免覆盖问题。文章提供了重写配置类的源码和Feign接口的示例。
1万+

被折叠的 条评论
为什么被折叠?



