栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

校验规则引擎设计-对象属性校验策略(初稿)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

校验规则引擎设计-对象属性校验策略(初稿)

闲暇时间对校验的思考:只为把校验工作“做的像锤子一样简单”(灵感来源于电影AK47诞生中的话《卡拉什尼科夫》,有兴趣可以搜索一下)

实现两行代码快速校验,最终实现需要增加什么校验,加配置刷新缓存即可

版权说明:若有转载和使用请注明出处和原作者,版权所有

基于以上思考,提取维度,不同维度设计不同的策略模式

可根据具体的校验维度来实现不同的策略,业务逻辑主要还是在表达式的处理上和配置上

    private String checkClassName;//校验类名
    private String checkServiceClassName;//校验服务类名

    
    private String chekWord;//校验对象属性
    private String checkexpression;//表达式,可根据具体的业务情况调整
    private String checkexpressionOrder; //校验次序
    private String checkexpressionDes; //表达式描述


    
    private String checkDimension; //校验维度   用户   代理  通用
    private String checkDimensionOrder; //维度顺序
    private String checkDimensionWord; //校验维度关键参数  用户的user_id,代理的话代理编号

    private String checkModel; //校验模型  非空,长度,
    private String checkModelOrder; //校验模式顺序
    private String checkModelDes; //校验模式描述

    private String checkResult; //校验结果,描述性内容

    private String status; //是否生效
    private String EffectTimeStatus; //是否设置生效时间段
    private String EffectTimeStart; //生效起始时间
    private String EffectTimEnd; //结束时间

maven依赖


    org.apache.commons
    commons-lang3
    3.12.0

    org.projectlombok
    lombok
    1.18.12
    provided

项目技术栈:springboot

最终实现方案:数据库配置+redis  实现基于不同维度的策略模式校验

根据维度抽象出最初模型,再根据不同场景抽象出不同策略模型,统一入口和出口

1.整体设计类,真正使用业务代码不两行搞定,底层校验策略规则设计和表达式需要根据不同场景开发测试并配置到数据库

 2.对象抽象模型

package com.unique.bean;

import com.unique.service.impl.CompareCheckService;
import com.unique.service.impl.LengthCheckService;
import lombok.Data;
import lombok.SneakyThrows;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.*;


@Data
public class CheckConfig {

    private int id;
    private String checkClassName;//校验类名
    private String checkServiceClassName;//校验服务类名

    
    private String chekWord;//校验对象属性
    private String checkexpression;//表达式,可根据具体的业务情况调整
    private String checkexpressionOrder; //校验次序
    private String checkexpressionDes; //表达式描述


    
    private String checkDimension; //校验维度   用户   代理  通用
    private String checkDimensionOrder; //维度顺序
    private String checkDimensionWord; //校验维度关键参数  用户的user_id,代理的话代理编号

    private String checkModel; //校验模型  非空,长度,
    private String checkModelOrder; //校验模式顺序
    private String checkModelDes; //校验模式描述

    private String checkResult; //校验结果,描述性内容

    private String status; //是否生效
    private String EffectTimeStatus; //是否设置生效时间段
    private String EffectTimeStart; //生效起始时间
    private String EffectTimEnd; //结束时间


}

2.校验顶层设计类

package com.unique.service;

import com.unique.bean.CheckConfig;

import java.lang.reflect.Field;
import java.util.Map;


public interface ICheckService {
    String checkParam(CheckConfig checkConfig, Object obj, Map mapName);
}

3.工具类

获取对象值

package com.unique.utils;

import com.unique.bean.CheckConfig;
import lombok.SneakyThrows;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;


public class CommonUtils {
    private CommonUtils(){}

    @SneakyThrows
    public static String getValue(CheckConfig checkConfig, Object obj, Map mapName) {
        Field field = mapName.get(checkConfig.getChekWord());
        if (field == null) {
            return "pass";
        }
        PropertyDescriptor propertyDescriptor = new PropertyDescriptor(field.getName(), obj.getClass());
        Method readMethod = propertyDescriptor.getReadMethod();
        return String.valueOf(readMethod.invoke(obj));
    }


}

