记录精彩的程序人生

java 自定义注解学习之:利用注解 + 反射 模拟持久层框架的初始化数据库(一)

Java 自定义注解

Java 注解很多地方都会用到,也为我们的开发提供了不少便利,但是对于 Java 自定义注解,却没有真正的去使用过,只是停留在概念的阶段,这两天突发奇想,就想利用 Java 的自定义注解做点事情,于是就有了此文。
此文将描述的是一个模拟持久层框架初始化数据的过程。就像hibernate 那样,不需要手动去数据库建表,就可以通过代码来初始化好数据库。
我本次就是打算模拟该过程,自己去实现一下。

准备注解

这只是一个简单的学习 demo ,所有都只是做一些简单的基本功能实现,代码也都是随便写的,不喜勿喷。

数据库表注解

/**
 * table annotation 
 * @author : gitor
 * @date : 2017/11/24 下午10:54
 */@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {
    //table name
  String value();
}

上面就是数据库表注解的代码,这个没有什么,看一眼就明白,我就不说了

数据库主键注解

/**
 * id 注解,注解与字段之上,用于标识该字段需要设置为数据库主键 
 * @author : gitor
 * @date : 2017/11/24 下午9:41
 */@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Id {
    // 自增标识,true 标识该字段需要数据库自增
  boolean value() default false ;
}

数据库主键的注解,这个注解加了一个是否自增的标识

准备 jdbc

/**
 * jdbc 工具类 
 * @author : gitor
 * @date : 2017/11/24 下午11:02
 */public class Jdbc {

    /**
 * get connection * @return
  */
  private Connection getConnection(){
        try {
            //load jdbc Driver
  Class.forName("com.mysql.jdbc.Driver");
  } catch (ClassNotFoundException e) {
            System.out.println("the jdbc driver not found!");
  e.printStackTrace();
  }

        String url = "jdbc:mysql://127.0.0.1:3306/init" ;
  String username = "root";
  String password = "lwl123";

  Connection conn = null ;

 try {
            conn =  DriverManager.getConnection(url,username,password);

  } catch (Exception e) {
            System.out.println("get connection filed!");
  e.printStackTrace();
  }
        return conn;
  }

    /**
 * excute init */  public  void init(String a){
        Connection conn = this.getConnection();
 if (conn == null){
            System.out.println("connection is null !");
 return ;  }
        try {
            Statement st = conn.createStatement();
  String sql = "SELECT * FROM  b ";
  PreparedStatement ps = conn.prepareStatement(sql);
  ResultSet rs = ps.executeQuery();
  System.out.println("here !");
 while (rs.next()){
                String name = rs.getString("name");
  System.out.println("name:"+name);
  }

        } catch (SQLException e) {
            e.printStackTrace();
  }
    }
}

就是一个简单的 jdbc 获取链接,没有做太多的东西

测试用的实体类

**
 * 测试用的实体类 
 * @author : gitor
 * @date : 2017/11/24 下午10:56
 */@Table("test")
public class Test {
    @Id(true)
    private Integer id;
 private String name;
 private Integer age;

 public Test() {

    }

    public Test(Integer id,String name,Integer age){
        this.id = id;
 this.name = name;
 this.age = age;
  }

    public Integer getId() {
        return id;
  }

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

    public Integer getAge() {
        return age;
  }

    public void setAge(Integer age) {
        this.age = age;
  }

    public String getName() {
        return name;
  }

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

注解解析类

/**
 * 解析注解 * @author : gitor
 * @date : 2017/11/25 下午2:35
 */public class ParseOneClass {

    /**
 * parse annotation */  private static void parseOneClass(Class s){

        Annotation  a= s.getAnnotation(Table.class);

  String className = s.getName();

  //获取某个类到所有属性
  Field[] fields = s.getDeclaredFields();

  //解析类
  if (a instanceof Table){
            Table table = (Table) a;
  System.out.println(className +"该类需要在数据库建表,数据库表名为:"+table.value());
  }
        //解析字段
  System.out.println("该类对应数据库表的字段为:");
 for(int i =0;ilength;i++){
            String name = fields[i].getName();
  Type type = fields[i].getGenericType();

  System.out.println("字段名:"+name+",类型:"+type);

  Annotation annotation =  fields[i].getAnnotation(Id.class);
 if(annotation instanceof Id){
                //是否自增
  boolean auto = ((Id) annotation).value();
 if(auto == true){
                    System.out.println("数据库主键为:"+name+",需要数据设为自增长!");
  }else{
                    System.out.println("数据库主键为:"+name+",不需要数据设为自增长!");
  }

            }
        }

    }

    /**
 * 对应包下面所有的类 */  public static  void parse(){

        String packageName = "entity";

//        List classNames = getClassName(packageName);
//        for (String className : classNames) {
//            System.out.println(className);
//        }
  parseOneClass(Test.class);
  }

}

目前由于我还为实现获取一个包下的所有类来操作,所以测试的时候为是直接指定类来测试的,后续会继续搞一下。

main 方法

/**
 * main Class 
 * @author : gitor
 * @date : 2017/11/24 下午9:38
 */public class Initor {
    public static void main(String[] args) {
//        Jdbc jdbc = new Jdbc();
//        jdbc.init("");
  Class s = Test.class;
  ParseOneClass.parse();
  }

}

测试结果

QQ图片20171125164457.png

由于还在拼接 sql 就下班了,所以最终的测试结果就直接控制台打印出来了,晚上回去再研究研究 一整个包进行扫描解析的。不过剩下的都是 jdbc 的事,还有扫描包的话,估计要直接读文件吧,在这个例子中注解的使用应该就这些了,没什么太大的难度。如果最后需要完整的 demo,那就等(二) 吧。

一个可菜可菜的码农

留下你的脚步