DAO设计模式 及案例分析

目录

程序分层

案例分析

定义数据库连接类

开发Value Object

开发数据层

开发数据层操作标准

数据层的实现类

定义数据层工厂类——DAOFactory

开发业务层

开发业务层标准 -——IEmpService

业务层的实现类

​定义业务层的工厂类——ServiceFactory

代码测试

第一种调用测试

第二种利用junit进行测试

实现部门操作

处理关系


程序分层

整个业务的核心在于后台业务层,业务层是整个程序提供的操作功能,而一个业务要想完成需要多个数据层的操作一起共同完成,而数据层的操作只是一个个原子性的数据库开发。而在实际开发之中,每个操作的业务往往需要牵扯到多个原子性的操作,也就是所有的原子性操作业务最终都在业务层中完成。

在实际开发中,业务的设计是非常复杂的,往往需要一个总业务层,而后牵扯到若干个子业务层。

数据层(数据访问层(Data Access Object)DAO),是专门进行数据库的原子性操作,在数据层之中最需要控制的是JDBC中的PreparedStatement接口的使用;

业务层(业务对象Business Object  BO)也可以被称为服务层(Service),业务层的核心目的是调用多个数据层的操作以完成整体的项目设计,这个是整个项目的核心所在。

案例分析

使用emp表,实现以下操作:

结论:用户所提供的所有的需求(功能)都应该划分为业务层,而开发人员必须通过业务层去进行数据层的设计。

 

首先定义项目名称DAOproject,并配置MySQL数据库。并且保证数据库已经打开。

为了方便程序的统一管理,所有的项目的父包名称为cn.ren。而子包根据不同的功能模块进行划分。

定义数据库连接类

需要进行数据库的开发,就需要取得数据库连接的取得与关闭才能正常工作,那么几乎所有的数据库的连接操作都是固定的步骤。那么就可单独定义一个DataBaseConnection,这个类主要实现连接对象的取得和数据库的关闭操作,保存在dbc子包中。下图是Oracle的图,MySQL一样。

范例:定义数据库连接

package cn.ren.dbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
/**
 * 本类专门负责数据库的连接与关闭操作,所以在本类构造方法里面需要进行数据库驱动加载和数据连接取得。
 * @author ren
 *
 */
