(8/8)RPC方法的參數,能用枚舉就請考慮枚舉

▄︻┻┳═一Agenda:html

▄︻┻┳═一(1/8)[代碼整潔之道]你真的會用枚舉嗎?非也!前端

▄︻┻┳═一(2/8)枚舉的錯誤用法 之 方法參數web

▄︻┻┳═一(3/8)枚舉的錯誤用法 之 方法參數(二)後端

▄︻┻┳═一(4/8)枚舉的錯誤用法 之 方法返回值安全

▄︻┻┳═一(5/8)枚舉的錯誤用法 之 方法體內部app

▄︻┻┳═一(6/8)枚舉的錯誤用法 之 分支判斷框架

▄︻┻┳═一(7/8)藉助枚舉說一下數據類型定義規範前後端分離

▄︻┻┳═一(8/8)RPC方法的參數,能用枚舉就請考慮枚舉socket


 

咱們都知道,在作後臺管理系統開發時,不少功能的管理頁都有一堆查詢條件,用來篩選業務數據記錄。其中,最多見的一個,當屬業務數據的狀態了。好比,用戶狀態、企業狀態、任務狀態,每人都能從本身的系統裏找出一大堆。ide

先問你們一個問題:對於一些列表頁,查詢所有狀態的數據,你給服務端接口傳的狀態值是什麼?

不用說,你們通常會傳:"0" 或者 "ALL"  或者 空串。

 

【言歸正傳】

咱們是ToB的系統。

 

 

 如上圖,在企業管理頁,有一個篩選條件是product,意爲企業所開通的業務產品,好比機票、酒店、保險。程序common包裏定義了ProductEnum。

public enum ProductEnum {
    AirTicket("AIRTICKET","機票"),
    Hotel("HOTEL","酒店"),
    Insurance("INSURANCE","保險"),
    ;
    
    ...
}

 

網站採用的是先後端分離,後端經過rpc調用dubbo接口。任務分工方面,其中一同窗寫dubbo服務;另外一同窗寫頁面先後端,調用dubbo服務獲取數據。

我在codereview時,發現獲取企業數據的dubbo服務接口EnterpriseService是以下定義的:

public interface EnterpriseService {

    /**
     * 獲取企業分頁數據
     * @param pageNo
     * @param pageSize
     * @param vo
     * @param product 業務線
     * @return
     */
    Result getPage(int pageNo, int pageSize, EnterpriseVO vo,String product);
}

其中,product參數是String。

web端呢,直接獲取頁面vo,而後調用這個dubbo接口

    @GetMapping(value = "/list")
    public Result<?> queryPageList(EnterpriseVO enterprise,
                                   @RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
                                   @RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
                                   HttpServletRequest req) {
        long start = System.currentTimeMillis();
        try {
            log.info("企業管理查詢開始>>>>>>>>");
            String product;
            if(StringUtils.isEmpty(enterprise.getProduct())){
                product = "";
            }else{
                product = enterprise.getProduct();
            }
            return enterpriseService.getPage(pageNo, pageSize ,enterprise,product);
        } finally {
            log.info("查詢企業列表,耗時={}",System.currentTimeMillis()-start);
        }
    }
View Code

 

個人直覺是,product參數爲何不用ProductEnum來限定呢。而後,再看接口實現類,發現這個getPage方法裏直接將product參數賦值給了pojo。而後就調用o/rm框架的query方法了。

 

當前端頁面查詢全部product的企業時,頁面傳的值,不論是"0" 或者 "ALL"  或者 空串,都會導致查的數據有誤呀。

 

終於,墨菲定律又奏效了!在QA測試的時候,bug暴露出來了。

 

【重構後的代碼】

dubbo接口——EnterpriseService.getPage

Result getPage(int pageNo, int pageSize, EnterpriseVO vo,@Nullable ProductEnum product);

 

web服務端——EnterpriseController.queryPageList

    @GetMapping(value = "/list")
    public Result<?> queryPageList(EnterpriseVO enterprise,
                                   @RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
                                   @RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
                                   HttpServletRequest req) {
        long start = System.currentTimeMillis();
        try {
            log.info("企業管理查詢開始>>>>>>>>");
            if (StringUtils.isEmpty(enterprise.getProduct())) {
                return enterpriseService.getPage(pageNo, pageSize, enterprise, null);
            } else {
                ProductEnum productEnum = ProductEnum.getBean(enterprise.getProduct());
                return enterpriseService.getPage(pageNo, pageSize, enterprise, productEnum);
            }
        } finally {
            log.info("查詢企業列表,分頁列表查詢,查詢企業數據,耗時={}",System.currentTimeMillis()-start);
        }
    }
View Code

 

【總結】

咱們能夠看到,當product改爲枚舉類型ProductEnum以後,就限定了調用方只能傳特定的枚舉值。不像String那樣開放,就像我前文闡述的,靈活自由每每會帶來更多隱患。

再者,你定義了String,調用方不清楚當所有的時候傳什麼,可能就按本身固有的方式來傳值了。在複雜的查詢邏輯裏,這樣的bug並非一測就能測出來的。QA把bug指出來時,就老實修復吧,別說調用你接口的同窗的傳值不對了。因此,給你們一個忠告,寫代碼能不隨意就別隨意。你們好纔是真的好。

 

【題外話】

曾經在作支付系統的出款時,由於咱們起初缺少安全意識,整個出款方法有作異常捕獲,當捕獲到異常後,即會把出款單的付款狀態改成失敗。無獨有偶,碰巧,某個上游支付渠道http接口響應超級慢,頻繁致使socket響應超時。socket超時,並不表明服務方沒有處理完成。因此,可怕的事情出現了,有一批付款單,渠道方是付款成功,我方呢,由於http超時而置爲了付款失敗。而後,商戶得知是付款失敗後,從新發起了出款。。。一夜兩個小時的時間,重複出款金額達到8萬!

以上這種狀況,沒有經歷過的人,也許體會不到咱們當時的五味陳雜。固然,這不是重點,我要說明的是,這種損失,咱們責怪人家接口,是不起任何做用的,反而讓人聽着有推卸之嫌。打鐵還需自身硬,繡花要得手綿巧,練好基本功很重要!

相關文章
相關標籤/搜索