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;
	}	
}