【JDBC-05】程序分层设计+DAO层设计

一. 程序分层设计模式

1.1 代码分层

1. 开发项目最终目的是让客户从浏览器端或者APP端操作数据,要实现这个功能就需要访问数据库,业务算法处理,请求的分发处理。
2. 访问数据库,业务算法处理,请求的分发处理这三个功能可以放在一起实现,但是全部放在一起代码会显得臃肿,不方便维护,于是就出现代码分层的概念。
3. 代码分层:把代码按照功能分为不同的层。
4. 最常见的代码分层组合模式:MVC模式

1.2 MVC模式

MVC模式:按照程序功能将代码分为三层,Model层(模型层),View层(显示层),Controller层(控制层)

在这里插入图片描述

详细说明:
Modle层:Modle层又分为dao层(数据访问层),
1. serveice层(业务层)
(1)sercice层:主要负责一些业务处理,比如取得连接,关闭数据库连接,事务回滚或者一些复杂的逻辑业务处理.........
(2)dao层: 负责访问数据库,进行数据操作,取的结果集ResultSet,将结果集ResultSet中的数据取出来封装到VO对象中返回给service层

2. Controller层:控制层,负责处理用户发送的请求。
3. View层:限制层,负责显示数据(渲染数据)。

分层的直接体现是将不同功能的代码保存到不同的包中。如下图所示:

在这里插入图片描述

1. 定义接口:
   需要为每一层定义标准,不能让上层代码对下层代码依赖程度过高,也就是高耦合。
2. MVC模式中代码的调用顺序:
   view-->Controller-->Service-->dao

二. DAO层基础设计模型

现在为emp数据表设计数据操作的DAO层
实际开发中DAO层需要先定义出自己的操作标准(接口),防止耦合过高。
再定义接口实现类

2.1 创建包结构

创建出包的结构,必须按照标准来

在这里插入图片描述

2.2 创建Emp对象

1. Emp对象,放到vo实体对象包
2. 简单java类中的基本数据类型必须使用基本数据类型包装类
3. 此简单java类必须实现Serializable接口,方便以后程序的扩展(比如序列化该类对象需要用到Serializable接口)
public class Emp  implements Serializable {
    private Integer empno;
    private String ename;
    private String  job;
    private double sal;
    private Date hiredate;

    public Emp() {
    }

    public Emp(Integer empno, String ename, String job, double sal, Date hiredate) {
        this.empno = empno;
        this.ename = ename;
        this.job = job;
        this.sal = sal;
        this.hiredate = hiredate;
    }

    public void setEmpno(Integer empno) {
        this.empno = empno;
    }

    public void setEname(String ename) {
        this.ename = ename;
    }

    public void setJob(String job) {
        this.job = job;
    }

    public void setSal(double sal) {
        this.sal = sal;
    }

    public void setHiredate(Date hiredate) {
        this.hiredate = hiredate;
    }

    public Integer getEmpno() {
        return empno;
    }

    public String getEname() {
        return ename;
    }

    public String getJob() {
        return job;
    }

    public double getSal() {
        return sal;
    }

    public Date getHiredate() {
        return hiredate;
    }

    @Override
    public String toString() {
        return "Emp{" +
                "empno=" + empno +
                ", ename='" + ename + '\'' +
                ", job='" + job + '\'' +
                ", sal=" + sal +
                ", hiredate=" + hiredate +
                '}';
    }
}

2.3 创建dao层接口(操作标准)

操作emp数据表的接口
import java.util.List;

/**
 * 操作数据库表Emp的接口
 * 定义6个方法
 * seletCount():统计查询数据量
 * 
 */

public interface IEmpDAO {
    /**
     * 根据查询关键字统计查询结果总数
     * @param kw 查询关键字
     * @return
     */
    int seletCount(String kw);

    /**
     * 模糊分页查询
     * @param kw  查询关键字
     * @param start 当前页
     * @param ls    显示页数
     * @return
     */
    List<Emp> selectSplitALL(String kw,int start,int ls);

