java实现传输Model字段属性校验

需求:对传入的数据DTO的属性字段进行校验,类似于hibernate validator需要校验的具体字段属性从数据库(oracle)读取。
思路:
1.将需要校验的model传入
2.通过反射获取其相应的接口名和对象名
3.根据两者在库中进行查找是否有进行校验配置,
若配置则返回配置列表,若未配置,返回校验成功(不需要校验)
4.定义两个数组,一个为需要校验(已配置)的属性配置的列表,一个为需校验的属性名列表
属性配置列表用于后续的相关的属性校验;
属性名列表用于判断是否需要进行后续校验;
5.根据反射获取对象的属性
6.不需要校验的属性直接排除
7.进行相应的属性对比
8.任一属性校验失败则置位失败

校验工具类:

package com.paypal.bank.front.manager.utils;

import com.paypal.bank.front.dal.model.validate.ValidateAttributeDO;
import com.paypal.bank.front.manager.ValidateAttributeManager;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
@Component//申明为spring组件
public class ValidateAttributeUtil {
    @Autowired
    private ValidateAttributeManager validateAttributeManager;
    /**
     * 静态初使化 一个工具类  这样是为了在spring初使化之前
     */
    private static ValidateAttributeUtil validateAttributeUtil;

    /**
     *  通过(注:@PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器执行一次。PostConstruct在构造函数之后执行,init()方法之前执行。PreDestroy()方法在destroy()方法执行执行之后执行)的方法public void init()先给该类赋值,然后通过注入进来。这样不影响dao等service下面调用的注入!
     */
    @PostConstruct
    public  void init(){
        validateAttributeUtil=this;
        validateAttributeUtil.validateAttributeManager=this.validateAttributeManager;
    }

    /**
     * 传入一个model获取从Model获取的相关的属性集合
     *
     * @param model         从外部传入的需要校验的bean
     */
    public static List<ValidateAttributeDO> getValidateAttributeList(Object model){
        String simpleName=model.getClass().getSimpleName();
        String packageName=model.getClass().getPackage().getName();

        List<ValidateAttributeDO> attributeList=validateAttributeUtil.validateAttributeManager.getValidateParamListWithInterfaceAndName(packageName,simpleName);
        return attributeList;
    }
    /**
     * 是否符合正则
     */
    public static boolean isMatchesPattern(Object str, String regex) {
        return String.valueOf(str).matches(regex);
    }

    /**
     * 传入一个model和其相关的属性集合对比
     *
     * @param model         从外部传入的需要校验的bean
     *                      * @return
     */
    public static Boolean isVerificationPass(Object model) {
        Boolean isSuccess = true;
        try {

            List<ValidateAttributeDO> attributeList=getValidateAttributeList(model);


            if (attributeList == null) {
                return true;
            }
            //从数据库查出的规则属性名list
            List attributeVList = new ArrayList();
            //需要校验的属性数组
            List attributeNameList = new ArrayList();
            for (int i = 0; i < attributeList.size(); i++) {
                ValidateAttributeDO m = attributeList.get(i);

                attributeNameList.add(m.getAttributeName());
                attributeVList.add(m);
            }
            //用于记录位置
            int index;

            //得到传入的model类的属性集合
            Field[] fields = model.getClass().getDeclaredFields();
            for (Field field : fields) {
                field.setAccessible(true);
                //获取一个属性
                //排除serialVersionUID属性
                if("serialVersionUID".equals(field.getName())){
                //if (field.getName().equals("serialVersionUID")) {
                    continue;
                }
                //获取属性名称
                String attributeName = field.getName();

                //此处对不需要校验的的属性直接排除
                if (!attributeNameList.contains(attributeName)) {
                    continue;
                }

                index = attributeNameList.indexOf(attributeName);
                //获取属性值
                Object attributeValue = getFieldValueByName(attributeName, model);

                //传入的属性名,属性值, 与从数据库获取的属性规则数组进行校验
                boolean singleAttributeValidateSuccess = validateMethods(attributeName, attributeValue, (ValidateAttributeDO) attributeVList.get(index));

                //若有任一属性失败则退出
                if (!singleAttributeValidateSuccess) {
                    isSuccess = false;
                    break;
                }
                //若成功,进行下一属性的判断continue;
            }
            return isSuccess;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }


    }

