欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

SpringCloud-Feign 多文件上传解决方案

最编程 2024-05-01 20:54:54
...
image

关于Feign接口单文件上传,比较简单,和普通的 SpringMVC 几乎是一样的,对应好参数和配置信息即可。

多文件上传却是个头疼的问题(和自己的水平有关吧)。

浏览了几篇博客,虽然有代码可以参考,但是并不详细。那么请看下面史上最细致的Feign多文件上传总结(自吹自擂一下),最细致谈不上,可以让你真正解决问题。

如果你遇到了下面的这个错误提示:

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 

恭喜你来对地方了!

有人说第二个错误“就是传输的文件数据为空了,比较简单”,真的简单么?当你什么都写了,参数也有文件了,但是调用Feign的时候就是报这个错误,这才是最头疼的问题,明明看着可以,其实就是不行,闹心不?

开始解说

环境版本

Spring-boot版本:

2.2.0.RELEASE

SpringCloud版本:

Hoxton.M3

JDK版本:

1.8

接口提供方

接口提供方不需要特殊处理,看一下实力代码,按照示例代码写就可以:

    @RequestMapping(value = "/upload/batch" , method = RequestMethod.POST , consumes = MediaType.MULTIPART_FORM_DATA_VALUE )
    public ResponseData upload( @NotNull( message = "文件业务类型不能为空") @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

这里的 文件参数 MultipartFile[] images 注解使用的是:

@RequestParam("images") 

之所以在这里提一下,因为在接口消费方使用的不是这个(多文件)。

接口消费方

引入依赖
        <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);
    }
}

之所以需要提供这样一个编码器,是因为在程序内部调用Feign接口已经不是表单环境了,需要重新对文件内容进行编码操作。
开篇的第一个错误和这个就有关系,说“boundary(分割线)”找不到,就是因为不是表单提交,表单提交的话,都会存在分割线(对post请求了解的都应该知道)。

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接口提供中使用。

在消费方对服务接口进行配置
@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)文件参数注解使用 @RequestPart,而不是 @RequestParam
3)将 FeignMultipartSupportConfig 配置加上

对于注意 2),如果还是使用 @RequestParam 的话,就会出现开篇的第一个错误;
consumes = MediaType.MULTIPART_FORM_DATA_VALUE 这个设置,如果在调用接口的定义上不实用就会出现开篇的第二个错误,原因还是因为,这里的调用不是表单环境了,需要我们手动告诉接口,我们的请求是Multipart类型的。在SpringMVC接口中,我们不需要配置也可以,因为会自动携带对应的信息。

好啦,以上就是对Feign多文件上传问题的解决过程,按照以上过程,是没有问题的。
希望可以帮到大家。