Java注解2--解析注解与注解反射生成SQL语句

  1. 三解析注解
    1. 注解处理器
    2. 解析注解的代码例子
    3. 测试元注解Retention
    4. 测试元注解Inherited
    5. 知识导图

(三)解析注解

1. 注解处理器

        何为解析注解?即通过反射获取类、函数或成员上的 运行时注解信息,从而实现动态控制程序运行的逻辑。
解析注解主要用到两个类库:
1.1.  java.lang.annotation.Annotation
Java使用Annotation接口来代表程序元素前面的注解,该接口是所有Annotation类型的父接口。
1.2. java.lang.reflect.AnnotatedElement
AnnotatedElement 接口代表程序中可以接受注解的程序元素,是所有程序元素(Class、Method 、Field、Package和Constructor)的父接口。获取该接口对象之后,即可以调用对象方法来访问Annotation信息,常用有如下几个:
         1. getAnnotations():返回该程序元素上存在的所有注解。
         2. isAnnotationPresent(annotation.class):判断该程序元素上是否包含指定类型的注解
         3. getDeclaredAnnotations():返回直接存在于此元素上的所有注释。与此接口中的其他方法不同,该方法将忽略继承的注释。

2. 解析注解的代码例子

定义一个注解如下:
  1. package jtzeng;  
  2. import java.lang.annotation.Documented;  
  3. import java.lang.annotation.ElementType;  
  4. import java.lang.annotation.Inherited;  
  5. import java.lang.annotation.Retention;  
  6. import java.lang.annotation.RetentionPolicy;  
  7. import java.lang.annotation.Target;  
  8. @Target({ElementType.METHOD,ElementType.TYPE})  
  9. @Retention(RetentionPolicy.RUNTIME)  
  10. @Inherited  
  11. @Documented  
  12. public @interface Description {   
  13.     String desc();  
  14.     String author() default "JTZeng";  
  15.     int age() default 21;  
  16. }   
package jtzeng;
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;
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Description { 
	String desc();
	String author() default "JTZeng";
	int age() default 21;
} 
定义一个使用了注解的Test类:
  1. package jtzeng;  
  2. @Description(desc="this is ElementType.TYPE",author="JTZeng",age=21)  
  3. public class Test1 {  
  4.     @Description(desc="this is ElementType.METHOD",author="JTZeng",age=18)  
  5.     public void run(){  
  6.         System.out.println("I can run!");  
  7.     }  
  8. }  
package jtzeng;
@Description(desc="this is ElementType.TYPE",author="JTZeng",age=21)
public class Test1 {
	@Description(desc="this is ElementType.METHOD",author="JTZeng",age=18)
	public void run(){
		System.out.println("I can run!");
	}
}
再编写一个解析类:
  1. package jtzeng;  
  2. import java.lang.annotation.Annotation;  
  3. import java.lang.reflect.Method;  
  4. public class ParseAnno {  
  5.     public static void main(String[] args) {  
  6.         try {  
  7.             /* 
  8.              * 1.使用类加载器加载类 
  9.              * Class.forName("类名字符串") (注意:类名字符串必须是全称,包名+类名) 
  10.              */  
  11.             Class c = Class.forName("jtzeng.Test1");  
  12.               
  13.             //2.判断类上是否存在注解,并获取类上面注解的实例  
  14.             if(c.isAnnotationPresent(Description.class)){  
  15.                 Description Description = (Description) c.getAnnotation(Description.class);  
  16.                 System.out.println(Description.desc());  
  17.                 System.out.println(Description.author());  
  18.                 System.out.println(Description.age());  
  19.             }  
  20.               
  21.             //3.判断方法上是否存在注解,并获取方法上面注解的实例  
  22.             Method[] ms = c.getMethods();  
  23.             for (Method method : ms) {  
  24.                 if(method.isAnnotationPresent(Description.class)){  
  25.                     Description Description = (Description)method.getAnnotation(Description.class);  
  26.                     System.out.println(Description.desc());  
  27.                     System.out.println(Description.author());  
  28.                     System.out.println(Description.age());  
  29.                 }  
  30.             }  
  31.             //另一种获取方法上的注解的解析方法  
  32.             for (Method method : ms) {  
  33.                 Annotation[] as = method.getAnnotations();  
  34.                 for (Annotation annotation : as) {  
  35.                     if(annotation instanceof Description){  
  36.                         System.out.println(((Description) annotation).desc());  
  37.                         System.out.println(((Description) annotation).author());  
  38.                         System.out.println(((Description) annotation).age());  
  39.                     }  
  40.                 }  
  41.             }  
  42.               
  43.         } catch (ClassNotFoundException e) {  
  44.             e.printStackTrace();  
  45.         }  
  46.     }  
  47. }  
