记一次feign上传多文件

微服务中,跨服务调用上传文件接口,使用feign方式调用

环境:

1. springboot2.2.1.RELEASE;

2.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>
   <exclusions>
      <exclusion>
         <groupId>org.springframework.cloud</groupId>
         <artifactId>spring-cloud-starter-openfeign</artifactId>
      </exclusion>
   </exclusions>
</dependency>

问题:多文件上传接口正常调用成功,但是,在控制台输出文件数量显示只收到一个文件

解决:

        经排查,客户端收到了多个文件并输出,然后feign调用,需要在feign接口上注入一个配置,经查看,引用的jar中包含一个SpringFormEncoder,源码如下:

/*
 * Copyright 2019 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package feign.form.spring;

import static feign.form.ContentType.MULTIPART;
import static java.util.Collections.singletonMap;

import java.lang.reflect.Type;
import java.util.HashMap;

import feign.RequestTemplate;
import feign.codec.EncodeException;
import feign.codec.Encoder;
import feign.form.FormEncoder;
import feign.form.MultipartFormContentProcessor;

import lombok.val;
import org.springframework.web.multipart.MultipartFile;

/**
 * Adds support for {@link MultipartFile} type to {@link FormEncoder}.
 *
 * @author Tomasz Juchniewicz &lt;tjuchniewicz@gmail.com&gt;
 * @since 14.09.2016
 */
public class SpringFormEncoder extends FormEncoder {

  /**
   * Constructor with the default Feign's encoder as a delegate.
   */
  public SpringFormEncoder () {
    this(new Encoder.Default());
  }

  /**
   * Constructor with specified delegate encoder.
   *
   * @param delegate  delegate encoder, if this encoder couldn't encode object.
   */
  public SpringFormEncoder (Encoder delegate) {
    super(delegate);

    val processor = (MultipartFormContentProcessor) getContentProcessor(MULTIPART);
    processor.addFirstWriter(new SpringSingleMultipartFileWriter());
    processor.addFirstWriter(new SpringManyMultipartFilesWriter());
  }

  @Override
  public void encode (Object object, Type bodyType, RequestTemplate template) throws EncodeException {
    if (bodyType.equals(MultipartFile[].class)) {
      val files = (MultipartFile[]) object;
      val data = new HashMap<String, Object>(files.length, 1.F);
      for (val file : files) {
        data.put(file.getName(), file);
      }
      super.encode(data, MAP_STRING_WILDCARD, template);
    } else if (bodyType.equals(MultipartFile.class)) {
      val file = (MultipartFile) object;
      val data = singletonMap(file.getName(), object);
      super.encode(data, MAP_STRING_WILDCARD, template);
    } else if (isMultipartFileCollection(object)) {
      val iterable = (Iterable<?>) object;
      val data = new HashMap<String, Object>();
      for (val item : iterable) {
        val 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;
    }
    val iterable = (Iterable<?>) object;
    val iterator = iterable.iterator();
    return iterator.hasNext() && iterator.next() instanceof MultipartFile;
  }
}

 在encode中,加入了对文件数组的处理

问题就出现在file.getName(),多个文件时,这个方式获取到的文件名称不变,因此只能获取到一个文件。

至此,重写该方法,如下代码解决: 

@Configuration
    class FeignMultipartSupportConfig {

        @Bean
        public Encoder springFormEncoder(ObjectFactory<HttpMessageConverters> messageConvertersObjectFactory) {
            // 避免实体作为参数无法接收
            SpringEncoder springEncoder = new SpringEncoder(messageConvertersObjectFactory);
            return new SpringMultipartEncoder(springEncoder);
        }


    }

 

public class SpringMultipartEncoder extends FormEncoder {
    public SpringMultipartEncoder() {
        this(new Default());
    }

    public SpringMultipartEncoder(Encoder delegate) {
        super(delegate);
        MultipartFormContentProcessor processor = (MultipartFormContentProcessor)this.getContentProcessor(ContentType.MULTIPART);
        processor.addFirstWriter(new SpringSingleMultipartFileWriter());
        processor.addFirstWriter(new SpringManyMultipartFilesWriter());
    }

    public void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException {
        if (bodyType.equals(MultipartFile[].class)) {
            MultipartFile[] files = (MultipartFile[])((MultipartFile[])object);
            Map<String, MultipartFile[]> data = Collections.singletonMap("files", files);
            super.encode(data, MAP_STRING_WILDCARD, template);
        } else if (bodyType.equals(MultipartFile.class)) {
            Map<String, Object> data = Collections.singletonMap("file", object);
            super.encode(data, MAP_STRING_WILDCARD, template);
        } else if (this.isMultipartFileCollection(object)) {
            Iterable<?> iterable = (Iterable)object;
            HashMap<String, Object> data = new HashMap();
            Iterator var6 = iterable.iterator();

            while(var6.hasNext()) {
                Object item = var6.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;
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值