清楚了业务层和数据层的区别后, 下面以Oracle数据库中的scott.emp数据表( empno、ename、job 、hiredate、sal、comm等基本字段)为例分析-个操作。
在该操作中, 客户要求可以实现以下6个功能;
开发:
1.项目准备
首先可以设置一个项目名称:DAOProject,并且由于此项目需要使用Oracle数据库,需要为其配置好数据库的驱动程序
2.数据库连接类
本次的操作既然要进行数据库的开发,
那么就必须进行数据库的连接取得与关闭才可以正常操作,那么几乎所有的数据库代码都是固定的步骤
那么就可以单独
定义一个DatabaseConnection类,这个类主要负责数据库的连接取得以及数据库的关闭操作
public class DatebaseConnection{
private static final String DBDRIVER="oracle.jdbc.driver.OracleDriver";
private static final String DBURL="jdbc:oracle:thin:@localhost:1521:mldn";
private static final String DBUSER="admin";
private static final String PASSWORD="123456";
private Connection conn=null;
public DatebaseConnection(){
try{
Class.forName(DBDRIVER);
this.conn=DriverManager.getConnection(DBURL,DBUSER,PASSWORD);
}catch(Exception e){
e.printStackTrace();
}
}
//取得数据库的连接对象,返回Connection类实例化对象
public Connection getConnection(){
return this.conn;
}
public void close(){
if(this.conn!=null){
try{
this.conn.close();
}catch(SQLException e){
e.printStackTrace();
}
}
}
}
3.开发Value Object
现在的程序严格来讲已经给出了四个层次,不同层次之间一定进行数据的传递
但是既然要操作的是指定的数据表,所以数据的结构必须要与表的结构一一对应,那么自然就可以想到简单java类(po,to,pojo,vo)
在实际的工作之中,针对于简单Java类的开发给出如下的要求:
考虑到日后程序又可能出现的分布式应用问题,所以简单java类必须要实现java.io.Serializable接口
简单Java类的名称必须与表名称保存一致
有可能采用这样的名字student_info,类名称为StudentInfo
类中的属性不允许使用基本数据类型,都必须使用基本数据类型的包装类
基本数据类型的数值型默认值是0,而如果是包装类默认值就是null
类中的属性必须封装,封装后的属性必须提供有setter,getter方法
类中可以定义有多个构造方法,但是必须保留有一个无参构造方法
【可选要求,基本不用】覆盖equals(),toString(),hashCode()
将所有的简单Java类保存在vo包中
定义Emp.java
public class Emp implements Serializable{
private Integer empno;
private String ename;
private String job;
private Date hiredate;
private Double sal;
private Double comm;
private Emp mgr;
private Dept dept;
public void setDept(Dept dept){
this.dept=dept;
}
public void setMgr(Emp mgr){
this.mgr=mgr;
}
public Dept getDept(){
return dept;
}
public Emp getMgr(){
return mgr;
}
public Integer setEmpno(Integer empno){
this.empno=empno;
}
public void getEmpno(){
return empno;
}
public String setEname(String ename){
this.ename=ename;
}
public void getEname(){
return ename;
}
public String setJob(String job){
this.job=job;
}
public void getJob(){
return job;
}
public Date setHiredate(Date hiredate){
this.hiredate=hiredate;
}
public void getHiredate(){
return hiredate;
}
public Date setSal(Double sal){
this.sal=sal;
}
public void getSal(){
return sal;
}
public Date setComm(Double comm){
this.comm=comm;
}
public void getComm(){
return comm;
}
}
//只要是实体表就要写简单Java类
4.开发数据层
数据层最终是交给业务层进行调用的,所以业务层必须知道数据层的执行标准
即:业务层需要明确的知道数据层的操作方法,但是不需要知道它的具体实现
开发数据层操作标准
不同层之间如果要进行访问,那么必须要提供有接口,以定义操作标准,那么对于数据层也是一样的,数据层最终要交给业务层执行,所以需要先定义数据层接口
对于数据层的接口给出如下的开发要求:
数据层既然是进行数据操作的,那么就将其保存在包下
既然不同的数据表的操作有可能使用不同的数据层开发,那么就针对于数据表进行命名
emp表,那么数据层的接口就应该定义为IEmpDAO
对于这数据层的开发严格来讲就只有两类功能
数据更新:建议操作方法为doXxx()的形式命名,例如doCreate(),doUpdate(),doRemove()
数据查询:对于查询分为两种形式
查询表中数据,以findXxx()形式命名,例如:findById(),findByName(),findAll()
统计表中的数据:以getXxx()形式命名,例如:getAllCount()
定义IEmpDAO接口
//定义emp表的数据层的操作标准
public interface IEmpDAO{
/**
*实例数据的增加操作
vo包含了更新加载数据的vo对象
数据保存成功返回true,否则返回false
Exception SQL执行异常
*/
public boolean doCreate(Emp vo)throws Exception;
/*实现数据的修改操作,本次修改时根据id进行全部字段数据的修改
vo包含了要修改数据的信息,一定要提供有ID内容
数据保存成功返回true,否则返回false
Exception SQL执行异常
*/
public boolean doUpdate(Emp vo)throws Exception;
/*
执行数据的批量删除操作,所以要删除的数据以Set集合的形式保存
ids包含了所有要删除的数据ID,不包含有重复内容
数据保存成功返回true(删除的数据个数与要删除的数据个数相同),否则返回false
Exception SQL执行异常
*/
public boolean doRemoveBatch(Set<Integer> ids)throws Exception;
/*
根据雇员编号查询指定的雇员信息
id要查询的雇员编号
如果雇员信息存在,则将数据以VO类对象的形式返回,如果雇员数据不存在,则返回null
Exception SQL执行异常
*/
public Emp findById(Integer id)throws Exception;
/*
查询指定数据表的全部记录,并且以集合的形式返回
如果表中有数据,则所有的数据会封装为VO对象而后利用List集合返回,
如果没有数据,那么集合的长度为0(size()==0,不是null)
Exception SQL执行异常
*/
public List<Emp> findAll() throws Exception;
/*
分页进行数据的模糊查询,查询结果以集合的形式返回
currentPage当前所在的页
lineSize 显示数据行数
column 要进行模糊查询的数据列
keyWord 模糊查询的关键字
如果表中有数据,则所有的数据会封装为VO对象而后利用List集合返回,
如果没有数据,那么集合的长度为0(size()==0,不是null)
Exception SQL执行异常
*/
public List<Emp> findAllSplit(Intger currentPage,Integer lineSize,String column,String keyWord)
throws Exception;
/*
进行模糊查询数据量的统计,如果表中没有记录统计的结果就是0
column 要进行模糊查询的数据列
keyWord 模糊查询的关键字
返回表中的数据量,如果没有数据返回0
Exception SQL执行异常
*/
public Integer getAllCount(String column,String keyWord)throws Exception;
}
数据层实现类
数据层的打开与关闭操作应该由业务层控制会比较合理
所有的数据层实现类要求保存在子包下
创建EmpDAOImpl子类
public class EmpDAOImpl extends AbstractDAOImpl1 implements IEmpDAO{
private Connection conn;//需要利用Connection对象操作
private PrepareStatement pstmt;
/*
如果要想使用数据层进行原子性的功能操作实现,必须要提供有Connection接口对象
另外,由于开发之中业务要调用数据层,所以数据库的打开与关闭交由业务层处理
conn表示数据库连接对象
*/
public EmpDAOImpl(Connection conn){
this.conn=conn;
}
public boolean doCreate(Emp vo)throws Exception{
String aql="INSERT INTO emp(empno,ename,job,hiredate,sal,comm,mgr,deptno)VALUSE(?,?,?,?,?,?,?,?)";
this.pstmt=this.conn.prepareStarement(sql);
this.pstmt.setInt(1,vo.getEmpno());
this.pstmt.setString(2,vo.getEname());
this.pstmt.setString(3,vo.getJob());
this.pstmt.setDate(4,new java.sql.Date(vo.getHiredate().getTime()));
this.pstmt.setDouble(5,vo.getSal());
this.pstmt.setDouble(6,vo.getComm());
if(vo.getMgr()==null){ //没有设置领导数据
this.pstmt.setNull(7,Types.NULL);
//this.pstmt.setString(7,null);
}else{
this.pstmt.setInt(7,vo.getMgr().getEmpno());
}
if(vo.getDept()==null){ //没有设置部门数据
this.pstmt.setNull(8,Types.Null);
}else{
this.pstmt.setInt(8,vo.getDept().getDeptno());
}
return this.pstmt.executeUpdate()>0;
}
public boolean doUpdate(Emp vo)throws Exception{
String aql="UPDATE emp SET empno=?,ename=?,job=?,hiredate=?,sal=?,comm=?,mgr=?,deptno=? WHERE empno" ;
this.pstmt.setString(1,vo.getEname());
this.pstmt.setString(2,vo.getJob());
this.pstmt.setDate(3,new java.sql.Date(vo.getHiredate().getTime()));
this.pstmt.setDouble(4,vo.getSal());
this.pstmt.setDouble(5,vo.getComm());
if(vo.getMgr()==null){ //没有设置领导数据
this.pstmt.setNull(6,Types.NULL);
//this.pstmt.setString(6,null);
}else{
this.pstmt.setInt(6,vo.getMgr().getEmpno());
}
if(vo.getDept()==null){ //没有设置部门数据
this.pstmt.setNull(7,Types.Null);
}else{
this.pstmt.setInt(7,vo.getDept().getDeptno());
}
this.pstmt.setInt(8,vo.getEmpno());
return this.pstmt.executeUpdate()>0;
}
public boolean doRemoveBatch(Set<Integer> ids)throws Exception{
return super.removeHandle(ids,"empno","empno");
}
public Emp findById(Integer id)throws Exception{
Emp vo=null;
String sql="SELECT empno,ename,job,hiredate,sal,comm FROM emp WHERE empno=?" ;
this.pstmt=this.conn.prepareStatement(sql);
this.pstmt.setInt(1,id);
ResultSet rs=this.pstmt.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;
}
public List<Emp> findAll() throws Exception{
List<Emp> all=new ArrayList<Emp>();
String sql="SELECT empno,ename,job,hiredate,sal,comm FROM emp";
this.pstmt=this.conn.prepareStatement(sql);
ResultSet rs=this.pstmt.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;
}
public List<Emp> findAllSplit(Intger currentPage,Integer lineSize,String column,String keyWord) throws Exception{
List<Emp> all=new ArrayList<Emp>();
String sql="SELECT*FROM"
+"(SELECT empno,ename,job,hiredate,sal,comm,ROWNUM rn"
+"FROM emp"
+"WHERE"+column+"LIKE ? AND ROWNUM<=?) temp"
+"WHERE temp.rn>?";
this.pstmt=this.conn.prepareStatement(sql);
this.pstmt.setString(1,"%"+keyWord+"%");
this.pstmt.setInt(2,currentPage*lineSize);
this.pstmt.setInt(3,(currentPage-1)*lineSize);
ResultSet rs=this.pstmt.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;
}
public Integer getAllCount(String column,String keyWord)throws Exception{
return super.countHandle("emp",column,keyWord);
}
public List<Emp>findAllDetails()throws Exception{
List<Emp> all=new ArrayList<Emp>();
String sql="SELECT e.empno,e.ename,e.job,e.hiredate,e.sal,e.comm,m.empno mno,m.ename mname,d.deptno dno,d.dname,d.loc FROM emp e,emp m,dept d"
+"Where e.mgr=m.empno(+)AND e.deptno=d.deptno";
this.pstmt=this.conn.prepareStatement(sql);
ResultSet rs=this.pstmt.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));
Emp mgr=new Emp();
mgr.setEmpno(rs.getInt(7));
mgr.setEname(rs.getString(8));
vo.setMgr(mgr);
Dept dept=new Dept();
dept.setDeptno(rs.getInt(9));
dept.setDname(rs.getString(10));
dept.setLoc(rs.getString(11));
vo.setDept(dept);
all.add(vo);
}
return all;
}
public List<Emp>findAllSplitDetails(Integer currentPage,Integer lineSize){
List<Emp> all=new ArrayList<Emp>();
String sql="SELECT*FROM"
+"(SELECT e.empno,e.ename,e.job,e.hiredate,e.sal,e.comm,m.empno mno,m.ename mname,d.deptno dno,d.dname,d.loc"
+"FROM emp e,emp m,dept d"
+"WHERE e."+column+"LIKE ? AND ROWNUM<=? AND e.mgr=m.empno(+)AND e.deptno=d.deptno) temp"
+"WHERE temp.rn>?";
this.pstmt=this.conn.prepareStatement(sql);
this.pstmt.setString(1,"%"+keyWord+"%");
this.pstmt.setInt(2,currentPage*lineSize);
this.pstmt.setInt(3,(currentPage-1)*lineSize);
ResultSet rs=this.pstmt.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));
Emp mgr=new Emp();
mgr.setEmpno(rs.getInt(7));
mgr.setEname(rs.getString(8));
vo.setMgr(mgr);
Dept dept=new Dept();
dept.setDeptno(rs.getInt(9));
dept.setDname(rs.getString(10));
dept.setLoc(rs.getString(11));
vo.setDept(dept);
all.add(vo);
}
return all;
}
public Emp findByIdDetails(Integer id)throws Exception{
Emp vo=null;
List<Emp> all=new ArrayList<Emp>();
String sql="SELECT*FROM"
+"(SELECT e.empno,e.ename,e.job,e.hiredate,e.sal,e.comm,m.empno mno,m.ename mname,d.deptno dno,d.dname,d.loc"
+"FROM emp e,emp m,dept d"
+"WHERE e.mgr=m.empno(+)AND e.deptno=d.deptno AND e.empno=?)"
this.pstmt=this.conn.prepareStatement(sql);
this.pstmt.setString(1,"%"+keyWord+"%");
this.pstmt.setInt(2,currentPage*lineSize);
this.pstmt.setInt(3,(currentPage-1)*lineSize);
ResultSet rs=this.pstmt.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));
Emp mgr=new Emp();
mgr.setEmpno(rs.getInt(7));
mgr.setEname(rs.getString(8));
vo.setMgr(mgr);
Dept dept=new Dept();
dept.setDeptno(rs.getInt(9));
dept.setDname(rs.getString(10));
dept.setLoc(rs.getString(11));
vo.setDept(dept);
}
return vo;
}
}
子类里面唯一需要注意的就是构造方法一定要接收一个Connection接口对象
定义数据层工厂类————DAOFactory
业务层要想进行数据层的调用,那么必须取得IEmpDAO接口对象,但是不同层之间如果要想取得接口对象实例,需要使用工厂设计模式,
这个工厂类将其保存在factory子包下。使用工厂的特征就是外层不需要知道具体的子类。
定义工厂类
public class DAOFactory{
public static IEmpDAO getIEmpDAOInstance(Connection conn){
return new EmpDAOImpl(conn);
}
public static IDeptDAO getIDeptDAOInstance(connection conn){
return new DeptDAOImpl(conn);
}
}
5.开发业务层
业务层是真正留给外部调用的,可能是控制层,或者是直接调用
既然业务层也是由不同的层进行调用,所以业务层开发的首要任务就是定义业务层的操作标准
开发业务层标准————IEmpService
既然描述的是emp表的操作,所以名称就定义为IEmpService,并且保存在Service子包下
但是对于业务层的方法定义并没有明确的要求,不过还是要写上有意义的统一名称;
/*
实现emp表的业务层的执行标准,此类一定要负责数据库的打开与关闭操作
此类可以通过DAOFactory类取得IEmpDAO接口对象
*/
public interface IEmpService{
/*
实现雇员数据的增加操作,本次操作要调用IEmpDAO接口的如下方法
需要调用IEmpDao.findById()方法,判断要增加数据的id是否已经存在
如果现在要增加的数据编号不存在则调用IEmpDAO.doCreate()方法,返回操作的结果
vo包含了要增加数据的VO对象
如果要增加数据的ID重复或者保存失败返回false,否则返回true
Exception SQL执行异常
*/
public boolean insert(Emp vo)throws Exception;
/*
实现雇员数据的修改操作,本次要调用IEmpDAO.doUpdate()方法,本次修改属于全部内容的修改
vo包含了要修改数据的VO对象
修改成功返回true,否则返回false
Exception SQL执行异常
*/
public boolean update(Emp vo)throws Exception;
/*
执行雇员数据的删除操作,可以删除多个雇员信息,调用IEmpDAO.doRemoveBatch()方法
ids 包含了全部要删除数据的集合,没有重复数据
删除成功返回true,否则返回false
Exception SQL执行异常
*/
public boolean delete(Set<Integer> ids)throws Exception;
/*
根据雇员编号查找雇员的完整信息,调用IEmpDAO.findById()方法
ids 要查找的雇员编号
如果找到了则雇员信息以VO对象返回,否则返回null
Exception SQL执行异常
*/
public Emp get(Integer ids)throws Exception;
/*
查询全部雇员信息,调用IEmpDAO.findAll()方法
查询结果以List集合的形式返回,如果没有数据则集合的长度为0
Exception SQL执行异常
*/
public Emp <Emp> list() throws Exception;
/*
实现数据的模糊查询与数据统计,要调用IEmpDAO接口的两个方法
调用IEmpDAO.finaAllSplit()方法,查询出所有的表数据,返回的List<Emp>
调用IEmpDAO.getAllCount()方法,查询出所有的数据量,返回的Integer
currentPage当前所在页
lineSize每页显示的记录数
column模糊查询的数据列
keyWord模糊查询关键字
本方法由于需要返回多种数据类型,所以使用Map集合返回,由于类型不统一
所以所有value的类型设置为Object,返回内容如下:
key=allEmp,value=IEmpDAO.findAllSplit()返回结果,List<Emp>
key=empCount,value=IEmpDAO.getAllCount()返回结果,Integer
Exception SQL执行异常
*/
public Map<String,Object> list(int currentPage,int lineSize,String column,String keyWord)throws Exception ;
public Map<String,Object> listDetails(int currentPage,int lineSize,String column,String keyWord)throws Exception ;
}
开发业务层实现类
负责控制数据库的打开和关闭,当存在了业务层对象后其目的就是为了操作数据库,
即,业务层对象实例化之后就必须准备好数据库连接
根据DAOFactory调用getIEmpDAOInstance()方法而后取得IEmpDAO接口对象
业务层的实现类保存在impl子包中
定义EmpServiceImpl子类
public class EmpServiceIpml implements IEmpService{
//在这个类的对象内部就提供有一个数据库连接类的实例化对象
private DatebaseConnection dbc=new DatebaseConnection();
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();
}
}
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();
}
}
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();
}
}
public Emp get(Integer ids)throws Exception{
try{
return DAOFactory.getIEmpDAOInstance(this.dbc.getConnection()).findById(ids);
}catch(Exception e){
throw e;
}finally{
this.dbc.close();
}
}
public Emp <Emp> list() throws Exception{
try{
return DAOFactory.getIEmpDAOInstance(this.dbc.getConnection()).findAll();
}catch(Exception e){
throw e;
}finally{
this.dbc.close();
}
}
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()).getAllCount(column,keyWord));
return map;
}catch(Exception e){
throw e;
}finally{
this.dbc.close();
}
}
public Map<String,Object> listDetails(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()).findAllSplitDetails(currentPage,LineSize,column,keyWord));
map.put("empCount",DAOFactory.getIEmpDAOInstance(this.dbc.getConnection()).getAllCount(column,keyWord));
return map;
}catch(Exception e){
throw e;
}finally{
this.dbc.close();
}
}
}
不同层之间的访问依靠的就是工厂类和接口进行操作
日后写的功能类只要写接口了取得对象就给我上工厂
定义业务层工厂类————ServiceFactory
业务层最终依然需要被其它的层所使用,所以需要为其定义工厂类
该类同样保存在factory子包下,如果从实际的开发来讲,业务层应该分为两种:
前台业务逻辑:可以将其保存在service.front包中,工厂类:ServiceFrontFactory
后台业务逻辑:可以将其保存在service.back包中,工厂类:ServiceBackFactory
public class ServiceFactory{
public static IEmpService getIEmpServiceInstance(){
return new EmpServiceImpl();
}
public static IDeptService getIDeptServiceInstance(){
return new DeptServiceImpl();
}
}
定义ServiceFactory
在实际的编写之中,子类永远都是不可见的,同时在整个操作里面
控制层完全看不见数据库的任何操作(没有任何的JDBC代码)
6.代码测试
因为最终的业务层是需要由用户去调用的,所以测试分为两种
按照传统方式产生对象,而后调用里面的方式进行操作,保存在test子包内
测试增加操作
TestEmpInsert
此时客户端的调用非常的简单,就是调用业务层方法。
public class TestEmpInsert{
public static void main(String[] args){
Emp vo=new Emp();
vo.setEmpno(8889);
vo.setEname("小米");
vo.setJob("摄影师");
vo.setHiredate(new Date());
vo.setSal(10.0);
vo.setComm(0.5);
try{
System.out.println(ServiceFactory.getIEmpServiceInstance().insert(vo));
}catch(Exception e){
e.printStackTrace();
}
}
}
测试分页查询功能
TestEmpSplit
整个的操作流程客户端的调用非常的容易,不需要涉及到具体的数据储存细节
public class TestEmpSplit{
public static void main(String[] args){
try{
Map<String,Object>map=ServiceFactory.getIEmpServiceInstance().list(2,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进行测试
对于这种业务的测试,使用junit是最好的选择。
首先要选择测试的类或接口,现在选择好IEmpService接口进行测试
选择IEmpService类,然后选择新建找到JUnit中的JUnit Test Case
点下一步,设置测试保存包,下一步,Available methods:里的选项全选
如果点完成,然后选择JUnit包,就完成了,接下来继续测试。
然后生成一个IEmpServiceTest.java文件生成,进行代码操作
然后对个个文件进行测试
public class IEmpServiceTest{
private static int empno;
static{
empno=new Random().nextInt(10000); //多态生成一个empno的数据
}
public void testInstance(){
Emp vo=new Emp();
vo.setEmpno(empno);
vo.setEname("小明");
vo.setJob("职位");
vo.setHiredate(new Date());
vo.setSal(10.0);
vo.setComm(0.5);
try{
TestCase.assertTrue(ServiceFactory.getIEmpServiceInstance().insert(vo));
}catch(Exception e){
e.printStackTrace();
}
}
public void testUpdate(){
Emp vo=new Emp();
vo.setEmpno(8889);
vo.setEname("小米");
vo.setJob("景色");
vo.setHiredate(new Date());
vo.setSal(10.0);
vo.setComm(0.5);
try{
TestCase.assertTrue(ServiceFactory.getIEmpServiceInstance().insert(vo));
}catch(Exception e){
e.printStackTrace();
}
}
public void testDelete(){
Set<Integer> ids=new HashSet<Integer>();
ids.add(8889);
try{
TestCase.assertTrue(ServiceFactory.getIEmpServiceInstance().delete(ids));
}catch(Exception e){
e.printStackTrace();
}
}
public void testGet(){
try{
TestCase.assertNotNull(ServiceFactory.getIEmpServiceInstance().get(7369));
}catch(Exception e){
e.printStackTrace();
}
}
public void testList(){
try{
TestCase.assertNotNull(ServiceFactory.getIEmpServiceInstance().list().size()>0);
}catch(Exception e){
e.printStackTrace();
}
}
public void testListIntIntStringString(){
try{
Map<String,Object>map=ServiceFactory.getIEmpServiceInstance().list(2,5,"ename","");
int count=(Integer)map.get("empCount");
System.out.println("数据量:"+count);
List<Emp>all=(List<Emp>)map.get("allEmps");
TestCase.assertTrue(count>0 && all.size()>0);
}catch(Exception e){
e.printStackTrace();
}
}
}
7.实现部门操作
要求使用部门表(dept)实现如下的功能:
【业务层】进行部门数据的添加
【数据层】判断要增加的部门编号是否存在,如果不存在则可以添加;
【数据层】实现部门数据的保存
【业务层】进行部门数据的修改
【数据层】进行部门数据修改
【业务层】进行部门数据的删除
【数据层】进行部门数据删除
【业务层】进行部门数据的全部查询
【数据层】查询全部
【业务层】可以根据部门编号查询一个部门完整信息
【数据层】根据编号查询
定义Dept.java类
public class Dept implements Serializable{
private Integer deptno;
private String dname;
private String loc;
private List<Emp>emps;
public void setEmps(List<Emp> emps){
this.emps=emps;
}
public List<Emp>getEmps(){
return emps;
}
public Integer getDeptno(){
return deptno;
}
public void setDeptno(Integer deptno){
this.deptno=deptno;
}
public String getDname(){
return dname;
}
public void setDname(String dname){
this.dname=dname;
}
public void setLoc(String loc){
this.loc=loc;
}
public String getLoc(){
return loc;
}
}
定义IDeptDAO接口
public interface IDeptDAO{
public boolean doCreate(Dept vo)throws Exception;
public boolean doUpdate(Dept vo)throws Exception;
public boolean doRemoveBatch(Set<Integer> ids)throws Exception;
public Dept findById(Integer id)throws Exception;
public List<Dept> findAll()throws Exception;
}
几乎所有的数据表都应该具备有基础CRUD功能(增加、修改全部、删除数据、根据编号查询、查询全部、分页显示、数据统计)。
那么这些功能的方法每个接口都重复定义。
在整个DAO接口定义的过程之中,不同的表区别在于:VO类、主键类型。
为了解决重复问题,使用泛型实现接口的继承操作。
/*
定义公共的DAO操作接口标准,基本的功能包括;增加、修改全部、删除数据、根据编号查询、查询全部、分页显示、数据统计
<K>表示要操作的主键类型,由子接口实现
<V>表示要操作的VO类型,由子接口实现
*/
public interface IDAO<K,V>{
/**
*实例数据的增加操作
vo包含了更新加载数据的vo对象
数据保存成功返回true,否则返回false
Exception SQL执行异常
*/
public boolean doCreate(V vo)throws Exception;
/*实现数据的修改操作,本次修改时根据id进行全部字段数据的修改
vo包含了要修改数据的信息,一定要提供有ID内容
数据保存成功返回true,否则返回false
Exception SQL执行异常
*/
public boolean doUpdate(V vo)throws Exception;
/*
执行数据的批量删除操作,所以要删除的数据以Set集合的形式保存
ids包含了所有要删除的数据ID,不包含有重复内容
数据保存成功返回true(删除的数据个数与要删除的数据个数相同),否则返回false
Exception SQL执行异常
*/
public boolean doRemoveBatch(Set<K> ids)throws Exception;
/*
根据雇员编号查询指定的雇员信息
id要查询的雇员编号
如果雇员信息存在,则将数据以VO类对象的形式返回,如果雇员数据不存在,则返回null
Exception SQL执行异常
*/
public V findById(K id)throws Exception;
/*
查询指定数据表的全部记录,并且以集合的形式返回
如果表中有数据,则所有的数据会封装为VO对象而后利用List集合返回,
如果没有数据,那么集合的长度为0(size()==0,不是null)
Exception SQL执行异常
*/
public List<V> findAll() throws Exception;
/*
分页进行数据的模糊查询,查询结果以集合的形式返回
currentPage当前所在的页
lineSize 显示数据行数
column 要进行模糊查询的数据列
keyWord 模糊查询的关键字
如果表中有数据,则所有的数据会封装为VO对象而后利用List集合返回,
如果没有数据,那么集合的长度为0(size()==0,不是null)
Exception SQL执行异常
*/
public List<V> findAllSplit(Intger currentPage,Integer lineSize,String column,String keyWord)
throws Exception;
/*
进行模糊查询数据量的统计,如果表中没有记录统计的结果就是0
column 要进行模糊查询的数据列
keyWord 模糊查询的关键字
返回表中的数据量,如果没有数据返回0
Exception SQL执行异常
*/
public Integer getAllCount(String column,String keyWord)throws Exception;
}
//所以重新定义IEmpDAO子接口为IEmpDAO1接口
//重新定义IDeptDAO子接口IDeptDAO1为接口
定义DeptDAOImpl子类
定义DeptDAOImpl子类;
public class DeptDAOImpl implements IDeptDAO{
private Connection conn;
private PreparedStatement pstmt;
public DeptDAOImpl(Connection conn){
this.conn=conn;
}
public boolean doCreate(Dept vo)throws Exception{
String sql="INSERT INTO dept(deptno,dname,loc)VALUES (?,?,?)";
this.pstmt=this.conn.prepareStatement(sql);
this.pstmt.setInt(1,vo.getDeptno());
this.pstmt.setString(2,vo.getDname());
this.pstmt.setString(3,vo.getLoc());
return this.pstmt.executeUpdate()>0;
}
public boolean doUpdate(Dept vo)throws Exception{
String sql="UPDATE dept SET deptno=?,dname,loc=? WHERE deptno=?";
this.pstmt=this.conn.prepareStatement(sql);
this.pstmt.setString(1,vo.getDname());
this.pstmt.setString(2,vo.getLoc());
this.pstmt.setInt(3,vo.getDeptno());
return this.pstmt.executeUpdate()>0;
}
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()).append(",");
}
sql.delete(sql.length()-1,sql.length()).append(")");
this.pstmt=this.conn.prepareStatement(sql.toString());
return this.pstmt.executeUpdate()==ids.size();
}
public Dept findById(Integer id)throws Exception{
Dept vo=null;
String sql="SELECT deptno,dname,loc FROM dept WHERE deptno=?";
this.pstmt.this.conn.prepareStatement(sql);
this.pstmt.setInt(1,id);
ResultSet rs=this.pstmt.executeQuery();
if(rs.next()){
vo=new Dept();
vo.setDeptno(rs.getInt(1));
vo.setDname(rs.getString);
vo.setLoc(rs.getString(3));
}
return vo;
}
public List<Dept> findAll()throws Exception{
List<Dept>all=new ArrayList<Dept>();
String sql="SELECT deptno,dname,loc FROM dept ";
this.pstmt.this.conn.prepareStatement(sql);
this.pstmt.setInt(1,id);
ResultSet rs=this.pstmt.executeQuery();
while(rs.next()){
Dept vo=new Dept();
vo.setDeptno(rs.getInt(1));
vo.setDname(rs.getString);
vo.setLoc(rs.getString(3));
all.add(vo);
}
return all;
}
public List<Emp> findAllSplit(Intger currentPage,Integer lineSize,String column,String keyWord) throws Exception{
throw new Exception("此方法未实现!");
}
public Integer getAllCount(String column,String keyWord)throws Exception{
throw new Exception("此方法未实现!");
}
修改DAOFactory类,增加新的接口对象取得方法:
开发IDeptService接口:
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 List<Dept>list() throws Exception;
public Dept get(int id)throws Exception;
}
实现DeptServiceImpl子类
public class DeptServiceImpl implements IDeptService{
private DatebaseConnection dbc=new DatebaseConnection();
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){
throws e;
}finally{
this.dbc.close();
}
}
public boolean update(Dept vo)throws Exception{
try{
return DAOFactory.getIDeptDAOInstance(this.dbc.getConnection()).doUpdate(vo);
}catch(Exception e){
throws e;
}finally{
this.dbc.close();
}
}
public boolean delete(Set<Integer> ids)throws Exception{
try{
return DAOFactory.getIDeptDAOInstance(this.dbc.getConnection()).doRemove(vo);
}catch(Exception e){
throws e;
}finally{
this.dbc.close();
}
}
public List<Dept>list() throws Exception{
try{
return DAOFactory.getIDeptDAOInstance(this.dbc.getConnection()).findAll();
}catch(Exception e){
throws e;
}finally{
this.dbc.close();
}
}
public Dept get(int id)throws Exception{
try{
return DAOFactory.getIDeptDAOInstance(this.dbc.getConnection()).findById(id);
}catch(Exception e){
throws e;
}finally{
this.dbc.close();
}
}
}
修改服务层工厂类
使用之前进行测试IDeptServiceTest.java
public class IDeptServiceTest{
public 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();
}
}
public 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();
}
}
public void testDelete(){
Set<Integer> ids=new HashSet<Integer>();
ids.add(11);
try{
TestCase.assertTrue(ServiceFactory.getIDeptServiceInstance().delete(ids));
}catch(Exception e){
e.printStackTrace();
}
}
public void testList(){
try{
TestCase.assertTrue(ServiceFactory.getIDeptServiceInstance().list().size()>0);
}catch(Exception e){
e.printStackTrace();
}
}
public void testGet(){
try{
TestCase.assertTrue(ServiceFactory.getIDeptServiceInstance().get(10));
}catch(Exception e){
e.printStackTrace();
}
}
}
8.处理关系
已经实现了雇员和部门的基础操作,但是在雇员里面存在有mgr和deptno两个关联字段。
修改VO类的定义;
修改Emp.java类;
修改Dept.java类;
修改EmpDAOImpl子类
增加数据时需要考虑到雇员的领导以及部门编号;
修改数据时也需要发生变化;
在查询单个雇员信息的时候也需要进行全部内容的查询,也就是说现在的查询里面需要定义新的功能
目的是为了与之前的单表查询区分开。
要重新编写IEmpDAO.java,之前的IEmpDAO.java保存,创建IEmpDAO2.java
public interface IEmpDAO extends IDAO<Integer,Emp>{
/*
查询雇员的详细信息,包括雇员对应的领导信息以及所在的部门信息
id 要查询的雇员编号
所有的数据以VO对象返回,如果没有则返回null
Exception SQL查询错误
*/
public Emp findByIdDetails(Integer id)throws Exception;
/*
查询雇员的完整信息
所有的数据对象以List集合返回,如果没有数据集合长度为0(size()==0)
Exception SQL查询错误
*/
public List<Emp>findAllDetails() throws Exception;
/*
currentPage当前所在的页
lineSize 显示数据行数
column 要进行模糊查询的数据列
keyWord 模糊查询的关键字
如果表中有数据,则所有的数据会封装为VO对象而后利用List集合返回,
如果没有数据,那么集合的长度为0(size()==0,不是null)
Exception SQL执行异常
*/
public List<Emp>findAllSplitDetails(Integer currentPage,Integer lineSize,String colum,String keyWord )throws Exception;
}
扩充IEmpDAO方法
测试:TestEmpSplitDetails
public class TestEmpSplitDetails{
try{
Map<String,Object>map=ServiceFactory.getIEmpServiceInstance().listDetails(2,5,"ename","");
int count=(Integer)map.get("empCount");
System.out.println("数据量:"+count);
List<Emp>all=(List<Emp>)map.get("allEmps");
Iteger<Emp>iter=all.iterator();
whille(iter.hasNext()){
Emp vo=iter.next();
Sysrem.out.println(vo.getEname()+","+vo.getJob()+","+vo.getMgr().getEname()+","+vo.getDept().getDname());
}
}catch(Exception e){
e.printStackTrace();
}
}