    /**
     * 根据属性名获取属性值
     */
    private static Object getFieldValueByName(String fieldName, Object o) {
        try {
            String firstLetter = fieldName.substring(0, 1).toUpperCase();
            String getter = "get" + firstLetter + fieldName.substring(1);
            Method method = o.getClass().getMethod(getter, new Class[]{});
            Object value = method.invoke(o, new Object[]{});
            return value;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    //进行校验 name为属性名,attributeValue为属性值,属性规则数组
    public static Boolean validateMethods(String attributeName, Object attributeValue, ValidateAttributeDO model) {
        //标识位
        Boolean isSuccess = false;

        //进行规则属性值的非空等判断(boolean类型的getNotEmpty默认为false)
        //若为非空校验“0”则返回(值为null,或者“0”),不需要进行长度以及正则校验了
        if ("0".equals(model.getIfNotEmpty())||StringUtils.isBlank(model.getIfNotEmpty())) {
            return !isSuccess;
        }
        //进行非空校验
        //若为null则返回,否则进入长度校验
        if (attributeValue == null) {
            System.out.println("name:" + attributeName + " value:" + attributeValue + " 进行非空校验不符合");
            return isSuccess;
        }
        //是否需要进行长度校验,若为0,即不需要进行长度校验
        if (model.getAttributeLength() == 0) {
            return !isSuccess;
        }
        //进行长度比较
        if (attributeValue.toString().length() > model.getAttributeLength()) {
            //长度不符合需求,则返回
            System.out.println("name:" + attributeName + " value:" + attributeValue + " 进行长度校验不符合");
            return isSuccess;
        }
        //长度符合后,是否需要进行正则判断,若不需要则返回
        //进行正则匹配,若不符合就返回
        if (StringUtils.isBlank(model.getRegixPattern())) {
            return !isSuccess;
        }
        if (!isMatchesPattern(attributeValue, model.getRegixPattern())) {
            System.out.println("name:" + attributeName + " value:" + attributeValue + " 进行正则判断不符合");
            return isSuccess;
        }
        //全部符合规则
        isSuccess = true;

        return isSuccess;
    }

}

数据实体类DO:

package com.paypal.bank.front.dal.model.validate;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

import java.io.Serializable;
import java.util.Date;

/**
 * 校验属性表
 *
 * @author bdw
 * @version Id: TransRight.java, v 0.1 2018/10/8 9:39 dyy Exp $$
 */
@Getter
@Setter
@ToString
public class ValidateAttributeDO implements Serializable{
    /**
     * id
     */
    private Integer validateId;
    /**
     * 接口方法名称
     */
    private String interfaceName;
    /**
     * 模型路径
     */
    private String modelName;
    /**
     * 属性名
     */
    private String attributeName;
    /**
     * 是否为空
     */
    private String ifNotEmpty;
    /**
     * 长度
     */
    private Integer attributeLength;
    /**
     * 正则
     */
    private String regixPattern;
    /**
     * 是否校验
     */
    private String ifValidate;
    /**
     * 更新者
     */
    private String updatedBy;
    /**
     * 更新时间
     */
    private Date updatedAt;
    /**
     * 创建者
     */
    private String createdBy;
    /**
     * 创建日期
     */
    private Date createdAt;

}

获取数据库内容的接口:

package com.paypal.bank.front.manager;

import com.paypal.bank.front.dal.model.validate.ValidateAttributeDO;

import java.util.List;

/**
 * gw-paypal-forwarding
 *
 * @author bdw
 * @Date:2018/10/8 10:01
 * @description:属性列表获取接口
 * @since
 **/
public interface ValidateAttributeManager {
    /**
     * 根据modelName获取列表
     */
    List<ValidateAttributeDO> getValidateParamListWithName(String modelName);
    /**
     * 根据interfaceName和modelName获取列表
     */
    List<ValidateAttributeDO> getValidateParamListWithInterfaceAndName(String interfaceName,String modelName);
    /**
     * 刷新所有校验缓存
     */
    Boolean refreshValidateCache();
}

接口实现类:

package com.paypal.bank.front.manager.impl;

import com.paypal.bank.front.dal.mapper.validate.ValidateAttributeMapper;
import com.paypal.bank.front.dal.model.validate.ValidateAttributeDO;
import com.paypal.bank.front.manager.ValidateAttributeManager;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

/**
 * gw-paypal-forwarding
 *
 * @author bdw
 * @Date:2018/10/8 10:03
 * @description:${description}
 * @since
 **/
@Service
@Slf4j
public class ValidateAttributeManagerImpl implements ValidateAttributeManager {

    private Cache<String,ArrayList> guavaCache= CacheBuilder.newBuilder().maximumSize(100).expireAfterWrite(30, TimeUnit.MINUTES).build();

    @Autowired
    private ValidateAttributeMapper validateAttributeMapper;

    @Override
    public List<ValidateAttributeDO> getValidateParamListWithName(final String modelName) {

        ArrayList<ValidateAttributeDO> arrayList=null;
        try {
            arrayList=guavaCache.get(modelName, new Callable<ArrayList>() {
                @Override
                public ArrayList call() throws Exception {
                    ArrayList arrayList1=validateAttributeMapper.selectAttributeListAboutName(modelName);
                    System.out.println("readDataSourcelistSize:"+arrayList1.size());
                    return arrayList1;
                }
            });
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        return arrayList;
    }

    @Override
    public List<ValidateAttributeDO> getValidateParamListWithInterfaceAndName(final String interfaceName,final String modelName) {
        ArrayList<ValidateAttributeDO> arrayList=null;
        try {
            arrayList=guavaCache.get(interfaceName+modelName, new Callable<ArrayList>() {
                @Override
                public ArrayList call() throws Exception {
                    ArrayList arrayList1=validateAttributeMapper.selectAttributeListAboutInterfaceAndName(interfaceName,modelName);
                    System.out.println("readDataSourcelistSize:"+arrayList1.size());
                    return arrayList1;
                }
            });
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        return arrayList;
    }

    /**
     * 刷新所有校验缓存
     */
    @Override
    public Boolean refreshValidateCache() {
        guavaCache.invalidateAll();
        return true;
    }
}

DAO层:

package com.paypal.bank.front.dal.mapper.validate;

import com.paypal.bank.front.dal.model.validate.ValidateAttributeDO;
import org.apache.ibatis.annotations.Param;

import java.util.ArrayList;

/**
 * 属性规则实现类查询
 *
 * <p>
 *     1.查询属性规则实现类信息
 * </p>
 *
 * @author  bdw
 * @version Id: BankClassCfgMapper.java, v 0.1 2018/9/29 17:49 dyy Exp $$
 */
public interface ValidateAttributeMapper {

    /**
     * 查询传入的方法中的属性列表
     * @param modelName model的名称
     * @return ValidateAttributeDO列表
     */
    ArrayList<ValidateAttributeDO> selectAttributeListAboutName(@Param(value="modelName") String modelName);

    /**
     * 查询接口路径以及modelName的列表
     * @param interfaceName 接口方法路径
     * @param modelName model的名称
     * @return ValidateAttributeDO列表
     */
    ArrayList<ValidateAttributeDO> selectAttributeListAboutInterfaceAndName(@Param(value = "interfaceName") String interfaceName, @Param(value = "modelName") String modelName);

}

Mapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.paypal.bank.front.dal.mapper.validate.ValidateAttributeMapper" >
    <resultMap id="BaseResultMap" type="com.paypal.bank.front.dal.model.validate.ValidateAttributeDO" >
        <result column="VALIDATEID"             property="validateId"               jdbcType="VARCHAR" />
        <result column="INTERFACE_NAME"             property="interfaceName"               jdbcType="VARCHAR" />
        <result column="MODEL_NAME"           property="modelName"             jdbcType="VARCHAR" />
        <result column="ATTRIBUTE_NAME"         property="attributeName"          jdbcType="VARCHAR" />
        <result column="IF_NOTEMPTY"             property="ifNotEmpty"               jdbcType="VARCHAR" />
        <result column="ATTRIBUTE_LENGTH"             property="attributeLength"               jdbcType="VARCHAR" />
        <result column="REGIXPATTERN"           property="regixPattern"             jdbcType="VARCHAR" />
        <result column="IF_VALIDATE"         property="ifValidate"          jdbcType="VARCHAR" />
        <result column="UPDATED_BY" property="updatedBy" jdbcType="VARCHAR"/>
        <result column="UPDATED_AT" property="updatedAt" jdbcType="TIMESTAMP"/>
        <result column="CREATED_BY" property="createdBy" jdbcType="VARCHAR"/>
        <result column="CREATED_AT" property="createdAt" jdbcType="TIMESTAMP"/>
    </resultMap>

    <sql id="columns">
        VALIDATEID,
        INTERFACE_NAME,
        MODEL_NAME,
        ATTRIBUTE_NAME,
        IF_NOTEMPTY,
        ATTRIBUTE_LENGTH,
        REGIXPATTERN,
        IF_VALIDATE,
        UPDATED_BY,
        UPDATED_AT,
        CREATED_BY,
        CREATED_AT
    </sql>
    <!-- 根据接口路径以及modelName查询-->
    <select id="selectAttributeListAboutInterfaceAndName" resultMap="BaseResultMap"
            parameterType="java.util.Map">
        SELECT
        <include refid="columns" />
        FROM
        T_VALIDATE_PARAMTER_ATTRIBUTE
        WHERE
        1=1
        <if test="modelName !=null and modelName != ''" >
            AND MODEL_NAME=#{modelName,jdbcType=VARCHAR}
        </if>
        <if test="interfaceName !=null and interfaceName != ''" >
            AND INTERFACE_NAME=#{interfaceName,jdbcType=VARCHAR}
        </if>
        AND IF_VALIDATE = '1'

    </select>
    <!-- 根据modelName查询-->
    <select id="selectAttributeListAboutName" resultMap="BaseResultMap" parameterType="java.lang.String">
        SELECT
        <include refid="columns"/>
        FROM
        T_VALIDATE_PARAMTER_ATTRIBUTE
        WHERE
        1=1
        <if test="modelName !=null and modelName != ''" >
            AND MODEL_NAME=#{modelName,jdbcType=VARCHAR}
        </if>
--         AND INTERFACE_NAME='com.alipay.entity'
        AND IF_VALIDATE='1'
    </select>

</mapper>

使用:

RequestDTO requestDTO=new RequestDTO();
requestDTO.setName("xiaomi");
requestDTO.setAge("10");
Bool bool=ValidateAttributeUtil.isVerificationPass(requestDTO);
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,635评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,628评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,971评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,986评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,006评论 6 394
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,784评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,475评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,364评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,860评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,008评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,152评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,829评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,490评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,035评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,156评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,428评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,127评论 2 356