    /**
     * 根据id查询数据
     * @param id
     * @return
     */
    Emp selectById(Integer id);

    /**
     * 根据id删除数据
     * @param id
     * @return
     */
    int delectById(Integer id);

    /**
     * 修改数据
     * @param emp
     * @return
     */
    int update(Emp emp);

    /**
     * 插入数据
     * @param emp
     * @return
     */
    int insert(Emp emp);
}

2.4 定义DAO层接口实现类

public class IEmpDAOImpl implements  IEmpDAO {
    private Connection conn;

    //无参构造
    public IEmpDAOImpl(){

    }

    //有参构造,初始化连接对象
    public IEmpDAOImpl(Connection conn){
        this.conn = conn;
    }

    @Override
    public int seletCount(String kw) throws Exception {
        PreparedStatement pst =null;
        String str = "SELECT empno,ename,job,sal,hiredate FROM emp WHERE ename LIKE ? ";

        try{
            pst = conn.prepareStatement(str);
            pst.setString(1,"%"+kw+"%");
            ResultSet rst = pst.executeQuery();
            if(rst.next()){
                return rst.getInt(1);
            }
        }catch(Exception e) {

            e.printStackTrace();
        }finally{
            ConnectionUtil.close(conn,pst);
        }
        return 0;
    }

    @Override
    public List<Emp> selectSplitALL(String kw, int start, int ls) throws Exception {
        //创建一个list集合存放emp对象
        ArrayList<Emp> emps = new ArrayList<Emp>();
        //定义发送sql对象
        PreparedStatement pst = null;
        String str1 = "SELECT empno,ename,job,sal,hiredate FROM emp WHERE ename LIKE '%?%' "+" LIMIT ?,?";

        try {
            //获取发送sql语句对象
            pst = conn.prepareStatement(str1);
            //为占位符赋值
            pst.setString(1,kw);
            pst.setInt(2,start);
            pst.setInt(3,ls);

            //发送查询申请,取得结果集
            ResultSet rst = pst.executeQuery();

            while (rst.next()) {
                //在for循环之中只可以调用一次rst.next(),要不然就相当于多个引用了
                emps.add( new Emp(rst.getInt(1), rst.getString(2), rst.getString(3), rst.getDouble(4), rst.getDate(5)));
            }
            return emps;
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            //关闭资源
           ConnectionUtil.close(conn,pst);
        }
        return null;
    }

    @Override
    public Emp selectById(Integer id) throws Exception {
        PreparedStatement pst =null;
        String str = "SELECT empno,ename,job,sal,hiredate FROM emp WHERE empno=?";

        try{
            pst = conn.prepareStatement(str);
            pst.setInt(1,id);
            ResultSet rst = pst.executeQuery();
            if(rst.next()){
                return new Emp(rst.getInt(1),rst.getString(2),rst.getString(3),rst.getDouble(4),rst.getDate(5));
            }
        }catch(Exception e) {

            e.printStackTrace();
        }finally{
           ConnectionUtil.close(conn,pst);
        }
        return null;
    }

    @Override
    public int delectById(Integer id) throws Exception {
        PreparedStatement pst=null;
        try {
            //获得连接对象
            conn = com.ConnectionUtil.ConnectionUtil.getConnection();
            //准备sql语句
            String sql = "DELETE FROM emp WHERE empno=?";
            //取得发送sql语句的对象
            pst = conn.prepareStatement(sql);
            //为占位符赋值
            pst.setInt(1,id);
            //发送sql语句指令
            return pst.executeUpdate();
        }catch (Exception e){
            e.printStackTrace();
        }finally{
            //关闭资源
            ConnectionUtil.close(conn,pst);
        }
        return 0;
    }

