dao层实现类继承该抽象类,可以将简单的查询修改代码简化.
例如:
/**
* @author howroad
* @Date 2018年3月15日
* @version 1.0
*/
public class UserDaoImpl extends ABaseDao<UserBean> implements IUserDao{
@Override
public int add(UserBean user) {
return excuteUpdate("insert into tb_user values(null,?,?,?,now())",user.getUsername(),user.getPassword(),user.getNickname());
}
@Override
public UserBean findById(int id) {
return fetchSingleEntity("select * from tb_user where id=?", id);
}
public List<UserBean> listByNickname(String nickName){
return fetchList("select * from tb_user where nickname=?",nickName);
};
}
抽象类如下(Java 9),正在学习,欢迎指出问题,不胜感激!
package com.project.test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import com.project.bean.PageBean;
/**dao层实现类继承此类可以由sql语句查得封装好的javaBean/List/PageBean/或执行修改
* @author howroad
* @Date 2018年3月18日
* @version 1.1 添加了对日期和count后的long类型的判断
* @version 1.2 添加了对空值和time类型的判断
* @version 1.3 添加了PagePean的获取
* @version 1.4 修改了查询不到不返回null的Bug
* @version 1.5 修复了pageBean的获取失败
* @version 1.6 保证了每个ResultSet和preparedStatement都关闭了,不在使用limit获得pageBean,重写了获得pageBean的方法,增加了备注,pageBean中对调了两个int参数的位置,切记切记!!
* @version 1.7 修复了pgaeBean第一条方法中多打开一个数据库的bug
*/
public abstract class ABaseDao<E> {
private final static String URL="jdbc:mysql://127.0.0.1:3306/db_forest_disaster?useUnicode=true&characterEncoding=UTF-8";
private final static String USER="root";
private final static String PASSWORD="luhao123";
static {
try {
//加载驱动
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
private Connection conn=null;
private Class<E> entityClass=null;
//java9中直接newInstance()方法已经过时
private Constructor<E> constructor=null;
private Field[] fields=null;
@SuppressWarnings("unchecked")
protected ABaseDao() {
//返回父类的类型
ParameterizedType pt=(ParameterizedType)this.getClass().getGenericSuperclass();
//得到父类的泛型
entityClass= (Class<E>) pt.getActualTypeArguments()[0];
//获得当前类的无参构造器
try {
constructor= entityClass.getDeclaredConstructor();
} catch (Exception e) {
e.printStackTrace();
}
//获得当前类的Field对象
fields=entityClass.getDeclaredFields();
}
/**
* 获得数据库连接
* @return 连接对象
*/
protected Connection getConn() {
try {
conn=DriverManager.getConnection(URL,USER,PASSWORD);
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
/**
* 关闭数据库连接
*/
protected void close() {
try {
if(conn!=null) conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* 获得结果集
* @param rs 结果集
* @param ps 预编译sql的PreparedStatement
* @param sql 查询语句
* @param objs 查询的条件
* @return 结果集
* 传入rs和ps是为了在外面关闭rs和ps
*/
private ResultSet excuteQuery(ResultSet rs,PreparedStatement ps,String sql,Object...objs) {
try {
ps=conn.prepareStatement(sql);
for(int i=0;i<objs.length;i++) {
ps.setObject(i+1, objs[i]);
}
rs=ps.executeQuery();
} catch (SQLException e) {
e.printStackTrace();
}
return rs;
}
/**
* 修改数据库字段
* @param sql DML语句
* @param objs 预编辑字段
* @return 修改和删除返回修改记录数,插入返回新的ID
*/
protected int excuteUpdate(String sql,Object...objs) {
int n=-1;
ResultSet rs=null;
PreparedStatement ps=null;
//连接
getConn();
try {
//设置ps
ps=conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
for(int i=0;i<objs.length;i++) {
ps.setObject(i+1, objs[i]);
}
//修改数据库
n=ps.executeUpdate();
//如果是插入等得到主键Id
rs=ps.getGeneratedKeys();
if(rs.next()) {
n=rs.getInt(1);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
//按顺序关闭
try {
if(rs!=null) rs.close();
if(ps!=null) ps.close();
close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return n;
}
/**
* 返回封装在JavaBean中的数据
* @param sql DQL语句
* @param objs 预查询字段
* @return 封装的JavaBean
*/
protected E fetchSingleEntity(String sql,Object...objs) {
E entity=null;
PreparedStatement ps = null;
ResultSet rs =null;
//获得查询结果集
getConn();
rs=excuteQuery(rs,ps,sql, objs);
try {
if(rs.next()) {
//创建对象
entity=constructor.newInstance();
//给它的每一个字段赋值
setField(entity, fields, rs);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
//按顺序关闭
try {
if(rs!=null) rs.close();
if(ps!=null) ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
close();
}
return entity;
}
/**
* 返回查询的集合
* @param sql DQL语句
* @param objs 预查询字段
* @return List集合
*/
protected List<E> fetchList(String sql,Object...objs){
List<E> list = new ArrayList<E>();
PreparedStatement ps =null;
ResultSet rs =null;
//获得结果集
getConn();
rs=excuteQuery(rs,ps,sql, objs);
try {
while(rs.next()) {
E entity=constructor.newInstance();
//给E的每一个字段赋值
setField(entity, fields, rs);
//添加到集合
list.add(entity);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
//按顺序关闭
try {
if(rs!=null) rs.close();
if(ps!=null) ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
close();
}
return list;
}
/**
* 返回封装好的页面信息
* @param pageSize 分页大小
* @param pageNo 当前页码
* @param sql 查询语句
* @param objs 预编译参数
* @return 封装好的PageBean
* 缺点:执行了两次数据库查询操作!!
*/
protected PageBean<E> fetchPageBean(int pageNo,int pageSize,String sql,Object...objs){
getConn();
//获得pageBean中的所有记录的总数
PreparedStatement ps = null;
ResultSet rs = null;
rs = excuteQuery(rs,ps,sql, objs);
int countRecord=countRs(rs);
//将limit添加进sql语句进行查询
PreparedStatement ps2 = null;
ResultSet rs2 = null;
int position = pageSize * (pageNo-1);
String sql2=sql+" limit "+position+","+pageSize;
rs2=excuteQuery(rs2,ps2,sql2, objs);
//创建集合对象
List<E> list = new ArrayList<E>();
try {
while(rs2.next()) {
//创建对象并给对象赋值
E entity=constructor.newInstance();
setField(entity, fields, rs2);
//添加进集合
list.add(entity);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
//按顺序关闭...
try {
if(rs2!=null) rs2.close();
if(rs!=null) rs.close();
if(ps2!=null) ps2.close();
if(ps!=null) ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
close();
}
return new PageBean<E>(list, pageNo, pageSize, countRecord);
}
//缺点:这个方法只执行了一次数据库查询,但是查询的比较多...
public PageBean<E> fetchPageBean2(int pageNo,int pageSize,String sql,Object...objs){
//获得查询所有记录的结果集
PreparedStatement ps = null;
ResultSet rs = null;
getConn();
rs = excuteQuery(rs,ps,sql, objs);
//创建list
List<E> list = new ArrayList<E>();
int countRecord = 0;
int start = pageSize * (pageNo-1);
int end = start+pageSize;
try {
while(rs.next()) {
//当前记录数大于end,重新给countRecord赋值
if(countRecord>=end) {
rs.last();
countRecord=rs.getRow();
break;
}
//如果当前记录是需要的数据
if(countRecord>=start) {
//创建对象并插入集合
E entity=constructor.newInstance();
setField(entity, fields, rs);
list.add(entity);
}
//每次循环自增
countRecord++;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//关闭连接
try {
if(rs!=null) rs.close();
if(ps!=null) ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
close();
}
return new PageBean<E>(list, pageNo, pageSize, countRecord);
}
/**
* 给定一个实体,按照结果集的字段数和javaBean的属性比较少的为准设置数据
* @param entity 实体
* @param fields 字段反射数组
* @param rs 结果集
* @throws Exception
* @throws Exception 异常
*/
private void setField(E entity,Field[] fields,ResultSet rs) throws Exception{
//获得查询的字段的总数(列)
int countRow = rs.getMetaData().getColumnCount();
//取列数和javaBean中比较小的,通常javaBean字段比较多
for (int i=0;i<fields.length&&i<countRow;i++) {
//取得修改权限
fields[i].setAccessible(true);
//如果是空不执行下面的判断直接设置
if(rs.getObject(i+1)==null) {
fields[i].set(entity, null);
continue;
}
//将java.sql.Date转换成字符串,(前提是javaBean中的时间都是字符串)
if(rs.getObject(i+1).getClass()==Class.forName("java.sql.Date")
||rs.getObject(i+1).getClass()==Class.forName("java.sql.Timestamp")) {
fields[i].set(entity,rs.getObject(i+1).toString());
continue;
}
//将count获得的long转换为int,(如果查询的结果类型是long,应该是查询语句使用了count)
if(rs.getObject(i+1).getClass()==Class.forName("java.lang.Long")) {
fields[i].set(entity, (int)(long)rs.getObject(i+1));
continue;
}
fields[i].set(entity, rs.getObject(i+1));
}
}
//专门给第一种获得pageBean的方法写的获得记录的条数
private int countRs(ResultSet rs) {
int n = -1;
try {
rs.last();
n=rs.getRow();
} catch (SQLException e) {
e.printStackTrace();
}
return n;
}
//专门写一个处理事务的
protected int excuteUpdate2(String sql,Object...objs) {
int n=-1;
ResultSet rs=null;
PreparedStatement ps=null;
try {
//设置ps
ps=conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
for(int i=0;i<objs.length;i++) {
ps.setObject(i+1, objs[i]);
}
//修改数据库
n=ps.executeUpdate();
//如果是插入等得到主键Id
rs=ps.getGeneratedKeys();
if(rs.next()) {
n=rs.getInt(1);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
//按顺序关闭
try {
if(rs!=null) rs.close();
if(ps!=null) ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return n;
}
}