@ParamsValidate 二 ValidateInterface接口、值、init.json

@ParamsValidate系列教程 https://blog.csdn.net/u010606397/article/category/7689866

一、ValidateInterface接口

在《@ParamsValidate 一 入门》教程中,我们新增了一个类ValidateInterfaceImpl 

@Component
public class ValidateInterfaceImpl extends ValidateInterfaceAdapter{

}

这个类没有覆盖父类的任何方法,使用了默认的配置。当需要自定义一些配置信息时,如:

1、修改json文件的根目录

2、修改读取json文件的解析器

3、修改校验级别

4、修改未通过校验时返回给前端的信息

5、使用redis存储json文件

就需要覆盖ValidateInterfaceAdapter的方法。

在params-validate的源码中,ValidateInterfaceAdapter是一个适配器,它提供了对ValidateInterface接口的默认实现。

扫描二维码关注公众号,回复: 10505921 查看本文章

ValidateInterface、ValidateInterfaceAdapter、ValidateInterfaceImpl 的关系如下图:

ValidateInterface接口共有6个方法(1.8-RELEASE版本),如下:

public interface ValidateInterface {

    String basePath();

    String getLevel();

    Parser getParser();

    Object validateNotPass(ResultValidate resultValidate);

    Map<String, Object> getKeyCache(ValidateConfig validateConfig);

    void setFileCache(ValidateConfig validateConfig, Map<String, Map<String, Object>> json);
}

ValidateInterfaceAdapter提供对接口的默认实现:

    /**
     * 默认根目录是resources/validate,json文件都放在此目录中
     * 可在ValidateInterfaceAdapter子类覆盖此方法,改变默认根目录
     */
    @Override
    public String basePath() {
        return "validate/";
    }

    /**
     * 校验级别
     * PvConst.LEVEL_STRICT  严格模式,发生异常,校验不通过,默认
     * PvConst.LEVEL_LOOSE   宽松模式,发生异常,不校验
     *
     * params-validate读取json文件或者json文件编写不合法等导致params-validate发生异常,默认是会拦截请求,不执行controller方法
     * 若在ValidateInterfaceAdapter子类覆盖此方法,返回PvConst.LEVEL_LOOSE,当params-validate校验发生异常,就不校验了,放行请求,执行controller方法。
     * 注意:当level设置为PvConst.LEVEL_LOOSE,在params-validate代码未发生异常的前提下,请求参数不符合校验规则,不会放行请求,params-validate返回校验信息给前端,controller方法不会执行。
     */
    @Override
    public String getLevel(){
        return PvConst.LEVEL_STRICT;
    }

    /**
     * json解析器
     * 1、使用默认解析器jackson,返回null
     * 2、使用gson,请返回 new Parser(Gson.class)。需要引入gson依赖
     * 3、使用fastjson,请返回new Parser(JSON.class, Feature[].class)。需要引入fastjson依赖
     * 提供对gson、fastjson的支持是因为jackson不支持在json文件中写注释。为了支持fastjson,搞得好坑爹。
     */
    @Override
    public Parser getParser() {
        return null;
    }

自定义返回信息

当请求参数未通过校验,若要自定义返回信息,可覆盖validateNotPass(ResultValidate resultValidate)方法

看下图:

未通过校验的参数信息放在了msgList中,name是请求参数的key,其他的是校验规则。可以从msgList中拿数据,组装后返回给前端。

注意:若请求参数全部填写正确,validateNotPass(ResultValidate resultValidate)不会执行,而是执行controller中的方法。

使用redis储存json文件

params-validate需要从json文件中读取校验规则,若每次校验都要读取文件,性能开销大,可在首次读取json文件后,就把json文件的内容存储到redis中,之后都从redis中读取校验规则。

