目录结构
1、注解类
package com.annotation.validation.annotation;
import java.lang.annotation.*;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FieldValidate {
/**
* 字段属性是否为空
* @return
*/
public boolean isEmpty() default false;
/**
* 字段长度
* @return
*/
public int max() default 0;
/**
* 当字段为条件必填时,需要配合conKey和conVal一起,例如conKey="idKind",conVal="90"
* @return
*/
public String conKey() default "";
public String conVal() default "";
}
package com.annotation.validation.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface BigDecimalValidate {
/**
* 字段长度
* @return
*/
public int length() default 10;
/**
* 保留小数位
* @return
*/
public int scale() default 2;
/**
* 是否可以是负数
* @return
*/
public boolean isNegative() default false;
}
package com.annotation.validation.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DateValidate {
/**
* 日期格式
* @return
*/
public String format() default "yyyy-MM-dd";
}
package com.annotation.validation.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ObjectValidate {
public Class<?> className();
}
2、校验工具类
package com.annotation.validation.utils;
import com.annotation.validation.annotation.BigDecimalValidate;
import com.annotation.validation.annotation.DateValidate;
import com.annotation.validation.annotation.FieldValidate;
import com.annotation.validation.annotation.ObjectValidate;
import com.annotation.validation.vo.ValidateVo;
import org.apache.commons.lang.StringUtils;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;
public class ValidateUtil {
private static Map<String ,Object> REFLECT_CACHE = new ConcurrentHashMap<>();
public static Map<String,Object> validateJson(Object bean,String prefixMsg){
Map <String,Object> result = new HashMap();
result.put("message","校验通过");
result.put("result",true);
Class<?> cls = bean.getClass();
StringBuffer errorMsgBuffer = new StringBuffer(prefixMsg);
boolean flag = true;
//检测field是否存在
String key = null;
try{
Field [] fields = null;
key = cls.getName();
if(REFLECT_CACHE.containsKey(key)){
fields = (Field[])REFLECT_CACHE.get(key);
}else{
fields = cls.getDeclaredFields();
REFLECT_CACHE.put(cls.getName(),fields);
}
for (Field field : fields) {
field.setAccessible(true);//反射时访问私有变量
Object value = field.get(bean);//获取字段值
Annotation[] annoArr = null;//获取字段上的注解集合
key = String.format("%s_%s",cls.getName(),field.getName());
if(REFLECT_CACHE.containsKey(key)){
annoArr = (Annotation[]) REFLECT_CACHE.get(key);
}else{
annoArr = field.getAnnotations();
REFLECT_CACHE.put(key,annoArr);
}
for (Annotation annotation : annoArr) {
Class<? extends Annotation> aClass = annotation.annotationType();//获取注解类型
Method [] methodArr = null;
key = String.format("%s_%s_%s",cls.getName(),field.getName(),aClass.getName());
if(REFLECT_CACHE.containsKey(key)){
methodArr = (Method[]) REFLECT_CACHE.get(key);
}else{
methodArr = aClass.getDeclaredMethods();
REFLECT_CACHE.put(key,methodArr);
}
for (Method method : methodArr) {
String methodName = method.getName();//获取注解类中的方法名
if("message".equals(methodName)||"conVal".equals(methodName)){//过滤错误提示方法的调用
continue;
}
if("conKey".equals(methodName)){//当字段为必填时,做特殊校验
result.put("message","校验通过");
result.put("result",true);
FieldValidate ann = field.getAnnotation(FieldValidate.class);
if(StringUtils.isNotBlank(ann.conKey())&&StringUtils.isNotBlank(ann.conVal())){
Method m = null;
key = String.format("METHOD_%s_%s",cls.getName(),methodName);
if(REFLECT_CACHE.containsKey(key)){
m = (Method) REFLECT_CACHE.get(key);
}else{
m = cls.getMethod(getMethodName(ann.conKey()));
REFLECT_CACHE.put(key,m);
}
String valStr = (String)m.invoke(bean);
String tmpr = ("," + ann.conVal() + ",");
int temp = ("," + ann.conVal() + ",").indexOf("," + valStr + ",");
if((StringUtils.isNotBlank(valStr)) && ("," + ann.conVal() + ",").indexOf("," + valStr + ",") >= 0) {
if(StringUtils.isBlank((String)value)) {
flag = false;
errorMsgBuffer.append(String.format("当字段[%s]符合条件[%s]时,[%s]字段不能为空",ann.conKey(),ann.conVal(),field.getName()) + ";");
}
}
}
continue;
}
// 初始化注解验证的方法处理类 (我的处理方法加载本类中)
Object obj = ValidateUtil.class.newInstance();
// 获取方法
try {
// 根据方法名获取该方法
Method m = null;
if(REFLECT_CACHE.containsKey(String.format("METHOD_%s", methodName))) {
m = (Method) REFLECT_CACHE.get(String.format("METHOD_%s", methodName));
} else {
m = obj.getClass().getDeclaredMethod(methodName, Object.class, Field.class);
REFLECT_CACHE.put(String.format("METHOD_%s", methodName), m);
}
// 调用该方法
result = (Map<String, Object>)m.invoke(obj, value, field);
/* 验证结果 拼接字符串 */
if(result.get("result").equals(false)) {
errorMsgBuffer.append(result.get("message"));
if(! (annotation instanceof ObjectValidate)) {
errorMsgBuffer.append(";");
}
flag = false;
}
} catch (Exception e) {
e.printStackTrace();
result.put("result", false);
result.put("message", String.format("%s执行数据校验时异常1:%s", prefixMsg, e));
return result;
}
}
}
}
}catch (Exception e){
e.printStackTrace();
result.put("result", false);
result.put("message", String.format("%s执行数据校验时异常2:%s", prefixMsg, e));
return result;
}
result.put("result", flag);
result.put("message", flag ? "校验成功" : errorMsgBuffer.toString());
return result;
}
public static String getMethodName(String fieldName){
byte[] bytes = fieldName.getBytes();
bytes[0] = (byte)((char)bytes[0] - 'a' + 'A');
return "get".concat(new String(bytes));
}
/**
* 验证最大值
*
* @author zhy
* @param value 参数值
* @param field 字段
* @return
*/
public Map<String, Object> max(Object value, Field field) {
Map<String, Object> validateResult = new HashMap<String, Object>();
FieldValidate annotation = field.getAnnotation(FieldValidate.class);
int len = 0;
if(value instanceof String) {
len = value.toString().length();
}
if(value != null && !value.equals("") && annotation.max() > 0 && len > annotation.max()) {
validateResult.put("message", String.format("[%s]]字段长度过长, 长度最大限制为%s", field.getName(), annotation.max()));
validateResult.put("result", false);
} else {
validateResult.put("message", "验证通过");
validateResult.put("result", true);
}
return validateResult;
}
/**
* 验证是否空值
*
* @author zhy
* @param value 参数值
* @param field 字段
* @return
*/
public Map<String, Object> isEmpty(Object value, Field field) {
Map<String, Object> validateResult = new HashMap<String, Object>();
validateResult.put("message", "验证通过");
validateResult.put("result", true);
FieldValidate annotation = field.getAnnotation(FieldValidate.class);
if(!annotation.isEmpty()) {
if(value == null || value.equals("")) {
validateResult.put("message", String.format("[%s]字段不能为空值", field.getName()));
validateResult.put("result", false);
}
if(value != null && value instanceof List) {
if(((List)value).size() == 0) {
validateResult.put("message", String.format("[%s]字段不能为空值", field.getName()));
validateResult.put("result", false);
}
}
}
return validateResult;
}
/**
* 校验日期格式是否正确
* @param value
* @param field
* @return
*/
public Map<String, Object> format(Object value, Field field) {
Map<String, Object> validateResult = new HashMap<String, Object>();
validateResult.put("message", "验证通过");
validateResult.put("result", true);
DateValidate annotation = field.getAnnotation(DateValidate.class);
if(StringUtils.isNotBlank((String)value)) {
try {
Date dateTime = convertStringToDate(annotation.format(), (String)value);
String dateStr = getDateString(dateTime, annotation.format());
if(!dateStr.equals((String)value)) {
validateResult.put("message", String.format("[%s]字段日期格式不正确, 日期格式为%s", field.getName(), annotation.format()));
validateResult.put("result", false);
}
} catch (Exception e) {
validateResult.put("message", String.format("[%s]字段日期格式不正确, 日期格式为%s", field.getName(), annotation.format()));
validateResult.put("result", false);
}
}
return validateResult;
}
/**
* 校验是否为Decimal规定的格式:校验长度
* @param value
* @param field
* @return
*/
public Map<String, Object> length(Object value, Field field) {
Map<String, Object> validateResult = new HashMap<String, Object>();
validateResult.put("message", "验证通过");
validateResult.put("result", true);
BigDecimalValidate annotation = field.getAnnotation(BigDecimalValidate.class);
String strVal = (String)value;
if(StringUtils.isNotBlank(strVal)) {
boolean flag = Pattern.matches("^-?[0-9]+\\.?[0-9]*$", strVal);
if(!flag) {
validateResult.put("message", String.format("[%s]字段不符合金额规则", field.getName()));
validateResult.put("result", false);
return validateResult;
}
if(strVal.replace(".", "").replace("-", "").length() > annotation.length()) {
validateResult.put("message", String.format("[%s]字段长度过长,最大长度为%s", field.getName(), annotation.length()));
validateResult.put("result", false);
}
}
return validateResult;
}
/**
* 校验是否可以是负数
* @param value
* @param field
* @return
*/
public Map<String, Object> isNegative(Object value, Field field) {
Map<String, Object> validateResult = new HashMap<String, Object>();
validateResult.put("message", "验证通过");
validateResult.put("result", true);
BigDecimalValidate annotation = field.getAnnotation(BigDecimalValidate.class);
String strVal = (String)value;
if(StringUtils.isNotBlank(strVal) && !annotation.isNegative()) {
boolean flag = Pattern.matches("^-?[0-9]+\\.?[0-9]*$", strVal);
if(flag) {
BigDecimal bigDecimal = new BigDecimal(strVal);
if(bigDecimal.compareTo(new BigDecimal(0)) < 0) {
validateResult.put("message", String.format("[%s]字段不能为负值", field.getName()));
validateResult.put("result", false);
}
}
}
return validateResult;
}
/**
* 校验是否为Decimal规定的格式:校验小数点位数
* @param value
* @param field
* @return
*/
public Map<String, Object> scale(Object value, Field field) {
Map<String, Object> validateResult = new HashMap<String, Object>();
validateResult.put("message", "验证通过");
validateResult.put("result", true);
BigDecimalValidate annotation = field.getAnnotation(BigDecimalValidate.class);
String strVal = (String)value;
if(StringUtils.isNotBlank(strVal)) {
String[] strs = strVal.split("\\.");
if((strs.length == 1 ? 0 : strs[1].length()) > annotation.scale()) {
validateResult.put("message", String.format("[%s]字段小数点位数过长,最大长度为%s", field.getName(), annotation.scale()));
validateResult.put("result", false);
}
}
return validateResult;
}
/**
* 对字段类型为对象或者List进行校验
* @param value
* @param field
* @return
*/
public Map<String, Object> className(Object value, Field field) {
Map<String, Object> validateResult = new HashMap<String, Object>();
if(value != null) {
if(value instanceof ArrayList) {
List<Object> list = (List<Object>) value;
validateResult.put("message", "验证通过");
validateResult.put("result", true);
StringBuffer buffer = new StringBuffer();
boolean flag = true;
for(Object val : list) {
Map<String, Object> result = ValidateUtil.validateJson(val, "");
if(!result.get("result").equals(true)) {
ObjectValidate annotation = field.getAnnotation(ObjectValidate.class);
flag = false;
buffer.append(String.format("%s对象中的参数有误:{%s}", annotation.className().getSimpleName(),
result.get("message")));
}
}
validateResult.put("result", flag);
validateResult.put("message", flag ? "验证通过" : buffer.toString());
} else {
Map<String, Object> result = ValidateUtil.validateJson(value, "");
if(result.get("result").equals(true)) {
validateResult.put("message", "验证通过");
validateResult.put("result", true);
} else {
ObjectValidate annotation = field.getAnnotation(ObjectValidate.class);
validateResult.put("result", false);
validateResult.put("message", String.format("%s对象中的参数有误:{%s}", annotation.className().getSimpleName(),
result.get("message")));
}
}
} else {
validateResult.put("message", "验证通过");
validateResult.put("result", true);
}
return validateResult;
}
public static final Date convertStringToDate(String aMask, String strDate) throws ParseException {
SimpleDateFormat df = null;
Date date = null;
df = new SimpleDateFormat(aMask);
try {
date = df.parse(strDate);
} catch (ParseException pe) {
throw new ParseException(pe.getMessage(), pe.getErrorOffset());
}
return date;
}
public static String getDateString(Date _date, String patternString) {
String dateString = "";
if (_date != null) {
SimpleDateFormat formatter = new SimpleDateFormat(patternString);
dateString = formatter.format(_date);
}
return dateString;
}
}
3、测试方法
public static void main(String []args){
ValidateVo vo = new ValidateVo();
vo.setApplicationId("csy12132");
vo.setLoanAmount("2.4444");
vo.setLoanDate("2020-10-23");
ValidateVo.InnerVo innerVo = new ValidateVo.InnerVo();
innerVo.setApplicationId("大世界");
List<ValidateVo.InnerVo>list = new ArrayList<>();
list.add(innerVo);
vo.setInnerList(list);
Map<String, Object> validateMap = ValidateUtil.validateJson(vo,String.format("调用接口[%s]参数有误",vo));
validateMap.forEach((key,value)->
System.out.println("key:"+key+",value:"+value));
}
4、输出