最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

微服務之間如何通過feign調(diào)用接口上傳文件

 更新時間:2021年06月30日 11:29:01   作者:想網(wǎng)名太麻煩  
這篇文章主要介紹了微服務之間如何通過feign調(diào)用接口上傳文件的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

具體需求:

我們的項目是基于springboot框架的springcloud微服務搭建的,后端服務技術(shù)層面整體上分為business服務和core服務,business服務用于作為應用層,直接連接客戶端,通常用于聚合數(shù)據(jù),core服務用來客戶端具體操作不同需求來控制數(shù)據(jù)庫,文件上傳是通過客戶端上傳接口,通過business服務,由服務端調(diào)用feign接口,也是第一次做這種文件中轉(zhuǎn),遇到各種問題,下面是我自己的解決方案,不喜勿噴,代碼小白一枚;

一、core服務層接口@requestmapping

屬性加上consumes=MediaType.MULTIPART_FORM_DATA_VALUE如下代碼

@PostMapping(value = "/upload",consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    @ResponseBody
    public Result<TbFile> upload(@RequestPart(value = "file",required = true) MultipartFile file,
                         @RequestParam(name = "id",required = true) Integer id,
                         @RequestParam(name = "desc",required = false)  String desc,
                         @RequestParam(name = "fileId",required = false) Integer fileId )

解釋:@RequestMapping存在以下兩個屬性:

1.String[] consumes() default {};

2.String[] produces() default {};

兩個屬性的解釋及參考例子:

① 屬性produces:指定返回值類型,并且可以設置返回值類型和返回值的字符編碼;代碼例子參考如下:

屬性produces="application/json"時,返回json數(shù)據(jù)

屬性produces="MediaType.APPLICATION_JSON_VALUE;charset=utf-8"時,設置返回數(shù)據(jù)的字符編碼為utf-8

@Controller    
@RequestMapping(value = "/getperson", method = RequestMethod.GET, produces="application/json")    
public Object getPerson(int id) {       
    //實現(xiàn)自己的邏輯調(diào)用
  Person p= new person();
 
    return p;
} 

特別說明:produces="application/json"和注解@ResponseBody是一樣的效果,使用了注解其實可以不使用該屬性了

② 屬性consumes: 指定處理請求當中的提交內(nèi)容類型(Content-Type):application/json, text/html等;

代碼例子參考如下:

 @PostMapping(value = "/upload",consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    @ResponseBody
    public Result<TbFile> upload(@RequestPart(value = "file",required = true) MultipartFile file,
                         @RequestParam(name = "id",required = true) Integer id,
                         @RequestParam(name = "desc",required = false)  String desc,
                         @RequestParam(name = "fileId",required = false) Integer fileId ){
}

解釋: MediaType.MULTIPART_FORM_DATA_VALUE 代表的值為multipart/form-data它會將表單的數(shù)據(jù)處理為一條消息,以標簽為單元,用分隔符分開。既可以上傳鍵值對,也可以上傳文件。當上傳的字段是文件時,會有Content-Type來表名文件類型;content-disposition,用來說明字段的一些信息;

二、business客戶層接口@requestmapping

屬性加上consumes=MediaType.MULTIPART_FORM_DATA_VALUE如下代碼

   @PostMapping(value = "/upload",produces = MediaType.APPLICATION_JSON_UTF8_VALUE,
            consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    @ResponseBody
    Result<TbFile> upload(@RequestPart(value = "file",required = true) MultipartFile file,
                  @RequestParam(name = "id",required = true) Integer id,
                  @RequestParam(name = "desc",required = false)  String desc,
                  @RequestParam(name = "fileId",required = false) Integer fileId );

具體大概就這么多。能力有限,多多指教!!!

feign微服務間文件上傳(Finchley版本)

在Spring Cloud 的Feign組件中并不支持文件的傳輸,會出現(xiàn)這樣的錯誤提示:

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的擴展包實現(xiàn)這個功能。

一. 示例介紹

服務名 端口號 角色
feign_upload_first 8100 feign服務提供者
feign_upload_second 8101 feign服務消費者

我們調(diào)用feign_upload_second的上傳文件接口上傳文件,feign_upload_second內(nèi)部使用feign調(diào)用feign_upload_first實現(xiàn)文件上傳。

二 、單文件上傳

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實現(xiàn)文件上傳的配置類

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

feign遠程調(diào)用接口

@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遠程調(diào)用接口

@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 測試

經(jīng)過測試發(fā)現(xiàn),無法上傳多個文件。經(jīng)過檢查,發(fā)現(xiàn)源碼里底層是有對MultipartFile[]類型的支持的,源碼中有個類叫SpringManyMultipartFilesWriter,是專門針對文件數(shù)組類型進行操作的,但是配置到項目里的SpringFormEncoder類里卻沒有對文件數(shù)組類型的判斷,以致不能支持文件數(shù)組的上傳

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類構(gòu)造時把SpringManyMultipartFilesWriter實例添加到了處理器列表里了,但是在encode方法里又只判斷了MultipartFile類型,沒有判斷數(shù)組類型,底層有對數(shù)組的支持但上層卻缺少了相應判斷。那么我們可以自己去擴展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();
  }
}

經(jīng)過測試可以上傳多個文件。

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • SpringBoot 統(tǒng)一公共返回類的實現(xiàn)

    SpringBoot 統(tǒng)一公共返回類的實現(xiàn)

    本文主要介紹了SpringBoot 統(tǒng)一公共返回類的實現(xiàn),配置后臺的統(tǒng)一公共返回類,這樣做目的是為了統(tǒng)一返回信息,文中示例代碼介紹的很詳細,感興趣的可以了解一下
    2022-01-01
  • Java中Cron表達式的生成解析及計算的工具類完整代碼

    Java中Cron表達式的生成解析及計算的工具類完整代碼

    這篇文章主要給大家介紹了關(guān)于Java中Cron表達式的生成解析及計算工具類的相關(guān)資料,Cron表達式是一個字符串,字符串空格分割,每一個域代表一個含義,一個cron表達式有至少6個,需要的朋友可以參考下
    2023-12-12
  • Java 八道經(jīng)典面試題之鏈表題

    Java 八道經(jīng)典面試題之鏈表題

    本位主要介紹了Java面試中常常遇到的八道經(jīng)典鏈表問題,文中示例代碼介紹的非常詳細,具有一定的參考價值,需要的小伙伴們可以學習一下
    2021-11-11
  • 一文教你搞懂SpringBoot自定義攔截器的思路

    一文教你搞懂SpringBoot自定義攔截器的思路

    在開發(fā)中,都離不開攔截器的使用,比如說在開發(fā)登錄功能時,實現(xiàn)權(quán)限管理功能時等,這篇文章主要帶大家使用SpringBoot梳理自定義攔截器的思路,需要的可以參考一下
    2023-08-08
  • 詳解Spring Cloud Config采用Git存儲時兩種常用的配置策略

    詳解Spring Cloud Config采用Git存儲時兩種常用的配置策略

    這篇文章主要介紹了詳解Spring Cloud Config采用Git存儲時兩種常用的配置策略,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-07-07
  • Java兩個乒乓球隊比賽名單問題(判斷素數(shù))

    Java兩個乒乓球隊比賽名單問題(判斷素數(shù))

    兩個乒乓球隊進行比賽,各出三人。甲隊為a,b,c三人,乙隊為x,y,z三人。已抽簽決定比賽名單。有人向隊員打聽比賽的名單。a說他不和x比,c說他不和x,z比,請編程序找出三隊賽手的名單
    2017-02-02
  • SpringBoot自定義FailureAnalyzer過程解析

    SpringBoot自定義FailureAnalyzer過程解析

    這篇文章主要介紹了SpringBoot自定義FailureAnalyzer,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-11-11
  • Java并發(fā)多線程編程之CountDownLatch的用法

    Java并發(fā)多線程編程之CountDownLatch的用法

    這篇文章主要介紹了Java并發(fā)多線程編程之CountDownLatch的用法,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • 淺析java 循序與二元搜索算法

    淺析java 循序與二元搜索算法

    這篇文章主要簡單介紹了java 循序與二元搜索算法,需要的朋友可以參考下
    2015-02-02
  • mybatis 集合嵌套查詢和集合嵌套結(jié)果的區(qū)別說明

    mybatis 集合嵌套查詢和集合嵌套結(jié)果的區(qū)別說明

    這篇文章主要介紹了mybatis 集合嵌套查詢和集合嵌套結(jié)果的區(qū)別說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09

最新評論

巴青县| 永川市| 临夏县| 天气| 安徽省| 阿克| 蛟河市| 蓬莱市| 治多县| 沁水县| 承德市| 固阳县| 原平市| 万荣县| 张家口市| 江北区| 岳普湖县| 靖边县| 临沧市| 香河县| 广南县| 江西省| 高碑店市| 绥江县| 比如县| 囊谦县| 贵州省| 苏州市| 房产| 汨罗市| 喀什市| 武义县| 阿拉尔市| 金沙县| 桃园县| 天柱县| 林甸县| 新泰市| 吉林市| 芦溪县| 定日县|