利用JAVA反射机制设计一个通用的DAO
反射机制
反射机制指的是程序在运行时能够获取自身的信息。在java中,只要给定类的名字,
那么就可以通过反射机制来获得类的所有信息。
反射机制创建类对象
Class c=Class.forName("className");注明:className必须为全名,也就是得包含包名,比如,com.cnblog.Bean;
Object obj=c.newInstance();//创建对象的实例
有了类对象就可以对该类的方法及属性进行操作
通用DAO
可以对所有单表的增删查改,无需新建对应的DAO文件,即新增表操作的的时候,只需要建立表的对应的javabean即可,无需新建表的DAO文件
代码结构也比较简单
连接数据库的类 DBConnection.java
DAO的实现类 DAOImpl.java
DAO的代理类 DAOProxy.java
各个表的bean
DBConnection.java 连接数据库的类
package Utils; import java.sql.Connection;
import java.sql.DriverManager; public class DBConnection {
private Connection conn;
private String url;
private String user;
private String password;
private String driver; public String getUrl() {
return url;
} public void setUrl(String url) {
this.url = url;
} public String getUser() {
return user;
} public void setUser(String user) {
this.user = user;
} public String getPassword() {
return password;
} public void setPassword(String password) {
this.password = password;
} public String getDriver() {
return driver;
} public void setDriver(String driver) {
this.driver = driver;
} public Connection connection()throws Exception{
try{
Class.forName(driver);
}catch(Exception e){
System.out.println("Load error!");
e.printStackTrace();
} try{
conn=DriverManager.getConnection(url, user, password);
}catch(Exception e){
System.out.println("Login error ,please check your login information");
e.printStackTrace();
} return conn; } public void close() throws Exception{ this.conn.close(); } }
DAOImpl.java 增删查改的实现类,所有的bean都作为Object进来,然后通过反射机制拼装数据库操作的sql
query() 传入的bean不需要每个属性都赋值,筛选已赋值的属性拼装sql,筛选的时候利用反射机制中的反射属性Field[] fields =object.getClass().getFields()
insert() 拼装sql时无需筛选未赋值的属性,未赋值的直接插入null
update() 传入两个bean,第一个是更新前的记录,第二个是更新后的记录
delete() 传入的bean不需要每个属性都赋值,筛选已赋值的属性拼装sql,筛选的时候利用反射机制中的反射属性Field[] fields =object.getClass().getFields()
package DAO; import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList; import Bean.*;
import Utils.DBConnection; public class DAOImpl { private DBConnection dataSource;
DAOImpl(DBConnection dataSource) throws Exception{
this.dataSource=dataSource;
} public ArrayList<Object> query(Object object) throws Exception{
Connection conn=null;
PreparedStatement ps=null;
ResultSet rs=null;
ArrayList result=new ArrayList();
//记录非空的属性值,用于SQL的变量绑定
ArrayList args=new ArrayList(); StringBuilder condition=new StringBuilder();
String sql="select * from "+object.getClass().getSimpleName()+" where 1=1 "; //取出对象中的值作为条件,如果值为null则不加入查询条件中
Field[] fields=object.getClass().getFields();
for(Field field:fields){
field.setAccessible(true);
if(this.isBlank(field.get(object))==false){
condition.append(" and ").append(field.getName()).append("=").append("?");
args.add(field.get(object));
} }
sql=sql+condition.toString(); //访问数据库返回查询结果
try{
conn=dataSource.connection();
ps=conn.prepareStatement(sql);
for(int i=0;i<args.size();i++){
//绑定变量下标从1开始
ps.setObject(i+1, args.get(i));
}
rs=ps.executeQuery(); //将查询结果放到bean中
while(rs.next()){
//利用反射机制新建bean实例
String className=object.getClass().getName();
Class<?> obj=Class.forName(className);
Object resultBean=obj.newInstance();
Field[] resultFields=resultBean.getClass().getFields();
for(Field resultField:resultFields){
resultField.setAccessible(true);
resultField.set(resultBean, rs.getObject(resultField.getName()));
} result.add(resultBean);
} }catch(Exception e){
System.out.println("Operation in database fail");
e.printStackTrace();
}finally{
if(rs != null){ // 关闭记录集
try{
rs.close() ;
}catch(SQLException e){
e.printStackTrace() ;
}
}
if(ps != null){ // 关闭声明
try{
ps.close() ;
}catch(SQLException e){
e.printStackTrace() ;
}
}
if(conn != null){ // 关闭连接对象
try{
conn.close() ;
}catch(SQLException e){
e.printStackTrace() ;
}
} }
return result;
} public boolean insert(Object object) throws Exception{
boolean flag=false;
Connection conn=null;
PreparedStatement ps=null; StringBuilder area=new StringBuilder("(");
StringBuilder value=new StringBuilder("(");
//获取Bean下所有的fields
Field[] fields=object.getClass().getFields();
//组装Sql
String sql="insert into "+object.getClass().getSimpleName(); for(int i=0 ;i<fields.length;i++){
area.append(fields[i].getName());
value.append("?");
if(i<fields.length-1){
area.append(",");
value.append(",");
}
} area.append(")");
value.append(")"); sql=sql+area.toString()+" values "+value.toString();
System.out.println(sql); try{
conn=dataSource.connection();
ps = conn.prepareStatement(sql);
for(int i=0;i<fields.length;i++){
fields[i].setAccessible(true);
//setObject 下标 从1开始
ps.setObject(i+1,fields[i].get(object));
System.out.println(fields[i]);
}
if(ps.executeUpdate()>0){
flag=true;
} }catch(Exception e){
System.out.println("Operation in database fail");
e.printStackTrace();
}finally{
if(ps != null){ // 关闭声明
try{
ps.close() ;
}catch(SQLException e){
e.printStackTrace() ;
}
}
if(conn != null){ // 关闭连接对象
try{
conn.close() ;
}catch(SQLException e){
e.printStackTrace() ;
}
}
} return flag;
} public boolean update(Object previous,Object follow) throws Exception{
boolean flag=false;
Connection conn=null;
PreparedStatement ps=null;
ArrayList preArgs=new ArrayList();
ArrayList folArgs=new ArrayList(); //获取where条件的字段值
Field[] preFields=previous.getClass().getFields(); //获取set的字段值
Field[] folFields=follow.getClass().getFields(); StringBuilder set=new StringBuilder("");
StringBuilder where=new StringBuilder(""); String sql="update "+previous.getClass().getSimpleName()+" set 1=1"; //组装sql语句
for(Field folField:folFields){
//如果bean中的属性值没有被set方法赋值过则不添加到sql语句的条件中
if(this.isBlank(folField.get(follow))==false){
set.append(",").append(folField.getName()).append(" = ").append("?");
folArgs.add(folField.get(follow)); }
} sql=sql+set.toString()+" where 1=1 "; for(Field preField:preFields){
if(this.isBlank(preField.get(previous))==false){ where.append(" and ").append(preField.getName()).append(" = ").append("?");
preArgs.add(preField.get(previous));
}
} sql=sql+where.toString();
System.out.println(sql); try{ conn=dataSource.connection();
ps=conn.prepareStatement(sql);
//先绑定set部分的变量,然后再绑定where部分的变量
for(int i=0;i<(folArgs.size()+preArgs.size());i++){
if(i<folArgs.size()){
ps.setObject(i+1, folArgs.get(i));
}else{
ps.setObject(i+1, preArgs.get(i-folArgs.size()));
} }
if(ps.executeUpdate()>0){
flag=true;
}
}catch(Exception e){
System.out.println("Operation in database fail");
e.printStackTrace();
}finally{
if(ps != null){ // 关闭声明
try{
ps.close() ;
}catch(SQLException e){
e.printStackTrace() ;
}
}
if(conn != null){ // 关闭连接对象
try{
conn.close() ;
}catch(SQLException e){
e.printStackTrace() ;
}
}
} return flag;
} public boolean delete(Object object) throws Exception{
boolean flag=false;
Connection conn=null;
PreparedStatement ps=null;
ArrayList args=new ArrayList(); //获取where条件的字段值
Field[] fields=object.getClass().getFields();
StringBuilder where=new StringBuilder(""); //拼装sql
String sql="delect from "+object.getClass().getSimpleName()+" where 1=1"; for(Field field:fields){
//如果属性值没有被set方法设置过,则不添加到条件进去
if(this.isBlank(field.get(object))==false){ where.append(" and ").append(field.getName()).append("=").append("?");
args.add(field.get(object));
}
} sql=sql+where.toString();
System.out.println(sql); try{
conn=dataSource.connection();
ps=conn.prepareStatement(sql);
for(int i=0;i>args.size();i++){
//绑定变量下标从1开始
ps.setObject(i+1, args.get(i));
}
if(ps.executeUpdate()>0){
flag=true;
}
}catch(Exception e){
System.out.println("Operation in database fail");
e.printStackTrace();
}finally{
if(ps != null){ // 关闭声明
try{
ps.close() ;
}catch(SQLException e){
e.printStackTrace() ;
}
}
if(conn != null){ // 关闭连接对象
try{
conn.close() ;
}catch(SQLException e){
e.printStackTrace() ;
}
}
}
return flag;
} /*
* @description 判断bean属性值是否为空
*/
public boolean isBlank(Object object){ boolean flag;
if(null==object||"".equals(object)){
flag=true;
}else{
flag=false;
} return flag;
} }
DAOProxy.java DAO的代理,DBConnection和DAOImpl的连接桥梁
package DAO; import java.util.ArrayList; import Utils.DBConnection; public class DAOProxy {
private DBConnection dataSource;
DAOProxy(DBConnection dataSource){
this.dataSource=dataSource; } public ArrayList doQuery(Object object)throws Exception{
ArrayList result=new ArrayList();
DAOImpl dao=new DAOImpl(dataSource);
result=dao.query(object);
return result;
} public boolean doInsert(Object object)throws Exception{
boolean result;
DAOImpl dao=new DAOImpl(dataSource);
result=dao.insert(object);
return result;
} public boolean doUpdate(Object previous,Object follow)throws Exception{
boolean result;
DAOImpl dao=new DAOImpl(dataSource);
result=dao.update(previous,follow);
return result; } public boolean doDelete(Object object)throws Exception{
boolean result;
DAOImpl dao=new DAOImpl(dataSource);
result=dao.delete(object);
return result;
} }
Bean.java 数据库表对应的javabean
建立对应的javabean时需要注意,属性类型最好不要用基本数据类型,因为这些数据类型会自动初始化,即int类型的属性默认是0,如果没有给该属性赋值,即插入到数据库的时候是0而不是空
其中一个bean的例子
package Bean; import java.math.BigDecimal;
import java.util.Date; public class Employee {
public BigDecimal emp_id;
public String emp_name;
public String emp_dep;
public Date entry_time;
public BigDecimal getEmp_id() {
return emp_id;
}
public void setEmp_id(BigDecimal emp_id) {
this.emp_id = emp_id;
}
public String getEmp_name() {
return emp_name;
}
public void setEmp_name(String emp_name) {
this.emp_name = emp_name;
}
public String getEmp_dep() {
return emp_dep;
}
public void setEmp_dep(String emp_dep) {
this.emp_dep = emp_dep;
}
public Date getEntry_time() {
return entry_time;
}
public void setEntry_time(Date entry_time) {
this.entry_time = entry_time;
} }
测试代码
public static void main(String[] args){
//设置数据库连接
DBConnection dbSource=new DBConnection();
dbSource.setDriver(driver);
dbSource.setUser(user);
dbSource.setPassword(password);
dbSource.setUrl(url);
DAOProxy testDAO=new DAOProxy(dbSource)
Employee jack=new Employee();
jack.setEmp_id(123);
jack.setEmp_name("jack");
jack.setEmp_dep("dev");
testDAO.doInsert(jack);
Employee jack2=new Employee();
jack2.setEmp_id(123);
jack2.setEmp_name("jack");
jack2.setEmp_dep("test");
testDAO.doUpdate(jack, jack2);
}