网上百度了很多办法均太过简单,大多都是携带几个简单的参数和一个File对象,如果将File和其他参数封装到一个对象或者DTO内就不行了
网上的例子 MultipartFile
Feign 无法直接传递文件参数,需要在client端引入几个依赖
io.github.openfeign.form:feign-form:3.0.3
io.github.openfeign.form:feign-form-spring:3.0.3
1. 创建服务端
方式与普通的文件上传方法一致
  
   - 
    
     
    
    
     
      @RestController
     
    
- 
    
     
    
    
     
      @RequestMapping(
      "/producer/upload")
     
    
- 
    
     
    
    
     
      class UploadProducer {
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
         
      @PostMapping(value = 
      '/upload', consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
     
    
- 
    
     
    
    
     
          String upload(
      @RequestPart(value = 
      "file") MultipartFile file) {
     
    
- 
    
     
    
    
             
      // ...
     
    
- 
    
     
    
    
             
      return 
      file
      .originalFilename
     
    
- 
    
     
    
    
     
          }
     
    
- 
    
     
    
    
     
      }
     
    
2. 创建client
  
   - 
    
     
    
    
     
      io
      .github
      .openfeign
      .form
      :feign-form
      :3.0.3
     
    
- 
    
     
    
    
     
      io
      .github
      .openfeign
      .form
      :feign-form-spring
      :3.0.3
     
    
  
   - 
    
     
    
    
     
      @FeignClient(name = 
      'upload', url = 
      '${upload.base-url}', path = 
      '/producer/upload')
     
    
- 
    
     
    
    
     
      interface UploadClient {
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
         
      @RequestMapping(value = 
      '/upload', method = RequestMethod.POST, consumes = MediaType.MULTIPART_FORM_DATA_VALUE
     
    
- 
    
     
    
    
     
                  , produces = MediaType.APPLICATION_JSON_VALUE)
     
    
- 
    
     
    
    
     
          String upload(
      @RequestPart(
      "file") MultipartFile file)
     
    
- 
    
     
    
    
     
      }
     
    
划重点
  
   - 
    
     
    
    
     
      @Configuration
     
    
- 
    
     
    
    
     
      class MultipartSupportConfig {
     
    
- 
    
     
    
    
         
      @Autowired
     
    
- 
    
     
    
    
     
          private ObjectFactory<HttpMessageConverters> messageConverters
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
         
      // new一个form编码器,实现支持form表单提交
     
    
- 
    
     
    
    
         
      @Bean
     
    
- 
    
     
    
    
     
          Encoder feignFormEncoder() {
     
    
- 
    
     
    
    
             
      return 
      new 
      SpringFormEncoder(new SpringEncoder(messageConverters))
     
    
- 
    
     
    
    
     
          }
     
    
- 
    
     
    
    
     
      }
     
    
3. 创建Controller,调用client接口
  
   - 
    
     
    
    
     
      @RestController
     
    
- 
    
     
    
    
     
      @RequestMapping(
      "/")
     
    
- 
    
     
    
    
     
      class RecordController {
     
    
- 
    
     
    
    
         
      @Autowired
     
    
- 
    
     
    
    
     
          private UploadClient uploadClient
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
         
      @RequestMapping(value = 
      '/upload', method = RequestMethod.POST, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
     
    
- 
    
     
    
    
     
          String upload(
      @RequestParam(
      "file") MultipartFile file) {
     
    
- 
    
     
    
    
             
      return 
      uploadClient
      .uploade(file)
     
    
- 
    
     
    
    
     
          }
     
    
- 
    
     
    
    
     
      }   
     
    
可以看到网上的例子只能传递简单的表单参数 下面我有种需求 如果携带一个对象呢? 对象信息如下
  
   - 
    
     
    
    
     
      package com.smdk.dsminio.vo;
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      import lombok.Data;
     
    
- 
    
     
    
    
     
      import lombok.ToString;
     
    
- 
    
     
    
    
     
      import org.springframework.web.multipart.MultipartFile;
     
    
- 
    
     
    
    
     
      import java.io.Serializable;
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      /**
     
    
- 
    
     
    
    
     
       * @author 神秘的凯
     
    
- 
    
     
    
    
     
       *date 2020-03-17 17:16
     
    
- 
    
     
    
    
     
       */
     
    
- 
    
     
    
    
     
      @Data
     
    
- 
    
     
    
    
     
      @ToString
     
    
- 
    
     
    
    
     
      public 
      class MultipartFileParam implements Serializable {
     
    
- 
    
     
    
    
         
      public  
      static 
      final 
      long serialVersionUID=
      1L;
     
    
- 
    
     
    
    
         
      // 用户id
     
    
- 
    
     
    
    
         
      private String uid;
     
    
- 
    
     
    
    
         
      //任务ID
     
    
- 
    
     
    
    
         
      private String id;
     
    
- 
    
     
    
    
         
      //总分片数量
     
    
- 
    
     
    
    
         
      private 
      int chunks;
     
    
- 
    
     
    
    
         
      //当前为第几块分片
     
    
- 
    
     
    
    
         
      private 
      int chunk;
     
    
- 
    
     
    
    
         
      //当前分片大小
     
    
- 
    
     
    
    
         
      private 
      long size = 
      0L;
     
    
- 
    
     
    
    
         
      //文件名
     
    
- 
    
     
    
    
         
      private String name;
     
    
- 
    
     
    
    
         
      //分片对象
     
    
- 
    
     
    
    
         
      private MultipartFile file;
     
    
- 
    
     
    
    
         
      // MD5
     
    
- 
    
     
    
    
         
      private String md5;
     
    
- 
    
     
    
    
         
      //BucketID
     
    
- 
    
     
    
    
         
      private  Long bucketId;
     
    
- 
    
     
    
    
         
      //文件夹ID
     
    
- 
    
     
    
    
         
      private Long parentFolderId;
     
    
- 
    
     
    
    
     
      }
     
    
如果这样直接上传Spring的解析器解析不到MultipartFileParam 自定义对象会直接报错 另外Spring只能解析自带的Multipart 对象
报错信息
%s is not a type supported by this encoder.....省略
那么如果传递自定义的参数对象呢 那就是重写Spring的对象解析器 代码如下
Feign 调用端代码
  
   - 
    
     
    
    
     
      package com.smdk.dsminio.apiservice;
     
    
- 
    
     
    
    
     
      import com.smdk.dsminio.config.FeignSupportConfig;
     
    
- 
    
     
    
    
     
      import com.smdk.dsminio.utils.AjaxResult;
     
    
- 
    
     
    
    
     
      import com.smdk.dsminio.vo.MultipartFileParam;
     
    
- 
    
     
    
    
     
      import org.springframework.cloud.openfeign.FeignClient;
     
    
- 
    
     
    
    
     
      import org.springframework.http.MediaType;
     
    
- 
    
     
    
    
     
      import org.springframework.web.bind.annotation.RequestMapping;
     
    
- 
    
     
    
    
     
      import org.springframework.web.bind.annotation.RequestMethod;
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      @FeignClient(value = "OSS-STORAGE-SERVICE",configuration = FeignSupportConfig.class)
     
    
- 
    
     
    
    
     
      public 
      interface FileService {
     
    
- 
    
     
    
    
         
      /**
     
    
- 
    
     
    
    
     
       * produces 用于指定返回类型为JSON格式
     
    
- 
    
     
    
    
     
       * consumes 用于指定生产者数据请求类型
     
    
- 
    
     
    
    
     
       * @param multipartFileParam
     
    
- 
    
     
    
    
     
       * @return
     
    
- 
    
     
    
    
     
       */
     
    
- 
    
     
    
    
         
      @RequestMapping(value = "//OSS-STORAGE-SERVICE-$SERVER_ID/api/uploadFileInfo", produces = {MediaType.APPLICATION_JSON_UTF8_VALUE},consumes = MediaType.MULTIPART_FORM_DATA_VALUE,method = RequestMethod.POST)
     
    
- 
    
     
    
    
         
      AjaxResult uploadFileInfo(MultipartFileParam multipartFileParam);
     
    
- 
    
     
    
    
     
      }
     
    
服务端
  
   - 
    
     
    
    
     
      package com.smdk.dsminio.controller;
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      import cn.hutool.log.StaticLog;
     
    
- 
    
     
    
    
     
      import com.smdk.dsminio.redis.RedisUtil;
     
    
- 
    
     
    
    
     
      import com.smdk.dsminio.service.FileStorageService;
     
    
- 
    
     
    
    
     
      import com.smdk.dsminio.utils.AjaxResult;
     
    
- 
    
     
    
    
     
      import com.smdk.dsminio.utils.Constants;
     
    
- 
    
     
    
    
     
      import com.smdk.dsminio.vo.MultipartFileParam;
     
    
- 
    
     
    
    
     
      import org.apache.commons.fileupload.servlet.ServletFileUpload;
     
    
- 
    
     
    
    
     
      import org.apache.commons.io.FileUtils;
     
    
- 
    
     
    
    
     
      import org.springframework.beans.factory.annotation.Autowired;
     
    
- 
    
     
    
    
     
      import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
     
    
- 
    
     
    
    
     
      import org.springframework.http.MediaType;
     
    
- 
    
     
    
    
     
      import org.springframework.web.bind.annotation.*;
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      import javax.servlet.http.HttpServletRequest;
     
    
- 
    
     
    
    
     
      import java.io.File;
     
    
- 
    
     
    
    
     
      import java.io.IOException;
     
    
- 
    
     
    
    
     
      import java.util.LinkedList;
     
    
- 
    
     
    
    
     
      import java.util.List;
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      /**
     
    
- 
    
     
    
    
     
       * 默认控制层
     
    
- 
    
     
    
    
     
       * Created by 神秘的凯 on 22020/11/11.
     
    
- 
    
     
    
    
     
       * version 1.0
     
    
- 
    
     
    
    
     
       */
     
    
- 
    
     
    
    
     
      @RestController
     
    
- 
    
     
    
    
     
      @RequestMapping(value = "/api")
     
    
- 
    
     
    
    
     
      public 
      class FileDiskStorageController {
     
    
- 
    
     
    
    
         
      @Autowired
     
    
- 
    
     
    
    
         
      private FileStorageService fileStorageService;
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
         
      /**
     
    
- 
    
     
    
    
     
       * 上传文件
     
    
- 
    
     
    
    
     
       *
     
    
- 
    
     
    
    
     
       * @param param
     
    
- 
    
     
    
    
     
       * @param request
     
    
- 
    
     
    
    
     
       * @return
     
    
- 
    
     
    
    
     
       * @throws Exception
     
    
- 
    
     
    
    
     
       */
     
    
- 
    
     
    
    
         
      @RequestMapping(value = "/uploadFileInfo", method = RequestMethod.POST)
     
    
- 
    
     
    
    
         
      public AjaxResult uploadFileInfo(MultipartFileParam multipartFileParam) {
     
    
- 
    
     
    
    
     
              StaticLog.info(
      "上传文件start。");
     
    
- 
    
     
    
    
             
      try {
     
    
- 
    
     
    
    
                 
      // 方法1
     
    
- 
    
     
    
    
                 
      //storageService.uploadFileRandomAccessFile(param);
     
    
- 
    
     
    
    
                 
      // 方法2 这个更快点
     
    
- 
    
     
    
    
                
      boolean uploadResult= fileStorageService.uploadFileByMappedByteBuffer(multipartFileParam);
     
    
- 
    
     
    
    
                
      if (uploadResult){
     
    
- 
    
     
    
    
                    
      return AjaxResult.success(uploadResult,
      "上传完毕");
     
    
- 
    
     
    
    
     
                 }
      else {
     
    
- 
    
     
    
    
                    
      return AjaxResult.fail(
      "分片上传中...正在上传第"+multipartFileParam.getChunk()+
      "块文件块,剩余"+(multipartFileParam.getChunks()-multipartFileParam.getChunk())+
      "个分块");
     
    
- 
    
     
    
    
     
                 }
     
    
- 
    
     
    
    
     
              } 
      catch (IOException e) {
     
    
- 
    
     
    
    
     
                  e.printStackTrace();
     
    
- 
    
     
    
    
     
                  StaticLog.error(
      "文件上传失败。{}", multipartFileParam.toString());
     
    
- 
    
     
    
    
                 
      return AjaxResult.fail(
      "文件上传失败");
     
    
- 
    
     
    
    
     
              }
     
    
- 
    
     
    
    
     
          }
     
    
- 
    
     
    
    
     
      }
     
    
核心重写feignFormEncoder 方法类 下面的的路由配置请忽略
  
   - 
    
     
    
    
     
      package com.smdk.dsminio.config;
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      import com.smdk.dsminio.vo.MultipartFileParam;
     
    
- 
    
     
    
    
     
      import feign.Request;
     
    
- 
    
     
    
    
     
      import feign.RequestInterceptor;
     
    
- 
    
     
    
    
     
      import feign.RequestTemplate;
     
    
- 
    
     
    
    
     
      import feign.codec.EncodeException;
     
    
- 
    
     
    
    
     
      import feign.codec.Encoder;
     
    
- 
    
     
    
    
     
      import feign.form.spring.SpringFormEncoder;
     
    
- 
    
     
    
    
     
      import org.springframework.context.annotation.Bean;
     
    
- 
    
     
    
    
     
      import org.springframework.context.annotation.Primary;
     
    
- 
    
     
    
    
     
      import org.springframework.context.annotation.Scope;
     
    
- 
    
     
    
    
     
      import java.io.IOException;
     
    
- 
    
     
    
    
     
      import java.lang.reflect.Type;
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
      import 
      static java.lang.String.format;
     
    
- 
    
     
    
    
     
      public 
      class FeignSupportConfig{
     
    
- 
    
     
    
    
         
      //转换参数请求模型封装
     
    
- 
    
     
    
    
         
      @Bean
     
    
- 
    
     
    
    
         
      @Primary
     
    
- 
    
     
    
    
         
      @Scope("prototype")
     
    
- 
    
     
    
    
         
      public Encoder feignFormEncoder() {
     
    
- 
    
     
    
    
             
      return 
      new SpringFormEncoder(
      new Encoder() {
     
    
- 
    
     
    
    
                 
      @Override
     
    
- 
    
     
    
    
                 
      public void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException {
     
    
- 
    
     
    
    
                     
      if (bodyType == String.class) {
     
    
- 
    
     
    
    
     
                          template.body(Request.Body.bodyTemplate(object.toString(),
      null));
     
    
- 
    
     
    
    
     
                      } 
      else 
      if (bodyType == 
      byte[].class) {
     
    
- 
    
     
    
    
     
                          template.body(Request.Body.encoded((
      byte[]) object,
      null));
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
                      }
      else 
      if (bodyType == MultipartFileParam.class) {
     
    
- 
    
     
    
    
     
                          MultipartFileParam multipartFileParam = (MultipartFileParam) object;
     
    
- 
    
     
    
    
                         
      try {
     
    
- 
    
     
    
    
     
                              template.body(Request.Body.encoded(multipartFileParam.getFile().getBytes(),
      null));
     
    
- 
    
     
    
    
     
                          } 
      catch (IOException e) {
     
    
- 
    
     
    
    
     
                              e.printStackTrace();
     
    
- 
    
     
    
    
     
                          }
     
    
- 
    
     
    
    
     
                      }
     
    
- 
    
     
    
    
                     
      else 
      if (object != 
      null) {
     
    
- 
    
     
    
    
                         
      throw 
      new EncodeException(format(
      "%s is not a type supported by this encoder.", object.getClass()));
     
    
- 
    
     
    
    
     
                      }
     
    
- 
    
     
    
    
     
                  }
     
    
- 
    
     
    
    
     
              });
     
    
- 
    
     
    
    
     
          }
     
    
- 
    
     
    
    
         
      @Bean
     
    
- 
    
     
    
    
         
      public feign.Logger.
      Level multipartLoggerLevel() {
     
    
- 
    
     
    
    
             
      return feign.Logger.Level.FULL;
     
    
- 
    
     
    
    
     
          }
     
    
- 
    
     
    
    
         
      //路由重构
     
    
- 
    
     
    
    
         
      @Bean
     
    
- 
    
     
    
    
         
      public RequestInterceptor cloudContextInterceptor() {
     
    
- 
    
     
    
    
             
      return 
      new RequestInterceptor() {
     
    
- 
    
     
    
    
                 
      @Override
     
    
- 
    
     
    
    
                 
      public void apply(RequestTemplate template) {
     
    
- 
    
     
    
    
     
                      String url = template.url();
     
    
- 
    
     
    
    
                     
      if (url.contains(
      "$SERVER_ID")) {
     
    
- 
    
     
    
    
     
                          url = url.replace(
      "$SERVER_ID", route(template));
     
    
- 
    
     
    
    
     
                          template.uri(url);
     
    
- 
    
     
    
    
     
                      }
     
    
- 
    
     
    
    
                     
      if (url.startsWith(
      "//")) {
     
    
- 
    
     
    
    
     
                          url = 
      "http:" + url;
     
    
- 
    
     
    
    
     
                          template.target(url);
     
    
- 
    
     
    
    
     
                          template.uri(
      "");
     
    
- 
    
     
    
    
     
                      }
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
     
                  }
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
      
     
    
- 
    
     
    
    
                 
      private CharSequence route(RequestTemplate template) {
     
    
- 
    
     
    
    
                     
      // TODO 你的路由算法在这里
     
    
- 
    
     
    
    
                     
      return 
      "01";
     
    
- 
    
     
    
    
     
                  }
     
    
- 
    
     
    
    
     
              };
     
    
- 
    
     
    
    
     
          }
     
    
- 
    
     
    
    
     
      }
     
    
可以看到我加了个判断 if (bodyType == MultipartFileParam.class) 进行自己封装的对象解析
大工告成 另外说下这个问题 品读了Spring的源码才搞定的 在此之前各种尝试和百度已经测试过无数前辈提供的方法 搞了两天才搞定这个bug 哎! 两天啊!!!!!!!!!!!!

转载:https://blog.csdn.net/fujiakai/article/details/109821141
查看评论
					