利用java的反射机制实现通用dao

来源:互联网 发布:软件著作权 版本升级 编辑:程序博客网 时间:2024/05/16 12:44

java的反射机制前面已经讲过,这里不再赘述,这篇文章将会利用反射,来实现一个通用的dao层。

1 一般情况下的dao层

我们先来看一下,通常,我们是如何写dao的。

public class Person {    public int pid;    public String pname;    public double psalary;    public Date pbirthday;    public int getPid() {        return pid;    }    public void setPid(int pid) {        this.pid = pid;    }    public String getPname() {        return pname;    }    public void setPname(String pname) {        this.pname = pname;    }    public double getPsalary() {        return psalary;    }    public void setPsalary(double psalary) {        this.psalary = psalary;    }    public Date getPbirthday() {        return pbirthday;    }    public void setPbirthday(Date pbirthday) {        this.pbirthday = pbirthday;    }    public Person() {        super();    }}

这是一个正常的javabean,这里的变量写成public不是我 不专业。。。而是我比较懒,方便后面写代码。。。

CREATE DATABASE reflect;USE reflect;CREATE TABLE person(    pid INT PRIMARY KEY,    pname VARCHAR(255) NOT NULL,    psalary FLOAT,    pbirthday DATE);INSERT INTO person VALUES(    1,'jack','1000','1995-11-27');CREATE TABLE animal(    aid INT PRIMARY KEY,    aname VARCHAR(255) NOT NULL);INSERT INTO animal VALUES(    1,'tom');

数据库脚本文件,这里采用mysql数据库

