Solon詳解(六)- 定製業務級別的驗證註解

劉之西東發表於2020-08-23

Solon詳解系列文章:
Solon詳解(一)- 快速入門
Solon詳解(二)- Solon的核心
Solon詳解(三)- Solon的web開發
Solon詳解(四)- Solon的事務傳播機制
Solon詳解(五)- Solon擴充套件機制之Solon Plugin
Solon詳解(六)- 定製業務級別的驗證註解

在業務的實現過程中,尤其是對外介面開發,我們需要對請求進行大量的驗證並返回錯誤狀態碼和描述。lombok 框架有很多很讚的註解,但是人家是throw一個異常,這與有些需求不一定能匹配。

該文將基於Solon的一些擴充套件基礎,簡單的實現一套定製的業務驗證機制。效果如下:


@XController
public class UserController extends VerifyController{
    @RepeatSubmit  //重複提交驗證
    @Whitelist     //IP白名單驗證
    @NotNull({"name", "mobile", "icon", "code"})  //非NULL驗證
    @XMapping("/user/add")
    public void addUser(UserModel user){
        //...
    }
}

一、定製開始

1、先定義一組驗證註解

@Inherited
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface NotNull {
    String[] value();
}

@Inherited
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Whitelist {
}

//... 更多略

2、然後,定義一個驗證用的攔截器

//
//Solon裡的所有攔截器,也都是 XHandler
//
public class VerifyInterceptor implements XHandler {
    @Override
    public void handle(XContext ctx) throws Throwable {
        //獲取上下文中的XAction
        //
        XAction action = ctx.attr("action");
        if (action != null) {
            handle0(ctx, action);
        }
    }

    protected void handle0(XContext ctx, XAction action) throws Throwable {
        //這裡的順序,要與業務的期望順序匹配
      
        //白名單
        checkWhitelist(ctx, action);

        //不能為Null
        checkNotNull(ctx, action);
        
        //...更多略
    }



    protected void checkWhitelist(XContext ctx, XAction action)  throws Throwable{
        if(ctx.getHandled()){
            return;
        }
        
        Whitelist anno = action.method().getAnnotation(Whitelist.class);
        if (anno != null) {
            String ip = IpUtils.getIP(ctx);
            if (WhitelistApi.existsOfServerIp(ip) == false) {
                ctx.setHandled(true);
                ctx.render(UapiCodes.CODE_16);
            }
        }
    }

    protected void checkNotNull(XContext ctx, XAction action)  throws Throwable{
        if(ctx.getHandled()){
            return;
        }
        
        NotNull anno = action.method().getAnnotation(NotNull.class);
        if (anno != null) {
            checkParamsIsOk(ctx, false, anno.value());
        }
    }
}

3、再是,定義一個支援驗證的控制器基類

//
// 建立一個有驗證攔截器的基類;@XBefore 註解是可繼承的...
//
@XBefore({VerifyInterceptor.class})
public class VerifyController {

}

完工了

二、附:關於 XContext 的部分擴充套件屬性

Solon 的上下文物件:XContext,有一組可擴充套件屬性的介面:attr(), attrSet(), attrMap()。用於記錄處理過程中的資料或物件。

以下是框架在執行過程中已記錄的擴充套件屬性:

擴充套件屬性 說明
ctx.attr("controller") 獲取當前控制器
ctx.attr("action") 獲取當前活動
ctx.result 獲取當前活動的執行結果,可用於統一的業務日誌記錄
ctx.attr("error") 獲取當前錯誤
ctx.attr("output") 獲取當前序列化輸出,可用於統一的業務日誌記錄

相關文章