自己动手写注解实现业务bean的字段验证

本文介绍了如何自定义Java注解,包括注解声明、注解生命周期及应用位置,并通过一个检查字符串字段有效性的示例展示了如何使用自定义注解进行参数校验。

我们用过 JDK给我们提供的  @Override  @Deprecated @SuppressWarning 注解  ,这些注解是JDK给我们提供的 ,我们只是在用别人写好的东西 ,那么我们是否可以自己写注解呢?当然是可以的  。

我们写的注解包括三个环节 

1、 注解的声明 ,也就是注解类的定义     形式如下        @interface 来进行注解的声明

package annotate;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.FIELD)  //这个标识注解应该标在那里   ElementType的几个枚举值就代表了  注解应该写在的位置 
@Retention(RetentionPolicy.RUNTIME)  //指定了注解保留的周期 
public @interface CheckString {
  
}

@Retention(RetentionPolicy.RUNTIME)   

指定了注解保留的周期 注解的生命周期有是三个   RetentionPolicy 枚举的三个值代表了三个声明周期  默认是CLASS

枚举常量摘要
CLASS
          编译器将把注释记录在类文件中,但在运行时 VM 不需要保留注释。
RUNTIME
          编译器将把注释记录在类文件中,在运行时 VM 将保留注释,因此可以反射性地读取。
SOURCE
          编译器要丢弃的注释。

 

@Target(ElementType.TYPE) 

这个标识注解应该标在那里   ElementType的几个枚举值就代表了  注解应该写在的位置

 

CONSTRUCTOR
          构造方法声明
FIELD
          字段声明(包括枚举常量)
LOCAL_VARIABLE
          局部变量声明
METHOD
          方法声明
PACKAGE
          包声明
PARAMETER
          参数声明
TYPE
          类、接口(包括注释类型)或枚举声明
使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口,由编译程序自动完成其他细节。在定义注解时,不能继承其他的注解或接口。@interface用来声明一个注解,其中的每一个方法实际上是声明了一个配置参数。方法的名称就是参数的名称,返回值类型就是参数的类型(返回值类型只能是基本类型、Class、String、enum)。可以通过default来声明参数的默认值。

Annotation类型里面的参数该怎么设定:
  第一,只能用public或默认(default)这两个访问权修饰.例如,String value();这里把方法设为defaul默认类型;   
  第二,参数成员只能用基本类型byte,short,char,int,long,float,double,boolean八种基本数据类型和 String,Enum,Class,annotations等数据类型,以及这一些类型的数组.例如,String value();这里的参数成员就为String;

package annotate;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.FIELD)  //这个标识注解应该标在那里   ElementType的几个枚举值就代表了  注解应该写在的位置 
@Retention(RetentionPolicy.RUNTIME)  //指定了注解保留的周期 
public @interface CheckString {
	/**
	 * 检验的正则表达式
	 */
	String regex() default ".*";

	/**
	 * 字段是否需要填写
	 */
	Exists exists() default Exists.Skipped;
	
	/**
	 * 字段最小长度
	 * @return
	 */
	int minlen() default 0;
	
	
	/**
	 * 字段最大长度
	 * @return
	 */
	int maxlen() default Short.MAX_VALUE;
}
枚举类:
package annotate;

public enum Exists {
	/**
	 * 跳过检验
	 */
	Skipped,
	
	/**
	 * 禁止填写
	 */	
	Prohibit,
	
	/**
	 * 非空字段
	 */	
	Required,
	
	/**
	 * 可选字段
	 */
	Optional
}

注解使用类:

package model;

import annotate.CheckString;
import annotate.Exists;

public class Persion {
  @CheckString(exists=Exists.Required)
  public String test;
  @CheckString(exists=Exists.Required)
  private String name;
  @CheckString(exists=Exists.Required)
  private String password;
  private String sex;
  private int age;
  
  public String getPassword() {
	return password;
}
public void setPassword(String password) {
	this.password = password;
}
public String getName() {
	return name;
}
public void setName(String name) {
	this.name = name;
}
public String getSex() {
	return sex;
}
public void setSex(String sex) {
	this.sex = sex;
}
public int getAge() {
	return age;
}
public void setAge(int age) {
	this.age = age;
}
@Override
public String toString() {
	return "Persion [name=" + name + ", password=" + password + ", sex=" + sex + ", age=" + age + ", test=" + test + "]";
}
public Persion(String name, String password) {
	super();
	this.name = name;
	this.password = password;
}
  


}

利用反射来操作注解  

Class类有一个 方法

 

<A extends Annotation>
A
   getAnnotation(Class<A> annotationClass)

 

这个方法接受一个注解的字节码参数  ,然后返回这个类所标识的注解对象 ,因为我们标识了一个注解就相当于产生了一个注解对象  。

 

booleanisAnnotationPresent(Class<? extendsAnnotation> annotationClass)

 

这个方法判断一个类是否被注解所标识

下面是代码示例

public class CheckParamUtil {
   public static void checkParam(Object o) throws Exception{
		 out:{
		   final Class<?> objClass=o.getClass();
		   Field[] farray=objClass.getDeclaredFields();//获取所有字段  包括private 不包括父类字段
		   Class<CheckString> chkString=CheckString.class;//CheckString的class
		   for(int i=0;i<farray.length;i++){
			   Field field=farray[i];//获取其中字段
			   String fieldName=field.getName();//获取字段名称
			   if(field.isAnnotationPresent(chkString)){//判断是否被chkstring注解所标识
				   //如果被标识
				  CheckString chk=field.getAnnotation(chkString);// 返回这个类所标识的注解对象
				  Exists e=chk.exists();  //获取字段是否需要填写
				  //获得字段的值
				  field.setAccessible(true);//private字段要设置为true才可以获取值或者修改值
				  String fValue=(String) field.get(o);
				  if(e==Exists.Required){//如果字段是必须填写
					  if(fValue==null||fValue.equals("")){
						  //如果字段是为空 
						  System.out.println(objClass.getSimpleName()+"."+fieldName+"必须填写");
						  break out;
					  }
				  }
			   }
		   }
	   }
   }

验证:

public class TestCheckParam {
    public static void main(String[] args) {
		Persion p=new Persion("zhangsan","111111");
		try {
			CheckParamUtil.checkParam(p);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

控制太打印:Persion.test必须填写

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

你是我的天晴

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值