一:為什么使用注解
在項目開發中,參數的校驗是不可避免的,通常情況下,我們會使用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方法。
