需求场景:

  1. 微服务之间调用接口一次性上传多个文件。
  2. 上传文件的同时附带其他参数。
  3. 多个文件能有效的区分开,以便进行不同处理。

  Spring cloud的微服务之间接口调用使用Feign。原装的Feign不支持文件的传输。需要借助“Feign-form”库才行。但是貌似“Feign-form”库(至少是3.0.3版本)只支持单文件上传。在接口中使用多文件参数时会报异常:

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.0.jar:na]
at feign.form.FormEncoder.encode(FormEncoder.java:87) ~[feign-form-3.0.3.jar:3.0.3]
at feign.form.spring.SpringFormEncoder.encode(SpringFormEncoder.java:62) ~[feign-form-spring-3.0.3.jar:3.0.3]
at feign.ReflectiveFeign$BuildEncodedTemplateFromArgs.resolve(ReflectiveFeign.java:351) ~[feign-core-9.5.0.jar:na]
at feign.ReflectiveFeign$BuildTemplateByResolvingArgs.create(ReflectiveFeign.java:213) ~[feign-core-9.5.0.jar:na]
at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:72) ~[feign-core-9.5.0.jar:na]
at feign.ReflectiveFeign$FeignInvocationHandler.invoke(ReflectiveFeign.java:103) ~[feign-core-9.5.0.jar:na]
at com.sun.proxy.$Proxy96.insertWithFiles(Unknown Source) ~[na:na]

  

在网上搜索一番后,参考博客“https://blog.csdn.net/ytzzh0726/article/details/79467843”,将”Feign-form”库中的”SpringFormEncoder”类改动一下,就可以支持多文件的上传。下面是具体实现方法:

微服务提供方Controller接口:

@ResponseBody
@RequestMapping(value="/psts/add/insertWithFiles", method = RequestMethod.POST)
public Object insertWithFiles(@RequestParam("baseInfo") String baseInfo, @RequestPart(value = "files") MultipartFile[] photoFiles) {
}

服务消费方pom引用Feign-form依赖:

<dependency>
<groupId>io.github.openfeign.form</groupId>
<artifactId>feign-form</artifactId>
<version>3.0.3</version>
</dependency>
<dependency>
<groupId>io.github.openfeign.form</groupId>
<artifactId>feign-form-spring</artifactId>
<version>3.0.3</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>

服务消费方声明一个“FeignSpringFormEncoder”类(这个类copy自”SpringFormEncoder”接口):

import feign.RequestTemplate;
import feign.codec.EncodeException;
import feign.codec.Encoder;
import feign.form.ContentType;
import feign.form.FormEncoder;
import feign.form.MultipartFormContentProcessor;
import feign.form.spring.SpringManyMultipartFilesWriter;
import feign.form.spring.SpringSingleMultipartFileWriter;
import org.springframework.web.multipart.MultipartFile; import java.lang.reflect.Type;
import java.util.Collections;
import java.util.Map; public class FeignSpringFormEncoder extends FormEncoder {
public FeignSpringFormEncoder() {
this(new Default());
} public FeignSpringFormEncoder(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);
// } //修改为下面的代码
if (bodyType.equals(MultipartFile.class)) {
MultipartFile file = (MultipartFile) object;
Map<String, Object> 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<String, Object> data = Collections.singletonMap(“files”, object);
super.encode(data, MAP_STRING_WILDCARD, template);
return;
}
}
super.encode(object, bodyType, template);
}
}

将“FeignSpringFormEncoder”作为bean提供给框架,代替“SpringFormEncoder”的“encode()”接口:

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

  以上方案测试可行。到目前为止需求1“多文件上传”和需求2“非文件类型参数上传”都已经满足了。下面来看看怎么对文件数组中的文件进行区分。服务提供方接收到的“MultipartFile”有两个接口“getName()”和“getOriginalFilename()”分别对应文件在http头的“Metadata”名称和文件原始名称。因为使用文件数组上传的功能,前一个名称被固定为“files”,不能用于区分文件。看来只能通过对文件原始名称进行约定来区分文件。但是如果这些文件是用户上传的,这就要求用户上传文件前对文件名称按照约定修改。显然这种接口方式对用户很不友好。限于篇幅,下一篇微博来探讨一下这个问题的解决方法。

