在业务的实现过程中,尤其是对外接口开发,我们需要对请求进行大量的验证并返回错误状态码和描述。在前面的内容中也已经使用过验证机制。

该文将介绍 solon.validation 框架的使用和扩展。效果如下:

//这个注解一定要加类上(或者基类上)
@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, @Validated User user){
//...
}
} @Data
public class User {
@NotNull
private String nickname; @Email
private String email;
}

Solon 的校验框架,可支持Context的参数较验(即请求传入的参数),也可支持实体字段较验。

注解 作用范围 说明
Date 参数 或 字段 校验注解的值为日期格式
DecimalMax(value) 参数 或 字段 校验注解的值小于等于@ DecimalMax指定的value值
DecimalMin(value) 参数 或 字段 校验注解的值大于等于@ DecimalMin指定的value值
Email 参数 或 字段 校验注解的值为电子邮箱格式
Length(min, max) 参数 或 字段 校验注解的值长度在min和max区间内(对字符串有效)
Logined 控制器 或 动作 校验本次请求主体已登录
Max(value) 参数 或 字段 校验注解的值小于等于@Max指定的value值
Min(value) 参数 或 字段 校验注解的值大于等于@Min指定的value值
NoRepeatSubmit 控制器 或 动作 校验本次请求没有重复提交
NotBlacklist 控制器 或 动作 校验本次请求主体不在黑名单
NotBlank 动作 或 参数 或 字段 校验注解的值不是空白
NotEmpty 动作 或 参数 或 字段 校验注解的值不是空
NotNull 动作 或 参数 或 字段 校验注解的值不是null
NotZero 动作 或 参数 或 字段 校验注解的值不是0
Null 动作 或 参数 或 字段 校验注解的值是null
Numeric 动作 或 参数 或 字段 校验注解的值为数字格式
Pattern(value) 参数 或 字段 校验注解的值与指定的正则表达式匹配
Size 参数 或 字段 校验注解的集合大小在min和max区间内(对集合有效)
Whitelist 控制器 或 动作 校验本次请求主体在白名单范围内

可作用在 [动作 或 参数] 上的注解,加在动作上时可支持多个参数的校验。

1、开始定制使用

solon.validation 通过 ValidatorManager,提供了一组定制和扩展接口。

@NoRepeatSubmit 改为分布式锁验证

NoRepeatSubmit 默认使用了本地延时锁。如果是分布式环境,需要定制为分布式锁:

public class NoRepeatSubmitCheckerNew implements NoRepeatSubmitChecker {
@Override
public boolean check(String key, int seconds) {
//使用分布式锁
//
return LockUtils.tryLock(XWaterAdapter.global().service_name(), key, seconds);
}
} ValidatorManager.setNoRepeatSubmitChecker(new NoRepeatSubmitCheckerNew());

或者 完全重写 NoRepeatSubmitValidator,并进行重新注册

@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,并进行重新注册

改造校验输出

solon.validation 默认输出 http 400 状态 + json;尝试改改去掉 http 400 状态。

@Configuration
public class Config {
@Bean //Solon 的 @Bean 也支持空函数,用于一些初始化动作
public void validInit() {
ValidatorManager.setFailureHandler((ctx, ano, rst, message) -> {
ctx.setHandled(true);
ctx.setRendered(true); if (Utils.isEmpty(message)) {
message = new StringBuilder(100)
.append("@")
.append(ano.annotationType().getSimpleName())
.append(" verification failed")
.toString();
} ctx.output(message); return true;
});
}
}

2、尝试添一个扩展注解

先定义个校验注解 @Date

偷懒一下,直接把自带的扔出来了。只要看这过程后,能自己搞就行了:-P

@Target({ElementType.PARAMETER})   //只让它作用到参数,不管作用在哪,最终都是对Context的校验
@Retention(RetentionPolicy.RUNTIME)
public @interface Date {
@Note("日期表达式, 默认为:ISO格式") //用Note注解,是为了用时还能看到这个注释
String value() default ""; String message() default "";
}

添加 @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 validateOfEntity(Class<?> clz, Date anno, String name, Object val0, StringBuilder tmp) {
if (val0 != null && val0 instanceof String == false) {
return Result.failure(clz.getSimpleName() + "." + name);
} String val = (String) val0; if (verify(anno, val) == false) {
return Result.failure(clz.getSimpleName() + "." + name);
} else {
return Result.succeed();
}
} /**
* 校验上下文的参数
* */
@Override
public Result validateOfContext(Context ctx, Date anno, String name, StringBuilder tmp) {
String val = ctx.param(name); if (verify(anno, val) == false) {
return Result.failure(name);
} else {
return Result.succeed();
}
} private boolean verify(Date anno, String val) {
//如果为空,算通过(交由@NotEmpty之类,进一步控制)
if (Utils.isEmpty(val)) {
return true;
} 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;
}
}
}

注册到校验管理器

@Configuration
public class Config {
@Bean
public void adapter() {
//
// 此处为注册验证器。如果有些验证器重写了,也是在此处注册
//
ValidatorManager.register(Date.class, new DateValidator());
}
}

可以使用它了

@Valid
@Controller
public class UserController extends VerifyController{
@Mapping("/user/add")
public void addUser(String name, @Date("yyyy-MM-dd") String birthday){
//...
}
}

