Springboot mini - Solon详解(六)- Solon的校验框架使用、定制与扩展
Springboot min -Solon 详解系列文章:
Springboot mini - Solon详解(一)- 快速入门
Springboot mini - Solon详解(二)- Solon的核心
Springboot mini - Solon详解(三)- Solon的web开发
Springboot mini - Solon详解(四)- Solon的事务传播机制
Springboot mini - Solon详解(五)- Solon扩展机制之Solon Plugin
在业务的实现过程中,尤其是对外接口开发,我们需要对请求进行大量的验证并返回错误状态码和描述。lombok 框架有很多很赞的注解,但是人家是throw一个异常,这与有些需求不一定能匹配。
该文将介绍Spring min -Solon的扩展验证框架:solon.extend.validation 的使用和扩展( org.noear:solon-web 已包含)。效果如下:
@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值 |
| 参数 | 校验注解的参数值为电子邮箱格式 | |
| 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 默认使用了本地延时锁。如果是分布式环境,需要定制为分布式锁:
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 提供一个名单库,所以需要通过一个接口实现完成对接。
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 状态。
@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
@Target({ElementType.PARAMETER}) //只让它作用到参数,不管作用在哪,最终都是对Context的校验
@Retention(RetentionPolicy.RUNTIME)
public @interface Date {
@Note("日期表达式, 默认为:ISO格式") //用Note注解,是为了用时还能看到这个注释
String value() default "";
String message() default "";
}
2、添加 @Date 的校验器实现类
public class DateValidator implements Validator<Date> {
public static final DateValidator instance = new DateValidator();
@Override
public String message(Date anno) {
return anno.message();
}
@Override
public Result validate(Context ctx, Date anno, String name, StringBuilder tmp) {
String val = ctx.param(name);
if (val == null || tryParse(anno, val) == false) {
tmp.append(',').append(name);
}
if (tmp.length() > 1) {
return Result.failure(tmp.substring(1));
} else {
return Result.succeed();
}
}
private boolean tryParse(Date anno, String val) {
try {
if (Utils.isEmpty(anno.value())) {
DateTimeFormatter.ISO_LOCAL_DATE_TIME.parse(val);
} else {
DateTimeFormatter.ofPattern(anno.value()).parse(val);
}
return true;
} catch (Exception ex) {
return false;
}
}
}
3、注册到校验管理器
@Configuration
public class Config {
@Bean
public void adapter() {
//
// 此处为注册验证器。如果有些验证器重写了,也是在此处注册
//
ValidatorManager.global().register(Date.class, DateValidator.instance);
}
}
4、使用一下
@Valid
@Controller
public class UserController extends VerifyController{
@Mapping("/user/add")
public void addUser(String name, @Date("yyyy-MM-dd") String birthday){
//...
}
}
附:Solon项目地址
- gitee: https://gitee.com/noear/solon
- github: https://github.com/noear/solon
Springboot mini - Solon详解(六)- Solon的校验框架使用、定制与扩展的更多相关文章
- Solon详解(九)- 渲染控制之定制统一的接口输出
Solon详解系列文章: Solon详解(一)- 快速入门 Solon详解(二)- Solon的核心 Solon详解(三)- Solon的web开发 Solon详解(四)- Solon的事务传播机制 ...
- Solon Web 开发,八、校验、及定制与扩展
Solon Web 开发 一.开始 二.开发知识准备 三.打包与运行 四.请求上下文 五.数据访问.事务与缓存应用 六.过滤器.处理.拦截器 七.视图模板与Mvc注解 八.校验.及定制与扩展 九.跨域 ...
- Solon 框架详解(九)- 渲染控制之定制统一的接口输出
Springboot min -Solon 详解系列文章: Springboot mini - Solon详解(一)- 快速入门 Springboot mini - Solon详解(二)- Solon ...
- Solon详解(十)- 怎么用 Solon 开发基于 undertow jsp tld 的项目?
Solon详解系列文章: Solon详解(一)- 快速入门 Solon详解(二)- Solon的核心 Solon详解(三)- Solon的web开发 Solon详解(四)- Solon的事务传播机制 ...
- Solon详解(11)- Mybatis 与 Solon 相亲相爱
Solon详解系列文章: Solon详解(一)- 快速入门 Solon详解(二)- Solon的核心 Solon详解(三)- Solon的web开发 Solon详解(四)- Solon的事务传播机制 ...
- Springboot mini - Solon详解(四)- Solon的事务传播机制
Springboot min -Solon 详解系列文章: Springboot mini - Solon详解(一)- 快速入门 Springboot mini - Solon详解(二)- Solon ...
- Springboot mini - Solon详解(七)- Solon Ioc 的注解对比Spring及JSR330
Springboot min -Solon 详解系列文章: Springboot mini - Solon详解(一)- 快速入门 Springboot mini - Solon详解(二)- Solon ...
- Springboot mini - Solon详解(八)- Solon的缓存框架使用和定制
Springboot min -Solon 详解系列文章: Springboot mini - Solon详解(一)- 快速入门 Springboot mini - Solon详解(二)- Solon ...
- Springboot mini - Solon详解(二)- Solon的核心
Springboot min -Solon 详解系列文章: Springboot mini - Solon详解(一)- 快速入门 Springboot mini - Solon详解(二)- Solon ...
随机推荐
- JWT鉴权
一.HTTP基本认证 Basic Authentication--当浏览器访问使用基本认证的网站的时候, 浏览器会提示你输入用户名和密码. http auth的过程: 客户端发送http请求 服务器发 ...
- Jmeter 处理接口乱码
第一步:添加 BeanShell Listener 第二步: 设置值 : prev.setDataEncoding("UTF-8") 第三步: 重新跑脚本,看接口返回值
- 信息收集之——旁站、C段
旁站的概念 旁站指的是同一服务器上的其他网站,很多时候,有些网站可能不是那么容易入侵.那么,可以查看该网站所在的服务器上是否还有其他网站.如果有其他网站的话,可以先拿下其他网站的webshell,然 ...
- bWAPP----Mail Header Injection (SMTP)
Mail Header Injection (SMTP) 本地没有搭环境,没法演示,附上转载的 https://www.acunetix.com/blog/articles/email-header- ...
- 如何使用Camtasia给视频或者图片调色
喜欢摄影过着做视频的朋友一定知道,一张好看的照片或者一段精美视频的构成因素很多,取景本身肯定是个很重要的条件,相机的素质是非常重要的硬件条件,接下来的就是后期的编辑和处理了,而在后期处理过程中调色就显 ...
- 怎么用在线思维导图Ayoa规划个人任务
在Ayoa的任务板功能中可以对某一任务进行详细设置,例如改变紧急情况/重要程度.添加到我的计划工具.设置开始日期.截止日期等. 图1:任务详情设置 而这里的"我的计划工具"就是一个 ...
- FL Studio中如何使用插件混杂功能中的琶音器
琶音指一串和弦音从低到高或从高到低依次连续奏出,可视为分解和弦的一种.通常作为一种专门的技巧训练用于练习曲中,有时作为短小的连接句或经过句出现在乐曲旋律声部中.在Trance类型电子音乐中,琶音的运用 ...
- DNS系列—DNS简介
DNS是什么? 如果了解互联网主机之间是用IP地址来进行通信的话,有了这个认识的前提,我们来聊一下什么是DNS.一个IP地址有十几个字符那么长,和手机号码长度差不多,我们怎么记住这些我们想要访问的主机 ...
- Contest 984
A 先手取最大,后手取最小,答案就是第 \(\left\lceil\frac{n}{2}\right\rceil\) 小的数. 用 nth_element 可以做到 \(O\left(n\right) ...
- C语言讲义——链表完整代码
#include <stdio.h> #include <stdlib.h> #include <string.h> struct Node { int _id; ...