Basedao
为什么要建立basedao:
若有新的功能需要添加,但是该功能与现有的dao层的接口的功能无关,
就需要新建一个dao层,实现要添加的方法,如果有和userdao或者recorddao相类似,但是参数类型不同的方法,也得再写一遍方法,这样大大提高了代码的工作量。所以建立basedao,把通用的方法放到里面,让其他的dao层接口继承该接口,其他的dao层实现类也继承该实现类,提高了代码的复用。
建立basedao好处:
为了贯彻单一职责原则,收集共性(所有dao层的通用方法),让其他dao负责他们相关的职责
单一职责原则
不要存在多于一个导致类改变的原因
简单的说,一个类就负责一项职责
* 没有说一个类只能有一个方法
优点:
1) 降低类的复杂度,一个类只负责一项职责,其逻辑肯定比负责多项职责简单的多
2) 提高类的可读性,提高系统的可维护性
3) 变更引起的风险降低,这个原则遵循的好,可以显著降低对其他功能的影响
4) 需要说明的是,单一职责原则不是OOP程序所独有的,只要是模块化的程序设计,都必须遵守这个原则
basedao的逻辑方法
在dao层新建basedao,其他dao层接口继承basedao
Basedao里写泛用性较强的抽象方法
Basedao实现类里实现basedao接口的方法,其他dao层实现类继承该方法
若子接口有自有的方法,则额外扩展即可.
因为Dao层的实现子类(UserDaoImpl,RecordDaoImpl)继承了basedao实现类(BaseDaoImpl)的方法,所以不需要额外写和basedao功能相同的方法,所以子类直接调用方法即可
#2. 案例中的baseDao必须满足以下条件才能使用
* 1. javaBean类名必须和表名一致
* 2. javaBean属性名必须和列名一致
* 3. 主键必须叫id
* 4. 必须用包装类型 int -> Integer
* 5. 必须有公开的无参构造
* 6. get set方法必须规范
具体实现
Basedao是泛型接口:
//泛型接口,通配符T,可以存放任意类型,传入的是什么类型,方法里面接收到的就是该类型
public interface BaseDao<T> {
//传入的对象可以是任何类型,抛出sql异常交给view层打印,让用户知道sql语句的问题
public interface BaseDao<T> {
void insert(T t,Connection conn) throws SQLException;
void delete(int id,Connection conn) throws SQLException;
void update(T t,Connection conn) throws SQLException;
T querybyid(int id,Connection conn) throws SQLException;
List<T> queryAll(Connection conn) throws SQLException;
int queryCount(Connection conn)throws SQLException;
}
BaseDaoImpl实现类
构造方法:获取当前对象的泛型(用于组装返回对象)
public class BaseDaoImpl<T> implements BaseDao<T> {
private Class<?> gclass;
//构造方法:
public BaseDaoImpl() {
// 获取泛型类型 - T
//Basedaoimpl被userdaoimpl继承
//This.getclass调用构造器的对象class com.bwf.dao.impl.UserDaoImpl
//getGenericSuperclass()获得带有泛型的父类com.bwf.dao.impl.BaseDaoImpl<com.bwf.bean.User>
//ParameterizedType参数化类型,即泛型
//Type是 Java 编程语言中所有类型的公共高级接口。它们包括原始类型、参数化类型、数组类型、类型变量和基本类型。
ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass();
//getActualTypeArguments获取参数化类型的数组,泛型可能有多个class com.bwf.bean.User
gClass = (Class<?>) pt.getActualTypeArguments()[0];
}
查询方法:返回的对象T是通过构造方法获得的
@Override
public T querybyid(Connection conn, int id) throws SQLException {
String sql = "select *from " + gclass.getSimpleName() + " where id=?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setObject(1, id);
ResultSet rs = ps.executeQuery();
// 实例化对象
T t;
try {
t = (T) gclass.newInstance();
if (rs.next()) {
Field[] df = gclass.getDeclaredFields();
for (int i = 0; i < df.length; i++) {
Field f = df[i];
// 拿到属性的值
Object value = rs.getObject(f.getName());
// 拿到setter方法
String setter = "set" + f.getName().substring(0, 1).toUpperCase() + f.getName().substring(1);
// 获得对象的属性
Method method = gclass.getMethod(setter, value.getClass());
method.invoke(t, value);
}
}
return t;
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} 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();
}
return null;
}
更新方法:(用到了反射)
@Override
public void update(Connection conn, T t) throws SQLException {
// 获得类对象
Class<?> class1 = t.getClass();
String tableName = class1.getSimpleName();
String getName = null;
// 获得成员属性
Field[] df = class1.getDeclaredFields();
// 拼接sql语句
// update User set id=?,uname=?,upwd=?,money=? where id=?
String sql = "update " + tableName + " set ";
for (int i = 0; i < df.length; i++) {
Field field = df[i];
getName = "get" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1);
sql += field.getName() + "=?";
if (i < df.length - 1) {
sql += ",";
} else {
sql += " where id=?";
}
}
// update User set id=?,uname=?,upwd=?,money=? where id=?
// 填充占位符
PreparedStatement ps = conn.prepareStatement(sql);
// 存放条件表达式 即id,数组下标第一
String where;
for (int i = 0; i < df.length; i++) {
Field field = df[i];
getName = "get" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1);
// 存放条件表达式 即id,数组下标第0位,填充第length+1位占位符
try {
if (i == 0) {
where = getName;
// 反射调用getId方法并把值拼接到最后一位
ps.setObject(df.length + 1, class1.getDeclaredMethod(where).invoke(t));
}
Method method = class1.getDeclaredMethod(getName);
ps.setObject(i + 1, method.invoke(t));
} 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();
}
}
int executeUpdate = ps.executeUpdate();
System.out.println(sql);
}
basedao类实现basedao接口
因为basedaoimpl需要通用,所以basedaoimpl的泛型类型也是T
public class BaseDaoImpl<T> implements BaseDao<T>
其他dao层实现类如何继承basedao实现类
子类/接口继承泛型类的写法
在子类/接口不设置泛型,而在父类明确的定义一个泛型类型
public interface RecordDao extends BaseDao<Record>
public class RecordDaoImpl extends BaseDaoImpl<Record>implements RecordDao {