openFeign多文件传输,源码微改,真实可用

最近做项目时候遇上服务间传输MultipartFile对象的问题,网上看了一些方法,放上去基本上没有啥卵用,最后看了写源码,微微修改了下,解决了问题,记录下希望以后遇上同样问题的同学不会太费时间!

引用包

这个和网上的相同

      <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>
        </dependency>

单文件上传

单文件上传很简单

  1. 配置编码器
@Configuration
public class GlobalFeignConfig {

    @Autowired
    private ObjectFactory<HttpMessageConverters> messageConverters;

    @Bean
    public Level level() {
        return Level.FULL;
    }


    @Bean
    public Encoder feignFormEncoder() {
        return new SpringFormEncoder(new SpringEncoder(messageConverters));
    }

}

配置到client端即可

  1. 注意 @RequestPart(“file”) MultipartFile file使用@RequestPart 而不是使用

多文件传输

如果直接用@RequestPart(“files”) MultipartFile[] files 会发现最后到服务提供者端总是就一个文件,明明是多个文件最后是一个!问题在哪里呢?
看一下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.
 */

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 feign.form.spring.SpringManyMultipartFilesWriter;
import feign.form.spring.SpringSingleMultipartFileWriter;
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 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;
  }
}

关键代码如下

 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);
    }

在循环中file.getName是相同的,所以一直覆盖
问题找到了,修改很简单:

 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(), files );
      }
      super.encode(data, MAP_STRING_WILDCARD, template);
    }

file 修改为 files,测试一下,应该ok了!

代码

client 端

@RestController
@RequestMapping("customerService")
@AllArgsConstructor
@Api(tags = "客户服务")
public class CustomerController {
    private final RemoteFileService remoteFileService;

    /**
     * 测试文件上传
     *
     * @return R
     */
    @ApiOperation(value = "测试文件上传", notes = "测试文件上传")
    @PostMapping("/test")
    public Result testFile(@RequestPart("files") MultipartFile[] files) {
        return Result.succeed(remoteFileService.uploadFiles(files, "userLogo/test/"));
    }

}

feign service

@FeignClient(value = "file-service", configuration = {FeignExceptionConfig.class, GlobalFeignConfig.class})
public interface RemoteFileService {
    /**
     * 上传文件
     *
     * @param file
     * @param fileName 指定的文件名(不指定可以为空)
     * @param path
     * @return
     */
    @PostMapping(value = "/fileInfo/uploadFile", produces = {MediaType.APPLICATION_JSON_UTF8_VALUE}, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    Result<FileInfo> uploadFile(@RequestPart("file") MultipartFile file, @RequestParam("fileName") String fileName, @RequestParam("path") String path);

    /**
     * 上传多张图片
     *
     * @param files
     * @param path
     * @return
     */
    @PostMapping(value = "/fileInfo/uploadFiles", produces = {MediaType.APPLICATION_JSON_UTF8_VALUE}, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    List<FileInfo> uploadFiles(@RequestPart("files") MultipartFile[] files, @RequestParam("path") String path);
}

server 端


    @PostMapping("/uploadFiles")
    public List<FileInfo> uploadFiles(@RequestPart("files") MultipartFile[] files, @RequestParam("path") String path) throws Exception {
        ……文件处理
        return null;
    }
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值