    @Override
    public int update(Emp emp) throws Exception {
        //准备sql语句
        String sql = "Update emp SET  ename=?,sal=? WHERE empno=?";
        PreparedStatement pst=null;
        try {
            //获得连接对象
            conn = com.ConnectionUtil.ConnectionUtil.getConnection();
            //取得发送sql语句的对象
            pst = conn.prepareStatement(sql);
            pst.setString(1,emp.getEname());
            pst.setDouble(2,emp.getSal());
            pst.setInt(3,emp.getEmpno());
            //发送sql语句指令
            return pst.executeUpdate();
        }catch (Exception e){
            e.printStackTrace();
        }finally{
            //关闭资源
            ConnectionUtil.close(conn,pst);
        }
        return 0;
    }

    @Override
    public int insert(Emp emp) throws Exception {
        //准备sql语句
        String sql = "insert INTO emp (ename,job,sal)" + "VALUES(?,?,?)";
        PreparedStatement pst=null;
        try {
            //获得连接对象
            conn = com.ConnectionUtil.ConnectionUtil.getConnection();

            //取得发送sql语句的对象,增加参数,取得主键自增长的值
            pst = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
            pst.setString(1,emp.getEname());
            pst.setString(2,emp.getJob());
            pst.setDouble(3,emp.getSal());
            //发送sql语句指令
            pst.executeUpdate();

            //返回主键自增值
            ResultSet key = pst.getGeneratedKeys();
            if(key.next()){
                System.out.println("主键自增长的值为"+key.getInt(1));
            }

        }catch (Exception e){
            e.printStackTrace();
        }finally{
            //关闭资源
            ConnectionUtil.close(conn,pst);
        }
        return 0;
    }
}

2.5 测试程序

import java.sql.Connection;

public class Test {
    public static void main(String[] args) throws Exception {
        //取得连接
        Connection conn = ConnectionUtil.getConnection();
        //实例化dao层实现类
        IEmpDAOImpl iEmpDAO = new IEmpDAOImpl(conn);
        //调用SelectById()方法查询7369员工
        System.out.println(iEmpDAO.selectById(7369));
    }
}

在这里插入图片描述

三. DAO层父接口定义

3.1 定义DAO层父接口的意义

1.背景:前面在DAO层只是定义了操作Emp表的接口,但是在实际开发中,不仅仅只有一张数据表,那么就需要为每一张数据表定义一个操作接口,就会发现每个接口中的方法都是基本相同,仅仅是参数不一样,就会有很多重复代码
2. 此时可以
 ---->定义一个父接口,将形式相同的方法抽象到父接口
 ---->父接口使用泛型,子接口继承父接口时指定出泛型类型
 ---->子接口不需要再编写公共方法,可以定义自己特有的方法。

在这里插入图片描述

3.2 定义公共父接口

import java.util.List;

/**
 * 对数据库所有表进行操作的父接口
 * 定义公共方法
 */
public interface IDAO<V> {
    /**
     * 根据查询关键字统计查询结果总数
     * @param kw 查询关键字
     * @return
     */
    int seletCount(String kw) throws Exception;

    /**
     * 模糊分页查询
     * @param kw  查询关键字
     * @param start 当前页
     * @param ls    显示页数
     * @return
     */
    List<V> selectSplitALL(String kw, int start, int ls) throws Exception;

    /**
     * 根据id查询数据
     * @param id
     * @return
     */
    V selectById(Integer id) throws Exception;

    /**
     * 根据id删除数据
     * @param id
     * @return
     */
    int delectById(Integer id) throws Exception;

    /**
     * 修改数据
     * @param v
     * @return
     */
    int update(V  v) throws Exception;

    /**
     * 插入数据
     * @param v
     * @return
     */
    int insert(V v) throws Exception;
}

1.创建Dept类,IDeptDAOImpl
import java.io.Serializable;

public class Dept implements Serializable {
    private Integer deptno;
    private String dname;
    private String loc;

    public Dept() {
    }

    public Dept(Integer deptno, String dname, String loc) {
        this.deptno = deptno;
        this.dname = dname;
        this.loc = loc;
    }

    public Integer getDeptno() {
        return deptno;
    }

    public String getDname() {
        return dname;
    }