package jtzeng;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
public class ParseAnno {
	public static void main(String[] args) {
		try {
			/*
			 * 1.使用类加载器加载类
			 * Class.forName("类名字符串") (注意:类名字符串必须是全称,包名+类名)
			 */
			Class c = Class.forName("jtzeng.Test1");
			
			//2.判断类上是否存在注解,并获取类上面注解的实例
			if(c.isAnnotationPresent(Description.class)){
				Description Description = (Description) c.getAnnotation(Description.class);
				System.out.println(Description.desc());
				System.out.println(Description.author());
				System.out.println(Description.age());
			}
			
			//3.判断方法上是否存在注解,并获取方法上面注解的实例
			Method[] ms = c.getMethods();
			for (Method method : ms) {
				if(method.isAnnotationPresent(Description.class)){
					Description Description = (Description)method.getAnnotation(Description.class);
					System.out.println(Description.desc());
					System.out.println(Description.author());
					System.out.println(Description.age());
				}
			}
			//另一种获取方法上的注解的解析方法
			for (Method method : ms) {
				Annotation[] as = method.getAnnotations();
				for (Annotation annotation : as) {
					if(annotation instanceof Description){
						System.out.println(((Description) annotation).desc());
						System.out.println(((Description) annotation).author());
						System.out.println(((Description) annotation).age());
					}
				}
			}
			
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}
}
运行解析类,结果如下,有三部分,第一部分是类上的注解,第二、三部分是不同的方法解析方法上的注解:


3.测试元注解@Retention

如果把@Retention改为SOURCE或者CLASS,再次运行ParseAnno类:

          运行结果如下,什么也没有,这进一步说明了,只有设置为RUNTIME,才可以在运行时通过反射机制来获取注解信息,从而实现动态控制程序运行的逻辑。


4. 测试元注解@Inherited

创建一个接口和一个父类,并改写Test1类:
  1. package jtzeng;  
  2. @Description(desc = "this is Interface")    //因为注解Description中的author和age成员有默认值,所以可以省略  
  3. public interface Invalid {  
  4.     @Description(desc = "this is Interface method")  
  5.     public void print();  
  6. }  
  7.   
  8.   
  9. package jtzeng;  
  10. @Description(desc = "this is class")  
  11. public class Valid {  
  12.     @Description(desc = "this is class method")  
  13.     public void run(){  
  14.         System.out.println("注解继承只能在子类中有效,不能在接口中继承");  
  15.     }  
  16. }  
  17.   
  18.   
  19. package jtzeng;  
  20. public class Test1 extends Valid implements Invalid {  
  21.     @Override  
  22.     public void run(){  
  23.         System.out.println("覆盖父类的方法");  
  24.     }  
  25.     @Override  
  26.     public void print() {  
  27.         System.out.println("实现接口的方法");  
  28.     }  
  29. }  
package jtzeng;
@Description(desc = "this is Interface")    //因为注解Description中的author和age成员有默认值,所以可以省略
public interface Invalid {
	@Description(desc = "this is Interface method")
	public void print();
}


package jtzeng;
@Description(desc = "this is class")
public class Valid {
	@Description(desc = "this is class method")
	public void run(){
		System.out.println("注解继承只能在子类中有效,不能在接口中继承");
	}
}


package jtzeng;
public class Test1 extends Valid implements Invalid {
	@Override
	public void run(){
		System.out.println("覆盖父类的方法");
	}
	@Override
	public void print() {
		System.out.println("实现接口的方法");
	}
}
再一次运行ParseAnno解析类,输出结果如下,说明只能继承父类的注解,并且是类上的注解:


5. 知识导图

最后给出一张Java注解的知识导图,觉得总结得不错,这里就直接拿来了,导图来源:http://www.cnblogs.com/peida/archive/2013/04/26/3038503.html

(四)注解反射生成SQL语句

1.任务说明

        ①有一张用户表,字段包括:用户ID、用户名、昵称、年龄、性别、所在城市、邮箱、手机号;
        ②使用java注解来对用户表的每个字段或字段的组合条件进行动态生成SQL查询语句。

2.代码实现

2.1 定义注解

定义一个描述用户表的注解:
  1. package dao;  
  2. import java.lang.annotation.ElementType;  
  3. import java.lang.annotation.Retention;  
  4. import java.lang.annotation.RetentionPolicy;  
  5. import java.lang.annotation.Target;  
  6.   
  7. @Target({ElementType.TYPE})  
  8. @Retention(RetentionPolicy.RUNTIME)  
  9. public @interface Table {  
  10.       
  11.     String value();  
  12. }  
package dao;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {
	
	String value();
}

定义一个描述用户表属性字段的注解:
  1. package dao;  
  2. import java.lang.annotation.ElementType;  
  3. import java.lang.annotation.Retention;  
  4. import java.lang.annotation.RetentionPolicy;  
  5. import java.lang.annotation.Target;  
  6.   
  7. @Target({ElementType.FIELD})  
  8. @Retention(RetentionPolicy.RUNTIME)  
  9. public @interface Column {  
  10.       
  11.     String value();  
  12. }  
package dao;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
	
	String value();
}

2.2 定义映射到数据库的bean

用户表,字段包括:用户ID、用户名、昵称、年龄、性别、所在城市、邮箱、手机号:
  1. package dao;  
  2.   
  3. @Table("user")  
  4. public class User {  
  5.       
  6.     @Column("id")  
  7.     private int id;  
  8.       
  9.     @Column("user_name")  
  10.     private String userName;  
  11.       
  12.     @Column("nick_name")  
  13.     private String nickName;  
  14.       
  15.     @Column("age")  
  16.     private int age;  
  17.       
  18.     @Column("city")  
  19.     private String city;  
  20.       
  21.     @Column("email")  
  22.     private String email;  
  23.       
  24.     @Column("mobile")  
  25.     private String mobile;  
  26.   
  27.     public int getId() {  
  28.         return id;  
  29.     }  
  30.     public void setId(int id) {  
  31.         this.id = id;  
  32.     }  
  33.     public String getUserName() {  
  34.         return userName;  
  35.     }  
  36.     public void setUserName(String userName) {  
  37.         this.userName = userName;  
  38.     }  
  39.     public String getNickName() {  
  40.         return nickName;  
  41.     }  
  42.     public void setNickName(String nickName) {  
  43.         this.nickName = nickName;  
  44.     }  
  45.     public int getAge() {  
  46.         return age;  
  47.     }  
  48.     public void setAge(int age) {  
  49.         this.age = age;  
  50.     }  
  51.     public String getCity() {  
  52.         return city;  
  53.     }  
  54.     public void setCity(String city) {  
  55.         this.city = city;  
  56.     }  
  57.     public String getEmail() {  
  58.         return email;  
  59.     }  
  60.     public void setEmail(String email) {  
  61.         this.email = email;  
  62.     }  
  63.     public String getMobile() {  
  64.         return mobile;  
  65.     }  
  66.     public void setMobile(String mobile) {  
  67.         this.mobile = mobile;  
  68.     }  
  69. }  
package dao;

@Table("user")
public class User {
	
	@Column("id")
	private int id;
	
	@Column("user_name")
	private String userName;
	
	@Column("nick_name")
	private String nickName;
	
	@Column("age")
	private int age;
	
	@Column("city")
	private String city;
	
	@Column("email")
	private String email;
	
	@Column("mobile")
	private String mobile;

	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}
	public String getNickName() {
		return nickName;
	}
	public void setNickName(String nickName) {
		this.nickName = nickName;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public String getCity() {
		return city;
	}
	public void setCity(String city) {
		this.city = city;
	}
	public String getEmail() {
		return email;
	}
	public void setEmail(String email) {
		this.email = email;
	}
	public String getMobile() {
		return mobile;
	}
	public void setMobile(String mobile) {
		this.mobile = mobile;
	}
}

2.3 返回SQL查询语句的实现

根据参数动态返回查询语句:
  1. package dao;  
  2. import java.lang.reflect.Field;  
  3. import java.lang.reflect.Method;  
  4.   
  5. public class ReturnQuery {  
  6.     public static String query(Object u){  
  7.         StringBuilder sqlStrBuilder = new StringBuilder();  
  8.         //1.获取到Class  
  9.         Class c = u.getClass();  
  10.         //判断是否包含Table类型的注解  
  11.         if(!c.isAnnotationPresent(Table.class)){  
  12.             return null;  
  13.         }  
  14.         //2.获取到table的名字  
  15.         Table t = (Table) c.getAnnotation(Table.class);  
  16.         String tableName = t.value();  
  17.         //加入 where 1=1 ,是为了防止未来如果没有条件的情况下也不会报错  
  18.         sqlStrBuilder.append("select * from ").append(tableName).append(" where 1=1");  
  19.           
  20.         Field[] fArray = c.getDeclaredFields();   //获取类属性的所有字段,  
  21.         //3.遍历所有的字段  
  22.         for (Field field : fArray) {   
  23.             //4.处理每个字段对应的sql  
  24.             //判断是否包含Column类型的注解  
  25.             if(!field.isAnnotationPresent(Column.class)){  
  26.                 continue;  
  27.             }  
  28.             //4.1.拿到字段上面注解的值,即Column注解的值  
  29.             Column column = field.getAnnotation(Column.class);  
  30.             String columnName = column.value();    
  31.             //4.2.拿到字段的名  
  32.             String filedName = field.getName();  
  33.             //获取相应字段的getXXX()方法  
  34.             String getMethodName = "get" + filedName.substring(01).toUpperCase()  
  35.                     + filedName.substring(1);  
  36.             //字段的值  
  37.             Object fieldValue = null;//属性有int、String等,所以定义为Object类  
  38.             try {  
  39.                 Method getMethod = c.getMethod(getMethodName);  
  40.                 fieldValue = getMethod.invoke(u);  
  41.             } catch (Exception e) {  
  42.                 e.printStackTrace();  
  43.             }   
  44.               
  45.             //4.3.拼接sql  
  46.             if(fieldValue==null || (fieldValue instanceof Integer && (Integer)fieldValue==0)){  
  47.                 continue;  
  48.             }  
  49.             sqlStrBuilder.append(" and ").append(filedName);  
  50.             if(fieldValue instanceof String){  
  51.                 if(((String)fieldValue).contains(",")){  
  52.                     String[] values = ((String)fieldValue).split(",");  
  53.                     sqlStrBuilder.append(" in(");  
  54.                     for (String v : values) {  
  55.                         sqlStrBuilder.append("'").append(v).append("'").append(",");  
  56.                     }  
  57.                     sqlStrBuilder.deleteCharAt(sqlStrBuilder.length()-1);  
  58.                     sqlStrBuilder.append(")");  
  59.                 }  
  60.                 else{  
  61.                     sqlStrBuilder.append("=").append("'").append(fieldValue).append("'");  
  62.                 }  
  63.             }  
  64.             else if(fieldValue instanceof Integer){  
  65.                 sqlStrBuilder.append("=").append(fieldValue);  
  66.             }  
  67.         }  
  68.         return sqlStrBuilder.toString();  
  69.           
  70.     }  
  71. }  
package dao;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class ReturnQuery {
	public static String query(Object u){
		StringBuilder sqlStrBuilder = new StringBuilder();
		//1.获取到Class
		Class c = u.getClass();
		//判断是否包含Table类型的注解
		if(!c.isAnnotationPresent(Table.class)){
			return null;
		}
		//2.获取到table的名字
		Table t = (Table) c.getAnnotation(Table.class);
		String tableName = t.value();
		//加入 where 1=1 ,是为了防止未来如果没有条件的情况下也不会报错
		sqlStrBuilder.append("select * from ").append(tableName).append(" where 1=1");
		
		Field[] fArray = c.getDeclaredFields();   //获取类属性的所有字段,
		//3.遍历所有的字段
		for (Field field : fArray) { 
			//4.处理每个字段对应的sql
			//判断是否包含Column类型的注解
			if(!field.isAnnotationPresent(Column.class)){
				continue;
			}
			//4.1.拿到字段上面注解的值,即Column注解的值
			Column column = field.getAnnotation(Column.class);
			String columnName = column.value();  
			//4.2.拿到字段的名
			String filedName = field.getName();
			//获取相应字段的getXXX()方法
			String getMethodName = "get" + filedName.substring(0, 1).toUpperCase()
					+ filedName.substring(1);
			//字段的值
			Object fieldValue = null;//属性有int、String等,所以定义为Object类
			try {
				Method getMethod = c.getMethod(getMethodName);
				fieldValue = getMethod.invoke(u);
			} catch (Exception e) {
				e.printStackTrace();
			} 
			
			//4.3.拼接sql
			if(fieldValue==null || (fieldValue instanceof Integer && (Integer)fieldValue==0)){
				continue;
			}
			sqlStrBuilder.append(" and ").append(filedName);
			if(fieldValue instanceof String){
				if(((String)fieldValue).contains(",")){
					String[] values = ((String)fieldValue).split(",");
					sqlStrBuilder.append(" in(");
					for (String v : values) {
						sqlStrBuilder.append("'").append(v).append("'").append(",");
					}
					sqlStrBuilder.deleteCharAt(sqlStrBuilder.length()-1);
					sqlStrBuilder.append(")");
				}
				else{
					sqlStrBuilder.append("=").append("'").append(fieldValue).append("'");
				}
			}
			else if(fieldValue instanceof Integer){
				sqlStrBuilder.append("=").append(fieldValue);
			}
		}
		return sqlStrBuilder.toString();
		
	}
}

2.4 返回SQL语句的测试类

  1. package dao;  
  2. public class Test {  
  3.     public static void main(String[] args) {  
  4.         User u1 = new User();  
  5.         u1.setId(9);  //查询id为9的用户  
  6.           
  7.         User u2 = new User();  
  8.         u2.setUserName("JTZeng");   //模糊查询用户名为JTZeng的用户  
  9.         u2.setAge(21);  
  10.           
  11.         User u3 = new User();  
  12.         u3.setEmail("123@163.com,123@qq.com");  //查询邮箱有任意一个的用户  
  13.           
  14.         String sql1 = ReturnQuery.query(u1);    //查询id为9的用户  
  15.         String sql2 = ReturnQuery.query(u2);    //查询用户名为JTZeng和年龄为21的用户  
  16.         String sql3 = ReturnQuery.query(u3);    //查询邮箱中有任意一个的用户  
  17.           
  18.         System.out.println(sql1);  
  19.         System.out.println(sql2);  
  20.         System.out.println(sql3);  
  21.     }  
  22. }  
package dao;
public class Test {
	public static void main(String[] args) {
		User u1 = new User();
		u1.setId(9);  //查询id为9的用户
		
		User u2 = new User();
		u2.setUserName("JTZeng"); 	//模糊查询用户名为JTZeng的用户
		u2.setAge(21);
		
		User u3 = new User();
		u3.setEmail("123@163.com,123@qq.com"); 	//查询邮箱有任意一个的用户
		
		String sql1 = ReturnQuery.query(u1); 	//查询id为9的用户
		String sql2 = ReturnQuery.query(u2);	//查询用户名为JTZeng和年龄为21的用户
		String sql3 = ReturnQuery.query(u3);	//查询邮箱中有任意一个的用户
		
		System.out.println(sql1);
		System.out.println(sql2);
		System.out.println(sql3);
	}
}

输出结果如下:


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值