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值
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 默认使用了本地延时锁。如果是分布式环境,需要定制为分布式锁:

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项目地址

Springboot mini - Solon详解(六)- Solon的校验框架使用、定制与扩展的更多相关文章

  1. Solon详解(九)- 渲染控制之定制统一的接口输出

    Solon详解系列文章: Solon详解(一)- 快速入门 Solon详解(二)- Solon的核心 Solon详解(三)- Solon的web开发 Solon详解(四)- Solon的事务传播机制 ...

  2. Solon Web 开发,八、校验、及定制与扩展

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

  3. Solon 框架详解(九)- 渲染控制之定制统一的接口输出

    Springboot min -Solon 详解系列文章: Springboot mini - Solon详解(一)- 快速入门 Springboot mini - Solon详解(二)- Solon ...

  4. Solon详解(十)- 怎么用 Solon 开发基于 undertow jsp tld 的项目?

    Solon详解系列文章: Solon详解(一)- 快速入门 Solon详解(二)- Solon的核心 Solon详解(三)- Solon的web开发 Solon详解(四)- Solon的事务传播机制 ...

  5. Solon详解(11)- Mybatis 与 Solon 相亲相爱

    Solon详解系列文章: Solon详解(一)- 快速入门 Solon详解(二)- Solon的核心 Solon详解(三)- Solon的web开发 Solon详解(四)- Solon的事务传播机制 ...

  6. Springboot mini - Solon详解(四)- Solon的事务传播机制

    Springboot min -Solon 详解系列文章: Springboot mini - Solon详解(一)- 快速入门 Springboot mini - Solon详解(二)- Solon ...

  7. Springboot mini - Solon详解(七)- Solon Ioc 的注解对比Spring及JSR330

    Springboot min -Solon 详解系列文章: Springboot mini - Solon详解(一)- 快速入门 Springboot mini - Solon详解(二)- Solon ...

  8. Springboot mini - Solon详解(八)- Solon的缓存框架使用和定制

    Springboot min -Solon 详解系列文章: Springboot mini - Solon详解(一)- 快速入门 Springboot mini - Solon详解(二)- Solon ...

  9. Springboot mini - Solon详解(二)- Solon的核心

    Springboot min -Solon 详解系列文章: Springboot mini - Solon详解(一)- 快速入门 Springboot mini - Solon详解(二)- Solon ...

随机推荐

  1. [原题复现]2019上海大学生WEB-Decade(无参数RCE、Fuzz)

    简介  原题复现:  考察知识点:无参数命令执行.Fuzz  线上平台:https://buuoj.cn(北京联合大学公开的CTF平台) 榆林学院内可使用信安协会内部的CTF训练平台找到此题 环境复现 ...

  2. 深入学习synchronized

    synchronized 并发编程中的三个问题: 可见性(Visibility) 是指一个线程对共享变量进行修改,另一个先立即得到修改后的最新值. 代码演示: public class Test01V ...

  3. Jmeter生成HTML测试报告

    jmeter轻便小巧,运行速度快,但是缺少直观的可视化测试报告,并且生成测试报告操作稍微有点麻烦. GUI界面没有生成测试报告的功能,只能使用命令行生成测试报告.这里需要提到一个jtl的文件,它是生成 ...

  4. Vim常用按键

  5. eslint报错: Unexpected any value in conditional. An explicit comparison or type cast is required

    原代码: record.modifiedTime? 修改后代码:typeof record.modifiedTime !== 'undefined' ?   (isAddType === true ? ...

  6. iOS程序内实现版本更新

    最近这段时间刚把手头里面的两个项目交付出去,很想写点东西但又不想随随便便的写些抒情的文字,其实生活中的很多事情.成长的路上遇到的很多问题,并非简简单单的抱怨.埋怨,用一种激情悲昂的情绪去逃避.去发泄所 ...

  7. 一万三千字的HashMap面试必问知识点详解

    目录 概论 Hasmap 的继承关系 hashmap 的原理 解决Hash冲突的方法 开放定址法 再哈希法 链地址法 建立公共溢出区 hashmap 最终的形态 Hashmap 的返回值 HashMa ...

  8. mybatis-plus使用记录

    如何and和or: QuoteSalaryEnum salaryMax = QuoteSalaryEnum.of(memberObjectInfo.getQuoteSalaryMax()); Quot ...

  9. 雪花算法 Java 版

    雪花算法根据时间戳生成有序的 64 bit 的 Long 类型的唯一 ID 各 bit 含义: 1 bit: 符号位,0 是正数 1 是负数, ID 为正数,所以恒取 0 41 bit: 时间差,我们 ...

  10. Spring Cloud 学习 (一) Eureka

    微服务的功能主要有以下几个方面: 服务的注册和发现 服务的负载均衡 服务的容错 服务网关 服务配置的统一管理 链路追踪 实时日志 服务注册是指向服务注册中心注册一个服务实例,服务提供者将自己的服务信息 ...