package com.mystery.dao;import java.sql.Connection;import java.sql.DriverManager;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Statement;import java.util.ArrayList;import java.util.List;import org.junit.Test;import com.mystery.domain.Person;public class PersonDao {    public static List<Person> select() throws SQLException {          Connection conn = null;          Statement st = null;          ResultSet rs = null;          List<Person> list = null;          try {              conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/reflect","root","123456");             st = conn.createStatement();              rs = st.executeQuery("select * from person");              list = new ArrayList<Person>();              while (rs.next()) {                  Person p = new Person();                  p.setPid(rs.getInt("pid"));                  p.setPname(rs.getString("pname"));                p.setPsalary(rs.getFloat("psalary"));                p.setPbirthday(rs.getDate("pbirthday"));                list.add(p);              }          } finally {              if (rs != null)                  rs.close();              if (st != null)                  st.close();              if (conn != null)                  conn.close();          }          return list;      }      @Test    public void test(){        try {            List<Person> l = select();            for (int i = 0; i < l.size(); i++) {                System.out.println(l.get(i).getPname());            }        } catch (SQLException e) {            e.printStackTrace();        }    }}

通常,我们都是这么写的,代码量也不是很大,为了省事,我就只写一个select方法了。但是,假如我们又多了一张表,也就是animal,怎么办呢?正常情况下,我们是这么做的:

package com.mystery.domain;public class Animal {    public int aid;    public String aname;    public int getAid() {        return aid;    }    public void setAid(int aid) {        this.aid = aid;    }    public String getAname() {        return aname;    }    public void setAname(String aname) {        this.aname = aname;    }}

话不多说,直接javabean

package com.mystery.dao;import java.sql.Connection;import java.sql.DriverManager;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Statement;import java.util.ArrayList;import java.util.List;import org.junit.Test;import com.mystery.domain.Animal;public class AnimalDao {    public static List<Animal> select() throws SQLException {          Connection conn = null;          Statement st = null;          ResultSet rs = null;          List<Animal> list = null;          try {              conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/reflect","root","123456");             st = conn.createStatement();              rs = st.executeQuery("select * from animal");              list = new ArrayList<Animal>();              while (rs.next()) {                  Animal a = new Animal();                  a.setAid(rs.getInt("aid"));                  a.setAname(rs.getString("aname"));                list.add(a);              }          } finally {              if (rs != null)                  rs.close();              if (st != null)                  st.close();              if (conn != null)                  conn.close();          }          return list;      }      @Test    public void test(){        try {            List<Animal> l = select();            for (int i = 0; i < l.size(); i++) {                System.out.println(l.get(i).getAname());            }        } catch (SQLException e) {            e.printStackTrace();        }    }}

然后很无耻的copy&paste一下,稍微做一些修改就好了。感觉也不是很费力。但是,假如又多了10张表呢?copy&paste是那些勤快的人的写法,像我这种比较懒的,就喜欢一劳永逸的写法。

一劳永逸的dao

    /**     * 查询功能     * @param cls 要查询的对象的class对象     * @return     * @throws Exception     */    public ArrayList<? extends Object> selectAll(Class<?> cls) throws Exception {          Connection conn = null;          Statement st = null;          ResultSet rs = null;          ArrayList<Object> list = null;        Object obj = cls.newInstance();        try {              conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/reflect","root","123456");             st = conn.createStatement();            rs = st.executeQuery(String.format(                       "select * from %s",cls.getSimpleName()                       ));             list = new ArrayList<Object>();              //这里如果javabean的属性是私有的会访问不到,解决方案有三种            //1.像我一样改成public  (极其不推荐)            //2.添加一句field.setAccessible(true);//设置允许访问              //3.调用javabean里的getset方法            Field[] fields = cls.getFields(); // 获得域列表              while (rs.next()) {                  for (Field field : fields) {                                    Object value = rs.getObject(field.getName());                      field.set(obj, value);  // 设定域值                  }                  list.add(obj);              }          } catch (Exception e) {            e.printStackTrace();        }finally {              if (rs != null)                  rs.close();              if (st != null)                  st.close();              if (conn != null)                  conn.close();          }          return list;      }

做个测试:

    @Test    public void testSelectAll(){        try {            @SuppressWarnings("unchecked")            //List<Person> l = (List<Person>) selectAll(Person.class,new Person());            List<Animal> l = (List<Animal>) selectAll(Animal.class);            for (int i = 0; i < l.size(); i++) {                System.out.println(l.get(i).getAname());            }        } catch (SQLException e) {            e.printStackTrace();        } catch (Exception e) {            e.printStackTrace();        }    }

这样,一个方法就可以查询所有的对象,无论是animal还是person,一个dao就够了,是不是方便了许多?

再写一个插入和删除

    /**     * 插入功能     * @param obj 要插入的对象     * @throws Exception     */    public void insert(Object obj) throws Exception {          Connection conn = null;          PreparedStatement st = null;          try {              conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/reflect","root","123456");             Class<?> cls = obj.getClass();            Field[] fields = cls.getFields();             // 下面一段代码准备SQL语句的两部分。              StringBuilder sbForFieldName = new StringBuilder();              StringBuilder sbForQuestionMark = new StringBuilder();              for (int i = 0; i < fields.length; i++) {                  if(i>0) {                      sbForFieldName.append(",");                      sbForQuestionMark.append(",");                  }                  sbForFieldName.append(fields[i].getName());                  sbForQuestionMark.append("?");              }              String FieldNames = sbForFieldName.toString();              String QuestionMarks = sbForQuestionMark.toString();              // 安全起见,我们需要用prepareStatement处理用户输入。              // 但是因为类的名称是可以由程序员控制的,我们用String.format生成语句              st = conn.prepareStatement(String.format(                          "INSERT INTO %s(%s) values(%s)",                          cls.getSimpleName(), FieldNames,  QuestionMarks));              //填充PreparedStatement              for (int i = 0; i < fields.length; i++) {                  st.setObject(i + 1, fields[i].get(obj));              }              st.executeUpdate();          } finally {              if (st != null)                  st.close();              if (conn != null) {                  conn.close();              }          }      }    /**     * 根据id删除对象  出入的对象必须已经对id赋值并且域名称必须包含'id'     * @param obj     * @return     * @throws Exception     */    public Boolean delete(Object obj) throws Exception {          Connection conn = null;          Statement st = null;          Class<?> cls = obj.getClass();        try {              conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/reflect","root","123456");             st = conn.createStatement();            Field[] fields = cls.getFields();            Object id = null;            for (Field field : fields) {                                if(field.getName().indexOf("id") != -1){                    id = field.get(obj);                    break;                }            }             st.executeUpdate(String.format(                       "DELETE FROM %s WHERE pid = %s;",cls.getSimpleName(),id                       ));         } catch (Exception e) {            e.printStackTrace();        }finally {               if (st != null)                  st.close();              if (conn != null)                  conn.close();          }          return true;      }    @SuppressWarnings("deprecation")    @Test    public void testInsert(){        Person p = new Person();        p.setPid(2);        p.setPbirthday(new Date(0,1,1));        p.setPname("jery");        p.setPsalary(1200);        try {            insert(p);            System.out.println("ok");        } catch (Exception e) {            e.printStackTrace();        }    }    @SuppressWarnings("deprecation")    @Test    public void testDelete(){        Person p = new Person();        p.setPid(2);        p.setPbirthday(new Date(0,1,1));        p.setPname("jery");        p.setPsalary(1200);        try {            delete(p);            System.out.println("ok");        } catch (Exception e) {            e.printStackTrace();        }    }

其他的功能就不贴出来了,源码我会放到我的github主页(https://github.com/CleverFan)上,感兴趣的可以去看一下。我也是个新手,有哪些地方不合理的欢迎大家批评指正,互相学习。

1 0
原创粉丝点击