spring cloud实战与思考(二) 微服务之间通过fiegn上传一组文件(上)的更多相关文章

  1. spring cloud实战与思考(三) 微服务之间通过fiegn上传一组文件(下)

    需求场景: 用户调用微服务1的接口上传一组图片和对应的描述信息.微服务1处理后,再将这组图片上传给微服务2进行处理.各个微服务能区分开不同的图片进行不同处理. 上一篇博客已经讨论了在微服务之间传递一组 ...

  2. 基于Spring Cloud和Netflix OSS构建微服务,Part 2

    在上一篇文章中,我们已使用Spring Cloud和Netflix OSS中的核心组件,如Eureka.Ribbon和Zuul,部分实现了操作模型(operations model),允许单独部署的微 ...

  3. 今天介绍一下自己的开源项目,一款以spring cloud alibaba为核心的微服务架构项目,为给企业与个人提供一个零开发基础的微服务架构。

    LaoCat-Spring-Cloud-Scaffold 一款以spring cloud alibab 为核心的微服务框架,主要目标为了提升自己的相关技术,也为了给企业与个人提供一个零开发基础的微服务 ...

  4. Spring Cloud(1):微服务简介

    架构的演进: 1.十年前:用户->单一服务器->单一数据库(支持十万级用户) 2.五年前:用户->负载均衡器->多台服务器->缓存集群->主从数据库(支持百万级用户 ...

  5. spring mvc文件上传(单个文件上传|多个文件上传)

    单个文件上传spring mvc 实现文件上传需要引入两个必须的jar包    1.所需jar包:                commons-fileupload-1.3.1.jar       ...

  6. spring boot:单文件上传/多文件上传/表单中多个文件域上传(spring boot 2.3.2)

    一,表单中有多个文件域时如何实现说明和文件的对应? 1,说明和文件对应 文件上传页面中,如果有多个文件域又有多个相对应的文件说明时, 文件和说明如何对应? 我们在表单中给对应的file变量和text变 ...

  7. spring cloud 入门,看一个微服务框架的「五脏六腑」

    Spring Cloud 是一个基于 Spring Boot 实现的微服务框架,它包含了实现微服务架构所需的各种组件. 注:Spring Boot 简单理解就是简化 Spring 项目的搭建.配置.组 ...

  8. spring cloud(学习笔记)微服务启动错误(1)

    今天下午在启动spring cloud微服务的时候,报了这个错误: Error starting ApplicationContext. To display the auto-configurati ...

  9. 基于Spring Cloud和Netflix OSS 构建微服务-Part 1

    前一篇文章<微服务操作模型>中,我们定义了微服务使用的操作模型.这篇文章中,我们将开始使用Spring Cloud和Netflix OSS实现这一模型,包含核心部分:服务发现(Servic ...

随机推荐

  1. C# 消息队列-Microsoft Azure service bus 服务总线

    先决条件 Visual Studio 2015或更高版本.本教程中的示例使用Visual Studio 2015. Azure订阅. 注意 要完成本教程,您需要一个Azure帐户.您可以激活MSDN订 ...

  2. excel函数2

    1截取函数的应用 实例: 2.日期的年周月星期数据处理

  3. DIV中文字换行显示

    居然第一次遇到这种问题,还想了半天到底是怎么回事,为什么明明div设置宽度了,里面的文字超过宽度后居然不换行. (1)word-break属性,可以让浏览器实现在任意位置换行. normal:使用浏览 ...

  4. SAP MM 可以不用创建盘点凭证直接录入盘点结果?

    SAP MM 可以不用创建盘点凭证直接录入盘点结果? 可以.SAP标准功能就支持这么做. 事务代码 MI09 (Enter Count w/o Reference to Document), 输入pl ...

  5. Java实现栈数据结构

    栈(英语:stack)又称为栈或堆叠,是计算机科学中一种特殊的串列形式的抽象数据类型,其特殊之处在于只能允许在链表或数组的一端(称为堆栈顶端指针,英语:top)进行加入数据(英语:push)和输出数据 ...

  6. 20181112-PostgreSQL数据库dmp文件导入(记录一次数据导入)

    20181112-PostgreSQL数据库dmp文件导入 标注:dmp文件导入,场景:多个schema导入 1. 环境准备: postgres集群master节点上,postgres用户执行以下操作 ...

  7. Jenkins自动化部署-----持续交付【转】

    感谢之前带领过我的leader,让我能够知道什么是好的开发方法. 在很早之前就接触过敏捷开发.什么是敏捷开发,简单来说就是让软件可靠地,快速地发布出来的一种开发方法和技巧. 而敏捷开发中有许多的实践, ...

  8. 使用jquery实现选项卡切换效果

    几张简陋的框架效果图 页面加载时: 选项卡操作后: css样式: <style type="text/css"> *{margin:0px;padding:0px;} ...

  9. ubuntu16.04系统深度学习开发环境、常用软件环境(如vscode、wine QQ、 360wifi驱动(第三代暂无))搭建相关资料

    事后补充比较全面的(找对资料真的省一半功夫):https://www.jianshu.com/p/5b708817f5d8?from=groupmessage Ubuntu16.04 + 1080Ti ...

  10. 与非java语言使用RSA加解密遇到的问题:algid parse error, not a sequence

    遇到的问题 在一个与Ruby语言对接的项目中,决定使用RSA算法来作为数据传输的加密与签名算法.但是,在使用Ruby生成后给我的私钥时,却发生了异常:IOException: algid parse ...