public class DataBaseConnection {
	private static final String DATABASE_DRIVER = "com.mysql.jdbc.Driver"; // 驱动程序
	private static final String DATABASE_URL = "jdbc:mysql://127.0.0.1:3306/bjpowernode" ;
	private static final String DATABASE_USER = "root";
	private static final String DATABASE_PASSWORD = "***********" ;
	private Connection conn = null;
	/**
	 * 在构造方法里面为conn对象进行实例化,可以直接取得数据库的连接对象
	 * 由于所有的操作都是基于数据库完成的,如果数据库得不到连接,那么就意味着所有的操作都可以停止了
	 */
	public DataBaseConnection() {
		try {
			Class.forName(DATABASE_DRIVER);
			this.conn = DriverManager.getConnection(DATABASE_URL,DATABASE_USER,DATABASE_PASSWORD);
		} catch (Exception e) {  // 虽然此处有异常但是抛出的意义不大
			e.printStackTrace();
		}
	}
	/**
	 * 取得一个数据库的连接对象
	 * @return Connection实例化对象
	 */
	public Connection getConnection() {
		return this.conn ;
	}
	/**
	 * 负责数据库的关闭
	 */
	public void close() {
		try {
			this.conn.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
}

在本程序之之中,DataBaseConnection只是无条件的提供数据库的连接,而至于说有多少个线程获取连接对象它并不关心。

补充:在以前的DAO设计模式之中还会考虑多数据库之间的移植问题,结构如下:

在实际的开发之中,所提供的第三方平台越来越完善了,所以以上的设计被慢慢忽略了,也不会再用了。

开发Value Object

现在的程序严格来说已经给出了四个层次。不同层次之间一定要进行数据的传递,但是既然要操作的是指定的数据表,所以数据的结构必须要与表的结构一一对应,那么就使用简单Java类。

在实际工作之中,针对简单Java类的开发提供如下要求:

  • 考虑到日后可能出现的分布式应用问题,所以简单Java类必须要实现java.io.Serializable接口;
  • 简单Java类名称需要与数据表的名称一一对应
  • 类中属性不允许使用基本数据类型,所有的基本数据类型都必须使用包装类,因为包装类的默认值为null;
  • 类中的属性必须使用private进行封装,并且提供setter、getter;
  • 类中可以定义多个构造方法,但是必须保留一个无参构造方法;
  • 【可选要求】覆写equals()、 toString()、hashCode()

将所有的简单Java类保存在vo包中

范例:定义Emp.java

package cn.ren.vo;

import java.io.Serializable;
import java.util.Date;

@SuppressWarnings("serial")
public class Emp implements Serializable {
	private Integer empno ;
	private String ename ;
	private String job ;
	private Date hiredate ;
	private Double sal ;
	private Double comm ;
    
        public Emp(){}
	// setter getter 不复制了
}

不管多少张表,只要是实体表,那么一定要写简单Java类,而且不要试图一次性将所有表转换,随用随转。

开发数据层

数据层最终交给业务层进行调用,所以业务层必须知道数据层的执行标准,即:业务层必须明确知道数据层的操作方法,但是不需要知道它的具体实现。不同层之间的访问一定要有标准存在。

开发数据层操作标准

不同层之间要进行访问,一定要定义接口,描述操作访问。

对于数据层的接口给出如下的开发要求:

  • 数据层既然进行数据操作的,那么将其保存在dao包下;

  • 不同的数据表操作有可能使用不同的数据层开发,那么就针对于数据表进行命名

           |- emp表,那么数据层的接口就应该定义为IEmpDAO;

  • 对于整个数据层的开发严格来讲就只有两类功能:

          |- 数据更新:建议它的操作方法以doXxx()形式命名,例如:doCreate()、doUpdate、doRemove();

          |- 数据查询:对于数据查询分为两种形式:

                    \- 查询表中数据:以findXxx()形式命名,例如:findById()  findByName()  findAll();

                    \- 统计表中数据,以getXxx()形式命名,例如:getAllCount();

范例:定义IEmpDAO接口

package cn.ren.dao;

import java.util.List;
import java.util.Set;

import cn.ren.vo.Emp;
/**
 * 定义数据层的开发标准
 * @author ren
 *
 */
public interface IEmpDAO {
	/**
	 * 实现数据的增加操作
	 * @param vo 包含要增加的vo对象
	 * @return 数据保存成功返回true,否则返回false;
	 * @throws Exception SQL执行异常;
	 */
	public boolean doCreate(Emp vo) throws Exception ;
	/**
	 * 实现数据的修改操作,本次修改是更具id进行全部字段的修改
	 * @param vo 包含要修改的信息,一定要提供有 ID内容
	 * @return 数据修改成功返回true,否则返回false
	 * @throws Exception SQL执行异常
	 */
	public boolean doUpdate(Emp vo) throws Exception ;
	/**
	 * 执行数据的批量删除操作,所有要删除的数据以Set集合形式保存
	 * @param ids 包含有所要删除数据的id,不包含重复内容
	 * @return 删除成功返回true(删除数据的个数与要删除的数据个数相同),否则返回false ;
	 * @throws Exception SQL执行异常
	 */
	public boolean doRemoveBatch(Set<Integer> ids) throws Exception ;
	/**
	 * 根据雇员编号,查询指定的信息
	 * @param id 要查询的雇员编号
	 * @return 如果雇员的信息存在,则以VO对象的形式返回,如果雇员信息不存在,则返回null
	 * @throws Exception SQL执行异常
	 */
	public Emp findById(Integer id) throws Exception ;
	/**
	 * 查询指定数据表的全部数据,以集合的形式返回
	 * @return 如果表中有数据,则所有的数据会封装为VO对象而后利用List集合返回,<br>
	 * 如果没有数据集合的长度为0 (size() == 0)
	 * @throws Exception SQL执行异常
	 */
	public List<Emp> findAll() throws Exception; 
	/**
	 * 分页进行数据的模糊查询,查询的结果以集合的形式返回
	 * @param currentPage 当前所在的页
	 * @param lineSize 每页显示的数据行数
	 * @param column 要进行模糊查询的数据列
	 * @param keyword 模糊查询的关键字
	 * @return 如果表中有数据,则所有的数据会封装为VO对象而后利用List集合返回,<br>
	 * 如果没有数据集合的长度为0 (size() == 0)
	 * @throws Exception SQL执行异常
	 */
	public List<Emp> findAllSplit(Integer currentPage, Integer lineSize, String column, String keyword) throws Exception ; 
	/**
	 *  进行模糊查询数据量的统计,如果表中没有记录统计的结果就是0
	 * @param column  要进行模糊查询的数据列
	 * @param keyword  模糊查询的关键字
	 * @return 返回表中的数据量,如果没有数据返回0
	 * @throws Exception SQL执行异常
	 */
	public Integer getAllCountt(String column, String keyword) throws Exception;
}

数据层的实现类

数据层需要被业务层调用,数据层需要进行数据库的连接(PreparedStatments()),由于在开发之中一个业务层操作需要执行多个数据层的调用,所以数据库的打开与关闭操作,应该由业务层控制会比较合理。

所有的数据层的实现类保存在dao.impl子包下。

范例:EmpDAOImpl子类

package cn.ren.dao.impl;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import cn.ren.dao.IEmpDAO;
import cn.ren.vo.Emp;

public class EmpDAOImpl implements IEmpDAO {
	private Connection conn ; // 需要利用Connection对象操作
	private PreparedStatement psmt ;
	/**
	 * 如果想要使用数据层进行原子性操作,必须提供有Connection接口对象<br>
	 * 另外,业务层需要调用数据层,所以数据库的打开和关闭交由业务层进行处理
	 * @param conn 表示数据库的连接对象
	 */
	public EmpDAOImpl(Connection conn) {
		this.conn = conn;
	}
	@Override
	public boolean doCreate(Emp vo) throws Exception {
		String sql = "insert into emp(empno,ename,job,hiredate,sal,comm) values (?,?,?,?,?,?)" ;
		this.psmt  = this.conn.prepareStatement(sql) ;
		this.psmt.setInt(1, vo.getEmpno());
		this.psmt.setString(2, vo.getEname());
		this.psmt.setString(3, vo.getJob());
		this.psmt.setDate(4, new java.sql.Date(vo.getHiredate().getTime()));
		this.psmt.setDouble(5,vo.getSal());
		this.psmt.setDouble(6, vo.getComm());
		
		return this.psmt.executeUpdate() > 0;
	}

	@Override
	public boolean doUpdate(Emp vo) throws Exception {
		String sql = "update emp set ename=?,job=?,hiredate=?,sal=?,comm=? where empno=?";
		this.psmt  = this.conn.prepareStatement(sql) ;
		this.psmt.setString(1, vo.getEname());
		this.psmt.setString(2, vo.getJob());
		this.psmt.setDate(3, new java.sql.Date(vo.getHiredate().getTime()));
		this.psmt.setDouble(4,vo.getSal());
		this.psmt.setDouble(5, vo.getComm());
		this.psmt.setInt(6, vo.getEmpno());
		return this.psmt.executeUpdate() > 0;
	}

	@Override
	public boolean doRemoveBatch(Set<Integer> ids) throws Exception {
		if (ids == null || ids.size() == 0) {
			return false ;
		}
		StringBuffer sql = new StringBuffer() ;
		sql.append("delete from emp where empno in (") ;
		Iterator<Integer> iter = ids.iterator() ;
		while(iter.hasNext()) {
			sql.append(iter.next());
			sql.append(",") ;
		}
		sql.delete(sql.length()-1, sql.length()).append(")") ;
		this.psmt = this.conn.prepareStatement(sql.toString());
		
		return this.psmt.executeUpdate() == ids.size();
	}

	@Override
	public Emp findById(Integer id) throws Exception {
		Emp vo = null;
		String sql = "select empno,ename,job,hiredate,sal,comm from emp where empno=?" ;
		this.psmt = this.conn.prepareStatement(sql) ;
		this.psmt.setInt(1, id);
		ResultSet rs = this.psmt.executeQuery() ;
		if (rs.next()) {
			vo = new Emp() ;
			vo.setEmpno(rs.getInt(1));
			vo.setEname(rs.getString(2));
			vo.setJob(rs.getString(3));
			vo.setHiredate(rs.getDate(4));
			vo.setSal(rs.getDouble(5)); 
			vo.setComm(rs.getDouble(6));
		}
		return vo;
	}

	@Override
	public List<Emp> findAll() throws Exception {
		List<Emp> all = new ArrayList<Emp>();
		String sql = "select empno,ename,job,hiredate,sal,comm from emp" ;
		this.psmt = this.conn.prepareStatement(sql) ;
		ResultSet rs = this.psmt.executeQuery() ;
		while(rs.next()) {
			Emp vo = new Emp() ;
			vo.setEmpno(rs.getInt(1));
			vo.setEname(rs.getString(2));
			vo.setJob(rs.getString(3));
			vo.setHiredate(rs.getDate(4));
			vo.setSal(rs.getDouble(5)); 
			vo.setComm(rs.getDouble(6));
			all.add(vo) ;
		}
		return all;
	}

	@Override
	public List<Emp> findAllSplit(Integer currentPage, Integer lineSize, String column, String keyword)
			throws Exception { // 分页
		List<Emp> all = new ArrayList<Emp>();
		String sql = " select empno,ename,job,hiredate,sal,comm from emp "
						+ " where ? like ? limit ?,? " ;
		this.psmt = this.conn.prepareStatement(sql) ;
		this.psmt.setString(1, column);
		this.psmt.setString(2, "%" + keyword + "%");
		this.psmt.setInt(3, (currentPage-1)*lineSize);
		this.psmt.setInt(4, lineSize);
		ResultSet rs = this.psmt.executeQuery() ;
		while(rs.next()) {
			Emp vo = new Emp() ;
			vo.setEmpno(rs.getInt(1));
			vo.setEname(rs.getString(2));
			vo.setJob(rs.getString(3));
			vo.setHiredate(rs.getDate(4));
			vo.setSal(rs.getDouble(5)); 
			vo.setComm(rs.getDouble(6));
			all.add(vo) ;
		}
		return all;
	}

	@Override
	public Integer getAllCountt(String column, String keyword) throws Exception {
		String sql = "select count(empno) from emp where ? like ?" ;
		this.psmt = this.conn.prepareStatement(sql);
		this.psmt.setString(1,column);
		this.psmt.setString(2, '%' + keyword + '%');
		ResultSet rs = this.psmt.executeQuery() ;

		if (rs.next()) {
			return rs.getInt(1);
		}
		return null;
	}

}

子类之中需要注意的是构造方法需要接收一个Connection接口对象。

定义数据层工厂类——DAOFactory

业务层要想进行数据层的调用,那么就必须取得IEmpDAO接口对象,但是不同层之间如果要想取得接口对象实例,需要使用工厂设计模式,这个工厂类保存在factory子包下。

范例:定义工厂类

package cn.ren.factory;

import java.sql.Connection;

import cn.ren.dao.IEmpDAO;
import cn.ren.dao.impl.EmpDAOImpl;

public class DAOFactory {
	public static IEmpDAO getIEmpDAOInstance(Connection conn) {
		return new EmpDAOImpl(conn) ;
	}


}

使用工厂的特征是外层不需要知道具体的子类 

开发业务层

业务层是真正留给外部调用的,可能是控制层或者直接调用,既然业务层也是不同层之间的调用,所以业务层开发的首要任务就是定义业务层的操作标准。

开发业务层标准 -——IEmpService

业务层也可以称为Service层,既然描述的是emp表的操作,所以名称就定义为IEmpService,并且保存在Service子包下,但是对于业务层的方法定义并没有明确的要求。

范例:定义IEmpService操作标准 

package cn.ren.service;

import java.util.List;
import java.util.Map;
import java.util.Set;

import cn.ren.vo.Emp;

/**
 * 定义emp表的业务层的执行标准 ,此类一定要负责数据库的打开与关闭操作
 * 
 * @author ren
 *
 */
public interface IEmpService {
	/**
	 * 实现雇员数据的增加操作,本次操作调用IEmpDAO接口的如下方法:<br>
	 * <li>判断id是否存在,IEmpDAO.findById()
	 * <li>如果id不存在,调用IEmpDAO.doCreate()方法
	 * 
	 * @param vo 包含要增加的数据对象
	 * @return id重复或者保存失败,返回false,否则返回true
	 * @throws Exception SQL执行异常
	 */
	public boolean insert(Emp vo) throws Exception;

	/**
	 * 实现雇员数据的修改操作,调用IEmpDAO.doUpdate()方法,本次修改属于全部内容的一次修改
	 * 
	 * @param vo 包含要修改 的vo对象
	 * @return 修改成功返回true。否则返回false
	 * @throws Exception SQL执行异常
	 */
	public boolean update(Emp vo) throws Exception;
	/**
	 * 执行雇员的数据删除操作,可以删除多个雇员信息,调用IEmpDAO.doRemoveBatch()方法
	 * @param ids 包含全部要删除数据的集合,没有重复数据
	 * @return 删除成功返回true,否则返回false;
	 * @throws Exception
	 */
	public boolean delete(Set<Integer> ids) throws Exception ;
	/**
	 * 根据id查找雇员完整信息,调用IEmpDAO.findById()方法
	 * @param id 要查找的雇员编号
	 * @return 如果找到了则雇员信息以vo对象返回,否则返回false
	 * @throws Exception
	 */
	public Emp get(int id) throws Exception ;
	/**
	 * 查询全部雇员信息,调用的是IEmpDAO.findAll()方法
	 * @return 查询结果以list集合的形式返回,如果没有数据集合的长度为0
	 * @throws Exception
	 */
	public List<Emp> list() throws 	Exception ;
	/**
	 * 实现数据的模糊查询与数据统计,调用IEmpDAO接口的两个方法:<br>
	 * <li> 调用IEmpDAO.findAllSplit()方法,查询出所有的表数据,返回List<Emp>;
	 * <li> 调用IEmpDAO.getAllCount()方法,查询所有的数据量,返回的Integer类型
	 * @param currentPage 当前所在页
	 * @param lineSize 每页显示的记录数
	 * @param column 模糊查询的数据列
	 * @param keyword 模糊查询的关键字
	 * @return 本方法需要返回多种数据类型,所以使用Map集合返回,由于类型不同一,所有的value设置为Object,返回内容如下:
	 * <li> key = allEmpsa, value = IEmpDAO.findAllSplit()返回结果,List<Emp> ;
	 * <li> key = empCount, value = IEmpDAO.getAllCount()返回结果,Integer
	 * @throws Exception
	 */
	public Map<String,Object> list(int currentPage, int lineSize, String column, String keyword) throws Exception ;
}

业务层的实现类

业务层实现类的核心功能:

  • 负责数据库的打开与关闭,当存在了业务层对象后其目的就是为了操作数据库,即:业务层对象实例化之后就必须准备好数据库连接;

  • 根据factoryDAO调用getIEmpDAOInstance()方法而后取得IEmpDAO接口对象。

  • 业务层的实现类保存在dao.Impl子包中

范例:定义EmpServiceImpl子类

package cn.ren.service.impl;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import cn.ren.dbc.DataBaseConnection;
import cn.ren.factory.DAOFactory;
import cn.ren.service.IEmpService;
import cn.ren.vo.Emp;

public class EmpServiceImpl implements IEmpService{
	// 在这个类的对象内部就提供一个数据库连接类的实例化对象
	private DataBaseConnection dbc = new DataBaseConnection() ;
	@Override
	public boolean insert(Emp vo) throws Exception {
		try {
			// 要增加雇员编号如果不存在,则findById返回的结果就是null,NULL表示可以进行新雇员数据的保存
			if(DAOFactory.getIEmpDAOInstance(this.dbc.getConnection()).findById(vo.getEmpno()) == null) {
				return DAOFactory.getIEmpDAOInstance(this.dbc.getConnection()).doCreate(vo) ;
			}
			return false ;
		} catch (Exception e) {
			throw e ;
		} finally {
			this.dbc.close();
		} 
	}

	@Override
	public boolean update(Emp vo) throws Exception {
		try {
			return DAOFactory.getIEmpDAOInstance(this.dbc.getConnection()).doUpdate(vo) ;
		} catch (Exception e) {
			throw e ;
		} finally {
			this.dbc.close();
		} 
	}

	@Override
	public boolean delete(Set<Integer> ids) throws Exception {
		try {
			return DAOFactory.getIEmpDAOInstance(this.dbc.getConnection()).doRemoveBatch(ids) ;
		} catch (Exception e) {
			throw e ;
		} finally {
			this.dbc.close();
		} 
	}

	@Override
	public Emp get(int id) throws Exception {
		try {
			return DAOFactory.getIEmpDAOInstance(this.dbc.getConnection()).findById(id);
		} catch (Exception e) {
			throw e ;
		} finally {
			this.dbc.close();
		} 
	}

	@Override
	public List<Emp> list() throws Exception {
		try {
			return DAOFactory.getIEmpDAOInstance(this.dbc.getConnection()).findAll() ;
		} catch (Exception e) {
			throw e ;
		} finally {
			this.dbc.close();
		} 
	}

	@Override
	public Map<String, Object> list(int currentPage, int lineSize, String column, String keyword) throws Exception {
		try {
			Map<String,Object> map = new HashMap<String,Object>() ;
			map.put("allEmps", DAOFactory.getIEmpDAOInstance(this.dbc.getConnection()).findAllSplit(currentPage, lineSize, column, keyword));
			map.put("empCount", DAOFactory.getIEmpDAOInstance(this.dbc.getConnection()).getAllCountt(column, keyword));
			return map ;
		} catch (Exception e) {
			throw e ;
		} finally {
			this.dbc.close();
		} 
	}

}

不同层之间的访问依靠的是工厂类和接口进行操作。

定义业务层的工厂类——ServiceFactory

业务层需要被其它层所使用,所以需要为其定义工厂类,该类也保存在factory中,但是实际开发中,业务层应该分为两种:

  • 前台业务逻辑:将其保存在service.font包中,工厂类:ServiceFontFactory
  • 后台业务逻辑:将其保存在service.back包中,工厂类:ServiceBackFactory

范例:定义ServiceFactory

package cn.ren.factory;

import cn.ren.service.IEmpService;
import cn.ren.service.impl.EmpServiceImpl;

public class ServiceFactory {
	public static IEmpService getIEmpServiceInstance() {
		return new EmpServiceImpl() ;
	}
}

在实际编写之中,子类永远是不可见的,同时在整个操作里面,控制层完全看不到数据库的操作(没有任何的JDBC代码)。

代码测试

因为最终的业务层是需要用户去调用的,所以测试分为两种。

第一种调用测试

按照传统的方式产生对象而后调用里面的方法进行操作。保存在test子包之中

范例:测试增加操作

package cn.ren.test;

import java.util.Date;

import cn.ren.factory.ServiceFactory;
import cn.ren.vo.Emp;

public class TestEmpInsert {
	public static void main(String[] args) {
		Emp vo = new Emp() ;
		vo.setEmpno(5757);
		vo.setEname("老弟");
		vo.setJob("程序员");
		vo.setHiredate(new Date());
		vo.setSal(100.00);
		vo.setComm(1.00);
		try {
			System.out.println(ServiceFactory.getIEmpServiceInstance().insert(vo));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

整个操作流程客户端的调用非常的容易,不需要涉及具体的数据存储细节。

范例:测试分页查询

package cn.ren.test;

import java.util.Iterator;
import java.util.List;
import java.util.Map;

import cn.ren.factory.ServiceFactory;
import cn.ren.vo.Emp;

public class TestEmpSplit {
	@SuppressWarnings("unchecked")
	public static void main(String[] args) {
		Map<String, Object> map;
		try {
			map = ServiceFactory.getIEmpServiceInstance().list(1, 5, "ename", "");
			int count = (Integer) map.get("empCount");
			System.out.println("数据量是:" + count);
			List<Emp> all = (List<Emp>) map.get("allEmps");
			Iterator<Emp> iter = all.iterator() ;
			while (iter.hasNext()) {
				Emp vo = iter.next() ;
				System.out.println("姓名:" + vo.getEname() + "、职位:" + vo.getJob());
		}
		} catch (Exception e) {
			e.printStackTrace();
		}
	
	}
}

这里的模糊查询并没有作用。

第二种利用junit进行测试

1、选择要进行测试的类或者接口,这里选择IEmpService接口进行测试

 范例:编写测试代码

package cn.ren.test.junit;

import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;

import org.junit.jupiter.api.Test;

import cn.ren.factory.ServiceFactory;
import cn.ren.vo.Emp;
import junit.framework.TestCase;

class IEmpServiceTest {
	private static int empno ;
	static {
		empno = new Random().nextInt(10000); // 动态生成一个empno数据
	}
	@Test
	void testInsert() {
		Emp vo = new Emp() ;
		vo.setEmpno(empno);
		vo.setEname("老弟-" + empno);
		vo.setJob("程序员-" + empno);
		vo.setHiredate(new Date());
		vo.setSal(100.00);
		vo.setComm(1.00);
		try {
			TestCase.assertTrue(ServiceFactory.getIEmpServiceInstance().insert(vo));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Test
	void testUpdate() {
		Emp vo = new Emp() ;
		vo.setEmpno(5757);
		vo.setEname("老弟");
		vo.setJob("失业");
		vo.setHiredate(new Date());
		vo.setSal(100.00);
		vo.setComm(1.00);
		try {
			TestCase.assertTrue(ServiceFactory.getIEmpServiceInstance().update(vo));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Test
	void testDelete() {
		Set<Integer> ids = new HashSet<Integer>();
		ids.add(5757);
		try {
			TestCase.assertTrue(ServiceFactory.getIEmpServiceInstance().delete(ids));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Test
	void testGet() {
		try {
			TestCase.assertNotNull(ServiceFactory.getIEmpServiceInstance().get(7369));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Test
	void testList() {
		try {
			TestCase.assertTrue( ServiceFactory.getIEmpServiceInstance().list().size() > 0);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@SuppressWarnings("unchecked")
	@Test
	void testListIntIntStringString() {
		Map<String, Object> map;
		try {
			map = ServiceFactory.getIEmpServiceInstance().list(1, 5, "ename", "");
			int count = (Integer) map.get("empCount");
			List<Emp> all = (List<Emp>) map.get("allEmps");
			TestCase.assertTrue(count > 0 && all.size() > 0);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}

此时测试通过,就可以让用户去调用了。

实现部门操作

 

1、定义Dept.java类

package cn.ren.vo;

import java.io.Serializable;

@SuppressWarnings("serial")
public class Dept implements Serializable {
	private Integer deptno;
	private String dname ;
	private String loc ;
	// setter getter 没复制
}

2、定义IDeptDAO接口

需要考虑一个问题,几乎所有的表都要进行CRUD功能(增加、修改全部、删除数据、根据编号查询、查询全部、分页显示、数据统计),那么这些功能的方法在每个接口都要定义,那么是否可以进行改进?在整个DAO接口定义的过程之中,不同表的区别在于:VO类、主键类型。那么为了解决重复问题,可以使用泛型接口的继承操作。

package cn.ren.dao;

import java.util.List;
import java.util.Set;
/**
 * 定义公共的 DAO操作标准,基本核心的功能包括:增加、修改全部、删除数据、根据编号查询、查询全部、分页显示、数据统计
 * @author ren
 * @param <K> 表示要操作的主键类型,有子接口实现
 * @param <V> 表示要操作的vo类型,由子接口实现
 */
public interface IDAO<K,V> {
	/**
	 * 实现数据的增加操作
	 * @param vo 包含要增加的vo对象
	 * @return 数据保存成功返回true,否则返回false;
	 * @throws Exception SQL执行异常;
	 */
	public boolean doCreate(V vo) throws Exception ;
	/**
	 * 实现数据的修改操作,本次修改是更具id进行全部字段的修改
	 * @param vo 包含要修改的信息,一定要提供有 ID内容
	 * @return 数据修改成功返回true,否则返回false
	 * @throws Exception SQL执行异常
	 */
	public boolean doUpdate(V vo) throws Exception ;
	/**
	 * 执行数据的批量删除操作,所有要删除的数据以Set集合形式保存
	 * @param ids 包含有所要删除数据的id,不包含重复内容
	 * @return 删除成功返回true(删除数据的个数与要删除的数据个数相同),否则返回false ;
	 * @throws Exception SQL执行异常
	 */
	public boolean doRemoveBatch(Set<K> ids) throws Exception ;
	/**
	 * 根据雇员编号,查询指定的信息
	 * @param id 要查询的雇员编号
	 * @return 如果雇员的信息存在,则以VO对象的形式返回,如果雇员信息不存在,则返回null
	 * @throws Exception SQL执行异常
	 */
	public V findById(K id) throws Exception ;
	/**
	 * 查询指定数据表的全部数据,以集合的形式返回
	 * @return 如果表中有数据,则所有的数据会封装为VO对象而后利用List集合返回,<br>
	 * 如果没有数据集合的长度为0 (size() == 0)
	 * @throws Exception SQL执行异常
	 */
	public List<V> findAll() throws Exception; 
	/**
	 * 分页进行数据的模糊查询,查询的结果以集合的形式返回
	 * @param currentPage 当前所在的页
	 * @param lineSize 每页显示的数据行数
	 * @param column 要进行模糊查询的数据列
	 * @param keyword 模糊查询的关键字
	 * @return 如果表中有数据,则所有的数据会封装为VO对象而后利用List集合返回,<br>
	 * 如果没有数据集合的长度为0 (size() == 0)
	 * @throws Exception SQL执行异常
	 */
	public List<V> findAllSplit(Integer currentPage, Integer lineSize, String column, String keyword) throws Exception ; 
	/**
	 *  进行模糊查询数据量的统计,如果表中没有记录统计的结果就是0
	 * @param column  要进行模糊查询的数据列
	 * @param keyword  模糊查询的关键字
	 * @return 返回表中的数据量,如果没有数据返回0
	 * @throws Exception SQL执行异常
	 */
	public Integer getAllCountt(String column, String keyword) throws Exception;
}

范例:定义IEmpDAO子接口

package cn.ren.dao;

import cn.ren.vo.Emp;
/**
 * 定义数据层的开发标准
 * @author ren
 *
 */
public interface IEmpDAO extends IDAO<Integer,Emp>{
	
}

范例:定义IDeptDAO子接口

package cn.ren.dao;

import cn.ren.vo.Dept;

public interface IDeptDAO extends IDAO<Integer,Dept>{

}

 

3、定义DeptDAOImpl子类

package cn.ren.dao.impl;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import cn.ren.dao.IDeptDAO;
import cn.ren.vo.Dept;


public class DeptDAOImpl implements IDeptDAO {
	private Connection conn ;
	private PreparedStatement psmt ;
	public DeptDAOImpl(Connection conn) {
		this.conn = conn ;		
	}
	@Override
	public boolean doCreate(Dept vo) throws Exception {
		String sql = "insert into dept(deptno,dname,loc) values (?,?,?) " ;
		this.psmt = this.conn.prepareStatement(sql) ;
		this.psmt.setInt(1, vo.getDeptno());
		this.psmt.setString(2, vo.getDname());
		this.psmt.setString(3, vo.getLoc());
		return this.psmt.executeUpdate() > 0;
	}

	@Override
	public boolean doUpdate(Dept vo) throws Exception {
		String sql = "update dept set dname=?,loc=? where deptno=? " ;
		this.psmt = this.conn.prepareStatement(sql) ;
		this.psmt.setString(1, vo.getDname());
		this.psmt.setString(2, vo.getLoc());
		this.psmt.setInt(3, vo.getDeptno());
		return this.psmt.executeUpdate() > 0;
	}

	@Override
	public boolean doRemoveBatch(Set<Integer> ids) throws Exception {
		if (ids == null || ids.size() == 0) {
			return false ;
		}
		StringBuffer sql = new StringBuffer() ;
		sql.append("delete from dept where deptno in (") ;
		Iterator<Integer> iter = ids.iterator() ;
		while(iter.hasNext()) {
			sql.append(iter.next());
			sql.append(",") ;
		}
		sql.delete(sql.length()-1, sql.length()).append(")") ;
		this.psmt = this.conn.prepareStatement(sql.toString());
		
		return this.psmt.executeUpdate() == ids.size();
	}

	@Override
	public Dept findById(Integer id) throws Exception {
		Dept vo = null;
		String sql = "select deptno,dname,loc from dept where deptno=?" ;
		this.psmt = this.conn.prepareStatement(sql) ;
		this.psmt.setInt(1, id);
		ResultSet rs = this.psmt.executeQuery() ;
		if (rs.next()) {
			vo = new Dept() ;
			vo.setDeptno(rs.getInt(1));
			vo.setDname(rs.getString(2));
			vo.setLoc(rs.getString(3));
		}
		return vo;
	}

	@Override
	public List<Dept> findAll() throws Exception {
		List<Dept> all = new ArrayList<Dept>();
		String sql = "select deptno,dname,loc from dept" ;
		this.psmt = this.conn.prepareStatement(sql) ;
		ResultSet rs = this.psmt.executeQuery() ;
		while(rs.next()) {
			Dept vo = new Dept() ;
			vo.setDeptno(rs.getInt(1));
			vo.setDname(rs.getString(2));
			vo.setLoc(rs.getString(3));
			all.add(vo) ;
		}
		return all;
	}

	@Override
	public List<Dept> findAllSplit(Integer currentPage, Integer lineSize, String column, String keyword)
			throws Exception {
		List<Dept> all = new ArrayList<Dept>();
		String sql = " select deptno,dname,loc from dept"
					+ " where ? like ? limit ?,? " ;
		this.psmt = this.conn.prepareStatement(sql) ;
		this.psmt.setString(1, column);
		this.psmt.setString(2, "%" + keyword + "%");
		this.psmt.setInt(3, (currentPage-1)*lineSize);
		this.psmt.setInt(4, lineSize);
		ResultSet rs = this.psmt.executeQuery() ;
		while(rs.next()) {
			Dept vo = new Dept() ;
			vo.setDeptno(rs.getInt(1));
			vo.setDname(rs.getString(2));
			vo.setLoc(rs.getString(3));
			all.add(vo) ;
		}
		return all;
	}

	@Override
	public Integer getAllCountt(String column, String keyword) throws Exception {
		String sql = "select count(deptno) from dept where ? like ?" ;
		this.psmt = this.conn.prepareStatement(sql);
		this.psmt.setString(1,column);
		this.psmt.setString(2, '%' + keyword + '%');
		ResultSet rs = this.psmt.executeQuery() ;
		if (rs.next()) {
			return rs.getInt(1);
		}
		return null;
	}

}

明显发现操作功能的代码和EmpDAOImpl子类的代码相似度大,可以利用反射的机制来改进

4、修改DAOFactoryctory类增加新的接口对象的取得方法

package cn.ren.factory;

import java.sql.Connection;

import cn.ren.dao.IDeptDAO;
import cn.ren.dao.IEmpDAO;
import cn.ren.dao.impl.DeptDAOImpl;
import cn.ren.dao.impl.EmpDAOImpl;

public class DAOFactory {
	public static IEmpDAO getIEmpDAOInstance(Connection conn) {
		return new EmpDAOImpl(conn) ;
	}
	public static IDeptDAO getIDeptDAOInstance(Connection conn) {
		return new DeptDAOImpl(conn);
	}

}

5、开发IDeptService接口

package cn.ren.service;

import java.util.List;
import java.util.Map;
import java.util.Set;

import cn.ren.vo.Dept;

public interface IDeptService {
	public boolean insert(Dept vo) throws Exception;
	public boolean update(Dept vo) throws Exception;
	public boolean delete(Set<Integer> ids) throws Exception ;
	public Dept get(int id) throws Exception ;
	public List<Dept> list() throws Exception ;
	public Map<String,Object> list(int currentPage, int lineSize, String column, String keyword) throws Exception ;
}


6、实现IDeptService接口的子类DeptServiceerviceImpl;

package cn.ren.service.impl;

import java.util.List;
import java.util.Map;
import java.util.Set;

import cn.ren.dbc.DataBaseConnection;
import cn.ren.factory.DAOFactory;
import cn.ren.service.IDeptService;
import cn.ren.vo.Dept;

public class DeptServiceImpl implements IDeptService {
	private DataBaseConnection dbc = new DataBaseConnection() ;
	
	@Override
	public boolean insert(Dept vo) throws Exception {
		 try {
			 if(DAOFactory.getIDeptDAOInstance(this.dbc.getConnection()).findById(vo.getDeptno()) == null) {
				 return DAOFactory.getIDeptDAOInstance(this.dbc.getConnection()).doCreate(vo);
			 }
			 return false;
		 } catch (Exception e) {
			 throw e;
		 } finally {
			 this.dbc.close();
		 }
	}

	@Override
	public boolean update(Dept vo) throws Exception {
		 try {
			 return DAOFactory.getIDeptDAOInstance(this.dbc.getConnection()).doUpdate(vo);
		 } catch (Exception e) {
			 throw e;
		 } finally {
			 this.dbc.close();
		 }
	}

	@Override
	public boolean delete(Set<Integer> ids) throws Exception {
		 try {
			 return DAOFactory.getIDeptDAOInstance(this.dbc.getConnection()).doRemoveBatch(ids);
		 } catch (Exception e) {
			 throw e ;
		 } finally {
			 this.dbc.close();
		 }
	}

	@Override
	public Dept get(int id) throws Exception {
		 try {
			 return DAOFactory.getIDeptDAOInstance(this.dbc.getConnection()).findById(id) ;
		 } catch (Exception e) {
			 throw e;
		 } finally {
			 this.dbc.close();
		 }
	}

	@Override
	public List<Dept> list() throws Exception {
		 try {
			 return DAOFactory.getIDeptDAOInstance(this.dbc.getConnection()).findAll() ;
		 } catch (Exception e) {
			 throw e;
		 } finally {
			 this.dbc.close();
		 }
	}
}

7、修改服务层工厂

package cn.ren.factory;

import cn.ren.service.IDeptService;
import cn.ren.service.IEmpService;
import cn.ren.service.impl.DeptServiceImpl;
import cn.ren.service.impl.EmpServiceImpl;

public class ServiceFactory {
	public static IEmpService getIEmpServiceInstance() {
		return new EmpServiceImpl() ;
	}
	public static IDeptService getIDeptServiceInstance() {
		return new DeptServiceImpl() ;
	}
}

在使用之前使用测试

package cn.ren.test;

import static org.junit.jupiter.api.Assertions.fail;

import java.util.HashSet;
import java.util.Set;

import org.junit.jupiter.api.Test;

import cn.ren.factory.ServiceFactory;
import cn.ren.vo.Dept;
import junit.framework.TestCase;

class IDeptServiceTest {

	@Test
	void testInsert() {
		Dept vo = new Dept();
		vo.setDeptno(11);
		vo.setDname("财务部");
		vo.setLoc("上海");
		try {
			TestCase.assertTrue(ServiceFactory.getIDeptServiceInstance().insert(vo));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Test
	void testUpdate() {
		Dept vo = new Dept();
		vo.setDeptno(11);
		vo.setDname("上部");
		vo.setLoc("上海");
		try {
			TestCase.assertTrue(ServiceFactory.getIDeptServiceInstance().update(vo));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Test
	void testDelete() {
		Set<Integer> ids = new HashSet<Integer>() ;
		ids.add(11);
		try {
			TestCase.assertTrue(ServiceFactory.getIDeptServiceInstance().delete(ids));
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}

	@Test
	void testGet() {
		try {
			TestCase.assertNotNull(ServiceFactory.getIDeptServiceInstance().get(10));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Test
	void testList() {
		try {
			TestCase.assertTrue(ServiceFactory.getIDeptServiceInstance().list().size() > 0);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}

处理关系

已经实现了雇员和部门的基础操作,但是在雇员里面需要有mgr和deptno两个关联字段。

1、修改VO类的定义

修改Emp.java类,增加如下代码:

	private Emp mgr ;
	private Dept dept ;
	public void setMgr(Emp mgr) {
		this.mgr = mgr;
	}
	public Emp getMgr() {
		return mgr;
	}
	public void setDept(Dept dept) {
		this.dept = dept;
	}
	public Dept getDept() {
		return dept;
	}

 修改Dept.java类,增加如下代码:

	private List<Emp> emps ;
	public void setEmps(List<Emp> emps) {
		this.emps = emps;
	}
	public List<Emp> getEmps() {
		return emps;
	}

2、修改EmpDAOImpl子类

增加数据时需要考虑到雇员的领导和部门编号

	@Override
	public boolean doCreate(Emp vo) throws Exception {
		String sql = "insert into emp(empno,ename,job,hiredate,sal,comm,mgr,deptno) values (?,?,?,?,?,?,?,?)" ;
		this.psmt  = this.conn.prepareStatement(sql) ;
		this.psmt.setInt(1, vo.getEmpno());
		this.psmt.setString(2, vo.getEname());
		this.psmt.setString(3, vo.getJob());
		this.psmt.setDate(4, new java.sql.Date(vo.getHiredate().getTime()));
		this.psmt.setDouble(5,vo.getSal());
		this.psmt.setDouble(6, vo.getComm());
		if (vo.getMgr() == null) {
			this.psmt.setNull(7, Types.NULL);
		} else {
			this.psmt.setInt(7, vo.getMgr().getEmpno());
		}
		if (vo.getDept() == null) {
			this.psmt.setNull(8, Types.NULL);
		} else {
			this.psmt.setInt(8, vo.getDept().getDeptno());
		}
		return this.psmt.executeUpdate() > 0;
	}

修改数据时也要考虑变化

	@Override
	public boolean doUpdate(Emp vo) throws Exception {
		String sql = "update emp set ename=?,job=?,hiredate=?,sal=?,comm=?, mgr=?, deptno=? where empno=?";
		this.psmt  = this.conn.prepareStatement(sql) ;
		this.psmt.setString(1, vo.getEname());
		this.psmt.setString(2, vo.getJob());
		this.psmt.setDate(3, new java.sql.Date(vo.getHiredate().getTime()));
		this.psmt.setDouble(4,vo.getSal());
		this.psmt.setInt(6, vo.getEmpno());
		if (vo.getMgr() == null) {
			this.psmt.setNull(6, Types.NULL);
		} else {
			this.psmt.setInt(6, vo.getMgr().getEmpno());
		}
		if (vo.getDept() == null) {
			this.psmt.setNull(7, Types.NULL);
		} else {
			this.psmt.setInt(7, vo.getDept().getDeptno());
		}
		this.psmt.setDouble(8, vo.getComm());
		return this.psmt.executeUpdate() > 0;
	}

在查询单个雇员信息的时候也需要进行全部内容的查询,也就是现在的查询里面需要定义新的功能,是为了与之前的单表查询区分开。扩充IEmpDAO方法;

package cn.ren.dao;

import java.util.List;

import cn.ren.vo.Emp;
/**
 * 定义数据层的开发标准
 * @author ren
 *
 */
public interface IEmpDAO extends IDAO<Integer,Emp>{
	/**
	 * 查询雇员的详情信息,包括雇员的领导信息及所在部门信息
	 * @param id 要查询的雇员编号
	 * @return 所有的数据以VO对象返回,没有返回NUll
	 * @throws Exception 
	 */
	public Emp findByIdDetails(Integer id) throws Exception;
	/**
	 * 查询雇员的完整信息
	 * @return 所有的数据对象,以List集合返回,如果没有数据集合长度为0;
	 * @throws EcWxception
	 */
	public List<Emp> findAllDetails() throws Exception ;
	/**
	 * 分页查询雇员的完整信息
	 * @param currentPage 当前所在的页
	 * @param lineSize 每页显示的数据行数
	 * @param column 要进行模糊查询的数据列
	 * @param keyword 模糊查询的关键字
	 * @return 如果表中有数据,则所有的数据会封装为VO对象而后利用List集合返回,<br>
	 * 如果没有数据集合的长度为0 (size() == 0)
	 * @throws Exception SQL执行异常
	 */
	public List<Emp> findAllSplitDetails(Integer currentPage, Integer LinSize, String column, String keyword) throws Exception ;
}

服务层增加方法等:

测试结果:

以上还未配置部门到部员的关系,完整代码奉上

 

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值