首页 > 其他分享 >【OpenFeign】【使用问题】OpenFeign 里如何调用 form-data 接口或者 MultipartFile 文件类型参数接口

【OpenFeign】【使用问题】OpenFeign 里如何调用 form-data 接口或者 MultipartFile 文件类型参数接口

时间:2024-01-15 21:34:40浏览次数:27  
标签:return OpenFeign form 接口 file import MultipartFile public String

1  前言

今儿有个需求涉及到文件上传的东西,关键是 OpenFeign 去调用,当然最后底牌我也可以创建普通的 HTTP 请求或者 RestTemplate 自己请求是不是也行,但是本人这个倔驴型性格,偶尔也会跟自己犟犟,就是要用 OpenFeign 把它搞出来。

首先我有两个这样的接口:

// 客户导入接口
@PostMapping(value = "/importCustomer")
public ResultVo<ImportRes> importCustomer(@RequestBody MultipartFile file) {
    ImportRes importRes = customerExcelService.importExcel(file);
    return ResultVo.ok(importRes);
}
// 商品导入接口
@PostMapping(value = "/itemImport")
public ResultVo<ImportRes> importExcel(@ApiParam(name = "file", value = "file", required = true) @RequestBody(value = "file") MultipartFile file,
    @RequestParam(value = "ownOrgSign") String ownOrgSign, @RequestParam(value = "importName",required = false) String importName) {
   // 业务逻辑
    return ResultVo.ok(importRes);
}

我们来看看用 OpenFeign 如何调用。 

2  实现步骤

2.1  引入 SpringFormEncoder

这是我们的关键类,首先双击 shift 搜搜自己的项目里边,有没有这个类 SpringFormEncoder,没有的话去添加一下依赖,引入进来哈。

2.2  新增配置类

import feign.codec.Encoder;
import feign.form.spring.SpringFormEncoder;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.cloud.openfeign.support.SpringEncoder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

/**
 * @author kuku
 */
@Configuration
public class FeignFormConfig {

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

    /**
     * 这里必须要设置 SpringEncoder 为默认的
     * 即 @Primary
     * 因为没有上边的 SpringFormEncoder 默认都是使用 SpringEncoder
     * 当你只引入上边的时候,我发现我别的 feign 调用就会出现错误,
     * 所以两者都引入,SpringEncoder 作为主的
     * @param messageConverters
     * @return
     */
    @Bean
    @Primary
    public Encoder springEncoder(ObjectFactory<HttpMessageConverters> messageConverters) {
        return new SpringEncoder(messageConverters);
    }
} 

2.3  @FeignClient 中设置配置类

将上边的 FeignFormConfig 配置,设置进 @FeignClient:

/**
 * @author kuku
 */
@FeignClient(name = "${feign.provider.channel-manage:channel-manage}"
        , path = "/channel-manage"
        , configuration = FeignFormConfig.class
        , contextId = "channelManagerFeignService")
public interface OaChannelFeignService {

    @PostMapping(value= "/import/importCustomer", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    ResultVo<ImportRes> importCustomer(MultipartFile file);
}
/**
 * @author kuku
 */
@FeignClient(name = "${feign.provider.channel-manage:items-manage}"
        , path = "/items"
        , configuration = FeignFormConfig.class
        , contextId = "itemsManagerFeignService")
public interface OaItemFeignService {

    @PostMapping(value= "/import/itemImport", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    ResultVo<ImportRes> importItem(@RequestParam("ownOrgSign") String ownOrgSign,
                                   @RequestParam("importName") String importName,
                                   MultipartFile file);

}

我的 Adapter,这个因项目而异,我们的 feign 调用前边都会加一层 Adapter:

@Component
public class OaAdapter {

    @Autowired
    private OaChannelFeignService oaChannelFeignService;

    @Autowired
    private OaItemFeignService oaItemFeignService;

    public ImportRes importCustomer(MultipartFile file) {
        ResultVo<ImportRes> resultVo = oaChannelFeignService.importCustomer(file);
        AppResultDtoUtil.parse(resultVo);
        return resultVo.getData();
    }public ImportRes importItem(String ownOrgSign, String importName, MultipartFile file) {
        ResultVo<ImportRes> resultVo = oaItemFeignService.importItem(ownOrgSign, importName, file);
        AppResultDtoUtil.parse(resultVo);
        return resultVo.getData();
    }
}

2.4  调用

@Slf4j
@Component
public class OaDownloadImportDownStream implements DownStream, IOaReceiveSync<YTOaSyncReqDto, ImportRes>  {
    @Autowired
    private OaAdapter oaAdapter;

