ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Springboot mini - Solon详解(六)- Solon的校验框架使用、定制与扩展

2020-12-13 14:34:50  阅读:233  来源: 互联网

标签:mini Solon Springboot 校验 参数值 注解 public String


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

标签:mini,Solon,Springboot,校验,参数值,注解,public,String
来源: https://www.cnblogs.com/noear/p/14128571.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有