    public String getLoc() {
        return loc;
    }

    public void setDeptno(Integer deptno) {
        this.deptno = deptno;
    }

    public void setDname(String dname) {
        this.dname = dname;
    }

    public void setLoc(String loc) {
        this.loc = loc;
    }

    @Override
    public String toString() {
        return "Dept{" +
                "deptno=" + deptno +
                ", dname='" + dname + '\'' +
                ", loc='" + loc + '\'' +
                '}';
    }
}

-------------------------------------------------------
//IDeptDAO
/**
 * 操作数据库表Dept的接口
 *
 */
public interface IDeptDAO extends  IDAO<Dept> {
}

---------------
//IDeptDAOImpl

public class IDeptDAOImpl extends DAOAdapter<Dept> implements IDeptDAO {
    private Connection conn;

    //无参构造
    public IDeptDAOImpl(){

    }

    //有参构造,初始化连接对象
    public IDeptDAOImpl(Connection conn){
        this.conn = conn;
    }

    @Override
    public int seletCount(String kw) throws Exception {
        PreparedStatement pst =null;
        String str = "SELECT deptno,dname,loc FROM emp WHERE dept LIKE ? ";

        try{
            pst = conn.prepareStatement(str);
            pst.setString(1,"%"+kw+"%");
            ResultSet rst = pst.executeQuery();
            if(rst.next()){
                return rst.getInt(1);
            }
        }catch(Exception e) {
            e.printStackTrace();
        }
        return 0;
    }

