万能的BaseDAO和注解的应用

首先科普一下BaseDAO:
BaseDAO一般是提供从数据库 增加、删除、修改记录、查询所有记录、查询符合某个条件记录、取得某条记录等方法的底层数据操作自定义类。
由于我们可能操作多个数据库表,这样就需要为每个表提供一个操作他的类 xxDAO, 这些DAO继承BaseDAO 就可以省略很多重复代码(从数据库 增加、删除、修改记录、查询所有记录、查询符合某个条件记录、取得某条记录等方法的代码)。

最初,我们的BaseDAO是这样子的:
 接口:
package com.kxrjkf.user.dao;
import java.sql.SQLException;
import com.kxrjkf.user.domain.User;
public  interface BaseDAO {
     void add(User user) throws SQLException;
    
     void update(User user) throws SQLException;
    
     void delete(User user) throws SQLException;
    
    User find( int id) throws SQLException;
}
 实现类:
(为使代码更加清晰明了,本文所有DAO的实现类均只实现add()方法) 
 
public  class BaseDAOImpl  implements BaseDAO {
     private QueryRunner qr  =  new QueryRunner();
     public  void add(User user)  throws SQLException {
         //sql
         String sql  =  "insert into user values(?,?,?)";
         //
         Object[] objects  =  new  Object[] { user.getId(),user.getUsername(),user.getPassword()};
         //
        qr.update(DBUtil.getConnection(), sql, objects);
    }
}
BaseDAO的接口和其实现类均和JavaBean的User类紧密耦合,不利于程序扩展性, BaseDAO 代码无法重用,质量低下 。。。
我们想要实现的是,一个 Base DAO,可以对任何JavaBean增删改查,如下所示:

public  class BaseDAO <T > {
 
    QueryRunner qr  =  new QueryRunner();
     public  void add(T bean)  throws SQLException {
         String sql  =  "insert into  values(?)";
         Object[] params ={ /**/};
        qr.update(sql, params);
    }
}
现在存在三个问题,
  1. 表名不确定
  2. 参数个数不确定
  3. 参数名称是什么不知道

现在我们假设:如果表名和JavaBean的类名相同,参数个数和JavaBean的属性个数相同,参数名称和JavaBean的属性名称相同

那么,此时我们能够实现嘛?
 

解:
我们可以写一个自己的DAO继承BaseDAO,在这个子类声明中明确泛型的具体类型(JavaBean,User) 
public   class   UserDAO  extends   BaseDAO{}
然后可以使用如下方法调用链
Class c = (Class) ((ParameterizedType)(this.getClass().getGenericSuperclass())).getActualTypeArguments()[0];
得到子类明确的泛型类型,这个类型即为JavaBean的类型User
表名即为:c.getSimpleName()        //User
此时可以解决第一个问题,表名不确定的问题,我们可以使JavaBean的类型与数据库表名相同,此时就可以获取JavaBean类名作为表名
然后我们可以通过反射,得到JavaBean的所有属性,这些属性作为参数,使JavaBean的属性名和数据库表内的列名称相同。
如此一来,便解决来了第二、三个问题  

我们就需要用到反射和泛型:
 改良后的DAO接口:
package com.kxrjkf.user.daoex;
import java.sql.SQLException;
import com.kxrjkf.user.domain.User;
public  interface BaseDAO <T > {
     void add(T bean) throws SQLException;
    
     void update(T bean) throws SQLException;
    
     void delete(T bean) throws SQLException;
    
    T find( int id) throws SQLException;
}
 改良后的实现类:
 
package com.kxrjkf.user.daoex.impl;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.sql.SQLException;
import org.apache.commons.dbutils.QueryRunner;
import com.kxrjkf.user.daoex.BaseDAO;
import com.kxrjkf.user.util.DBUtil;
public  class BaseDAOImpl <T >  implements BaseDAO <T > {
     //
     private  Class clazz  = ( Class) ((ParameterizedType)( this.getClass().getGenericSuperclass())).getActualTypeArguments()[0];
     private QueryRunner qr  =  new QueryRunner();
     public  void add(T bean)  throws SQLException {
         //1SQL
         String sql  =  "insert into " + clazz.getSimpleName()  + " values(";
         //JavaBean
         int sum  = clazz.getDeclaredFields().length;
         //
         for ( int i  = sum; i  > 0; i --) {
            sql += "?";
             if (i !=1) {
                sql += ",";
            }
        }
        sql += ")";    //insert into user values(?,?,?)
         //2Object
         Object[] objects  =null;
         try {
             //JavaBean
            Field[] fields  = clazz.getDeclaredFields();
             //Object
            objects  =  new  Object[fields.length];
             //Object
             for ( int i  = 0; i  < objects.length; i ++) {
                 //访使
                fields[i].setAccessible(true);
                 //Object
                objects[i]  = fields[i].get(bean);
            }
        }  catch ( Exception e) {
            e.printStackTrace();
        }
         //3sql
        qr.update(DBUtil.getConnection(), sql, objects);
    }
}
 