    @Override
    public ImportRes execute(OaSyncReqDto reqDto) {
        String importType = reqDto.getImportType();
        String fileUrl = reqDto.getFileUrl();
        ConditionUtil.mustNotBlank(fileUrl, "fileUrl文件路径不能为空");
        ConditionUtil.mustNotBlank(importType, "importType导入类型不能为空");

        // 下载附件
        File file = null;
        ImportRes res = null;
        try {
            file = File.createTempFile("random", ".xlsx");
            HttpUtil.downloadFile(fileUrl, file);

            DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
            String contentType = new MimetypesFileTypeMap().getContentType(file);
            // 这里切记要写死 file
            FileItem fileItem = diskFileItemFactory.createItem("file", contentType, false, file.getName());
            try (
                    InputStream inputStream = new ByteArrayInputStream(FileCopyUtils.copyToByteArray(file));
                    OutputStream outputStream = fileItem.getOutputStream()
            ) {
                FileCopyUtils.copy(inputStream, outputStream);
            } catch (Exception e) {
                throw e;
            }
            // 包装成 MultipartFile
            MultipartFile multipartFile = new CommonsMultipartFile(fileItem);

            // 根据类型调用导入
            switch (importType) {
                case "item" : {
                    res = oaAdapter.importItem("123", "save", multipartFile);
                }; break;
                case "customer" : {
                    res = oaAdapter.importCustomer(multipartFile);
                }; break;
                default: {
                    throw new AppException("未知importType=" + importType + "当前导入类型未接入");
                }
            }

            // todo分析下导入结果
            System.out.println(res);
        } catch (IOException e) {
            log.error("", e);
            throw new Exception(e.getMessage());
        } finally {
            if (Objects.nonNull(file)) {
                try {
                    file.delete();
                } catch (Exception e) {
                    log.error("删除临时文件失败", e);
                }
            }
        }
        return res;
    }

    @Override
    public SyncBusinessTypeEnums getBusinessType() {
        return SyncBusinessTypeEnums.OA_DOWNLOAD_IMPORT;
    }

    @Override
    public String getBusinessCode(YTOaSyncReqDto data) {
        return data.getFlowNo();
    }
}

3  小结

好了,到这里,调用就结束了,但是期间还是有很多的疑问,下节我们从源码剖析下原理,

标签:return,OpenFeign,form,接口,file,import,MultipartFile,public,String
From: https://www.cnblogs.com/kukuxjx/p/17966293

相关文章

  • terraform
    Terraform是一种基础设施即代码(InfrastructureasCode,IaC)工具,用于自动化管理和部署云基础设施。它由HashiCorp开发,可用于管理各种云平台,如AWS、Azure、GoogleCloud等,以及各种其他基础设施组件,如Docker、Kubernetes等。 Terraform使用一种类似于编程语言的声明式语法来描述所......
  • FFmpeg之AVFormat
    (目录)一、概述  avformat中实现了目前多媒体领域中的几乎所有封装格式,可以封装,可以解封装(也叫解复用),根据需求不同,所支持的也有所不同,ffmpeg能否支持一种封装格式的视频的封装与解封装,完全取决于这个库,例如mp4、flv、mkv等容器的封装与解封装;又或者RTMP、RTSP、TCP、UDP等协议......
  • openfeign 忽略ssl证书 亲测有效
    请求https接口异常Causedby:javax.net.ssl.SSLHandshakeException:PKIXpathbuildingfailed:sun.security.provider.certpath.SunCertPathBuilderException:unabletofindvalidcertificationpathtorequestedtarget atjava.base/sun.security.ssl.Alert.createSSL......
  • C#中的接口
    接口接口是指一组函数成员而不实现它们的引用类型。只有类是结构体实现接口。例如:namespaceCSharpProject1;interfaceIInfo{stringGetName();intGetAge();}classCA:IInfo{publicstringName;publicintAge;publicstringGetName()......
  • ABAP:接口文档下载
    *&---------------------------------------------------------------------**&ReportZTEST_RFC*&---------------------------------------------------------------------**&*&----------------------------------------------------------------......
  • ICLR 2022: Anomaly Transformer论文阅读笔记(2) 深度解析代码
    AnomalyTransformer是一个由Transformer:AttentionIsAllYouNeed启发出的检测时间序列异常点的无监督学习算法。在这一篇我会深度解析论文算法以及代码的一一对应,让人更方便能读懂和使用源代码。阅读笔记前篇:ICLR2022:AnomalyTransformer论文阅读笔记+代码复现阅读前提......
  • 自定义注解实现接口入参字段校验
    使用的类javax.validation导入的包<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId><version>xxxx.RELEASE</version></dependency>通过springb......
  • java Flink 校验接口数据
    要使用Java编写Flink程序来校验接口的数据,可以按照以下步骤进行操作。首先,需要引入相关依赖包。在pom.xml文件中添加如下依赖项:org.apache.flinkflink-streaming-java_2.12{FLINK版本号}其中{FLINK版本号}应该被替换为所使用的Flink版本号。创建一个新的Java类,并导入必要......
  • mvc5接口报错:The JSON request was too large to be deserialized的一种原因
    是mvc5版本的接口,接口使用了dynamic接收数组,json对象数组只有56个,length长度不到10万,但是提交就报TheJSONrequestwastoolargetobedeserialized这个错。在.netcore中,dynamic是不需要前端把字段用stringfy序列化为字符串的就能处理的。但是mvc5如果不在前端把dynamic接收......
  • 软件测试(功能、接口、性能、自动化)详解
    软件测试(功能、接口、性能、自动化)详解前言:软件测试是软件开发过程中不可或缺的重要环节,它用于验证软件的质量、可靠性和性能是否符合预期。软件测试涵盖了多个方面,包括功能测试、接口测试、性能测试和自动化测试。一、软件测试功能测试测试用例编写是软件测试的基本技能;也......