1. <output id="hzk7v"><pre id="hzk7v"><address id="hzk7v"></address></pre></output>
      <output id="hzk7v"></output>
    2. <nav id="hzk7v"><i id="hzk7v"><em id="hzk7v"></em></i></nav>
    3. <listing id="hzk7v"><delect id="hzk7v"><em id="hzk7v"></em></delect></listing>

      使用Feign扩展包实现微服务间文件上传

       更新时间£º2019年04月24日 11:44:05   作者£ºAaronSimon   我要评论

      这篇文章主要为大家详细介绍了使用Feign扩展包实现微服务间文件上传£¬具有一定的参考价值£¬感兴趣的小伙伴们可以参?#23478;?#19979;

      在Spring Cloud 的Feign组件中并不支持文件的传输£¬会出现这样的错误提示£º

      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.1.jar:na]
        at feign.form.FormEncoder.encode(FormEncoder.java:87) ~[feign-form-3.3.0.jar:3.3.0]
        at feign.form.spring.SpringFormEncoder.encode(SpringFormEncoder.java:64) ~[feign-form-spring-3.3.0.jar:3.3.0]
      
      

      但是我们可以通过使用Feign的扩展包实现这个功能¡£

      一. 示例介绍

      我们调用feign_upload_second的上传文件接口上传文件£¬feign_upload_second内部使用feign调用feign_upload_first实现文件上传¡£

      二 ¡¢单文件上传

      2.1 feign_upload_first服务提供者

      文件上传的服务提供者接口比较简单£¬如下所示£º

      @SpringBootApplication
      public class FeignUploadFirstApplication {
       @RestController
       public class UploadController {
      
        @RequestMapping(value = "/uploadFile",method = RequestMethod.POST, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
        public String handleFileUpload(@RequestPart(value = "file") MultipartFile file) {
         return file.getOriginalFilename();
        }
       }
       public static void main(String[] args) {
        SpringApplication.run(FeignUploadFirstApplication.class, args);
       }
      }
      
      

      2.2 feign_upload_second服务消费者

      增加扩展包依赖

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

      新增feign实现文件上传的配置类

      @Configuration
      public class FeignSupportConfig {
       @Bean
       public Encoder feignFormEncoder() {
        return new SpringFormEncoder();
       }
      }
      

      feign远程调用接口

      @FeignClient(name = "file",url = "http://localhost:8100",configuration = FeignSupportConfig.class)
      public interface UploadService {
       @RequestMapping(value = "/uploadFile", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
       String handleFileUpload(@RequestPart(value = "file") MultipartFile file);
      }

      上传文件接口

      @RestController
      public class UploadController {
       @Autowired
       UploadService uploadService;
      
       @RequestMapping(value = "/uploadFile",method = RequestMethod.POST, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
       public String handleFileUpload(@RequestPart(value = "file") MultipartFile file) {
        return uploadService.handleFileUpload(file);
       }
      }

      2.3 测试

      使用postman进行测试£¬可以正常上传文件

      三¡¢多文件上传

      既然单个文件可以上传£¬那么多文件应该也没问题吧£¬我们对上面的代码进行修改

      3.1 feign_upload_first服务提供者

      文件上传的服务提供者接口比较简单£¬如下所示£º

      @SpringBootApplication
      public class FeignUploadFirstApplication {
       @RestController
       public class UploadController {
      
        @RequestMapping(value = "/uploadFile",method = RequestMethod.POST, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
        public String handleFileUpload(@RequestPart(value = "file") MultipartFile file) {
         return file.getOriginalFilename();
        }
      
        @RequestMapping(value = "/uploadFile2",method = RequestMethod.POST, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
        public String handleFileUpload(@RequestPart(value = "file") MultipartFile[] file) {
         String fileName = "";
         for(MultipartFile f : file){
          fileName += f.getOriginalFilename()+"---";
         }
         return fileName;
        }
       }
       public static void main(String[] args) {
        SpringApplication.run(FeignUploadFirstApplication.class, args);
       }
      }

      3.2 feign_upload_second服务消费者

      feign远程调用接口

      @FeignClient(name = "file",url = "http://localhost:8100",configuration = FeignSupportConfig.class)
      public interface UploadService {
       @RequestMapping(value = "/uploadFile", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
       String handleFileUpload(@RequestPart(value = "file") MultipartFile file);
      
       @RequestMapping(value = "/uploadFile2", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
       String handleFileUpload(@RequestPart(value = "file") MultipartFile[] file);
      }

      上传文件接口

      @RestController
      public class UploadController {
       @Autowired
       UploadService uploadService;
      
       @RequestMapping(value = "/uploadFile",method = RequestMethod.POST, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
       public String handleFileUpload(@RequestPart(value = "file") MultipartFile file) {
        return uploadService.handleFileUpload(file);
       }
      
       @RequestMapping(value = "/uploadFile2",method = RequestMethod.POST, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
       public String handleFileUpload2(@RequestPart(value = "file") MultipartFile[] file) {
        return uploadService.handleFileUpload(file);
       }
      }

      3.3 测试

      经过测试发现£¬无法上传多个文件¡£经过检查£¬发现源码里底层是有对MultipartFile[]类型的支持的£¬源码中有个类叫SpringManyMultipartFilesWriter£¬是专门针对文件数组类型进行操作的£¬但是配置?#36739;?#30446;里的SpringFormEncoder类里却没有对文件数组类型的判断£¬以致不能支持文件数组的上传

      SpringManyMultipartFilesWriter源码

      public class SpringManyMultipartFilesWriter extends AbstractWriter {
       private final SpringSingleMultipartFileWriter fileWriter = new SpringSingleMultipartFileWriter();
      
       public SpringManyMultipartFilesWriter() {
       }
      
       public void write(Output output, String boundary, String key, Object value) throws Exception {
        if (value instanceof MultipartFile[]) {
         MultipartFile[] files = (MultipartFile[])((MultipartFile[])value);
         MultipartFile[] var6 = files;
         int var7 = files.length;
      
         for(int var8 = 0; var8 < var7; ++var8) {
          MultipartFile file = var6[var8];
          this.fileWriter.write(output, boundary, key, file);
         }
        } else if (value instanceof Iterable) {
         Iterable<?> iterable = (Iterable)value;
         Iterator var11 = iterable.iterator();
      
         while(var11.hasNext()) {
          Object file = var11.next();
          this.fileWriter.write(output, boundary, key, file);
         }
        }
      
       }
      
       public boolean isApplicable(Object value) {
        if (value == null) {
         return false;
        } else if (value instanceof MultipartFile[]) {
         return true;
        } else {
         if (value instanceof Iterable) {
          Iterable<?> iterable = (Iterable)value;
          Iterator<?> iterator = iterable.iterator();
          if (iterator.hasNext() && iterator.next() instanceof MultipartFile) {
           return true;
          }
         }
      
         return false;
        }
       }
      }

      SpringFormEncoder源码

      public class SpringFormEncoder extends FormEncoder {
       public SpringFormEncoder() {
        this(new Default());
       }
      
       public SpringFormEncoder(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);
        }
       }
      }

      从上面SpringFormEncoder的源码上可以看到SpringFormEncoder类构造时把SpringManyMultipartFilesWriter实例添加到了处理器列表里了£¬但是在encode方法里又只判断了MultipartFile类型£¬没有判断数组类型£¬底层有对数组的支?#20540;?#19978;层却缺少了相应判断¡£那么我们可以自己去扩展FormEncoder£¬仿照SpringFormEncoder源码£¬只修改encode方法¡£

      3.3 扩展FormEncoder支持多文件上传

      扩展FormEncoder,命名为FeignSpringFormEncoder

      public class FeignSpringFormEncoder extends FormEncoder {
       /**
        * Constructor with the default Feign's encoder as a delegate.
        */
       public FeignSpringFormEncoder() {
        this(new Default());
       }
      
      
       /**
        * Constructor with specified delegate encoder.
        *
        * @param delegate delegate encoder, if this encoder couldn't encode object.
        */
       public FeignSpringFormEncoder(Encoder delegate) {
        super(delegate);
      
        MultipartFormContentProcessor processor = (MultipartFormContentProcessor) getContentProcessor(ContentType.MULTIPART);
        processor.addWriter(new SpringSingleMultipartFileWriter());
        processor.addWriter(new SpringManyMultipartFilesWriter());
       }
      
      
       @Override
       public void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException {
        if (bodyType.equals(MultipartFile.class)) {
         MultipartFile file = (MultipartFile) object;
         Map 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 data = Collections.singletonMap(file.length == 0 ? "" : file[0].getName(), object);
          super.encode(data, MAP_STRING_WILDCARD, template);
          return;
         }
        }
        super.encode(object, bodyType, template);
       }
      }
      
      

      注册配置类

      @Configuration
      public class FeignSupportConfig {
       @Bean
       public Encoder feignFormEncoder() {
        return new FeignSpringFormEncoder();
       }
      }

      经过测试可以上传多个文件¡£

      以上就是本文的全部内容£¬希望对大家的学习有所帮助£¬也希望大家多多支持脚本之家¡£

      相关文章

      • Zookeeper和Eureka哪个更好?

        Zookeeper和Eureka哪个更好?

        今天小编就为大家分享一篇关于Zookeeper和Eureka哪个更好?£¬小编觉得内容挺不错的£¬现在分享给大家£¬具有很好的参考价值£¬需要的朋友一起跟随小编来看看吧
        2019-02-02
      • Java中循环冗余校验£¨CRC32£©的实现

        Java中循环冗余校验£¨CRC32£©的实现

        CRC校验实用程序库在数据存储和数据通讯领域£¬为了保证数据的正确£¬就不得不采用检错的手段£¬下面这篇文章主要给大家介绍了关于Java中循环冗余校验£¨CRC32£©实现的相关资?#24076;?#38656;要的朋友可以参考借鉴£¬下面来一起看看吧¡£
        2017-10-10
      • Java实现?#35745;?#19982;Base64编码互转

        Java实现?#35745;?#19982;Base64编码互转

        这篇文章主要介绍了Java中实现?#35745;?#19982;Base64编码互转的方法,比较实用,需要的朋友可以参考下¡£
        2016-06-06
      • Java实现打飞机小游戏£¨附完整源码£©

        Java实现打飞机小游戏£¨附完整源码£©

        这篇文章主要介绍了Java实现打飞机小游戏£¨附完整源码£©£¬这里整理了详细的代码£¬具有一定的参考价值£¬感兴趣的小伙伴们可以参?#23478;?#19979;
        2017-10-10
      • Spring框架web项目实战全代码分享

        Spring框架web项目实战全代码分享

        这篇文章主要介绍了Spring框架web项目实战全代码分享£¬具有一定参考价值£¬需要的朋友可以了解下¡£
        2017-11-11
      • 详解springmvc拦截器拦截静态资源

        详解springmvc拦截器拦截静态资源

        本篇文章主要介绍了详解springmvc拦截器拦截静态资源£¬具有一定的参考价值£¬感兴趣的小伙伴们可以参?#23478;?#19979;¡£
        2017-01-01
      • MyBatis中insert操作返回主键的实现方法

        MyBatis中insert操作返回主键的实现方法

        在使用MyBatis做持久层时£¬insert语句默认是不返回记录的主键值£¬而是返回插入的记录条数¡£这篇文章主要介绍了MyBatis中insert操作返回主键的方法,需要的朋友可以参考下
        2016-09-09
      • Java处理Webp?#35745;?#26684;式转换的示例代码

        Java处理Webp?#35745;?#26684;式转换的示例代码

        这篇文章主要介绍了Java处理Webp?#35745;?#26684;式转换的示例代码£¬小编觉得挺不错的£¬现在分享给大家£¬也给大家做个参考¡£一起跟随小编过来看看吧
        2018-09-09
      • java String 可变性的分析

        java String 可变性的分析

        这篇文章主要介绍了java String 可变性的分析的相关资料,通常大家?#26082;?#20026;java String 是不可变的£¬这里分析下源码来?#24471;?#23427;的可变性£¬需要的朋友可以参考下
        2017-03-03
      • 彻底理解Java 中的ThreadLocal

        彻底理解Java 中的ThreadLocal

        这篇文章主要介绍了彻底理解Java 中的ThreadLocal的相关资料,需要的朋友可以参考下
        2017-07-07

      最新评论

      3dÊÔ»úºÅÖвÊÍø

        1. <output id="hzk7v"><pre id="hzk7v"><address id="hzk7v"></address></pre></output>
          <output id="hzk7v"></output>
        2. <nav id="hzk7v"><i id="hzk7v"><em id="hzk7v"></em></i></nav>
        3. <listing id="hzk7v"><delect id="hzk7v"><em id="hzk7v"></em></delect></listing>

            1. <output id="hzk7v"><pre id="hzk7v"><address id="hzk7v"></address></pre></output>
              <output id="hzk7v"></output>
            2. <nav id="hzk7v"><i id="hzk7v"><em id="hzk7v"></em></i></nav>
            3. <listing id="hzk7v"><delect id="hzk7v"><em id="hzk7v"></em></delect></listing>