背景

​ Spring Cloud现在已经被越来越多的公司采用了,微服务架构比传统意义上的单服务架构从复杂度上多了很多,出现了很多复杂的场景。比如,我们的产品是个app,支持第三方登录功能,在手机端调用第三方授权接口之后,返回了用户的相关信息,比如open_id,性别,头像等。这些信息我们需要保存在我们服务器上,当时针对头像是应该保存图片的url还是图片本身发生了歧义,在一番讨论之后,得出的结果是,我们需要通过url将图片下载到我们本地,然后调用我们自己的文件微服务中上传功能保存起来。

​ 跨服务之间调用,我们采用的是Feign组件,原生的Feign组件并不支持文件上传,但是如果添加了Feign-Form模块,那么就能上传文件,下面我通过一篇文章来讲述如何通过Feign上传文件,代码已经上传github地址。

说明

个人博客首发: https://Shiyajian.github.io

github项目地址:https://github.com/Shiyajian/examples ,请找spring-cloud/chapter1

本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

工具

  • IDE :IntelliJ IDEA
  • JDK : jdk 8
  • 构建工具:Gradle 4.10.2
  • Spring Cloud 版本:Finchley.SR2 (截止2018-11-25最新的GA版本,基于boot 2.0.6)
  • Spring Boot 版本:2.0.6.RELEASE (截止2018-11-25最新为2.1.0.RELEASE)

此处采用Gradle而没有使用Maven作为依赖构建和管理的工具,主要原因是我们公司目前使用的是Gradle,而且从编译速度,代码可读性和清晰度上都远远优于Maven。

项目结构

​ 本项目分为三个角色,分别如下:

  • eureka-server : 注册中心
  • provider-server: 服务提供者,此处模拟一个文件服务器,提供文件上传功能
  • consumer-server: 服务消费者,此处模拟一个业务服务,需要调用文件上传服务

大致的依赖图如下:

配置并运行

​ 我们首先通过运行感受一下通过Feign上传文件的流程,在整个项目可以完整运行后,我们再参考文章和代码一起分析其中设置,并将其应用到自己的应用中

  • 首先clone项目到本地

    git clone https://github.com/Shiyajian/examples.git
  • 安装并配置Gradle

  • 将项目导入到IDEA中

  • 确认IDEA支持Lombok插件,默认IDEA都支持的,此步骤可忽略

  • 更改IDEA设置,Project Settings(Mac中为Preferences)-> Compiler -> Annoatation Processors -> [√] Enable annotation processing

  • 刷新Gradle,下载依赖并编译

  • 启动注册中心

  • 启动Provider项目

    • 找到 examples/spring-cloud/chapter1/provider/provider-service中的ProviderApplication,运行main方法
    • 刷新注册中心页面,找到服务证明成功
  • 运行Consumer项目中的测试

    • 打开examples/spring-cloud/chapter1/consumer/consumer-server/src/test目录
    • 修改com.shiyajian.examples.consumer.service.impl.ConsumerServiceImplTest类中文件的路径为本机电脑上存在的文件
    • 运行测试方法
    • 方法绿灯结束,在控制台能找到输出为成功

Provider 服务配置说明

