J2EE之DAO设计模式及简单实现

JAVAEE(Java Enterprise Edition ) 模式 : DAO模式
因此在了解DAO模式之前,我们先来学习一下Java EE的体系结构:
(一)JavaEE体系结构
这里写图片描述

客户端

  • 客户端层:DHTML(Dynanic HTML:HTML+CSS+JavaScript)、JavaApplication(带有main函数的Java程序)

服务器端

  • web层(接收请求,生成响应):Servlet、JSP

  • 业务逻辑层(编写程序业务处理流程):EJB(企业版JavaBean),例如容器管理,线程并发等都包含其中,因此体积庞大,使用复杂,中小型软件不使用

  • 持久层(数据库的增删改查)(数据访问层):Java访问数据库依赖于JDBC接口规范

上述JavaEE体系构成,规范了一个Java程序的构成。因此,假如要设计一款Java EE的软件就需要遵循上面的结构。即我想做一个功能,按照这套结构,从客户端开始,应该写4个程序(如上图所示)。

Struts:实现Servlet与JSP的传统功能
Spring:管理JavaBean的状态
Hibernate:完成数据库的增删改查

实际上,做一套软件,使用Servlet+JSP+JavaBean+JDBC完全可以完成,SSH是对传统开发方式的一个封装,可以在SSH框架的基础上继续进行开发,相对于从Servlet和JSP一点点进行开发,可以大大降低开发的复杂度。

服务器端三层也被称为经典三层结构,即web层(表现层),业务逻辑层,数据持久层,出现了很多结合三层JavaEE的设计模式,DAO模式就是数据持久层的设计模式

MVC 和 JavaEE经典三层结构的比较
实际上MVC 和 JavaEE经典三层结构是由两拨人分别提出的,两者间可以有着如下的对应:

  • 三层结构中业务层、数据持久层 —- Model
  • 三层结构中web层 JSP —- View
  • 三层结构中web层 Servlet —- Controller

(二)DAO(Data Access Object 数据访问对象)设计模式

1、DAO模式的功能:

  • 封装对于数据源的操作,数据源可能是文件、数据库等任意存储方式(可以与数据库或者文件进行交互,业务层在去操作数据层时,不需要知道数据层底层的存储实现)
  • 负责管理与数据源的连接
  • 负责数据的存取(CRUD)

其原理可以用如下图进行解释:

这里写图片描述

DAO模式更通俗的来说,数据层用DAO完全封装了数据源底层实现(相互间传递的是对象,不需要知道其具体实现),提供了增删改查功能;业务层如果操作数据源采用对象的方式,就是说业务层要存一个User的数据,只需要将User数据交给DAO层(数据层),DAO会将数据存到数据库或者文件当中,想查询,即返回一个对象即可。即业务层和数据层进行通信传递的都是对象就是DAO模式好处是业务层开发人员不需要会表写SQL,只要将对象封装好传给数据层即可,通过对象操作完成对数据源增删改查。(使业务层和数据层分离)。

2、DAO模式的构成

DAO模式的构成可以通过如下图进行讲解:

这里写图片描述

  • Business Object :代表数据的使用者 (业务层程序)
  • DataAccessObject :抽象并封装了对底层数据源的操作 (数据层程序)
  • DataSource 数据源 — mysql数据库
  • TransferObject 表示数据的Java Bean

BussinessObject 通过 将transferObject 传递 DataAccessObject 完成对DataSource的增删改查

(三)用DAO模式重写对users表增删改查 (业务层传递一个对象到数据层完成数据库的增删改查)
业务层通过对象的操作,完成对数据源增删改查
DAO模式,将增删改查sql封装起来,方法参数和返回值都是对象,业务层通过操作这些对象,完成对数据库增删改查

接下来我们来写一个DAO模式的实例:
按照DAO模式的结构,我们创建4个package:

这里写图片描述

其中cn.megustas.service代表业务层BusinessObject,代表使用者;cn.megustas.dao代表DataAccessObject,封装了对源数据的增删改查操作,返回对象;cn.megustas.domain代表TransferObject,其中是表示数据的JavaBean;cn.megustas.jdbc是将常用的数据库连接等语句封装于Untils,方便直接调用使用。

假设在database中已经存在如下的table:

