需求:对传入的数据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);