获取bean

package com.unique.utils;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;


@Component
public class SpringBeanUtils implements ApplicationContextAware {
    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    public Object getBean(String name) {

        return applicationContext.getBean(name);
    }

    public  T getBean(Class aclass) {
        return applicationContext.getBean(aclass);
    }


}

4.校验实现类

非空

package com.unique.service.impl;

import com.unique.bean.CheckConfig;
import com.unique.service.ICheckService;
import com.unique.utils.CommonUtils;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.lang.reflect.Field;
import java.util.Map;


@Service
@Slf4j
public class EmptyCheckService implements ICheckService {

    @SneakyThrows
    @Override
    public String checkParam(CheckConfig checkConfig, Object obj, Map mapName) {
        String value = CommonUtils.getValue(checkConfig, obj, mapName);
        if ("pass".equals(value)) {
            return null;
        }
        if (value == null || "null".equals(value)) {
            return checkConfig.getCheckResult();
        }
        return null;
    }
}

长度

package com.unique.service.impl;

import com.unique.bean.CheckConfig;
import com.unique.service.ICheckService;
import com.unique.utils.CommonUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.lang.reflect.Field;
import java.util.Map;


@Service
@Slf4j
public class LengthCheckService implements ICheckService {

    @Override
    public String checkParam(CheckConfig checkConfig, Object obj, Map mapName) {
        String value = CommonUtils.getValue(checkConfig, obj, mapName);
        if ("pass".equals(value)) {
            return null;
        }
        String[] split = checkConfig.getCheckexpression().split("\|");
        if ("null".equals(value)||checkLowBorder(value, split[1])||checkHighBorder(value, split[1])) {
            return checkConfig.getCheckResult();
        }
        return null;
    }




    public boolean checkLowBorder(String value, String check_expression) {
        if (check_expression == null || value == null || "null".equals(value)) {
            return false;
        }
        try {
            if ("(".equals(String.valueOf(check_expression.charAt(0)))) {
                if (StringUtils.length(value) <= Integer.parseInt(String.valueOf(check_expression.charAt(1)))) {
                    return true;
                }
            } else if ("[".equals(String.valueOf(check_expression.charAt(0)))) {
                if (StringUtils.length(value) < Integer.parseInt(String.valueOf(check_expression.charAt(1)))) {
                    return true;
                }
            }
        } catch (NumberFormatException e) {
            log.error("LengthCheckService.checkLowBorder异常:{}", e.getMessage());
            return false;
        }
        return false;
    }

    public boolean checkHighBorder(String value, String check_expression) {
        if (check_expression == null || value == null || "null".equals(value)) {
            return false;
        }
        try {
            if (")".equals(String.valueOf(check_expression.charAt(1)))) {
                if (StringUtils.length(value) >= Integer.parseInt(String.valueOf(check_expression.charAt(1)))) {
                    return true;
                }
            } else if ("]".equals(String.valueOf(check_expression.charAt(1)))) {
                if (StringUtils.length(value) > Integer.parseInt(String.valueOf(check_expression.charAt(1)))) {
                    return true;
                }
            }
            if (check_expression.length() == 5) {
                if (")".equals(String.valueOf(check_expression.charAt(4)))) {
                    if (StringUtils.length(value) >= Integer.parseInt(String.valueOf(check_expression.charAt(3)))) {
                        return true;
                    }
                } else if ("]".equals(String.valueOf(check_expression.charAt(4)))) {
                    if (StringUtils.length(value) > Integer.parseInt(String.valueOf(check_expression.charAt(3)))) {
                        return true;
                    }
                }
            }
        } catch (NumberFormatException e) {
            log.error("LengthCheckService.checkHighBorder异常:{}", e.getMessage());
            return false;
        }
        return false;
    }
}

普通替换

package com.unique.service.impl;

import com.unique.bean.CheckConfig;
import com.unique.service.ICheckService;
import lombok.SneakyThrows;
import org.springframework.stereotype.Service;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;


