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

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多文件上传问题的解决过程,按照以上过程,是没有问题的。
希望可以帮到大家。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,902评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,037评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,978评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,867评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,763评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,104评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,565评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,236评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,379评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,313评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,363评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,034评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,637评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,719评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,952评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,371评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,948评论 2 341