使用注解校验参数

Posted 格物致知

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用注解校验参数相关的知识,希望对你有一定的参考价值。

一:为什么使用注解

在项目开发中,参数的校验是不可避免的,通常情况下,我们会使用if条件判断,如果

前台传递很多参数过来,那么需要写很多累赘的if代码来校验参数,而使用注解可以避免

这个问题,注解需要依赖javaBean,在字段上我们可以绑定一些元数据,然后在校验的

使用使用,下面是一个简单的实例:

自定义注解:NotNull

package com.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 
 */

/**
 * @author Administrator
 * 校验非空字段
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented 
@Inherited
public @interface NotNull {
	String value();
}

 

javaBean:Person,在字段上面我们可以绑定一些元数据

/**
 * 
 */
package com.hlcui.entity;

import com.annotation.NotNull;

/**
 * @author Administrator
 *
 */
public class Person {
	
	@NotNull(value="身份证号不能为空")
	private String id;
	
	@NotNull(value="姓名不能为空")
	private String name;
	
	private String salary;
	
	private String mgr;
	
	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getSalary() {
		return salary;
	}

	public void setSalary(String salary) {
		this.salary = salary;
	}

	public String getMgr() {
		return mgr;
	}

	public void setMgr(String mgr) {
		this.mgr = mgr;
	}

	public String getName() {
		return name;
	}


	public void setName(String name) {
		this.name = name;
	}

	@Override
	public String toString() {
		return "Person [id=" + id + ", name=" + name + ", salary=" + salary + ", mgr=" + mgr + "]";
	}
	
}

 

自定义异常类:

/**
 * 
 */
package com.hlcui.exception;

/**
 * @author Administrator
 *
 */
public class CustBusinessException extends RuntimeException{

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	public CustBusinessException()
    {
    }

    public CustBusinessException(String s)
    {
        super(s);
    }

    public CustBusinessException(String s, Throwable throwable)
    {
        super(s, throwable);
    }

    public CustBusinessException(Throwable throwable)
    {
        super(throwable);
    }

}

 

我们还需要一个注解解析器,也可以叫做控制器,通常是通过反射得到注解信息:

/**
 * 
 */
package com.hlcui.util;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;

import com.annotation.NotNull;
import com.hlcui.exception.CustBusinessException;

/**
 * @author Administrator
 *
 */
public class CommonUtils {
	
	/**
	 * 通过反射来获取javaBean上的注解信息,判断属性值信息,然后通过注解元数据
	 * 来返回
	 * @param t
	 */
	public static <T> void doValidator(T t){
		Class<?> clazz = t.getClass();
		Field[] fields = clazz.getDeclaredFields();
		for(Field field:fields){
			NotNull notNull = field.getDeclaredAnnotation(NotNull.class);
			if(null!=notNull){
				Object value = getValue(t,field.getName());
				if(!notNull(value)){
					throwExcpetion(notNull.value());
				}
			}
		}
	}
	
	public static <T> Object getValue(T t,String fieldName){
		Object value = null;
		try {
			BeanInfo beanInfo = Introspector.getBeanInfo(t.getClass());
			PropertyDescriptor[] props = beanInfo.getPropertyDescriptors();
			for(PropertyDescriptor property:props){
				if(fieldName.equals(property.getName())){
					Method method = property.getReadMethod();
					value = method.invoke(t,new Object[]{});
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return value;
	}
	
	public static boolean notNull(Object value){
		if(null==value){
			return false;
		}
		if(value instanceof String && isEmpty((String)value)){
			return false;
		}
		if(value instanceof List && isEmpty((List<?>)value)){
			return false;
		}
		return null!=value;
	}
	
	public static boolean isEmpty(String str){
		return null==str || str.isEmpty();
	}
	
	public static boolean isEmpty(List<?> list){
		return null==list || list.isEmpty();
	}
	
	public static void throwExcpetion(String msg){
		if(null!=msg){
			throw new CustBusinessException(msg);
		}
	}
	
	public static void handlerExcpetion(Exception e){
		if(e instanceof CustBusinessException){
			System.out.println(((CustBusinessException)e).getMessage());
		}else{
			System.out.println("调用失败");
		}
	}
}

 

然后我们可以测试校验情况:

/**
 * 
 */
package com.hlcui.test;

import org.junit.Test;

import com.hlcui.entity.Person;
import com.hlcui.util.CommonUtils;

/**
 * @author Administrator
 *
 */
public class TestAnnotation {

	@Test
	public void testNotNull() {
		try {
			Person person = new Person();
			person.setId("1");
			person.setName("李白");
			CommonUtils.doValidator(person);
		} catch (Exception e) {
			CommonUtils.handlerExcpetion(e);
		}
	}

}

 

首先把

person.setId("1");

这行注释掉,运行结果会怎样呢?

身份证号不能为空

  

校验成功!

下面将比较重要的代码做一下讲解:

1:

public static <T> void doValidator(T t){
		Class<?> clazz = t.getClass();
		Field[] fields = clazz.getDeclaredFields();
		for(Field field:fields){
			NotNull notNull = field.getDeclaredAnnotation(NotNull.class);
			if(null!=notNull){
				Object value = getValue(t,field.getName());
				if(!notNull(value)){
					throwExcpetion(notNull.value());
				}
			}
		}
	}

 

首先形参为一个实体对象,这里是使用泛型,然后通过getClass()方法,获取该对象的字节码对象Class,

进而得到所有的字段,然后遍历字段,获取每个字段上面的注解,如果没有注解,则为null,说明不需要校验

,如果不为null,则获取该字段的值,然后判断是否为空(包括null或者""),如果是则抛出异常。

2:

public static <T> Object getValue(T t,String fieldName){
		Object value = null;
		try {
			BeanInfo beanInfo = Introspector.getBeanInfo(t.getClass());
			PropertyDescriptor[] props = beanInfo.getPropertyDescriptors();
			for(PropertyDescriptor property:props){
				if(fieldName.equals(property.getName())){
					Method method = property.getReadMethod();
					value = method.invoke(t,new Object[]{});
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return value;
	}

 

这里面用到了内省(反射中专门针对javaBean),根据该类的字节码文件获取Beaninfo对象,顾名思义就是

包含bean信息的一个对象,然后获取每一个字段的描述器,通过描述器可以获取每个字段的名称、set方法、get

方法,可以获取字段的值,也可以set对象的值,很方便。

当然还可以使用拼接的方式,接set+字段,来得到set方法,和get方法。

 

以上是关于使用注解校验参数的主要内容,如果未能解决你的问题,请参考以下文章

SpringBoot自定义校验注解

注解+反射 参数校验更加简洁

注解+反射 参数校验更加简洁

SpringBoot Validation参数校验 详解自定义注解规则和分组校验

spring注解式参数校验

Spring Boot参数校验以及分组校验的使用