@Service
public class ReplaceCheckService implements ICheckService {
    @SneakyThrows
    @Override
    public String checkParam(CheckConfig checkConfig, Object obj, Map mapName) {
        Field field = mapName.get(checkConfig.getChekWord());
        if (field == null) {
            return "pass";
        }
        PropertyDescriptor propertyDescriptor = new PropertyDescriptor(field.getName(), obj.getClass());
        Method readMethod = propertyDescriptor.getReadMethod();
        String value = String.valueOf(readMethod.invoke(obj));
        String[] split = checkConfig.getCheckexpression().split("\|");
        field.set(obj, checkReplace(value, split[1]));
        return null;
    }

    public static String checkReplace(String value, String expression) {
        if (value == null || expression == null) {
            return value;
        }
        String[] splitAll = expression.split(";");
        for (String s : splitAll) {
            String[] split = s.split(",");
            value = value.replace(split[0], split[1]);
        }
        return value;
    }
}

正则替换

package com.unique.service.impl;

import com.unique.bean.CheckConfig;
import com.unique.service.ICheckService;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;


@Service
@Slf4j
public class ReplaceRegCheckService implements ICheckService {

    @SneakyThrows
    @Override
    public String checkParam(CheckConfig checkConfig, Object obj, Map mapName) {
        Field field = mapName.get(checkConfig.getChekWord());
        if (field == null) {
            return "pass";
        }
        PropertyDescriptor propertyDescriptor = new PropertyDescriptor(field.getName(), obj.getClass());
        Method readMethod = propertyDescriptor.getReadMethod();
        String value = String.valueOf(readMethod.invoke(obj));
        String[] split = checkConfig.getCheckexpression().split("\|");
        field.set(obj, checkReplaceReg(value, split[1]));
        return null;
    }

    public static String checkReplaceReg(String value, String expression) {
        if (value == null || expression == null) {
            return value;
        }
        String[] splitAll = expression.split(";");
        for (String s : splitAll) {
            String[] split = s.split(",");
            value = value.replaceAll(split[0], split[1]);
        }
        return value;
    }
}

范围比较

package com.unique.service.impl;

import com.unique.bean.CheckConfig;
import com.unique.service.ICheckService;
import com.unique.utils.CommonUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.Map;


@Service
@Slf4j
public class CompareCheckService implements ICheckService {


    @Override
    public String checkParam(CheckConfig checkConfig, Object obj, Map mapName) {
        String value = CommonUtils.getValue(checkConfig, obj, mapName);
        if ("pass".equals(value)) {
            return null;
        }
        String[] split = checkConfig.getCheckexpression().split("\|");
        if ("null".equals(value)||checkLowBorder(value, split[1]) || checkHighBorder(value, split[1])) {
            return checkConfig.getCheckResult();
        }
        return null;
    }


    public boolean checkLowBorder(String value, String check_expression) {
        if (check_expression == null || value == null) {
            return false;
        }
        try {
            if ("(".equals(String.valueOf(check_expression.charAt(0)))) {
                BigDecimal bigDecimal = BigDecimal.valueOf(Long.parseLong(value));
                BigDecimal valueOf = BigDecimal.valueOf(Long.parseLong(String.valueOf(check_expression.charAt(1))));
                int compare = bigDecimal.compareTo(valueOf);
                if (compare <= 0) {
                    return true;
                }
            } else if ("[".equals(String.valueOf(check_expression.charAt(0)))) {
                BigDecimal bigDecimal = BigDecimal.valueOf(Long.parseLong(value));
                BigDecimal valueOf = BigDecimal.valueOf(Long.parseLong(String.valueOf(check_expression.charAt(1))));
                int compare = bigDecimal.compareTo(valueOf);
                if (compare < 0) {
                    return true;
                }
            }
        } catch (NumberFormatException e) {
            log.error("BorderCheckService.checkLowBorder异常:{}", e.getMessage());
            return false;
        }
        return false;
    }

