v1.5.3 本版釋出了,本次版本更新新增了較多功能,其中有許多重大更新。
重點更新內容
1. 新增Forest快捷介面
以前版本使用 Forest,必須先定義一個 interface 介面類,這種形式可以滿足大多數情況的場景。 但若想快速存取一個url可能顯得不合時宜。 所以本次更新新增了快捷介面,不用再從定義介面開始了。
它大概長這個樣子:
// Get請求
// 並以 String 型別接受資料
String str = Forest.get("/").executeAsString();
// Post請求
// 並以自定義的 MyResult 型別接受
MyResult myResult = Forest
.post("/")
.execute(MyResult.class);
// 通過 TypeRefernce 參照類傳遞泛型引數
// 就可以將響應資料以帶複雜泛型引數的型別接受了
Result<List<User>> userList = Forest
.post("/")
.execute(new TypeReferenceList<Result<List<User>>>() {});
// 定義各種引數
// 並以 Map 型別接受
Map<String, Object> map = Forest.post("/")
.backend("okhttp3") // 設定後端為 okhttp3
.contentTypeJson() // 設定 Content-Type 頭為 application/json
.host("127.0.0.1") // 設定地址的host為 127.0.0.1
.port(8080) // 設定地址的埠為 8080
.addBody("a", 1) // 新增 Body 項(鍵值對): a, 1
.addBody("b", 2) // 新增 Body 項(鍵值對: b, 2
.maxRetryCount(3) // 設定請求最大重試次數為 3
// 設定 onSuccess 回撥函數
.onSuccess((data, req, res) -> { log.info("success!"); })
// 設定 onError 回撥函數
.onError((ex, req, res) -> { log.info("error!"); })
// 設定請求成功判斷條件回撥函數
.successWhen((req, res) -> res.noException() && res.statusOk())
// 執行並返回Map資料型別物件
.executeAsMap();
2. 請求成功條件/重試條件
2.1 @Success
註解
先要定義 SuccessWhen 介面的實現類
public class TestSuccessWhen implements SuccessWhen {
/**
* 請求成功條件
* @param req Forest請求物件
* @param res Forest響應物件
* @return 是否成功
*/
@Override
public boolean successWhen(ForestRequest req, ForestResponse res) {
// 沒有異常 並且 狀態碼在正常範圍 並且 狀態碼不等於203
// 當然在這裡也可以寫其它條件,比如 通過 res.getData() 或 res.getConent() 獲取業務資料
// 再更具業務資料判斷是否成功
return res.noException() && res.statusOk() && res.statusCode() != 203;
}
}
在Forest請求介面方法上掛上 @Success
註解
@Get("http://localhost:${port}/")
@Success(condition = TestSuccessWhen.class)
String getData();
若呼叫 getData() 後,返回的狀態碼為 203, 就會被認為是請求失敗,如果設定了重試次數大於0,就會去執行重試任務。 若沒有重試次數可用,則進入 onError 請求失敗流程
2.2 使用 @Retry
註解
先定義 RetryWhen 介面實現類
public class TestRetryWhen implements RetryWhen {
/**
* 請求重試條件
* @param request Forest請求物件
* @param response Forest響應物件
* @return 是否重試
*/
@Override
public boolean retryWhen(ForestRequest request, ForestResponse response) {
// 如果響應狀態碼為 203 就進行重試,儘管此時請求是成功的
// 當然在這裡也可以寫其它條件,比如 通過 res.getData() 或 res.getConent() 獲取業務資料
// 再更具業務資料判斷是否進行重試
return response.statusIs(203);
}
}
在Forest請求介面方法上掛上 @Retry
註解
// maxRetryCount 為最大重試次數
// maxRetryInterval 為最大重試時間間隔, 單位為毫秒
// condition 為請求重試條件,即自定義的 RetryWhen 介面實現類
@Get("http://localhost:${port}/")
@Retry(maxRetryCount = "3", maxRetryInterval = "10", condition = TestRetryWhen.class)
String sendData();
若呼叫 sendData() 後,返回的狀態碼為 203, 就會被認為需要重試,如果設定了重試次數大於0,就會去執行重試任務。 若沒有重試次數可用,則進入 onSuccess 請求成功流程
2.3 兩種重試的區別
可能有小夥伴有疑問,既然通過 SuccessWhen 成功條件判斷失敗後也可以觸發重試,那為何還要 RetryWhen 呢?
Forest的重試機制是這樣的:1. 先判定是否成功,失敗的話觸發重試 2. 如果是成功的,則判斷是否符合重試條件,符合的話也觸發重試.
這兩者的區別是:
因為請求失敗而重試的請求,當最後一次重試也是失敗的話,就會進入請求失敗流程(如呼叫 onError)
因為觸發重試條件而重試的請求,此時請求判斷是成功的,所以只要最後一次重試也是成功的,就會進入請求成功流程 (如呼叫 onSuccess)
簡單一句話描述: successWhen失敗就重試,retryWhen即便成功也重試
2.4 OnRetry
回撥函數
不管是哪一種重試方式,只要觸發了請求重試,都會在重試請傳送之前呼叫 OnRetry
回撥函數
可以在攔截器中實現 onRetry 回撥函數
public class TestRetryInterceptor implements Interceptor<Object> {
/**
* 在請重試前呼叫 onRetry 回撥函數
*
* @param request Forest請求物件
* @param response Forest響應物件
*/
@Override
public void onRetry(ForestRequest request, ForestResponse response) {
// 將當前重試次數新增到 Forest 請求物件的附件中
request.addAttachment("retry-interceptor", request.getCurrentRetryCount());
}
}
將實現了 onRetry 方法的攔截器關聯到相關介面上
@BaseRequest(baseURL = "http://localhost:${port}/", interceptor = TestRetryInterceptor.class)
public interface RetryClient {
@Get("/")
@Retry(maxRetryCount = "${0}", maxRetryInterval = "${1}", condition = TestRetryWhen.class)
ForestRequest<String> testRetryRequest(int retryCount, long retryInterval);
@Get("/")
@Retry(maxRetryCount = "${0}", maxRetryInterval = "${1}", condition = TestRetryWhen.class)
String testRetry(int retryCount, long retryInterval, OnSuccess<String> onSuccess);
}
此時 RetryClient 介面下的任意一個方法觸發重試時,都會先呼叫 TestRetryInterceptor 攔截器類的 onRetry 方法。
其它新特性
新增特性:
- feat: Forest快捷介面 (#I4893Q)
- feat: 支援全域性變數動態繫結方法 (#I478N2)
- feat: 支援參照properties的字串模板 (#I3P1QK)
- feat: 支援獲取響應原因短語,即響應狀態文字 (#I4BJVF)
- feat: 自定義組合註解 (#I4BISF)
- feat: 可自定義請求是否成功的條件 (#I4AEMT)
- feat: 可動態設定主機地址和埠號 (#I4AEJ8)
- feat: 自定義重試條件 (#I493N3)
- feat: 新增 OnRetry 回撥函數 (#I493N6)
- feat: 新增
@Headers
註解 (#I4BJQ6) - feat: Forest請求介面繼承規則 (#I4B0N7)
- feat: 自動重定向控制 (#I4B0FM)
- feat: 全域性變數支援動態繫結方法 (#I478N2)
- feat: 在請求紀錄檔中顯示後端框架名稱 (#I4AKTD)
- feat: 新建forest-mock子專案 (#I468JB)
Fix的Bug:
- fix: POST請求中,空Map無法轉成{} JSON字串 (#I455O2)
- fix: 過濾器引數總是為第一個引數 (#I43VV0)
- fix: 自定義請求頭content-type會替換為大寫 (#I46WNW)
- fix: 在Spring專案中如果不設定轉換器就會找不到Converter (#I46FKV)
- fix: Response不帶Content-Type和Content-Encoding頭時無法正常解析 (#I455PO)
- fix: 當請求 302 請求時,Forest 會自動的存取重定向的url,導致 302 的響應頭拿不到 (#I4AF3B)
- fix: SpringSSLKeyStore 在Spring中初始化失敗 fix: 設定有ForestConfiguration引數的轉換器的時候,在springboot中會初始化失敗 (#I4AKT3)
- fix: 在多執行緒環境下使用上傳檔案介面,執行時間長後會報出堆疊溢位的錯誤 (#I37UGY)
- fix: BeanPostProcessor 介面在低版本 springboot 環境下不相容
優化內容:
- opt: 優化 StringUtils 工具類方法
- opt: 優化 URLUtils 工具類方法
程式碼改動:
- add: SpringForestProperties類
- add: 在所有請求註解中(如
@Request
,@Get
)新增 responseEncoding 屬性,用於強制指定響應資料的編碼格式 - add: SpringForestObjectFactory類 add: ForestResponse.isRedirection 方法
- add: ForestResponse.getRedirectionLocation 方法
- add: ForestResponse.redirectionRequest 方法
- add: ForestHeaderMap.clone 方法
- add: ForestQueryMap.clone 方法
- refactor: retryCount屬性不在建議使用
- update: 去掉MethodLifeCycle
- refactor: 修改Forest介面掃描邏輯
- refactor: 將 TypeReference 類改為抽象類
特別鳴謝:
感謝他們參與的貢獻,排名不分先後
- @CHMing
- @ifaxin