Java DAO设计模式

 

清楚了业务层和数据层的区别后, 下面以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();
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值