    public boolean checkHighBorder(String value, String check_expression) {
        if (check_expression == null || value == null || "null".equals(value)) {
            return false;
        }
        try {
            if (")".equals(String.valueOf(check_expression.charAt(1)))) {
                BigDecimal bigDecimal = BigDecimal.valueOf(Long.parseLong(value));
                BigDecimal valueOf = BigDecimal.valueOf(Long.parseLong(String.valueOf(check_expression.charAt(0))));
                int compare = bigDecimal.compareTo(valueOf);
                if (compare >= 0) {
                    return true;
                }
            } else if ("]".equals(String.valueOf(check_expression.charAt(1)))) {
                BigDecimal bigDecimal = BigDecimal.valueOf(Long.parseLong(value));
                BigDecimal valueOf = BigDecimal.valueOf(Long.parseLong(String.valueOf(check_expression.charAt(0))));
                int compare = bigDecimal.compareTo(valueOf);
                if (compare > 0) {
                    return true;
                }
            }
            if (check_expression.length() == 5) {
                if (")".equals(String.valueOf(check_expression.charAt(4)))) {
                    BigDecimal bigDecimal = BigDecimal.valueOf(Long.parseLong(value));
                    BigDecimal valueOf = BigDecimal.valueOf(Long.parseLong(String.valueOf(check_expression.charAt(3))));
                    int compare = bigDecimal.compareTo(valueOf);
                    if (compare >= 0) {
                        return true;
                    }
                } else if ("]".equals(String.valueOf(check_expression.charAt(4)))) {
                    BigDecimal bigDecimal = BigDecimal.valueOf(Long.parseLong(value));
                    BigDecimal valueOf = BigDecimal.valueOf(Long.parseLong(String.valueOf(check_expression.charAt(3))));
                    int compare = bigDecimal.compareTo(valueOf);
                    if (compare > 0) {
                        return true;
                    }
                }
            }
        } catch (NumberFormatException e) {
            log.error("BorderCheckService.checkHighBorder异常:{}", e.getMessage());
            return false;
        }
        return false;
    }
}

包含校验

package com.unique.service.impl;

import com.unique.bean.CheckConfig;
import com.unique.service.ICheckService;
import com.unique.utils.CommonUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;
import java.util.Map;


@Slf4j
@Service
public class ContainsCheckService implements ICheckService {
    @Override
    public String checkParam(CheckConfig checkConfig, Object obj, Map mapName) {
        String value = CommonUtils.getValue(checkConfig, obj, mapName);
        if ("pass".equals(value)) {
            return null;
        }
        String[] split = checkConfig.getCheckexpression().split("\|");
        
        if (checkContains(value, split[2]) && "normal".equals(split[1])) {
            return checkConfig.getCheckResult();
        }
        return null;
    }

    private static boolean checkContains(String value, String expression) {
        if (expression != null) {
            List strings = Arrays.asList(expression.split(","));
            return strings.stream().anyMatch(keyWord -> value.contains(keyWord));
        }
        return false;
    }
}

5.业务测试类

package com.unique.controller;

import com.unique.bean.CheckConfig;
import com.unique.service.ICheckService;
import com.unique.bean.User;
import com.unique.utils.SpringBeanUtils;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


@Slf4j
@RestController
public class CheckController {

    @Resource
    private SpringBeanUtils springBeanUtils;