此时我们完成了上述目标“ 一个DAO,可以对任何JavaBean增删改查
但是别忘了,所有这一切,都建立在我们的三个条件都成立的情况下:
1、表名和JavaBean的类名相同
2、参数个数和JavaBean的属性个数相同
3、参数名称和JavaBean的属性名称相同

虽然达成需求,完成了BaseDAO与JavaBean解耦,但显然这还是不够完美,扩展性和灵活性仍然受到限制
此时我们可以使用properties或者XML配置文件来解决这个问题。
那么,问题又来了,如何使用我们今天刚学习的注解来替代配置文件呢?

 首先,我们需要来三个自定义注解

表名注解:用于指示JavaBean所处表名 
 
package com.kxrjkf.user.domain;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)     //
@Target(ElementType.TYPE)    //
public @ interface Table {
     String value();
}
 
主键注解:用于表示JavaBean中的哪个属性是主键
 
package com.kxrjkf.user.domain;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @ interface ID {
     String value();
}
 
列名注解:用于表示 JavaBean中的属性所对应的列名称
 
package com.kxrjkf.user.domain;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @ interface Column {
     String value();
}
 
此时,我们的JavaBean需要使用注解
 
package com.kxrjkf.user.domain;
@Table( "user")     //
public  class User {
    @ID( "id")    //
     private  int id;
    @Column( "username")
     private  String username;
    @Column( "password")
     private  String password;
}
 
我们需要修改BaseDAO,让他使用可配置的注解来执行增删改查操作,这里就显得有些麻烦
 
package com.kxrjkf.user.daoex.impl;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.sql.SQLException;
import org.apache.commons.dbutils.QueryRunner;
import com.kxrjkf.user.daoex.BaseDAO;
import com.kxrjkf.user.domain.Column;
import com.kxrjkf.user.domain.ID;
import com.kxrjkf.user.domain.Table;
import com.kxrjkf.user.util.DBUtil;
public  class BaseDAOImplEXS <T >  implements BaseDAO <T > {
     private  Class clazz  = ( Class) ((ParameterizedType)( this.getClass().getGenericSuperclass())).getActualTypeArguments()[0];
     private QueryRunner qr  =  new QueryRunner();
     public  void add(T bean)  throws SQLException {
         //1SQL
        
         //
        Table table  = (Table) clazz.getAnnotation(Table. class);
         String tableName  = table.value();
        
         String sql  =  "insert into " + tableName  + " values(";
         int sum  = clazz.getDeclaredFields().length;
         for ( int i  = sum; i  > 0; i --) {
            sql += "?";
             if (i !=1) {
                sql += ",";
            }
        }
        sql += ")";    //insert into user values(?,?,?)
         //2Object
        
         //
        Field[] fields  = clazz.getDeclaredFields();
         int zong =fields.length;      //
         String zhujian  = null;       //
         String[] lie  =  new  String[zong];     //
        
         for ( int i  = 0; i  < lie.length; i ++) {
             try {
                ID id  = fields[i].getAnnotation(ID. class);   //
                zhujian  = id.value();    //
                 continue;    //
            }  catch ( NullPointerException e) {
                 //
            }
             try {
                Column column  = fields[i].getAnnotation(Column. class);   //
                lie[i]  = column.value();
            }  catch ( NullPointerException e) {
                 //
            }
        }
         System.out.println(zong);
         Object[] objects  =null;
         try {
            objects  =  new  Object[zong];
             for ( int i  = 0; i  < zong; i ++) {
                fields[i].setAccessible(true);
                objects[i]  = fields[i].get(bean);
/*              System.out.println(fields[i].getName()+":"+objects[i]);
 *              
                 id:3
                 username:zhangsan
                 password:123456*/
            }
        }  catch ( Exception e) {
            e.printStackTrace();
        }
         for ( Object object : objects) {
             System.out.println(object);
        }
         //3sql
        qr.update(DBUtil.getConnection(), sql, objects);
    }
}
 
 为了方便演示,把一些通用操作全部写到了add()方法中,实际使用时这些方法只需执行一次
 
此时终于完成了对于任何JavaBean都可以操作 的add()方法,扩展性强,十分灵活,可配置,BaseDAO与JavaB ean解耦,表名、列名与JavaBean解耦

搞了这么多,还仅仅是一个add方法。
太晚了,睡觉。

你可能感兴趣的:(JavaWEB,Java)