Solon Web 开发,八、校验、及定制与扩展
在业务的实现过程中,尤其是对外接口开发,我们需要对请求进行大量的验证并返回错误状态码和描述。在前面的内容中也已经使用过验证机制。
该文将介绍 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值 |
| 参数 或 字段 | 校验注解的值为电子邮箱格式 | |
| 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 开发,八、校验、及定制与扩展的更多相关文章
- Solon Web 开发
Solon Web 开发 一.开始 二.开发知识准备 三.打包与运行 四.请求上下文 五.数据访问.事务与缓存应用 六.过滤器.处理.拦截器 七.视图模板与Mvc注解 八.校验.及定制与扩展 九.跨域 ...
- Solon Web 开发,一、开始
Solon Web 开发 一.开始 二.开发知识准备 三.打包与运行 四.请求上下文 五.数据访问.事务与缓存应用 六.过滤器.处理.拦截器 七.视图模板与Mvc注解 八.校验.及定制与扩展 九.跨域 ...
- Solon Web 开发,二、开发知识准备
Solon Web 开发 一.开始 二.开发知识准备 三.打包与运行 四.请求上下文 五.数据访问.事务与缓存应用 六.过滤器.处理.拦截器 七.视图模板与Mvc注解 八.校验.及定制与扩展 九.跨域 ...
- Solon Web 开发,四、请求上下文
Solon Web 开发 一.开始 二.开发知识准备 三.打包与运行 四.请求上下文 五.数据访问.事务与缓存应用 六.过滤器.处理.拦截器 七.视图模板与Mvc注解 八.校验.及定制与扩展 九.跨域 ...
- Solon Web 开发,五、数据访问、事务与缓存应用
Solon Web 开发 一.开始 二.开发知识准备 三.打包与运行 四.请求上下文 五.数据访问.事务与缓存应用 六.过滤器.处理.拦截器 七.视图模板与Mvc注解 八.校验.及定制与扩展 九.跨域 ...
- Solon Web 开发,六、过滤器、处理、拦截器
Solon Web 开发 一.开始 二.开发知识准备 三.打包与运行 四.请求上下文 五.数据访问.事务与缓存应用 六.过滤器.处理.拦截器 七.视图模板与Mvc注解 八.校验.及定制与扩展 九.跨域 ...
- Solon Web 开发,七、视图模板与Mvc注解
Solon Web 开发 一.开始 二.开发知识准备 三.打包与运行 四.请求上下文 五.数据访问.事务与缓存应用 六.过滤器.处理.拦截器 七.视图模板与Mvc注解 八.校验.及定制与扩展 九.跨域 ...
- Solon Web 开发,九、跨域处理
Solon Web 开发 一.开始 二.开发知识准备 三.打包与运行 四.请求上下文 五.数据访问.事务与缓存应用 六.过滤器.处理.拦截器 七.视图模板与Mvc注解 八.校验.及定制与扩展 九.跨域 ...
- Solon Web 开发,十一、国际化
Solon Web 开发 一.开始 二.开发知识准备 三.打包与运行 四.请求上下文 五.数据访问.事务与缓存应用 六.过滤器.处理.拦截器 七.视图模板与Mvc注解 八.校验.及定制与扩展 九.跨域 ...
随机推荐
- 缓存系统redis操作、mongdb、memeche
mongdb :默认数据持久化,存在内存的同时也向硬盘写数据. redis:可配置数据持久化,默认数据在内存中 memeche:only support 内存模式 redis操作 https://ww ...
- Unhandled Exception: FormatException: Unexpected character
错误原因 json格式不正确,检查:是否加了注释.最后一个是否加了逗号... 正确格式 { "name": "shellon", "age" ...
- IDEA设置默认(指定)的注释作者信息
有时候我们想在IDEA里面创建的时候就默认设置一个指定的作者信息 填入作者信息 然后点击ok /** * * @author yvioo */ 然后我们新建文件的时候就会自动带上这个了,模板可以根据自 ...
- JS(JQuery) 省市区三级联动下拉选择
引入 area.js /* * 全国三级城市联动 js版 */ function Dsy(){ this.Items = {}; } Dsy.prototype.add = function(id,i ...
- 第一篇CSDN博客,大家好!
大家好,我是负雪明烛! 我这昵称的来源是喜欢一句很有意蕴的古诗--苍山负雪,明烛天南. 我喜欢这句诗,很多的账号都用了这个"负雪明烛"的昵称,如果大家在其他地方看到叫这个名字的人, ...
- 【LeetCode】763. Partition Labels 解题报告(Python & C++)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 解题方法 日期 题目地址:https://leetcode.com/pr ...
- 【LeetCode】116. 填充每个节点的下一个右侧节点指针 Populating Next Right Pointers in Each Node 解题报告(Python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 递归 日期 题目地址:https://leetcode ...
- 团队编程二——web应用之人事管理系统
该项目是B-S模式的web应用,以下是团队各成员的Coding链接: ------Aaric---https://coding.net/u/Aaric/p/Personnel_management_s ...
- P4081 [USACO17DEC]Standing Out from the Herd P
知识点: 广义 SAM 原题面 Luogu 「扯」 随便「口胡」一下居然「过」了. 比较考验「代码能力」,第一次感觉「大模拟」没有白写((( 还有这个「符号」实在是太「上头」了. 前置知识 在线构造广 ...
- 图片 Augmentation整理
目录 Augmentation Flipping 翻转 Grayscale Equalize 均衡直方图 Posterize 减少颜色通道位数 Cropping Rotation Translatio ...