    @Override
    public List<Dept> selectSplitALL(String kw, int start, int ls) throws Exception {
        //创建一个list集合存放dept对象
        ArrayList<Dept> depts = new ArrayList<Dept>();
        //定义发送sql对象
        PreparedStatement pst = null;
        String str1 = "SELECT deptno,dname,loc FROM dept WHERE dname LIKE '%?%' "+" LIMIT ?,?";

        try {
            pst = conn.prepareStatement(str1);
            pst.setString(1,kw);
            pst.setInt(2,start);
            pst.setInt(3,ls);

            ResultSet rst = pst.executeQuery();
            while (rst.next()) {
                //在for循环之中只可以调用一次rst.next(),要不然就相当于多个引用了
                depts.add( new Dept(rst.getInt(1), rst.getString(2), rst.getString(3)));
            }
            return depts;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public Dept selectById(Serializable  id) throws Exception {
        PreparedStatement pst =null;
        String str = "SELECT deptno,dname,loc FROM dept WHERE deptno=?";

        try{
            pst = conn.prepareStatement(str);
            pst.setObject(1,id);
            ResultSet rst = pst.executeQuery();
            if(rst.next()){
                return new Dept(rst.getInt(1),rst.getString(2),rst.getString(3));
            }
        }catch(Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public int delectById(Serializable id) throws Exception {
        PreparedStatement pst=null;
        try {
            //准备sql语句
            String sql = "DELETE FROM dept WHERE deptno=?";
            pst.setObject(1,id);
            //取得发送sql语句的对象
            pst = conn.prepareStatement(sql);
            //发送sql语句指令
            return  pst.executeUpdate();
        }catch (Exception e){
            e.printStackTrace();
        }
        return 0;
    }

    @Override
    public int update(Dept dept) throws Exception {
        //准备sql语句
        String sql = "Update emp SET  dname=?,loc=? WHERE deptno=?";
        PreparedStatement pst=null;
        try {
            //取得发送sql语句的对象
            pst = conn.prepareStatement(sql);
            pst.setString(1,dept.getDname());
            pst.setString(2,dept.getLoc());
            pst.setInt(3,dept.getDeptno());
            //发送sql语句指令
            return pst.executeUpdate();
        }catch (Exception e){
            e.printStackTrace();
        }
        return 0;
    }

    @Override
    public int insert(Dept dept) throws Exception {
        //准备sql语句
        String sql = "insert INTO dept (deptno,dname,loc)" + "VALUES(?,?,?)";
        PreparedStatement pst=null;
        try {

            //取得发送sql语句的对象,增加参数,取得主键自增长的值
            pst = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
            pst.setInt(1,dept.getDeptno());
            pst.setString(2,dept.getDname());
            pst.setString(3,dept.getLoc());
            //发送sql语句指令
            pst.executeUpdate();

            //返回主键自增值
            ResultSet key = pst.getGeneratedKeys();
            if(key.next()){
                System.out.println("主键自增长的值为"+key.getInt(1));
            }

        }catch (Exception e){
            e.printStackTrace();
        }
        return 0;
    }
}

2. 定义操作dept数据表的接口,继承父接口IDAO,泛型为Dept
/**
 * 操作数据库表Dept的接口
 *
 */
public interface IDeptDAO extends  IDAO<Dept> {
}
3. 让操作Emp数据表的接口,继承父接口IDAO,泛型为Emp

/**
 * 操作数据库表Emp的接口
 *
 */

public interface IEmpDAO  extends IDAO<Emp> {

}

3.3 测试程序


public class Test {
    public static void main(String[] args) throws Exception {
        //取得连接
        Connection conn = ConnectionUtil.getConnection();
        //实例化dao层实现类
        IDAO iEmpDAO = new IEmpDAOImpl(conn);
        //调用SelectById()方法查询7369员工
        System.out.println(iEmpDAO.selectById(7369));
    }
}

在这里插入图片描述

四. 适配器模式

4.1 使用适配器的意义

1. 在DAO层开发中所有实现类都要覆写父接口中的所有方法,但是父接口中的某些方法对于某些实现类是不需要的
2. 此时就可以使用适配器设计模式让实现类可以自由选择覆写父接口中的方法。
3. 就是定义一个类去实现父接口,然后让子接口在实现对应接口的同时继承适配器类(继承又实现)

在这里插入图片描述

4.2 定义适配器类

import java.util.List;

public class DAOAdapter<T> implements IDAO<T> {

    @Override
    public int seletCount(String kw) throws Exception {
        return 0;
    }

    @Override
    public List<T> selectSplitALL(String kw, int start, int ls) throws Exception {
        return null;
    }

    @Override
    public T selectById(Integer id) throws Exception {
        return null;
    }

    @Override
    public int delectById(Integer id) throws Exception {
        return 0;
    }

    @Override
    public int update(T t) throws Exception {
        return 0;
    }

    @Override
    public int insert(T t) throws Exception {
        return 0;
    }
}

4.3 改变子接口实现类继承结构

public class IEmpDAOImpl extends DAOAdapter<Emp> implements IEmpDAO {
    private Connection conn;
    -------------------------------------------------------------
public class IDeptDAOImpl extends DAOAdapter<Dept> implements IDeptDAO {
    private Connection conn;
此时,子接口实现类不需要强制性覆写所有父接口中的方法,可以自由选择覆写自己需要的方法,使代码变得灵活

4.4 完善父接口

把参数的Integer类型变成Serializable类型
而实现类中为占位符赋值时使用setObject()方法
/**
 * 对数据库所有表进行操作的父接口
 * 定义公共方法
 */
public interface IDAO<V> {
    /**
     * 根据查询关键字统计查询结果总数
     * @param kw 查询关键字
     * @return
     */
    int seletCount(String kw) throws Exception;

    /**
     * 模糊分页查询
     * @param kw  查询关键字
     * @param start 当前页
     * @param ls    显示页数
     * @return
     */
    List<V> selectSplitALL(String kw, int start, int ls) throws Exception;

    /**
     * 根据id查询数据
     * @param id
     * @return
     */
    V selectById(Serializable id) throws Exception;

    /**
     * 根据id删除数据
     * @param id
     * @return
     */
    int delectById(Serializable  id) throws Exception;

    /**
     * 修改数据
     * @param v
     * @return
     */
    int update(V  v) throws Exception;

    /**
     * 插入数据
     * @param v
     * @return
     */
    int insert(V v) throws Exception;
}

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值