Feign接口实现多文件上传

本文详细介绍了如何通过Feign接口实现单文件和多文件的上传操作。在单文件上传中,服务提供者和消费者均遵循常规的Spring Boot文件上传方式。在多文件上传部分,由于Feign-form-spring库的限制,需要重写配置类以正确处理文件数组,避免覆盖问题。文章提供了重写配置类的源码和Feign接口的示例。


前言

springBoot版本 2.1.15.RELEASE
springCloud版本 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. 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>
  1. 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);

  1. 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);

  1. 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. 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>
  1. 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));
    }
}

  1. 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);
    
  1. 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);
    }
    
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值