/**
* 通用的查询方法
* 这里的SQL语句作为一个变量参数传递进来
* 如果是根据id或者name等模糊查询还需要将具体的参数传递进来
* 但是这里是通用的方法,我们不知道具体传入的是emp还是dept
* 所以直接利用一个对象数组的这样一个参数传递进来
*/
//返回一个结果集
public List<E> query(String sql,Object[] parames,Class<?> cla){
//这里还需要一个Class<?>属性来通过方法的名字以及方法的参数属性
//来得到一个方法,这里利用了反射的原理
List<E> list = new ArrayList<E>();
//获取连接
con = JDBCUtil.getConnection();
//预处理
try {
ps = con.prepareStatement(sql);
//由于这里的SQL语句是一个变量
//不知道需要查询哪些变量和哪些字段
//以及对应的字段名是什么
//预处理之后需要设置通过SQL语句传入进来的值
//比如通过id进行查询,and name like%S%等
//那么就需要先将这些问号设置具体的值,而这些值是存放在
//一个对象数组里面的,我们需要通过遍历拿到对应的值,才能进行
//具体的设置
for (int i = 0; i < parames.length; i++) {
ps.setObject(i+1, parames[i]);
}
//做好SQL语句的准备工作之后就是执行SQL语句了
ResultSet rs = ps.executeQuery();
//接下来的工作就是将查询的结果从数据库中返回给用户
//同样利用rs的游标性质,通过while循环取出来
ResultSetMetaData data = rs.getMetaData();
//变化结果集的列数
//通过变化结果集来获取列数
int count = data.getColumnCount();
E o = null;
while(rs.next()){
//通过rs先通过字段类型和字段名称来取出每一行对应的字段的值
//但是现在我们不知道具体是什么类型和字段
//这里我们通过结果集的metadata的属性来获取
//返回的数据类型为结果集变化数据
//然后我们从变化的数据中(metadata)获取字段名称也就是列名
//这里的参数需要传入第几列data.getColumnName(column)
//所以我们还需要拿到变化结果集中由多少列
//遍历data中的列数,依次获取对应的列名
for (int i = 1; i <=count ; i++) {
/*
* 从结果集中获取数据
*/
//之前的做法是通过rs.getstring("addr")
//但是这里我不知道取出的是什么类型的的字段名称
//所以直接用getObject来表示
//然后具体的字段名称直接再用for循环遍历列名的时候
//用i来取值
Object val = rs.getObject(i);
//获取到数据之后就是开始new一个student或者emp将从结果集中取出的一行行的数据
//封装成一个对象,然后添加到结果集中
//但是这里我们不能通过new一个对象来获取
//因为可能有的实体类没有构建构造方法
//并且构造器需要严格要求字段的顺序保持一致
//所以这里我们实例化对象的时候采用set+具体的字段名称
//所以这里我们需要先获取到具体的字段名称,
String columnName = data.getColumnName(i);
//获取到实体的具体的字段名称之后就需要构造一个和实体类里面
//定义的set方法一样的格式来调用set函数
String relMethodName = "set"+columnName.substring(0,1).toUpperCase()+columnName.substring(1).toLowerCase();
/*
* public void setName(String name) {
this.name = name;
}
到这里我们已经拿到了setName(),下面还需要拿到字段的属性
同样是利用结果变化数据来拿到columnclassname
*/
String columnClassName = data.getColumnClassName(i);
//但是这里我们拿到的只是字段的属性名称,是一个字符串类型的
//我们需要通过这个名称来转为具体的属性
//就需要通过forname的反射来实现
try {
Class<?> columnType = Class.forName(columnClassName);
//由于这里返回的class属性太多我们不知道具体是哪个,比如可能有string double int 或者public void 函数等
//所以这里我们利用Class<?>的泛化来表示 通过属性名称反射的属性
/**
* 同时需要注意的是虽然我们已经得到了具体的字段属性
* 但是Java的数据类型表示方法和数据库的数据类型表示方法不一致
* 所以我们还需要将Java中数据类型转为数据库的类型
* 主要需要转换的就是decimal类型
*/
//所以这里需要一个if判断得到的column type属性是否有decimal属性,有的话
//就将对应的属性转为int类型
//同时还需要将里面的值也要强制转为int类型
if(java.math.BigDecimal.class.equals(columnType)){
columnType = int.class;
//这里的val是通过getobject属性获取的,是object类型,所以需要先强制转换为
//bigdecimal类型,然后转为int类型
val = ((java.math.BigDecimal)val).intValue();
}
try {
//到这里我们已经拿到了方法名字如:setName
//以及需要设置的字段的类型 如 string
//那么就相当于我们可以创建一个public void setName(String name) {}
//这样的函数方法了
//要拿到一个实体的set方法那么我们需要先得到这个属性的class属性
//但是这个实体是一个变化的可能是Emp,或者Dept,
//所以这里也需要通过一个参数传递进来
Method method = cla.getMethod(relMethodName, columnType);
try {
//现在我们已经得到了方法
/**
* public void setName(String name) {
this.name = name;
}
*/
//然后就是需要找到this 也就是调用方法的执行体
//而这里的this指的就是当前的对象
//但是在这个通用的查询方法中我们并不知道
//传入进来的对象到底是什么,所以我们初始化一个对象
//利用E o = null,来实例化一个对象泛指所有的对象
//然后利用方法的invoke属性来执行将取出的val设置给对象O
method.invoke(o, val);
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//封装好对象之后就需要添加到集合中
//遍历一张表就添加一次
//for循环完了就添加一个对象
list.add(o);
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return list;
}
然后再写一个具体的子类继承上面的通用方法
StuDAO
public class StuDAO extends BaseDAO<Student> {
public List<Student> findAll(Object[] parames){
String sql = "select * from student";
//调用父类的方法query
return this.query(sql, parames, Student.class);
//返回当前方法的query方法
//方法中调用方法
//子类中的方法调用父类中的方法
}
这里还需要一个中转作用的StuService,起一个在数据库和用户中间的参数传递的桥梁
public class Stuservice {
/**
* findAll()
*/
public List<Student> findAll(){
//查询所有的时候不需要参数
//这里定义需要传入的参数为空的集合
Object[] parames ={};
//调用StuDAO的方法findAll
return sd.findAll(parames);
}
}
在测试类中进行测试
public class TestInfo {
private StudentDAO sd = new StudentDAO();
private Stuservice ss = new Stuservice();
/**
* 查询所有
*/
@Test
public void testFindAll(){
//调用StuService的方法findAll,返回一个结果集
List<Student> list = ss.findAll();
for (Student student : list) {
System.out.println(student);
}
}
}