Feign之Multipartfile文件傳輸填坑

Multipartfile文件傳輸

1. 添加依賴

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

2. 添加配置類

@Configuration
public class FeignMultipartConfig {
    @Bean
    @Primary
    @Scope("prototype")
    public SpringFormEncoder multipartFormEncoder() {
        return new SpringFormEncoder();
    }
    @Bean
    public feign.Logger.Level multipartLoggerLevel() {
        return feign.Logger.Level.FULL;
    }
}

3. 接口編寫

@FeignClient使用配置類

@PostMapping設置

consumes = MediaType.MULTIPART_FORM_DATA_VALUE

使用@RequestPart(),不能使用@RequestParam()

@FeignClient(value = "face-service",configuration = FeignMultipartConfig.class)
public interface FaceClient {
 @PostMapping(value = "/search/student", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    ResponseBase<SearchStudentFaceVO> searchStudentFace(@RequestPart("file") MultipartFile file);
}

feign不能正常傳遞參數MultipartFile(文件)的解決

之前工作中有個業務場景:需要把文件以MultipartFile進行服務之間的調用(使用的是Feign),特此記錄下踩到的坑

需要註意的是:使用默認的springcloud自帶的spring-cloud-starter-openfeign是不支持傳遞文件的。

我看網上有很多使用feign-form和feign-form-spring支持的jar包,然後配置SpringFormEncoder,但我試瞭,沒有成功,最後使用瞭另外一種方法,在此記錄下吧:

方法一:使用外部依賴

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

新建配置類:

package com.jsyd.ict.ictservicemanager.configuration;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.cloud.openfeign.support.SpringEncoder;
import org.springframework.context.annotation.Bean;
import feign.codec.Encoder;
import feign.form.spring.SpringFormEncoder;
import org.springframework.context.annotation.Configuration;
/**
 * 處制定瞭註入的feignFormEncoder可以覆蓋掉原本的encoder
 * 該方式可以讓發送multipartFile成為可能
 * @author wangyang
 * @version 1.0
 * @date 2021/4/13 19:13
 */
@Configuration
public class MultipartSupportConfig {
    @Autowired
    private ObjectFactory<HttpMessageConverters> messageConverters;
    @Bean
    public Encoder feignFormEncoder() {
        return new SpringFormEncoder(new SpringEncoder(messageConverters));
    }
}

配置feign接口:

package com.jsyd.ict.ictservicemanager.feign;
import com.jsyd.ict.ictservicemanager.util.resp.RespUtil;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.InputStream;
/**
 * 能力的調用
 *
 * @author wangyang
 * @version 1.0
 * @date 2021/3/11 21:01
 */
@FeignClient(name = "ict-service-capacity", configuration = MultipartSupportConfig.class)
public interface CapacityFeign {
    @RequestMapping(value = "contentAudit/baiduImgAuditByFile", method = RequestMethod.POST, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    RespUtil baiduImgAuditByFile(@RequestPart(value = "file") MultipartFile file);
}

註意:文件的傳輸需要使用@RequestPart()註解

服務端:

    @RequestMapping(value = "/baiduImgAuditByFile", method = RequestMethod.POST)
    public RespUtil baiduImgAuditByFile(@RequestParam("file") MultipartFile file)  {
  // 調用service
        return null;
    }

結果發現,這樣是獲取不到結果的,研究瞭好一會,因為要著急聯調,就沒有繼續跟蹤瞭,有時間在深入研究下。

後來使用瞭下面的方法,成功傳參

方法二:使用HttpServletRequest獲取

上述操作都不需要,即:不需要導入依賴,也不需要創建文件,隻需要在服務端通過HttpServletRequest去設置

使用HttpServletRequest設置:

偽代碼如下:

    @RequestMapping(value = "/baiduImgAuditByFile", method = RequestMethod.POST)
    public RespUtil baiduImgAuditByFile(MultipartFile file, HttpServletRequest request) {
        if (file == null) {
            // 解決服務間調用無法接受MultipartFile參數的問題
            String contentType = request.getContentType();
            if (contentType != null && contentType.toLowerCase().startsWith("multipart/")) {
                MultipartHttpServletRequest multipartRequest =
                        WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class);
                if (multipartRequest != null) {
                    MultiValueMap<String, MultipartFile> multiFileMap = multipartRequest.getMultiFileMap();
                    for (Map.Entry<String, List<MultipartFile>> entry : multiFileMap.entrySet()) {
                        file = entry.getValue().get(0);
                    }
                }
            }
        }
        // 處理業務邏輯
        return null;
    }

主要說明如下圖:

即通過HttpServletRequest 的方式即使文件獲取不到,也可以進行特殊處理,從而獲取文件。

以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。

推薦閱讀: