欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

简单的注解剖析

程序员文章站 2022-05-10 12:00:48
周边有许多同事只会使用注解,并不了解注解的原理。于是随手写一个小Demo,普及下注解的使用原理,顺便加深自己的理解。如有错误,欢迎大牛指正。 1 注解类基本样式 2 注解类的元素解析 元注解: 总共有四个元注解,分别是:@Target,@Retention,@Documented,@Inherite ......

  周边有许多同事只会使用注解,并不了解注解的原理。于是随手写一个小Demo,普及下注解的使用原理,顺便加深自己的理解。如有错误,欢迎大牛指正。

1 注解类基本样式

/**
 *
 * @author qpf
 * 此注解用于对表名的设置
 *
 */
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {
    String value();
}

2 注解类的元素解析

元注解:
 
总共有四个元注解,分别是:@Target,@Retention,@Documented,@Inherited,属于jdk注解,作用如下:
      @Target 表示该注解用于什么地方,可能的值在枚举类 ElemenetType 中,包括: 
          ElemenetType.CONSTRUCTOR----------------------------构造器声明 
          ElemenetType.FIELD --------------------------------------域声明(包括 enum 实例) 
          ElemenetType.LOCAL_VARIABLE------------------------- 局部变量声明 
          ElemenetType.METHOD ----------------------------------方法声明 
          ElemenetType.PACKAGE --------------------------------- 包声明 
          ElemenetType.PARAMETER ------------------------------参数声明 
          ElemenetType.TYPE--------------------------------------- 类,接口(包括注解类型)或enum声明 
           
     @Retention 表示在什么级别保存该注解信息。可选的参数值在枚举类型 RetentionPolicy 中,包括: 
          RetentionPolicy.SOURCE ---------------------------------注解将被编译器丢弃 
          RetentionPolicy.CLASS -----------------------------------注解在class文件中可用,但会被VM丢弃 
          RetentionPolicy.RUNTIME -------将在运行期也保留注释,因此可以通过反射机制读取注解的信息。 
@Documented 将此注解包含在 javadoc 中 ,它代表着此注解会被javadoc工具提取成文档。在doc文档中的内容会因为此注解的信息内容不同而不同。相当与@see,@param 等。
 @Inherited 允许子类继承父类中的注解。
 
 
注解使用方法:
@Table("StudentInfo")
public class StudentInfo extends BaseTable
{
     //学生姓名
     @Column("name")
     private String name;
     
     //性别
     @Column("sex")
     private String sex;
}
 
注意:@Target设置了注解放在什么地方,设置为ElemenetType.FIELD,则需要将注解放置在属性的上方。设置为ElemenetType.TYPE,则需要放置在class上方。放错位置,编译器会报错。
原理:把public @interface Table {String value();}和@Table("StudentInfo")
放在一起看,其实注解就是返回你所设置的指定类型的值。其实就是在调用注解的value()方法,会返回String类型的值,值为注解中设置的“StudentInfo”。后面例子中会有详细介绍。还需注意一点,注解中返回的类型是有限定的,且方法一定要是无参的,不懂的可自行百度。
 

3 利用注解实现小Demo

3.1 需求内容

1、有一张学生信息表,字段包括姓名,年级,班级,教师名,性别等;

2、利用注解,对表实例的每个字段进行检查,并打印出查询sql   

3.2 代码结构

简单的注解剖析

annotation:存放创建的注解。
bean:存放数据库表所用到的javaBean
test:main函数,用于测试并打印查询sql;
 

3.3 注解类

/**
 *
 * @author qpf
 * 此注解用于对表字段的设置
 */
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
    String value();
}

 

/**
 *
 * @author qpf
 * 此注解用于对表名的设置
 *
 */
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {
    String value();
}

 

3.4 学生信息表的javabean

下面的代码删去了get和set方法。

/**
 *
 * @author qpf
 * Table标签里为表名
 * Column标签里为数据库字段名
 */
@Table("StudentInfo")
public class StudentInfo extends BaseTable
{
     //学生姓名
     @Column("name")
     private String name;
     
     //性别
     @Column("sex")
     private String sex;
     
     //年级
     @Column("grade")
     private String grade;
     
     //班级
     @Column("class_num")
     private String classNum;
     
     //班主任
     @Column("teacher")
     private String teacher;
     
     //总分
     @Column("total_scores")
     private String totalScores;
     
     //微信号
     @Column("weChat_num")
     private String weChatNum;
     
     //手机号
     @Column("tel_num")
     private String telNum;
     
     //父亲名
     @Column("father_name")
     private String fatherName;
     
     //母亲名
     @Column("mother_name")
     private String motherName;
}
 

  

3.5 AnnotationTest方法

public class AnnotationTest {
     /**
      * 需求设计:
      *    1、有一张学生信息表,字段包括姓名,年级,班级,教师名,性别等;
      *    2、利用注解,对每个字段的组合条件进行检查,并打印出sql     
      */
     public static void main(String[] args)
     {
         // TODO Auto-generated method stub
         StudentInfo studentInfo=new StudentInfo();
         studentInfo.setName("Tom");
         studentInfo.setSex("men");
         studentInfo.setTelNum("18255005147,18255005148,18255005149");
         studentInfo.setWeChatNum("qpf123456");
         String sql=querySql(studentInfo);
         System.out.println((sql==null)?"":sql);
     }
     public static String querySql(BaseTable table)
     {
         //获取类加载器
         Class<?> cTable=table.getClass();
         //判断类中是否包含Table的注解
         boolean tableIsExists=cTable.isAnnotationPresent(Table.class);
         
         //判断是否为表实例
         if(!tableIsExists)
         {
              return null;
         }
         
         //获取表名
         String tableName=cTable.getAnnotation(Table.class).value();
         
         //初始化表查询语句
         StringBuilder builder=new StringBuilder("select * from");
         builder.append(" "+tableName+" where 1=1");
         
         //获取表实例中的所有字段
         Field[] fields=cTable.getDeclaredFields();
         
         
         try
         {
              for (Field field : fields)
              {
                   //判断是否为表数据字段
                boolean columnIsExist=field.isAnnotationPresent(Column.class);
                   
                   if(!columnIsExist)
                   {
                       continue;
                   }
                   
                   //判断表数据字段的值是否为null
                   field.setAccessible(true);
                   String fieldValue=(String)field.get(table);
                   if(null==fieldValue || "".equals(fieldValue))
                   {
                       continue;
                   }
                   
                   //检测到需要拼接字段时,再获取数据库字段名
                   String columnName=field.getAnnotation(Column.class).value();
                   
                   //需要用in的字段处理
                   if(fieldValue.contains(","))
                   {
                       builder.append(" and "+columnName+" in(");
                       String[] strs=fieldValue.split(",");
                       
                       for (int i = 0; i < strs.length; i++)
                       {
                            builder.append("'"+strs[i]+"'");
                            if(i!=strs.length-1)
                            {
                                 builder.append(",");
                            }
                       }
                            
                       builder.append(")");
                   }
                   else
                   {
                    builder.append(" and "+columnName+"="+"'"+fieldValue+"'");
                   }
                   
              }
         }
         catch (Exception e)
         {
              // TODO Auto-generated catch block
              e.printStackTrace();
         }
         
         return builder.toString();
     }
}

  

上面方法打印出的查询sql语句为:

select * from StudentInfo where 1=1 and name='Tom' and sex='men' and weChat_num='qpf123456' and tel_num in('18255005147','18255005148','18255005149')