Solon Web 开发,八、校验、及定制与扩展的更多相关文章

  1. Solon Web 开发

    Solon Web 开发 一.开始 二.开发知识准备 三.打包与运行 四.请求上下文 五.数据访问.事务与缓存应用 六.过滤器.处理.拦截器 七.视图模板与Mvc注解 八.校验.及定制与扩展 九.跨域 ...

  2. Solon Web 开发,一、开始

    Solon Web 开发 一.开始 二.开发知识准备 三.打包与运行 四.请求上下文 五.数据访问.事务与缓存应用 六.过滤器.处理.拦截器 七.视图模板与Mvc注解 八.校验.及定制与扩展 九.跨域 ...

  3. Solon Web 开发,二、开发知识准备

    Solon Web 开发 一.开始 二.开发知识准备 三.打包与运行 四.请求上下文 五.数据访问.事务与缓存应用 六.过滤器.处理.拦截器 七.视图模板与Mvc注解 八.校验.及定制与扩展 九.跨域 ...

  4. Solon Web 开发,四、请求上下文

    Solon Web 开发 一.开始 二.开发知识准备 三.打包与运行 四.请求上下文 五.数据访问.事务与缓存应用 六.过滤器.处理.拦截器 七.视图模板与Mvc注解 八.校验.及定制与扩展 九.跨域 ...

  5. Solon Web 开发,五、数据访问、事务与缓存应用

    Solon Web 开发 一.开始 二.开发知识准备 三.打包与运行 四.请求上下文 五.数据访问.事务与缓存应用 六.过滤器.处理.拦截器 七.视图模板与Mvc注解 八.校验.及定制与扩展 九.跨域 ...

  6. Solon Web 开发,六、过滤器、处理、拦截器

    Solon Web 开发 一.开始 二.开发知识准备 三.打包与运行 四.请求上下文 五.数据访问.事务与缓存应用 六.过滤器.处理.拦截器 七.视图模板与Mvc注解 八.校验.及定制与扩展 九.跨域 ...

  7. Solon Web 开发,七、视图模板与Mvc注解

    Solon Web 开发 一.开始 二.开发知识准备 三.打包与运行 四.请求上下文 五.数据访问.事务与缓存应用 六.过滤器.处理.拦截器 七.视图模板与Mvc注解 八.校验.及定制与扩展 九.跨域 ...

  8. Solon Web 开发,九、跨域处理

    Solon Web 开发 一.开始 二.开发知识准备 三.打包与运行 四.请求上下文 五.数据访问.事务与缓存应用 六.过滤器.处理.拦截器 七.视图模板与Mvc注解 八.校验.及定制与扩展 九.跨域 ...

  9. Solon Web 开发,十一、国际化

    Solon Web 开发 一.开始 二.开发知识准备 三.打包与运行 四.请求上下文 五.数据访问.事务与缓存应用 六.过滤器.处理.拦截器 七.视图模板与Mvc注解 八.校验.及定制与扩展 九.跨域 ...

随机推荐

  1. STL源码剖析-waked_ptr

    目录一.提问二. 代码实现2.1 mweak_ptr的具体实现2.2 测试用例一.提问weak_ptr为什么会存在?shared_ptr不是已经有了引用计数吗?具体原因详见模拟实现boost库中的sh ...

  2. 面试官问我TCP三次握手和四次挥手,我真的是

    候选者:面试官你好,请问面试可以开始了吗 面试官:嗯,开始吧 面试官:今天来聊聊TCP吧,TCP的各个状态还有印象吗? 候选者:还有些许印象的,要不我就来简单说下TCP的三次握手和四次挥手的流程吧 候 ...

  3. centos使用docker安装tomcat8

    下载镜像 docker pull tomcat:8 启动 docker run -d -p 8080:8080 -v /data/tomcat/webapps/:/usr/local/tomcat/w ...

  4. java.lang.StackOverflowError报错

    严重: Exception initializing page contextjava.lang.StackOverflowErrorat javax.servlet.http.HttpServlet ...

  5. cmake之Visual studio无法显示头文件

    本文演示cmake版本:3.18 1. 问题 使用cmake创建的Visual Studio 项目都没有显示头文件, 比如: 可以清楚的看见,项目lib_pipe没有显示头文件 2. 配置CMakeL ...

  6. java源码——文件读写和单词统计

    本文要解决的问题:"键盘输入一段英语语句,将这段话写入content.txt中,然后输出这段话,并且统计语句中英文单词的数目以及各个单词出现的次数." 分析问题知,核心是文件读写和 ...

  7. 【LeetCode】970. Powerful Integers 解题报告(Python & C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 暴力搜索 日期 题目地址:https://leetc ...

  8. Distillation as a Defense to Adversarial Perturbations against Deep Neural Networks

    目录 概 主要内容 算法 一些有趣的指标 鲁棒性定义 合格的抗干扰机制 Nicolas Papernot, Patrick McDaniel, Xi Wu, Somesh Jha, Ananthram ...

  9. [高数]高数部分-Part II 导数与微分

    Part II 导数与微分 回到总目录 Part II 导数与微分 一元函数微分的定义 一元函数定义注意点 基本求导公式 基本求导方法 复合函数求导 隐函数求导 对数求导法 反函数求导 参数方程求导 ...

  10. 基于Java swing+mysql+eclipse的【水电费管理系统】

    本项目为前几天收费帮学妹做的一个项目,Java swing项目,在工作环境中基本使用不到,但是很多学校把这个当做编程入门的项目来做,故分享出本项目供初学者参考. CSDN9.9赞助下载: https: ...