Provider服务为上传服务的提供者,这里模拟的是一个文件服务器,通过上面图,我们可以看到项目分为2部分,下面就进行详细解读:

  • provider-api

    这个项目最终打成一个可以被引用的jar包,consumer-server通过引用这个jar包可以通过注入方式引用其中的方法,provider-server也需要引用这个jar包,然后实现其中的逻辑,供consumer-server远程调用。配置api的方法如下:

    • 添加org.springframework.cloud:spring-cloud-starter-openfeign依赖,只需要这一个依赖就够了,里面保存Fegin-Form等依赖。

    • 编写配置类FeignMultipartSupportConfig.java

      public class FeignMultipartSupportConfig {
      
          @Bean
      @Primary
      @Scope("prototype")
      public Encoder multipartFormEncoder(ObjectFactory<HttpMessageConverters> messageConverters) {
      return new FeignSpringFormEncoder(new SpringEncoder(messageConverters));
      } }
    • 编写自定义的Encoder,因为这个有个设计得BUG,本身可以解析文件数组,但是代码缺少对应的判断,此处参考文章:https://blog.csdn.net/tony_lu229/article/details/73823757,代码不贴了,详细见工程

    • 定义自己的接口,这里我定义的是ProviderClient,代码简单如下:

      @FeignClient(value = "provider-server", configuration = FeignMultipartSupportConfig.class)
      public interface ProviderClient { @PostMapping(value = "client/upload/{id}", consumes = MULTIPART_FORM_DATA_VALUE)
      String uploadFile(@RequestPart("file") MultipartFile file,
      @PathVariable("id") String id,
      @RequestParam("name") String name); @PostMapping(value = "client/uploads", consumes = MULTIPART_FORM_DATA_VALUE)
      List<ProviderResponse> uploadFiles(@RequestPart("files") MultipartFile[] files, @RequestParam("author") String author); }

      这个接口定义时候需要有以下注意的几点:

      • @FeignClient中的value,对应的是服务实现类在eureka中注册的名字,也就是spring.application.name的值
      • configuration必须配置,就是咱们上面添加的两个类,用来编解码使用
      • 方法可以使用类似Controller中的一些注解,比如方法上可以加@RequestMapping,@PostMapping等,类上面不可以加,我试的时候,在class上加了@RequestMapping之后报错,项目启动时候显示Url报错,其实,也完全不需要加
      • 接受文件的时候,必须是@RequestPart注解,我曾经看有文章说,@RequestPart和@RequestParam通用,但是我自己测试并不是这样
      • consumes对应请求的contentType,必须为:multipart/form-data,此处使用了静态导包。
      • 在传统Controller中,我本身会经常简写@RequestParam,忽略他的value字段。但是Feign接口中不行,如果这些注解没有括号中的value那么就会报错
      • 不支持@RequestBody注解
    • provider-server

      这个项目是最后实际提供服务的项目,所以必须实现provider-api接口中的方法,并且注册到eureka服务中。

      • 添加对feign的依赖,添加api项目的依赖,其他依赖略

        compile project(":provider-api")
        "org.springframework.cloud:spring-cloud-starter-feign:$feignVersion"
      • 实现provider-api中ProviderClient接口,生成实现类,并编写业务代码,需要注意两点

        • 因为父级已经在方法上增加了@PostMapping,此处可以省略
        • 如果是通过IDEA快生成的实现类,那么参数前面的@RequestPart、@RequestParam的注解需要加上,不然报错
    • consumer-server

      这个项目是消费对方提供服务的项目,需要做的也比较简单。

      • 添加provider-api的项目依赖,正式环境下,两个项目可能是不同组开发的,所以需要引入jar包,而不是直接编译此工程,这里仅做展示使用

        compile project(":provider-api")
      • 在启动类上增加注解,扫描添加Feign功能对应的包

        @SpringCloudApplication
        // 这个注解非常重要,不然引用不到client中的方法
        @EnableFeignClients("com.shiyajian.examples.provider")
        public class ConsumerApplication {
        public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class);
        }
        }
      • 在需要的地方通过@Autowird方式注入,然后就可以进行调用了

        @Autowired
        ProviderClient providerClient;
        ……
        providerClient.dosomething();
        ……

    总结

    ​ 整个通过Feign-Form上传文件的案例就写完了,第一次写博客,写的不好还望见谅,如果文章解释的不够清楚,可以参考我的项目中的代码,代码上可能会更清晰点,代码我已经测试通过的,可以放心使用。文章中如果有写错误的地方还望各位指正,当然,如果有什么好的建议也可以给我评论和留言,如果你还其他关于java方面的教程和示例代码你也可以告诉我,我如果不忙的时候,我就会写出来。

    意外

    ​ 在发文章之前又做了一次测试,这次测试没有通过,通过调查发现,Eureka中项目的注册地址变成了:MacBook-Pro.local:provider-server:8100,然后调用时候就发生url错误,请求fe80:0:0:0:***:8100这个地址,等重新联网之后再次启动,注册地址就变成 192.168.1.101这种地址。

      文章发布在github上没有问题,在园子里面出现了格式BUG,调了好长时间没调好, 就先这样将就着看吧。猜测原因是小标题后面带个代码块样式就被顶跑了,但是不知道怎么处理,刚开始用Markdown,以后再研究吧,见谅见谅。

    其他

    ​ QQ群:757696438是我的个人好友群,目前也就30来个人,主要就是吹牛侃大山,顺便学习技术共同进步。欢迎各种浪的飞起、闷骚到爆的同志来玩,但是不欢迎装逼的。