覆盖getKeyCache、setFileCache这两个方法,即可实现params-validate与redis的整合。示例代码如下:

    /**
     * ValidateConfig这个对象储存@ParamsValidate注解的值
     * 获取@ParamsValidate中的key在redis中的校验规则
     */
    @Override
    public Map<String, Object> getKeyCache(ValidateConfig validateConfig) {
        String redisKey = createRedisKey(validateConfig);
        return (Map<String, Object>)redisTemplate.opsForHash().get(redisKey, validateConfig.getKey());
    }

    /**
     * 将整个json文件的内容存储为hash结构
     */
    @Override
    public void setFileCache(ValidateConfig validateConfig, Map<String, Map<String, Object>> json) {
        String redisKey = createRedisKey(validateConfig);
        redisTemplate.opsForHash().putAll(redisKey, json);
    }

    /**
     * 使用basePath()返回的目录名+@ParamsValidate的file文件名作为redis的key
     */
    private String createRedisKey(ValidateConfig validateConfig){
        String basePath = PvUtil.trimBeginEndChar(basePath(), '/') + "/";
        String fileName = validateConfig.getFile().substring(0, validateConfig.getFile().lastIndexOf(".json"));
        fileName = PvUtil.trimBeginEndChar(fileName, '/');
        String temp = basePath + fileName;
        return temp.replaceAll("[\\/\\-]",":");
    }

举例说明,resources/validate/learn-params-validate.json的内容如下:

{
    "userValidate": {
        "name": {
            "request": true,
            "minLength": 10,
            "maxLength": 100,
            "regex": "^[a-zA-Z0-9_]+$",
            "message": "名字必须是字母、数字、_"
        },
        限于篇幅,省略部分内容
    },

    "userValidate02": {
        限于篇幅,省略部分内容。
    }
}

params-validate首次读取此文件,在redis中生成的数据如下:

至此,已经可以使用缓存了,但是有个bug,即修改某些校验规则后,项目重新上线,我们要删除缓存中的校验规则,不然就会出现脏读取。下面在ValidateInterfaceImpl的基础上给出一种简单实现。实际上新建一个类实现ApplicationRunner,在run方法中删除redis中的校验规则才是最好的方案。

@Component
public class ValidateInterfaceImpl extends ValidateInterfaceAdapter implements InitializingBean {
    @Autowired
    RedisTemplate redisTemplate;

    //类属性初始化后,删除redis缓存校验规则
    @Override
    public void afterPropertiesSet() throws Exception {
        ExecutorService es = Executors.newFixedThreadPool(1);
        es.execute(new Runnable() {
            @Override
            public void run() {
                Set<String> keys = redisTemplate.keys(basePath().replace("/",":") + "*");
                redisTemplate.delete(keys);
            }
        });
        es.shutdown();
    }
}

二、@ParamsValidate详解

1、file的配置:

ValidateInterface#basePath()+file值,就是json文件的路径。假设ValidateInterface#basePath()返回值是"validate/"

①、若xx.json路径为resources/validate/xx.json,则file="/xx.json"

②、若xx.json路径为resources/validate/dir1/dir2/xx.json,则file="/dir1/dir2/xx.json"

2、key的配置

①、填写json文件最外层的key即可(这个不懂怎么表达了)

3、level的配置

level共有两个值PvConst.LEVEL_STRICT、PvConst.LEVEL_LOOSE。在@ParamsValidate上配置level,此level只在当前controller方法上有效,且优先级高于ValidateInterface#getLevel()中配置的值。

三、配置init.json

校验规则中的regex正则表达式有很多是可以共用的,可以将这些公用的正则表达式抽取出来,放到init.json文件中。

注意:

1、文件名必须是init.json。

2、init.json必须放置在ValidateInterface#basePath()目录中。

3、init.json中正则表达式的key必须以 REGEX_ 开头,注意后面有下划线。

举个例子,init.json如下:

{
    "REGEX_BOOLEAN": "^(true)$|^(false)$",
    "REGEX_CHAR": "^[a-zA-Z0-9_]+$"
}

其他json文件引用init.json中的正则:

    "userValidateInit": {
        "name": {
            "request": true,
            "minLength": 10,
            "maxLength": 100,
            "regex": "REGEX_CHAR",
            "message": "名字必须是字母、数字、_"
        },
        "single": {
            "regex": "REGEX_BOOLEAN",
            "message": "single必须是true、false"
        }
    },

教程代码  https://github.com/CodingSoldier/test-params-validate

params-validate项目地址   github   码云  

发布了51 篇原创文章 · 获赞 14 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/u010606397/article/details/86563210