这段时间封装了很多的sdk,有一些sdk要求请求参数做验证,由于封装sdk肯定是用到第三方的依赖越少越好,所以自己不才写了一个注解的校验,本版本校验没有给出自定一点message,如果要可以自己加上,修改一下即可。下面就说一下这个怎么实现的吧:
一:注解类:
注解类代码如下:
package com.blog.annotation.one;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.Target;import static java.lang.annotation.ElementType.FIELD;import static java.lang.annotation.RetentionPolicy.RUNTIME;/** * @author 哲思小辉 * @className CheckNull * @description 校验参数一个注解 * @createTime 7月30日 16:48:38 */@Target({FIELD, ElementType.TYPE, ElementType.PARAMETER})@Retention(RUNTIME)public @interface CheckNull {/*** 是否校验为null** @return*/boolean notNull() default false;/*** 默认检查为空** @return*/boolean notEmpty() default false;/*** 长度最小值,集合最小值,map键最小个数** @return*/int minLength() default 0;/*** 长度最大值,集合最小值,map键最大个数** @return*/int maxLength() default 0;/*** 长度固定值** @return*/int equalLength() default 0;/*** 最小值 (针对基本数据类型)** @return*/String minValue() default "";/*** 最大值 (针对基本数据类型)** @return*/String maxValue() default "";/*** 相等的值** @return*/String equalValue() default "";/*** String包含的数值, Map中必须存在的key** @return*/String[] strContains() default {};/*** 是否去除前后空格(字符串)** @return*/boolean trim() default true;}
二、校验使用注解的实例对象方法
注解写好了,现在要写它的校验,如何来判断该字段是否符合注解里面定义的呢,下面就是校验的代码:
package com.blog.annotation.one;import java.lang.reflect.Field;import java.util.*;/** * @author 哲思小辉 * @className CheckNullUtil * @description 单一注解检测工具 * @createTime 7月30日 16:40:52 */public final class CheckNullUtils {private CheckNullUtils() {}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 Setset;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);}/*** 判断为空并且如果字符串不去除空格** @param object* @param message* @throws Exception*/public static void checkNullAndEmpty(Object object, String message) throws Exception {checkNull(object, message);checkEmpty(object, message, false);}/*** 判断为空并且如果字符串就去除前后的空格** @param object* @param message* @throws Exception*/public static void checkNullAndTrimEmpty(Object object, String message) throws Exception {checkNull(object, message);checkEmpty(object, message, true);}/*** 校验是不是为null** @param message* @param object* @throws Exception*/public static void checkNull(Object object, String message) {checkBoolean(object == null, message);}/*** 校验元素为不为空** @param object* @param message* @param isTrim* @throws Exception*/public static void checkEmpty(Object object, String message, boolean isTrim) {// 先检测是否为nullcheckNull(object, message);boolean isOperator = false;if (object instanceof String) {// 字符串长度为0String str = (String) object;str = isTrim ? str.trim() : str;isOperator = str.length() == 0;} else if (object instanceof Collection) {// 个数为0isOperator = ((Collection) object).isEmpty();} else if (object instanceof Map) {// 键值为空isOperator = ((Map) object).isEmpty();} else if (object.getClass().isArray()) {// 数组长度为0isOperator = ((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* @param message* @throws Exception*/private static void checkFields(Object req, String message) throws Exception {checkNull(req, message);Class> aClass = req.getClass();CheckNull checkNull = aClass.getAnnotation(CheckNull.class);if (checkNull != null && checkNull.notEmpty()) {checkEmpty(req, message, checkNull.trim());}// 获取里面的属性Field[] fields = aClass.getDeclaredFields();if (fields == null || fields.length == 0) {return;}for (int i = 0; fields != null && i < fields.length; i++) {Field field = fields[i];CheckNull annotation = field.getAnnotation(CheckNull.class);if (annotation != null) {int maxLength = annotation.maxLength();boolean isMax = maxLength > 0;int minLength = annotation.minLength();boolean isMin = minLength > 0;int equalLength = annotation.equalLength();boolean isEqual = equalLength > 0;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));}String nullEmptyStr = String.format(ILLEGAL_NULL_OR_EMPTY_STR, fieldName);// 如果注解中notNull为true就检验是否为nullif (annotation.notNull()) {checkNull(object, nullEmptyStr);}// 如果注解中notEmpty为true就检验是否为空if (annotation.notEmpty()) {checkEmpty(object, nullEmptyStr, checkNull.trim());}// 不为空就校验里面的参数数据if (object != null) {Class> type = field.getType();Class>[] interfaces = type.getInterfaces();Class> superclass = type.getSuperclass();String[] strings = annotation.strContains();// 获取接口HashSet> classSet = new HashSet<>(Arrays.asList(interfaces));if (type.equals(String.class)) {String str = (String) object;int length = str.length();if (annotation.trim()) {str = str.trim();}// 校验长度是不是小于最小值checkBoolean(isMin && length < minLength, String.format(ILLEGAL_MIN_LENGTH_STR, fieldName,minLength));// 校验长度是不是大于最大值checkBoolean(isMax && length > maxLength, String.format(ILLEGAL_MAX_LENGTH_STR, fieldName,maxLength));// 校验长度是否相等checkBoolean(isEqual && length != equalLength, String.format(ILLEGAL_EQUAL_LENGTH_STR,fieldName, equalLength));// 是否包含值if (strings != null) {Set valueSet = new HashSet<>(Arrays.asList(strings));checkBoolean(!valueSet.contains(str), String.format(ILLEGAL_STR, fieldName));}} else if (Number.class.equals(superclass) || set.contains(type)) {compareNumber(object, type, annotation.maxValue(), annotation.minValue(), annotation.equalValue(),fieldName);if (strings.length > 0) {Set valueSet = new HashSet<>(Arrays.asList(strings));checkBoolean(!valueSet.contains(String.valueOf(object)), String.format(ILLEGAL_STR,fieldName));}} else if (type.isAnnotationPresent(CheckNull.class)) {// 如果是使用了NotNull注解的类进行里面参数校验checkFields(object, String.format(ILLEGAL_NULL_OR_EMPTY_STR, fieldName));} else if (classSet.contains(Collection.class)) {// 当前集合的泛型类型Collection collection = (Collection) object;int colletionSize = collection.size();checkCollectionAndMapAndArray(colletionSize, equalLength, minLength, maxLength, fieldName);if (colletionSize > 0) {for (Object o : collection) {checkObject(o, String.format(ILLEGAL_FIELD_ERROR_STR, fieldName));}}} else if (Map.class.equals(type) || classSet.contains(Map.class)) {Map map = (Map) object;int mapSize = map.size();// 校验个数是不是小于最小值checkBoolean(isMin && mapSize < minLength, String.format(ILLEGAL_MIN_SIZE_STR, fieldName, minLength));// 校验个数是不是大于最大值checkBoolean(isMax && mapSize > maxLength, String.format(ILLEGAL_MAX_SIZE_STR, fieldName, maxLength));// 校验个数是否相等checkBoolean(isEqual && mapSize != equalLength, String.format(ILLEGAL_STR, fieldName));for (int m = 0; 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);for (int k = 0; arrayLength > 0 && k < arrayLength; k++) {checkObject(arrays[k], String.format(ILLEGAL_FIELD_ERROR_STR, fieldName));}}}}}}/*** 比较基本数据类型 封装数据类型** @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));}/*** 集合类型、Map类型、数组元素个数校验** @param collectionSize* @param equalLength* @param minLength* @param maxLength* @param fieldName*/private static void checkCollectionAndMapAndArray(int collectionSize, int equalLength, int minLength,int maxLength, String fieldName) {// 检验元素个数是否小于最小值checkBoolean(minLength != 0 && collectionSize < minLength, String.format(ILLEGAL_MIN_SIZE_STR,fieldName,minLength));// 检验元素个数是否大于最大值checkBoolean(maxLength != 0 && collectionSize > maxLength, String.format(ILLEGAL_MAX_SIZE_STR, fieldName,maxLength));// 检验元素个数是否等于固定值checkBoolean(equalLength != 0 && collectionSize != equalLength, String.format(ILLEGAL_EQUAL_SIZE_STR, fieldName,minLength));}}
可以看到对长度,是否为null,为空,个数,数值大小都做了校验,满足大多数的需求,可能需要一些特殊类型数据的校验就自行加就OK了。注解和校验类都写好了现在就是测试的时候了,
三、测试一波
Person类代码忽略set,get方法了哦
public class Person {@CheckNull(trim = true, minLength = 2, maxLength = 5)private String name;private List list;@CheckNullprivate Test[] tests;@CheckNull(minLength = 2)private Integer[] integers;@CheckNull(minLength = 3)private Double[] ints;@CheckNullprivate Test test;@CheckNull(minValue = "3", strContains = {"3.222", "3.88"})private float a;@CheckNull(minValue = "2")private Integer b;@CheckNull(strContains = {"a", "b"}, minLength = 2, maxLength = 2)private HashMap map;@CheckNull(minLength = 2, maxLength = 3)private Map map2;public Person(String name, List list, int a, Integer b, HashMap map, Map map2) {this.name = name;this.list = list;this.a = a;this.b = b;this.map = map;this.map2 = map2;}}
test类也忽略了set,get方法了哦
public class Test {private Integer age;private String name;public static void main(String[] args) throws Exception {List lists = new ArrayList<>();lists.add("a");HashMapmap = new HashMap<>();map.put("a", "df");Person a = new Person(" ", lists, 1, 1, map, map);a.setTest(new com.blog.annotation.one.Test());a.setA(3.88f);a.setInts(new Double[]{});CheckNullUtils.checkObject(a, "请求参数为空");}}
测试的时候把
checkBoolean这个抛出异常的注释了,所有的异常都是该方法的抛出
结果为:
校验结果还可以吧,自己觉得把错误信息修改成英文可能逼格会高点,这种高逼格的事情就留给你们去做了,我还是喜欢低调点,谁让我渣呢,没有办法,继续学习,一起加油。