好久之前更新了单个注解参数校验以后。偷懒了好久,今天就把多个注解自定义的参数校验写了一下,思路是一样的,只是一个注解包含的字段把它分解成了多个注解,类似于java-valid自带的不同功能的校验注解一般,自带的主要适用于不为空,数字型范围之类的校验,对于该属性包含几个值,集合元素个数的限制等都要自定义实现。下面我们这几肝一下:(打工人的觉悟,肝就完了)
我把原先的注解分成了四类
@Checked // 主要用来标记方法或者类是否是校验的
@CheckLength// 校验长度的,集合大小的
@CheckNull// 检验是否为空,去掉前后空格后是否为空
@CheckValues//校验参数值范围的
这几个注解的代码我就不贴上来的,去码云上面拉取就好了哦。
https://gitee.com/yh128/SpringDemoProject
主要看使用注解校验的工具类:
package com.blog.annotation.two;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.*;
/**
* @author 哲思小辉
* @version 1.0.0
* @ClassName CheckNullUtil.java
* @Description 多个注解校验工具类
* @Param
* @createTime 2020年07月26日 15:32:00
*/
public final class CheckNullUtil {
private static final String ILLEGAL_STR = "%s值非法";
private static final String ILLEGAL_NULL_OR_EMPTY_STR = "%s为空";
/**
* 长度类错误字符串
*/
private static final String ILLEGAL_MIN_LENGTH_STR = "%s长度小于%s";
private static final String ILLEGAL_MAX_LENGTH_STR = "%s长度大于%s";
private static final String ILLEGAL_EQUAL_LENGTH_STR = "%s长度不等于%s";
/**
* 个数类错误字符串
*/
private static final String ILLEGAL_MIN_SIZE_STR = "%s元素个数小于%s";
private static final String ILLEGAL_MAX_SIZE_STR = "%s元素个数大于%s";
private static final String ILLEGAL_EQUAL_SIZE_STR = "%s元素个数不等于%s";
/**
* 数值类错误字符串
*/
private static final String ILLEGAL_MIN_VALUE_STR = "%s值小于%s";
private static final String ILLEGAL_MAX_VALUE_STR = "%s值大于%s";
private static final String ILLEGAL_EQUAL_VALUE_STR = "%s值不等于%s";
private static final String ILLEGAL_FIELD_MISSING_STR = "%s字段缺失";
private static final String ILLEGAL_FIELD_ERROR_STR = "%s中有参数为空";
private static final String GET_VALUE_FAIL_STR = "参数%s获取值失败";
private static final String REQUEST_OBJECT_NOT_NULL_STR = "请求对象为空";
/**
* 基本数据类型set
*/
private static Set<Class> set;
static {
set = new HashSet<>();
set.add(int.class);
set.add(short.class);
set.add(byte.class);
set.add(boolean.class);
set.add(float.class);
set.add(double.class);
set.add(long.class);
set.add(char.class);
}
/**
* 校验是不是null,以及是不是为空
*
* @param object
* @param message
* @throws Exception
*/
public static void checkNullAndEmpty(Object object, String message) throws Exception {
checkNull(object, message);
checkEmpty(object, message, null);
}
/**
* 校验是不是为null
*
* @param message
* @param object
* @throws Exception
*/
public static void checkNull(Object object, String message) {
message = message == null ? REQUEST_OBJECT_NOT_NULL_STR : message;
checkBoolean(object == null, message);
}
/**
* 校验元素为不为空
*
* @param object
* @param message
* @throws Exception
*/
public static void checkEmpty(Object object, String message, Boolean isTrim) {
// 先检测是否为null
checkNull(object, message);
boolean isOperator = false;
if (object instanceof String) {
// 字符串长度为0
String str = (String) object;
str = isTrim ? str.trim() : str;
isOperator = str.length() == 0;
} else if (object instanceof Collection) {
// 集合为空
isOperator = ((Collection) object).isEmpty();
} else if (object instanceof Map) {
// Map为空
isOperator = ((Map) object).isEmpty();
} else if (object.getClass().isArray()) {
// 数组个数为0
isOperator = ((Object[]) object).length == 0;
} else if (object.getClass().isArray()) {
// 数组长度为0
isOperator = ((Object[]) object).length == 0;
}
checkBoolean(isOperator, message);
}
/**
* 校验Boolean值,如果为true就抛出异常
*
* @param isOperator
* @param message
*/
public static void checkBoolean(Boolean isOperator, String message) {
if (isOperator != null && isOperator) {
System.out.println("-------> " + message);
// throw new IllegalArgumentException(message);
}
}
/**
* 检验Object
*
* @param req
* @throws Exception
*/
public static void checkObject(Object req) throws Exception {
checkObject(req, REQUEST_OBJECT_NOT_NULL_STR);
}
/**
* 检验Object 自定义错误信息
*
* @param req
* @param message
* @throws Exception
*/
public static void checkObject(Object req, String message) throws Exception {
checkFields(req, message);
}
/**
* 校验object对象
*
* @param req
* @throws Exception
*/
public static void checkFields(Object req, String message) throws Exception {
checkNull(req, message);
CheckNull checkNull = req.getClass().getAnnotation(CheckNull.class);
if (checkNull != null && checkNull.notEmpty()) {
checkEmpty(req, message, null);
}
Class<?> aClass = req.getClass();
Field[] fields = aClass.getDeclaredFields();
for (int i = 0; fields != null && i < fields.length; i++) {
Field field = fields[i];
Class<?> type = field.getType();
field.setAccessible(true);
String fieldName = field.getName();
Object object = null;
try {
object = field.get(req);
} catch (IllegalAccessException e) {
throw new Exception(String.format(GET_VALUE_FAIL_STR, fieldName));
}
// 获取校验null和空的注解
CheckNull valueField = field.getAnnotation(CheckNull.class);
CheckValues valuesCheckAn = field.getAnnotation(CheckValues.class);
CheckLength lengthAn = field.getAnnotation(CheckLength.class);
boolean isValuesAn = valuesCheckAn != null;
boolean isLengthAn = lengthAn != null;
// 如果没有任何自定义注解直接返回不校验
if (valueField == null && !isValuesAn && !isValuesAn) {
continue;
}
// 如果注解不为空就校验
if (valueField != null) {
String nullEmptyStr = String.format(ILLEGAL_NULL_OR_EMPTY_STR, fieldName);
checkNull(valueField, nullEmptyStr);
if (valueField.notEmpty()) {
checkEmpty(object, nullEmptyStr, valueField.trim());
}
}
// 参数数据不为空再判断
if (object != null) {
int equalLength = lengthAn == null ? 0 : lengthAn.equalLength();
int maxLength = lengthAn == null ? 0 : lengthAn.maxLength();
int minLength = lengthAn == null ? 0 : lengthAn.minLength();
String[] strings = valuesCheckAn == null ? null : valuesCheckAn.containValues();
Type superclass = type.getSuperclass();
// 获取接口
Class<?>[] interfaces = type.getInterfaces();
HashSet<Class<?>> classSet = new HashSet<>(Arrays.asList(interfaces));
if (String.class.equals(type)) {
// String 类型处理
boolean trim = valueField == null ? false : valueField.trim();
String str = (String) object;
if (trim) {
str = str.trim();
}
if (isLengthAn) {
int length = str.length();
checkBoolean(minLength != 0 && length < minLength, String.format(ILLEGAL_MIN_LENGTH_STR, fieldName,
minLength));
checkBoolean(maxLength != 0 && length > maxLength, String.format(ILLEGAL_MAX_LENGTH_STR,
fieldName,
maxLength));
checkBoolean(equalLength != 0 && length != equalLength, String.format(ILLEGAL_EQUAL_LENGTH_STR, fieldName,
equalLength));
}
if (isValuesAn && strings.length > 0) {
Set<String> valueSet = new HashSet<>(Arrays.asList(strings));
checkBoolean(!valueSet.contains(str), String.format(ILLEGAL_STR, fieldName));
}
} else if (Number.class.equals(superclass) || set.contains(type)) {
// 基本数据类型处理
if (isValuesAn) {
String maxValue = valuesCheckAn.maxValue();
String minValue = valuesCheckAn.minValue();
String equalValue = valuesCheckAn.equalValue();
compareNumber(object, type, maxValue, minValue, equalValue, fieldName);
if (strings.length > 0) {
Set<String> valueSet = new HashSet<>(Arrays.asList(strings));
checkBoolean(!valueSet.contains(String.valueOf(object)), String.format(ILLEGAL_STR,
fieldName));
}
}
} else if (classSet.contains(Collection.class)) {
// 集合类型处理
Collection collection = (Collection) object;
int collectionSize = collection.size();
checkCollectionAndMapAndArray(collectionSize, equalLength, minLength, maxLength, fieldName, isLengthAn);
if (collectionSize > 0) {
for (Object o : collection) {
checkObject(o, String.format(ILLEGAL_FIELD_ERROR_STR, fieldName));
}
}
} else if (classSet.contains(Map.class) || Map.class.equals(type)) {
// Map类型处理
Map map = (Map) object;
int mapSize = map.size();
checkCollectionAndMapAndArray(mapSize, equalLength, minLength, maxLength, fieldName, isLengthAn);
for (int m = 0; isValuesAn && mapSize > 0 && m < strings.length; m++) {
checkBoolean(!map.containsKey(strings[m]), String.format(ILLEGAL_FIELD_MISSING_STR, fieldName));
}
} else if (type.isArray()) {
// 数组的校验
Object[] arrays = (Object[]) object;
int arrayLength = arrays.length;
checkCollectionAndMapAndArray(arrayLength, equalLength, minLength, maxLength, fieldName, isLengthAn);
for (int k = 0; isValuesAn && arrayLength > 0 && k < arrayLength; k++) {
checkObject(arrays[k], String.format(ILLEGAL_FIELD_ERROR_STR, fieldName));
}
} else if (valueField != null) {
// 如果注解不为空就检验该类
checkObject(object, null);
}
}
}
}
/**
* 集合类型、Map类型、数组元素个数校验
*
* @param collectionSize
* @param equalLength
* @param minLength
* @param maxLength
* @param fieldName
* @param isLengthAn
*/
private static void checkCollectionAndMapAndArray(int collectionSize, int equalLength, int minLength,
int maxLength, String fieldName, boolean isLengthAn) {
// 检验元素个数是否小于最小值
checkBoolean(isLengthAn && minLength != 0 && collectionSize < minLength, String.format(ILLEGAL_MIN_SIZE_STR,
fieldName,
minLength));
// 检验元素个数是否大于最大值
checkBoolean(isLengthAn && maxLength != 0 && collectionSize > maxLength, String.format(ILLEGAL_MAX_SIZE_STR, fieldName,
maxLength));
// 检验元素个数是否等于固定值
checkBoolean(isLengthAn && equalLength != 0 && collectionSize != equalLength, String.format(ILLEGAL_EQUAL_SIZE_STR, fieldName,
minLength));
}
/**
* 比较基本数据类型 封装数据类型
*
* @param object
* @param type
* @param maxValue
* @param minValue
* @param equalValue
* @param filedName
*/
private static void compareNumber(Object object, Class<?> type, String maxValue, String minValue,
String equalValue, String filedName) {
boolean isMaxValue = false;
boolean isMinValue = false;
boolean isEqualValue = false;
if (Integer.class.equals(type) || int.class.equals(type)) {
Integer into = (Integer) object;
into = into == null ? 0 : into;
isMaxValue = !"".equals(maxValue) && Integer.valueOf(maxValue) < into;
isMinValue = !"".equals(minValue) && Integer.valueOf(minValue) > into;
isEqualValue = !"".equals(equalValue) && !Integer.valueOf(equalValue).equals(into);
} else if (Long.class.equals(type) || long.class.equals(type)) {
Long into = (Long) object;
into = into == null ? 0 : into;
isMaxValue = !"".equals(maxValue) && Long.valueOf(maxValue) < into;
isMinValue = !"".equals(minValue) && Long.valueOf(minValue) > into;
isEqualValue = !"".equals(equalValue) && !Long.valueOf(equalValue).equals(into);
} else if (Short.class.equals(type) || short.class.equals(type)) {
Short into = (Short) object;
into = into == null ? 0 : into;
isMaxValue = !"".equals(maxValue) && Short.valueOf(maxValue) < into;
isMinValue = !"".equals(minValue) && Short.valueOf(minValue) > into;
isEqualValue = !"".equals(equalValue) && !Short.valueOf(equalValue).equals(into);
} else if (Double.class.equals(type) || double.class.equals(type)) {
Double into = (Double) object;
into = into == null ? 0 : into;
isMaxValue = !"".equals(maxValue) && Double.valueOf(maxValue) < into;
isMinValue = !"".equals(minValue) && Double.valueOf(minValue) > into;
isEqualValue = !"".equals(equalValue) && !Double.valueOf(equalValue).equals(into);
} else if (Float.class.equals(type) || float.class.equals(type)) {
Float into = (Float) object;
into = into == null ? 0 : into;
isMaxValue = !"".equals(maxValue) && Float.valueOf(maxValue) < into;
isMinValue = !"".equals(minValue) && Float.valueOf(minValue) > into;
isEqualValue = !"".equals(equalValue) && !Float.valueOf(equalValue).equals(into);
}
checkBoolean(isMinValue, String.format(ILLEGAL_MIN_VALUE_STR, filedName, minValue));
checkBoolean(isMaxValue, String.format(ILLEGAL_MAX_VALUE_STR, filedName, maxValue));
checkBoolean(isEqualValue, String.format(ILLEGAL_EQUAL_VALUE_STR, filedName, equalValue));
}
}
主要就是注解类和注解工具类李阿敏判断逻辑不一样,使用的时候可以
使用工具类校验,或者通过aop调用工具类校验,实例代码就不上了,看了单个注解的,多个注解的就通了。
如果使用本代码请自测通过后使用,因为我写的不一定就是标准的。有问题的请联系我,小辉很愿意和你探讨技术问题,尽管小辉技术有点渣,但是还是有点上进心的。加油吧,打工人。
文章同时会更新到公众号,觉得对你有帮助或者有用的可以关注一下哦
版权声明:本文为qq_26584263原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。