这里写图片描述

TransferObject:

package cn.megustas.domain;
/*
 * 传输对象,保存User相关数据
 * 
 * @author Megustas
 */
public class User {
    //需要注意,类属性需要与数据库中的字段一一对应
    private int id;
    private String name;
    private String pwd;
    private String email;


    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getPwd() {
        return pwd;
    }
    public void setPwd(String pwd) {
        this.pwd = pwd;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }

}

*小技巧:对于JavaBean中的get/set方法的生成,可以选中成员变量,右键-Source-Generate Getters and Setters

JDBCUtils:

package cn.megustas.jdbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ResourceBundle;

/*
 * JDBC 工具类,抽取公共方法
 * 
 * @author Megustas
 * 
 */
public class JDBCUtils {
    private static final String DRIVERCLASS;
    private static final String URL;
    private static final String USER;
    private static final String PWD;

    static {
        ResourceBundle bundle = ResourceBundle.getBundle("dbconfig");
        DRIVERCLASS = bundle.getString("DRIVERCLASS");
        URL = bundle.getString("URL");
        USER = bundle.getString("USER");
        PWD = bundle.getString("PWD");
    }

    // 建立连接
    public static Connection getConnection() throws Exception {
        loadDriver();
        return DriverManager.getConnection(URL, USER, PWD);
    }

    // 装载驱动
    private static void loadDriver() throws ClassNotFoundException {
        Class.forName(DRIVERCLASS);
    }

    // 释放资源
    public static void release(ResultSet rs, Statement stmt, Connection conn) {
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            rs = null;
        }

        release(stmt, conn);
    }

    public static void release(Statement stmt, Connection conn) {
        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            stmt = null;
        }
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            conn = null;
        }
    }
}

DataAccessObject:

*注意,(1)一定要在try{}catch{}后使用finally进行资源释放(2)sql中字符串需要使用‘’

package cn.megustas.dao;

import java.sql.Connection;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

import cn.megustas.domain.User;
import cn.megustas.jdbc.JDBCUtils;

/**
 * 数据层一个程序
 * DAO层返回对象,在业务层通过操作这些对象来实现增删改查
 * 
 * @author Megustas
 * 
 */
public class UserDAO {


