利用java的反射机制实现通用dao
2016-08-15 17:27
651 查看
java的反射机制前面已经讲过,这里不再赘述,这篇文章将会利用反射,来实现一个通用的dao层。
这是一个正常的javabean,这里的变量写成public不是我 不专业。。。而是我比较懒,方便后面写代码。。。
数据库脚本文件,这里采用mysql数据库
通常,我们都是这么写的,代码量也不是很大,为了省事,我就只写一个select方法了。但是,假如我们又多了一张表,也就是animal,怎么办呢?正常情况下,我们是这么做的:
话不多说,直接javabean
然后很无耻的copy&paste一下,稍微做一些修改就好了。感觉也不是很费力。但是,假如又多了10张表呢?copy&paste是那些勤快的人的写法,像我这种比较懒的,就喜欢一劳永逸的写法。
做个测试:
这样,一个方法就可以查询所有的对象,无论是animal还是person,一个dao就够了,是不是方便了许多?
再写一个插入和删除
其他的功能就不贴出来了,源码我会放到我的github主页(https://github.com/CleverFan)上,感兴趣的可以去看一下。我也是个新手,有哪些地方不合理的欢迎大家批评指正,互相学习。
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)上,感兴趣的可以去看一下。我也是个新手,有哪些地方不合理的欢迎大家批评指正,互相学习。
相关文章推荐
- Java基于自定义注释和反射机制实现初级通用DAO
- java利用反射机制模拟spring IOC实现
- java中利用反射机制实现调用给定为字符串的方法名
- 利用Java的反射与代理机制实现IOC
- 利用java 反射机制来实现一个servlet处理多种请求
- 利用Java的反射与代理机制实现AOP
- java中利用反射机制实现调用给定为字符串的方法名
- 利用Java的反射机制实现Bean实体与Map自动转换的工具类
- 利用Java的反射与代理机制实现IOC
- 利用Java的反射与代理机制实现AOP
- Java 中利用泛型和反射机制抽象DAO的实例
- 利用Java的反射与代理机制实现AOP
- java利用反射机制模拟spring IOC实现
- 利用java类的反射机制,实现了 映射 获得post(get)的参数 的BaseServlet
- java利用反射实现Object-c中的KVC机制
- 利用Java的反射与代理机制实现AOP
- 利用Java的反射与代理机制实现IOC
- java 利用泛性和反射机制实现collections.sort排序模板
- Java 利用反射、泛型实现dao层的增删改查
- JAVA 反射机制实现 reflect