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

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

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

具體需求:

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

一、core服務(wù)層接口@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存在以下兩個(gè)屬性:

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

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

兩個(gè)屬性的解釋及參考例子:

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

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

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

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

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

② 屬性consumes: 指定處理請(qǐng)求當(dāng)中的提交內(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它會(huì)將表單的數(shù)據(jù)處理為一條消息,以標(biāo)簽為單元,用分隔符分開(kāi)。既可以上傳鍵值對(duì),也可以上傳文件。當(dāng)上傳的字段是文件時(shí),會(huì)有Content-Type來(lái)表名文件類型;content-disposition,用來(lái)說(shuō)明字段的一些信息;

二、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微服務(wù)間文件上傳(Finchley版本)

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

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]

但是我們可以通過(guò)使用Feign的擴(kuò)展包實(shí)現(xiàn)這個(gè)功能。

一. 示例介紹

服務(wù)名 端口號(hào) 角色
feign_upload_first 8100 feign服務(wù)提供者
feign_upload_second 8101 feign服務(wù)消費(fèi)者

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

二 、單文件上傳

2.1 feign_upload_first服務(wù)提供者

文件上傳的服務(wù)提供者接口比較簡(jiǎn)單,如下所示:

@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服務(wù)消費(fèi)者

增加擴(kuò)展包依賴

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

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

feign遠(yuǎn)程調(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 測(cè)試

使用postman進(jìn)行測(cè)試,可以正常上傳文件

三、多文件上傳

既然單個(gè)文件可以上傳,那么多文件應(yīng)該也沒(méi)問(wèn)題吧,我們對(duì)上面的代碼進(jìn)行修改

3.1 feign_upload_first服務(wù)提供者

文件上傳的服務(wù)提供者接口比較簡(jiǎn)單,如下所示:

@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服務(wù)消費(fèi)者

feign遠(yuǎn)程調(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 測(cè)試

經(jīng)過(guò)測(cè)試發(fā)現(xiàn),無(wú)法上傳多個(gè)文件。經(jīng)過(guò)檢查,發(fā)現(xiàn)源碼里底層是有對(duì)MultipartFile[]類型的支持的,源碼中有個(gè)類叫SpringManyMultipartFilesWriter,是專門針對(duì)文件數(shù)組類型進(jìn)行操作的,但是配置到項(xiàng)目里的SpringFormEncoder類里卻沒(méi)有對(duì)文件數(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)造時(shí)把SpringManyMultipartFilesWriter實(shí)例添加到了處理器列表里了,但是在encode方法里又只判斷了MultipartFile類型,沒(méi)有判斷數(shù)組類型,底層有對(duì)數(shù)組的支持但上層卻缺少了相應(yīng)判斷。那么我們可以自己去擴(kuò)展FormEncoder,仿照SpringFormEncoder源碼,只修改encode方法。

3.3 擴(kuò)展FormEncoder支持多文件上傳

擴(kuò)展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);
  }
}

注冊(cè)配置類

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

經(jīng)過(guò)測(cè)試可以上傳多個(gè)文件。

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

相關(guān)文章

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

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

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

    Java中Cron表達(dá)式的生成解析及計(jì)算的工具類完整代碼

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

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

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

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

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

    詳解Spring Cloud Config采用Git存儲(chǔ)時(shí)兩種常用的配置策略

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

    Java兩個(gè)乒乓球隊(duì)比賽名單問(wèn)題(判斷素?cái)?shù))

    兩個(gè)乒乓球隊(duì)進(jìn)行比賽,各出三人。甲隊(duì)為a,b,c三人,乙隊(duì)為x,y,z三人。已抽簽決定比賽名單。有人向隊(duì)員打聽(tīng)比賽的名單。a說(shuō)他不和x比,c說(shuō)他不和x,z比,請(qǐng)編程序找出三隊(duì)賽手的名單
    2017-02-02
  • SpringBoot自定義FailureAnalyzer過(guò)程解析

    SpringBoot自定義FailureAnalyzer過(guò)程解析

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

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

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

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

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

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

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

最新評(píng)論

克拉玛依市| 保靖县| 巴彦淖尔市| 古浪县| 方正县| 南通市| 静安区| 凌海市| 太谷县| 哈巴河县| 法库县| 安平县| 秀山| 桃园县| 深州市| 曲水县| 荥经县| 峨眉山市| 龙里县| 四会市| 南乐县| 永和县| 元谋县| 鄢陵县| 疏勒县| 依兰县| 仁寿县| 台前县| 庆阳市| 慈溪市| 汉中市| 兖州市| 昔阳县| 沂源县| 龙胜| 新余市| 普兰县| 台州市| 哈密市| 定陶县| 仲巴县|