Springboot mini - Solon詳解(六)- Solon的校驗框架使用、定製與擴充套件
阿新 • • 發佈:2020-12-13
> Springboot min -Solon 詳解系列文章:
> [Springboot mini - Solon詳解(一)- 快速入門](https://www.cnblogs.com/noear/p/14115763.html)
> [Springboot mini - Solon詳解(二)- Solon的核心](https://www.cnblogs.com/noear/p/14115817.html)
> [Springboot mini - Solon詳解(三)- Solon的web開發](https://www.cnblogs.com/noear/p/14115846.html)
> [Springboot mini - Solon詳解(四)- Solon的事務傳播機制](https://www.cnblogs.com/noear/p/14119759.html)
> [Springboot mini - Solon詳解(五)- Solon擴充套件機制之Solon Plugin](https://www.cnblogs.com/noear/p/14125526.html)
在業務的實現過程中,尤其是對外介面開發,我們需要對請求進行大量的驗證並返回錯誤狀態碼和描述。lombok 框架有很多很讚的註解,但是人家是throw一個異常,這與有些需求不一定能匹配。
該文將介紹Spring min -Solon的擴充套件驗證框架:`solon.extend.validation` 的使用和擴充套件( `org.noear:solon-web` 已包含)。效果如下:
```java
@Valid
@Controller
public class UserController {
@NoRepeatSubmit //重複提交驗證
@Whitelist //白名單驗證
@NotNull({"name", "mobile", "icon", "code"}) //非NULL驗證
@Numeric({"code"})
@Mapping("/user/add")
public void addUser(String name, @Pattern("^http") String icon, int code, @Pattern("^13\\d{9}$") String mobile){
//...
}
}
```
相較於 Spring 的 Validator 是爭對 Bean,Solon 則是爭對 Context(即http引數)。這點區別非常大,Solon 的設計是在 Action 執行之前對 http 引數進行校驗。
| 註解 | 作用範圍 | 說明 |
| -------- | -------- | -------- |
| Date | 引數 | 校驗註解的引數值為日期格式 |
| DecimalMax(value) | 引數 | 校驗註解的引數值小於等於@ DecimalMax指定的value值 |
| DecimalMin(value) | 引數 | 校驗註解的引數值大於等於@ DecimalMin指定的value值 |
| Email | 引數 | 校驗註解的引數值為電子郵箱格式 |
| Length(min, max) | 引數 | 校驗註解的引數值長度在min和max區間內 |
| Max(value) | 引數 | 校驗註解的引數值小於等於@Max指定的value值 |
| Min(value) | 引數 | 校驗註解的引數值大於等於@Min指定的value值 |
| NoRepeatSubmit | 控制器 或 動作 | 校驗本次請求沒有重複 |
| NotBlank | 動作 或 引數 | 校驗註解的引數值不是空白 |
| NotEmpty | 動作 或 引數 | 校驗註解的引數值不是空 |
| NotNull | 動作 或 引數 | 校驗註解的引數值不是null |
| NotZero | 動作 或 引數 | 校驗註解的引數值不是0 |
| Null | 動作 或 引數 | 校驗註解的引數值是null |
| Numeric | 動作 或 引數 | 校驗註解的引數值為數字格式 |
| Pattern(value) | 引數 | 校驗註解的引數值與指定的正則表示式匹配 |
| Whitelist | 控制器 或 動作 | 校驗本次請求在白名單範圍內 |
| | |
| Valid | 控制器 或 動作 | 為控制器 或 動作啟用驗證能力 |
可作用在 [動作 或 引數] 上的註解,加在動作上時可支援多個引數的校驗。
### 一、定製使用
solon.extend.validation 通過 ValidatorManager,提供了一組定製和擴充套件介面。
#### 1、@NoRepeatSubmit 改為分散式鎖
NoRepeatSubmit 預設使用了本地延時鎖。如果是分散式環境,需要定製為分散式鎖:
```java
public class NoRepeatLockNew implements NoRepeatLock {
@Override
public boolean tryLock(String key, int seconds) {
//使用分散式鎖
//
return LockUtils.tryLock(XWaterAdapter.global().service_name(), key, seconds);
}
}
ValidatorManager.setNoRepeatLock(new NoRepeatLockNew());
```
或者 完全重寫 NoRepeatSubmitValidator,並進行重新註冊
#### 2、@Whitelist 實現驗證
框架層面沒辦法為 Whitelist 提供一個名單庫,所以需要通過一個介面實現完成對接。
```java
public class WhitelistCheckerNew implements WhitelistChecker {
@Override
public boolean check(Whitelist anno, Context ctx) {
String ip = IPUtils.getIP(ctx);
return WaterClient.Whitelist.existsOfServerIp(ip);
}
}
ValidatorManager.setWhitelistChecker(new WhitelistCheckerNew());
```
或者 完全重寫 WhitelistValidator,並進行重新註冊
#### 3、改造校驗輸出
solon.extend.validation 預設輸出 http 400 狀態 + json;嘗試改改去掉 http 400 狀態。
```java
@Configuration
public class Config {
@Bean //Solon 的 @Bean 也支援空函式,為其它提執行申明
public void adapter() {
ValidatorManager.global().onFailure((ctx, ano, rst, message) -> {
ctx.setHandled(true);
if (Utils.isEmpty(message)) {
message = new StringBuilder(100)
.append("@")
.append(ano.annotationType().getSimpleName())
.append(" verification failed")
.toString();
}
ctx.output(message);
return true;
});
}
}
```
### 二、添一個擴充套件註解
#### 1、先定義個校驗註解 @Date
偷懶一下,直接把自帶的扔出來了。只要看著能自己搞就行了:-P
```java
@Target({ElementType.PARAMETER}) //只讓它作用到引數,不管作用在哪,最終都是對Context的校驗
@Retention(RetentionPolicy.RUNTIME)
public @interface Date {
@Note("日期表示式, 預設為:ISO格式") //用Note註解,是為了用時還能看到這個註釋
String value() default "";
String message() default "";
}
```
#### 2、新增 @Date 的校驗器實現類
```java
public class DateValidator implements V