spring cloud实战与思考(二) 微服务之间通过fiegn上传多个文件1

需求场景:

  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”,不能用于区分文件。看来只能通过对文件原始名称进行约定来区分文件。但是如果这些文件是用户上传的,这就要求用户上传文件前对文件名称按照约定修改。显然这种接口方式对用户很不友好。限于篇幅,下一篇微博来探讨一下这个问题的解决方法。

原文地址:https://www.cnblogs.com/standup/p/9090113.html

时间: 2024-09-29 05:53:03

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

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

需求场景: 用户调用微服务1的接口上传一组图片和对应的描述信息.微服务1处理后,再将这组图片上传给微服务2进行处理.各个微服务能区分开不同的图片进行不同处理. 上一篇博客已经讨论了在微服务之间传递一组图片和对应参数的解决方案.现在来看看如何对组内文件进行区分.当前项目中使用了"commons-fileupload"和"feign-form"两个库进行文件传输. "commons-fileupload"库可以将http request转换成&quo

Spring Cloud(Dalston.SR5)--Zuul 网关-微服务集群

通过 url 映射的方式来实现 zuul 的转发有局限性,比如每增加一个服务就需要配置一条内容,另外后端的服务如果是动态来提供,就不能采用这种方案来配置了.实际上在实现微服务架构时,服务名与服务实例地址的关系在 eureka server 中已经存在了,所以只需要将Zuul注册到 eureka server上去发现其他服务,就可以实现对 serviceId 的映射,并且启用了 eureka server 同时也会启用 ribbon 对服务进行负载均衡调用,加入 Zuul 到微服务集群架构图如下:

spring cloud实战与思考(一) spring config全局配置方案设计

"spring cloud"的配置中心工具"spring cloud config"提供了分布式系统配置文件集中管理解决方案.该工具功能强大,实现也很简单.网上可以搜索到很多开发教程和用例.本文并不是分享"spring cloud config"的开发方法,而是想聊一聊它的使用. 任何一个工具不管多么强大和便利,如果用的不好,也达不到期望的效果.拿到"spring cloud config"后,我期望基于这个工具构建的配置文件

关于Spring Cloud大型互联网分布式企业微服务云架构

第一篇文章简单给大家介绍了Spring Cloud架构,我这边结合了当前大部分企业的通用需求,包括技术的选型比较严格.苛刻,不仅要用业界最流行的技术,还要和国际接轨,在未来的5~10年内不能out.作为公司的架构师,也要有一种放眼世界的眼光,不仅要给公司做好的技术选型,而且还要快速响应企业的业务需求,能够为企业快速定制化业务.以下是我为公司规划的大型互联网分布式企业微服务云架构:欢迎大家和我一同来搭建大型互联网分布式企业微服务云架构,我会把搭建架构的详细步骤记录下来,作为以后大家学习参考的资料,

SpringCloud(10)使用Spring Cloud OAuth2和JWT保护微服务

采用Spring Security AOuth2 和 JWT 的方式,避免每次请求都需要远程调度 Uaa 服务.采用Spring Security OAuth2 和 JWT 的方式,Uaa 服务只验证一次,返回JWT.返回的 JWT 包含了用户的所有信息,包括权限信息. 1.什么是JWT? JSON Web Token(JWT)是一种开放的标准(RFC 7519),JWT定义了一种紧凑且自包含的标准,该标准旨在将各个主体的信息包装为 JSON 对象.主体信息是通过数字签名进行加密和验证的.常使用

用Spring Cloud OAuth2和JWT保护微服务

采用Spring Security AOuth2 和 JWT 的方式,避免每次请求都需要远程调度 Uaa 服务.采用Spring Security OAuth2 和 JWT 的方式,Uaa 服务只验证一次,返回JWT.返回的 JWT 包含了用户的所有信息,包括权限信息. 1.什么是JWT?# JSON Web Token(JWT)是一种开放的标准(RFC 7519),JWT定义了一种紧凑且自包含的标准,该标准旨在将各个主体的信息包装为 JSON 对象.主体信息是通过数字签名进行加密和验证的.常使

Spring Cloud Alibaba 初体验(二) Nacos 服务注册与发现

一.服务注册 添加依赖: <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> <version>2.2.0.RELEASE</version> <type>pom.sha256</type> </depend

3.开始使用Spring Cloud实战微服务

                 开始使用Spring Cloud实战微服务 3.1. Spring Cloud实战前提 3.1.1. 需要的技术储备 3.1.2. 使用的工具及软件版本 3.2. 服务提供者与服务消费者 3.3. 编写服务提供者 3.3.1. 手动编写项目 3.3.2. 使用Spring Initializr快速创建Spring Boot项目 3.4. 编写服务消费者 3.5. 为项目整合Spring Boot Actuator 3.6. 硬编码有哪些问题 原文地址:https

Spring Cloud实战之初级入门(四)— 利用Hystrix实现服务熔断与服务监控

目录 1.环境介绍 2.服务监控 2.1 加入依赖 2.2 修改配置文件 2.3 修改启动文件 2.4 监控服务 2.5 小结 3. 利用hystrix实现消费服务熔断 3.1 加入服务熔断 3.2 测试服务熔断 4. 利用turbine监控所有应用 4.1 创建工程 4.2 修改配置文件 4.3 修改启动文件 4.4 启动 5.一点点重要的事情 1.环境介绍 本篇文章涉及到前面文章的工程,mirco-service-provider.mirco-service-consumer以及需要另外新建