Spring Cloud下使用Feign Form实现微服务之间的文件上传的更多相关文章

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

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

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

    需求场景: 微服务之间调用接口一次性上传多个文件. 上传文件的同时附带其他参数. 多个文件能有效的区分开,以便进行不同处理. Spring cloud的微服务之间接口调用使用Feign.原装的Feig ...

  3. spring cloud深入学习(一)-----什么是微服务?什么是rpc?spring cloud简介

    近年来,微服务非常的流行,那么为什么是它?简单介绍一下. 为什么是微服务? 微服务架构是一种将单应用程序作为一套小型服务开发的方法,每种应用程序都在其自己的进程中运行,并与轻量级机制(通常是HTTP资 ...

  4. spring cloud: zuul(四): 正则表达式匹配其他微服务(给其他微服务加版本号)

    spring cloud: zuul(四): 正则表达式匹配其他微服务(给其他微服务加版本号) 比如我原来有,spring-boot-user微服务,后台进行迭代更新,另外其了一个微服务: sprin ...

  5. 使用ajax提交form表单,包括ajax文件上传 转http://www.cnblogs.com/zhuxiaojie/p/4783939.html

    使用ajax提交form表单,包括ajax文件上传 前言 使用ajax请求数据,很多人都会,比如说: $.post(path,{data:data},function(data){ ... },&qu ...

  6. 使用ajax提交form表单,包括ajax文件上传【转载】

    [使用ajax提交form表单,包括ajax文件上传] 前言 转载:作者:https://www.cnblogs.com/zhuxiaojie/p/4783939.html 使用ajax请求数据,很多 ...

  7. Java后台使用httpclient入门HttpPost请求(form表单提交,File文件上传和传输Json数据)

    一.HttpClient 简介 HttpClient 是 Apache Jakarta Common 下的子项目,用来提供高效的.最新的.功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 ...

  8. 使用ajax提交form表单,包括ajax文件上传

    前言 使用ajax请求数据,很多人都会,比如说: $.post(path,{data:data},function(data){ ... },"json"); 又或者是这样的aja ...

  9. html form一点基础知识,实现文件上传

    form用于提交文件需要修改其entype属性. enctype属性:规定在发送表单数据之前如何对其进行编码. 默认情况,enctype的编码格式是application/x-www-form-url ...

随机推荐

  1. selenium如何获取已定位元素的属性值?

    HTML源代码: <div class="res-status" data-fortune="5" data-selfsos="" d ...

  2. JVM类加载(3)—初始化

    3.初始化 在准备阶段,变量已经赋过一次系统要求的初始值,而在初始化阶段,则根据程序员通过程序制定的主观计划去初始化类变量(静态变量)和其他资源,或者从另外一个角度表达:初始化过程是执行类构造器< ...

  3. mybatis 学习一 总体概述

    mybatis使用起来不复杂,大体上来说,就是将db连接信息,所有的sql语句信息,都放到配置文件里面,然后去读配置信息,根据db信息,创建好session工厂,然后拿到sqlsession回话之后, ...

  4. [bzoj2038]莫队算法学习

    解题关键:莫队最重要的是区间之间以$O(1)$的复杂度进行转化,由于电脑原因,后续补上公式推导. #include<cstdio> #include<cstring> #inc ...

  5. 基本算法思想之穷举法(C++语言描述)

    穷举算法(Exhaustive Attack method)是最简单的一种算法,其依赖于计算机的强大计算能力来穷尽每一种可能性,从而达到求解问题的目的.穷举算法效率不高,但是适应于一些没有规律可循的场 ...

  6. Static与Const的区别

    static static局部变量 将一个变量声明为函数的局部变量,那么这个局部变量在函数执行完成之后不会被释放,而是继续保留在内存中 static 全局变量 表示一个变量在当前文件的全局内可访问 s ...

  7. JSK 糟糕的bug

    传送门 题目居然复制不了(QAQ) 分析 TrieJSK已经2比较详细了,就不再单独写博客了,此题相较于Trie模板有一点不同,此题要求比较前缀却没有规定前面是后面的前缀还是后面是前面的前缀,所以我们 ...

  8. IOHelper(自制常用的输入输出的帮助类)

    常用的读写文件,和地址转换(win和linux均支持),操作文件再也不是拼接那么的low了 using System; using System.Diagnostics; using System.I ...

  9. 图像标注工具labelImg使用方法

    最近在做打标签的工作,为了与大家参考学习,总结了在windows的环境下,基于anaconda的图像标注工具labellmg的一种使用方法! 1 搭建anaconda 以前写过怎么搭建anaconda ...

  10. JDK源码-java.lang.String

    1.开篇明志 本文来看看String的源码. 2.Java7 API String介绍 String 类代表字符串.Java 程序中的所有字符串字面值(如 “abc” )都作为此类的实例实现. 字符串 ...