zoukankan      html  css  js  c++  java
  • spring cloud实战与思考(二) 微服务之间通过fiegn上传一组文件(上)

    需求场景:

    1. 微服务之间调用接口一次性上传多个文件。
    2. 上传文件的同时附带其他参数。
    3. 多个文件能有效的区分开,以便进行不同处理。

      Spring cloud的微服务之间接口调用使用Feign。原装的Feign不支持文件的传输。需要借助“Feign-form”库才行。但是貌似“Feign-form”库(至少是3.0.3版本)只支持单文件上传。在接口中使用多文件参数时会报异常:

    feign.codec.EncodeException: class [Lorg.springframework.web.multipart.MultipartFile; is not a type supported by this encoder.
        at feign.codec.Encoder$Default.encode(Encoder.java:90) ~[feign-core-9.5.0.jar:na]
        at feign.form.FormEncoder.encode(FormEncoder.java:87) ~[feign-form-3.0.3.jar:3.0.3]
        at feign.form.spring.SpringFormEncoder.encode(SpringFormEncoder.java:62) ~[feign-form-spring-3.0.3.jar:3.0.3]
        at feign.ReflectiveFeign$BuildEncodedTemplateFromArgs.resolve(ReflectiveFeign.java:351) ~[feign-core-9.5.0.jar:na]
        at feign.ReflectiveFeign$BuildTemplateByResolvingArgs.create(ReflectiveFeign.java:213) ~[feign-core-9.5.0.jar:na]
        at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:72) ~[feign-core-9.5.0.jar:na]
        at feign.ReflectiveFeign$FeignInvocationHandler.invoke(ReflectiveFeign.java:103) ~[feign-core-9.5.0.jar:na]
        at com.sun.proxy.$Proxy96.insertWithFiles(Unknown Source) ~[na:na]

      

    在网上搜索一番后,参考博客https://blog.csdn.net/ytzzh0726/article/details/79467843”,将”Feign-form”库中的”SpringFormEncoder”类改动一下,就可以支持多文件的上传。下面是具体实现方法:

    微服务提供方Controller接口:

    @ResponseBody
    @RequestMapping(value="/psts/add/insertWithFiles", method = RequestMethod.POST)
    public Object insertWithFiles(@RequestParam("baseInfo") String baseInfo, @RequestPart(value = "files") MultipartFile[] photoFiles) {
    }

     

    服务消费方pom引用Feign-form依赖:

    <dependency>
        <groupId>io.github.openfeign.form</groupId>
        <artifactId>feign-form</artifactId>
        <version>3.0.3</version>
    </dependency>
    <dependency>
        <groupId>io.github.openfeign.form</groupId>
        <artifactId>feign-form-spring</artifactId>
        <version>3.0.3</version>
    </dependency>
    <dependency>
        <groupId>commons-fileupload</groupId>
        <artifactId>commons-fileupload</artifactId>
        <version>1.3.3</version>
    </dependency>

     

    服务消费方声明一个“FeignSpringFormEncoder”类(这个类copy”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.Map;
    
    public class FeignSpringFormEncoder extends FormEncoder {
        public FeignSpringFormEncoder() {
            this(new Default());
        }
    
        public FeignSpringFormEncoder(Encoder delegate) {
            super(delegate);
            MultipartFormContentProcessor processor = (MultipartFormContentProcessor)this.getContentProcessor(ContentType.MULTIPART);
            processor.addWriter(new SpringSingleMultipartFileWriter());
            processor.addWriter(new SpringManyMultipartFilesWriter());
        }
    
    public void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException {
              //注释掉原来的代码
    //        if (!bodyType.equals(MultipartFile.class)) {
    //            super.encode(object, bodyType, template);
    //        } else {
    //            MultipartFile file = (MultipartFile)object;
    //            Map<String, Object> data = Collections.singletonMap(file.getName(), object);
    //            super.encode(data, MAP_STRING_WILDCARD, template);
    //        }
    
            //修改为下面的代码
            if (bodyType.equals(MultipartFile.class)) {
                MultipartFile file = (MultipartFile) object;
                Map<String, Object> data = Collections.singletonMap(file.getName(), object);
                super.encode(data, MAP_STRING_WILDCARD, template);
                return;
            } else if (bodyType.equals(MultipartFile[].class)) {
                MultipartFile[] file = (MultipartFile[]) object;
                if(file != null) {
                    Map<String, Object> data = Collections.singletonMap(“files”, object);
                    super.encode(data, MAP_STRING_WILDCARD, template);
                    return;
                }
            }
            super.encode(object, bodyType, template);
        }
    }

     

    “FeignSpringFormEncoder”作为bean提供给框架,代替“SpringFormEncoder”的“encode()”接口

    @Configuration
    public class FeignMultipartSupportConfig {
    
        @Bean
        @Primary
        @Scope("prototype")
        public Encoder multipartFormEncoder() {
    //        return new SpringFormEncoder();
            return new FeignSpringFormEncoder();
        }
    
        @Bean
        public feign.Logger.Level multipartLoggerLevel() {
            return feign.Logger.Level.FULL;
        }
    }

      以上方案测试可行。到目前为止需求1“多文件上传”和需求2“非文件类型参数上传”都已经满足了。下面来看看怎么对文件数组中的文件进行区分。服务提供方接收到的“MultipartFile”有两个接口“getName()”和“getOriginalFilename()”分别对应文件在http头的“Metadata”名称和文件原始名称。因为使用文件数组上传的功能,前一个名称被固定为“files”,不能用于区分文件。看来只能通过对文件原始名称进行约定来区分文件。但是如果这些文件是用户上传的,这就要求用户上传文件前对文件名称按照约定修改。显然这种接口方式对用户很不友好。限于篇幅,下一篇微博来探讨一下这个问题的解决方法。

  • 相关阅读:
    P1135 奇怪的电梯
    pycharm设置快捷键在keymap下拉列表没有eclipse怎么办
    记录selenium简单实现自动点击操作
    selenium 批量下载文件,json,重命名
    python3.6+selenium使用chrome浏览器自动将文件下载到指定路径
    selenium + Java 设置文件默认下载路径
    详解介绍Selenium常用API的使用Java语言(完整版)
    Pycharm安装robot framework运行插件
    Python之robotframework+pycharm测试框架!
    基于Python3 Robot framework环境搭建
  • 原文地址:https://www.cnblogs.com/standup/p/9090113.html
Copyright © 2011-2022 走看看