    @RequestMapping(value = "checkParam")
    public String checkParam(User user) {
        user = new User();
        user.setAge(3);
        user.setName("123");
        user.setAddress("410-6220 Blundel road,*Buzzer 545");

        

        CheckConfig checkConfig = new CheckConfig();
        checkConfig.setCheckClassName("class com.unique.bean.User");
        checkConfig.setChekWord("name");
        checkConfig.setCheckexpression("empty");
        checkConfig.setCheckResult("The name is empty");
        checkConfig.setCheckModel("empty");
        checkConfig.setCheckServiceClassName("com.unique.service.impl.EmptyCheckService");

        CheckConfig checkConfig4 = new CheckConfig();
        checkConfig4.setCheckClassName("class com.unique.bean.User");
        checkConfig4.setChekWord("name");
        checkConfig4.setCheckexpression("length|[3,8]");
        checkConfig4.setCheckResult("the name is limit [3,8]");
        checkConfig4.setCheckModel("length");
        checkConfig4.setCheckServiceClassName("com.unique.service.impl.LengthCheckService");

        
        CheckConfig checkConfig2 = new CheckConfig();
        checkConfig2.setCheckClassName("class com.unique.bean.User");
        checkConfig2.setChekWord("age");
        checkConfig2.setCheckexpression("compare|[3,8]");
        checkConfig2.setCheckResult("The age is  limit (3,8]");
        checkConfig2.setCheckModel("compare");
        checkConfig2.setCheckServiceClassName("com.unique.service.impl.CompareCheckService");


        CheckConfig checkConfig3 = new CheckConfig();
        checkConfig3.setCheckClassName("class com.unique.bean.User");
        checkConfig3.setChekWord("address");
        checkConfig3.setCheckexpression("replace|*,,null;-, ;"); // 如果替换为空串,则表达式需要多一个逗号分割,最后一个
        checkConfig3.setCheckModel("replace");
        checkConfig3.setCheckServiceClassName("com.unique.service.impl.ReplaceCheckService");



        CheckConfig checkConfig6 = new CheckConfig();
        checkConfig6.setCheckClassName("class com.unique.bean.User");
        checkConfig6.setChekWord("address");
        checkConfig6.setCheckexpression("replaceReg|[^a-zA-Z ]+,,null;");//多个正则替换以分号分割,如果要替换为空串,逗号分割部分后加上一个非空数据
        checkConfig6.setCheckModel("replaceReg");
        checkConfig6.setCheckServiceClassName("com.unique.service.impl.ReplaceRegCheckService");


        CheckConfig checkConfig5 = new CheckConfig();
        checkConfig5.setCheckClassName("class com.unique.bean.User");
        checkConfig5.setChekWord("address");
        checkConfig5.setCheckexpression("contains|normal|Blundel,Road");// special模式下 替换大写,替换成小写,正则替换
        checkConfig5.setCheckResult("The address cannot contain Blundel,Road");
        checkConfig5.setCheckModel("contains");
        checkConfig5.setCheckServiceClassName("com.unique.service.impl.ContainsCheckService");

        
        List checkConfigs = new ArrayList<>();
        checkConfigs.add(checkConfig);
        checkConfigs.add(checkConfig2);
        checkConfigs.add(checkConfig3);
        checkConfigs.add(checkConfig4);
        checkConfigs.add(checkConfig5);
        checkConfigs.add(checkConfig6);

        
        Map mapName = getStringFieldMap(user);

        String s = null;
        try {
            
            s = checkParam(checkConfigs, user, mapName);
        } catch (Exception e) {
            log.error("校验异常:{}", e.getMessage());
        }
        log.info("对象:{}",user);
        if (s != null) {
            return s;
        }
        return null;
    }

    private Map getStringFieldMap(Object obj) {
        Map mapName = new HashMap<>();
        Field[] declaredFields = obj.getClass().getDeclaredFields();
        for (Field declaredField : declaredFields) {
            declaredField.setAccessible(true);
            mapName.put(declaredField.getName(), declaredField);
        }
        return mapName;
    }

    @SneakyThrows
    private String checkParam(List checkConfigs, User user, Map mapName) {
        if (checkConfigs != null && checkConfigs.size() > 0) {
            for (CheckConfig checkConfig : checkConfigs) {
                if (StringUtils.isNotEmpty(checkConfig.getCheckServiceClassName())) {
                    Class aClass = Class.forName(checkConfig.getCheckServiceClassName());
                    
                    if (String.valueOf(user.getClass()).equals(checkConfig.getCheckClassName())) {
                        log.info("校验类匹配:{}",String.valueOf(user.getClass()).equals(checkConfig.getCheckClassName()));
                    }
                    ICheckService bean = (ICheckService) springBeanUtils.getBean(aClass);
                    String s = bean.checkParam(checkConfig, user, mapName);
                    if (s != null) {
                        return s;
                    }
                }
            }
        }
        return null;
    }


}

验证结果

http://localhost:9002/checkParam

The address cannot contain Blundel,Road

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/657600.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号