背景
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,下載依賴並編譯
-
啟動注冊中心
- 找到 examples/spring-cloud/eureka-server中的EurekaApplication,運行main方法
- 打開瀏覽器,運行:http://localhost:8761/,能打開證明成功
-
啟動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來個人,主要就是吹牛侃大山,順便學習技術共同進步。歡迎各種浪的飛起、悶騷到爆的同志來玩,但是不歡迎裝逼的。
-