    public User login(User user) {
        // JDBC查询
        User existUser = null;
        Connection conn = null;
        PreparedStatement stmt = null;
        ResultSet rs = null;
        try {
            conn = JDBCUtils.getConnection();
            String sql = "select * from users where name = ? and pwd = ?"; // 数据库编译时
            stmt = conn.prepareStatement(sql); // 将sql 发送给数据库进行编译
            // 设置参数
            stmt.setString(1, user.getName()); // or -- 传入数据值,不会作为关键字 --防止注入
            stmt.setString(2, user.getPwd());

            // 因为之前 将sql 传递数据库
            rs = stmt.executeQuery();
            // 如果登陆成功 只有一条记录
            if (rs.next()) {
                existUser = new User();
                existUser.setId(rs.getInt("id"));
                existUser.setName(rs.getString("name"));
                existUser.setPwd(rs.getString("pwd"));
                existUser.setEmail(rs.getString("email"));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return existUser;
    }
    //返回一个对象
    public User findById(int id) {
        User user = null;
        // 查询数据
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;

        try {
            conn = JDBCUtils.getConnection();
            stmt = conn.createStatement();
            String sql = "select * from users where id = " + id;
            rs = stmt.executeQuery(sql);
            // 结果集只有一条,看id是否有效,有效即返回
            if (rs.next()) {
                // 结果集每行 一条记录 ----- User对象
                user = new User();
                user.setId(rs.getInt("id"));
                user.setName(rs.getString("name"));
                user.setPwd(rs.getString("pwd"));
                user.setEmail(rs.getString("email"));

            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.release(rs, stmt, conn);
        }

        return user;
    }
    //DAO强调的是对象,因此一条记录会返回一个对象,数据表中有很多条记录,因此返回一个List
    public List<User> findAll() {
        List<User> users = new ArrayList<User>();
        // 查询数据
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;

        try {
            conn = JDBCUtils.getConnection();
            stmt = conn.createStatement();
            String sql = "select * from users";
            rs = stmt.executeQuery(sql);
            while (rs.next()) {
                // 结果集每行 一条记录 ----- User对象
                User user = new User();
                user.setId(rs.getInt("id"));
                user.setName(rs.getString("name"));
                user.setPwd(rs.getString("pwd"));
                user.setEmail(rs.getString("email"));

                users.add(user);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.release(rs, stmt, conn);
        }

        return users;
    }

    // 全字段修改
    public void update(User user) {
        Connection conn = null;
        Statement stmt = null;

        try {
            conn = JDBCUtils.getConnection();
            stmt = conn.createStatement();
            // 参数在传入user对象中
            // 在修改时,通过id修改该条记录所有字段
            String sql = "update users set name='" + user.getName()
                    + "' ,pwd='" + user.getPwd() + "',email='"
                    + user.getEmail() + "' where id = " + user.getId();
            stmt.executeUpdate(sql);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.release(stmt, conn);
        }
    }

    public void delete(User user) {
        Connection conn = null;
        Statement stmt = null;

        try {
            conn = JDBCUtils.getConnection();
            stmt = conn.createStatement();
            // 参数在传入user对象中
            String sql = "delete from users where id = " + user.getId();
            stmt.executeUpdate(sql);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.release(stmt, conn);
        }
    }

    // 封装了数据源 增删改查底层实现,insert方法内是具体的数据库插入操作
    public void insert(User user) {
        // 将 user中数据 保存到数据库
        Connection conn = null;
        Statement stmt = null;
        try {
            conn = JDBCUtils.getConnection();
            stmt = conn.createStatement();
            //参数传入user对象中
            String sql = "insert into users values("+user.getId()+",'"
                    +user.getName()+",'"+user.getPwd()+",'"
                    +user.getEmail()+"')";
            stmt.executeQuery(sql);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally{
            JDBCUtils.release(stmt, conn);
        }
    }
}

BusinessObject:
可以发现,业务层进行数据的增删改查,无需写SQL语句,只需创建对应的对象,调用数据层(DataAccessObject)方法就可以实现(也就是说在实际工程中可以将业务进行分工,业务层的操作人员可以不必会SQL等相关操作也可以进行数据库的增删改查)

package cn.megustas.service;

import java.util.List;


import org.junit.Test;

import cn.megustas.dao.UserDAO;
import cn.megustas.domain.User;

/**
 * 业务层一个程序
 * 
 * @author Megustas
 * 
 */
public class UserService {
    /**
     * 根据用户名 和 密码查询其它信息
     * 
     * @param user
     * @return 如果返回null证明 用户名或者密码错误
     */
    public User login(User user) {
        // 查询 将 user对象传递 DAO
        UserDAO userDAO = new UserDAO();
        return userDAO.login(user);
    }

    @Test
    public void testFindById() {
        int id = 3;
        UserDAO userDAO = new UserDAO();
        User user = userDAO.findById(id);
        System.out.println(user.getName());
    }

    @Test
    public void testFindAll() {
        UserDAO userDAO = new UserDAO();
        List<User> users = userDAO.findAll();
        for (User user : users) {
            System.out.println(user.getName());
        }
    }

    @Test
    public void testUpdate() {
        User user = new User();
        user.setId(3);
        user.setName("大国");
        user.setPwd("123456");
        user.setEmail("daguo@itcast.cn");

        UserDAO userDAO = new UserDAO();
        userDAO.update(user);
    }

    @Test
    public void testDelete() {
        User user = new User();
        user.setId(10);

        UserDAO userDAO = new UserDAO();
        userDAO.delete(user);
    }

    @Test
    //插入数据,在业务层此时只需要创建一个User对象,调用数据层方法就可以完成
    public void testInsert() {
        User user = new User();
        user.setId(10);
        user.setName("小王");
        user.setPwd("123");
        user.setEmail("xiaowang@itcast.cn");
        // 业务层将 对象 传递 数据层DAO 完成对数据表增删改查
        UserDAO userDAO = new UserDAO();
        userDAO.insert(user);
    }
}

具体代码完整下载可以去Git:https://coding.net/u/TwistFate/p/DaoTest/git

©️2020 CSDN 皮肤主题: 书香水墨 设计师:CSDN官方博客 返回首页