【Java从零到架构师第二季】【08】引入DAO_JDBC封装


持续学习&持续更新中…

学习态度:守破离


编写一个小例子(数据库+Servlet+JSP)

准备工作

1 添加jar包到项目

将mysql的驱动和JSP的taglibsjar包引入项目

在这里插入图片描述

2 建表 & 初始化表数据
CREATE TABLE customer(
		id INT AUTO_INCREMENT PRIMARY KEY,
		name VARCHAR(20) NOT NULL,
		age INT,
		height DOUBLE
);


INSERT INTO customer(name, age, height) VALUES('张三', 10, 1.8);
INSERT INTO customer(name, age, height) VALUES('李四', 20, 1.2);
INSERT INTO customer(name, age, height) VALUES('王五', 30, 1.4);
INSERT INTO customer(name, age, height) VALUES('赵六', 14, 2.3);
INSERT INTO customer(name, age, height) VALUES('田七', 13, 1.8);
INSERT INTO customer(name, age, height) VALUES('王婆', 50, 3.2);
INSERT INTO customer(name, age, height) VALUES('李逵', 40, 0.8);
INSERT INTO customer(name, age, height) VALUES('宋江', 50, 1.9);

编写Java代码

Customer Bean
public class Customer {
    
    

    private Integer id;
    private String name;
    private Integer age;
    private Double height;

    public Customer(Integer id, String name, Integer age, Double height) {
    
    
        this.id = id;
        this.name = name;
        this.age = age;
        this.height = height;
    }

    public Customer(String name, Integer age, Double height) {
    
    
        this.name = name;
        this.age = age;
        this.height = height;
    }

    public Customer() {
    
    
    }

    public Integer getId() {
    
    
        return id;
    }

    public void setId(Integer id) {
    
    
        this.id = id;
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public Integer getAge() {
    
    
        return age;
    }

    public void setAge(Integer age) {
    
    
        this.age = age;
    }

    public Double getHeight() {
    
    
        return height;
    }

    public void setHeight(Double height) {
    
    
        this.height = height;
    }
    
}


ListServlet
@WebServlet("/list")
public class ListServlet extends HttpServlet {
    
    

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) {
    
    
        final String mysqlDriver = "com.mysql.jdbc.Driver";
        final String url = "jdbc:mysql://localhost:3306/my_db";
        final String username = "root";
        final String password = "root";
        final String sql = "SELECT id, name, age, height FROM user";
        try {
    
    
            Class.forName(mysqlDriver);
        } catch (ClassNotFoundException e) {
    
    
            System.err.println("MySQL数据库驱动加载失败!");
            return;
        }
        try (
                final Connection connection = DriverManager.getConnection(url, username, password);
                final PreparedStatement preparedStatement = connection.prepareStatement(sql);
                final ResultSet resultSet = preparedStatement.executeQuery()
        ) {
    
    

            List<Customer> customers = new ArrayList<>(20);
            while (resultSet.next()) {
    
    
                final Integer id = resultSet.getInt("id");
                final String name = resultSet.getString("name");
                final Integer age = resultSet.getInt("age");
                final Double height = resultSet.getDouble("height");

                customers.add(new Customer(id, name, age, height));
            }

            req.setAttribute("customers", customers);
            req.getRequestDispatcher("pages/list.jsp").forward(req, resp);
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
    }

}
AddCustomerServlet
@WebServlet("/addcustomer")
public class AddCustomerServlet extends HttpServlet {
    
    

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        req.setCharacterEncoding("utf-8");

        String customerName = req.getParameter("customer_name");
        int customerAge = 0;
        double customerHeight = 0.0;
        try {
    
    
            customerAge = Integer.parseInt(req.getParameter("customer_age"));
            customerHeight = Double.parseDouble(req.getParameter("customer_height"));
        } catch (Exception e) {
    
    
            resp.sendRedirect("/seven_crms_jdbc/pages/addcustomer.html");
            System.out.println("用户输入错误");
            return;
        }
        final String mysqlDriver = "com.mysql.jdbc.Driver";
        final String url = "jdbc:mysql://localhost:3306/my_db";
        final String username = "root";
        final String password = "root";
        final String sql = "INSERT INTO user(name, age, height) VALUES(?, ?, ?)";
        try {
    
    
            Class.forName(mysqlDriver);
        } catch (ClassNotFoundException e) {
    
    
            System.err.println("MySQL数据库驱动加载失败!");
            return;
        }
        try (
                final Connection connection = DriverManager.getConnection(url, username, password);
                final PreparedStatement preparedStatement = connection.prepareStatement(sql)
        ) {
    
    
            preparedStatement.setString(1, customerName);
            preparedStatement.setInt(2, customerAge);
            preparedStatement.setDouble(3, customerHeight);

            if (1 == preparedStatement.executeUpdate()) {
    
    
                resp.sendRedirect("/seven_crms_jdbc/list");
                System.out.println("插入数据成功");
            } else {
    
    
                resp.sendRedirect("/seven_crms_jdbc/pages/addcustomer.html");
                System.out.println("插入数据失败 执行sql错误");
            }

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

}
list.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>jsp list</title>
    <style>
        table, tr, th, td {
      
      
            border: 1px solid black;
            text-align: center;
        }

        th, td {
      
      
            display: inline-block;
            width: 200px;
        }

    </style>
</head>
<body>

<div>
    <a href="pages/addcustomer.html">添加用户</a>
</div>

<table>
    <tr>
        <th>姓名</th>
        <th>年龄</th>
        <th>身高</th>
    </tr>

    <c:forEach items="${customers}" var="customer">
        <tr>
            <td>${customer.name}</td>
            <td>${customer.age}</td>
            <td>${customer.height}</td>
        </tr>
    </c:forEach>

</table>

</body>
</html>
addcustomer.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>add customer</title>
</head>
<body>

<form action="/seven_crms_jdbc/addcustomer" method="post">
    <div>姓名<input type="text" name="customer_name"></div>
    <div>年龄<input type="number" name="customer_age"></div>
    <div>身高<input type="number" name="customer_height"></div>

    <button type="submit">保存</button>
</form>

</body>
</html>

该例子存在的一些问题

  • 现在一个请求就对应一个Servlet,Servlet的功能过于单一:ListServlet负责从数据库中获取数据并展示,AddCustomerServlet负责添加数据到数据库。那如果再想要一个删除数据操作呢?再添加一个DeleteServlet?

  • 还有一个问题,现在浏览器中输入http://host:port/list,这个list是谁的list?Customer的?Company的?能不能考虑实现一个CustomerServlet,让该Servlet操作对customer表的增删改查?实现一个CompanyServlet,让该Servlet操作对company表的增删改查?

  • 要知道,Servlet只是负责解析客户端请求的,负责解析客户端想干嘛的。数据库访问代码不应该写在Servlet中。

  • 项目中存在大量重复、繁琐代码。

这些问题该如何解决?

解决该项目问题

① 引入配置文件

什么是配置文件

在这里插入图片描述

具体实现

1 创建db.properties文件

李明杰老师讲的是在项目中的src目录下新建该文件。

在这里插入图片描述

在这里插入图片描述

但是在IDEA2021.1.1中,直接在src中创建db.properties加载不出来,需要在自动生成的resources目录下创建db.properties文件。

在这里插入图片描述

2 往properties中写入配置信息
mysql_driver=com.mysql.jdbc.Driver
mysql_url=jdbc:mysql://localhost:3306/my_db
mysql_username=root
mysql_password=root
3 加载配置文件
    /*
        这些常量不应该写死。
        因为到时候需要将项目中的.java文件编译为.class文件部署到服务器上
        如果将这些常量写死的话,到时候如果MySQL服务器的用户名或者密码发生改变的话,
        只能将该项目修改后再次编译为.class文件,然后再次部署到服务器上,这样会很麻烦。
    */
    private static String MYSQL_DRIVER;
    private static String MYSQL_URL;
    private static String MYSQL_USERNAME;
    private static String MYSQL_PASSWORD;
    
    static {
    
    
        Properties properties = new Properties();
        try (InputStream is = Dbs.class.getClassLoader().getResourceAsStream("db.properties")) {
    
    
            properties.load(is);
            MYSQL_DRIVER = properties.getProperty("mysql_driver");
            MYSQL_URL = properties.getProperty("mysql_url");
            MYSQL_USERNAME = properties.getProperty("mysql_username");
            MYSQL_PASSWORD = properties.getProperty("mysql_password");
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
    }

② 引入Dbs

什么是Dbs

Dbs就是一个数据库工具类,里面封装了一些常用的操作数据库的方法。

实现Dbs

public final class Dbs {
    
    
    private static String MYSQL_DRIVER;
    private static String MYSQL_URL;
    private static String MYSQL_USERNAME;
    private static String MYSQL_PASSWORD;

    static {
    
    
        Properties properties = new Properties();
        try (InputStream is = Dbs.class.getClassLoader().getResourceAsStream("db.properties")) {
    
    
            properties.load(is);
            MYSQL_DRIVER = properties.getProperty("mysql_driver");
            MYSQL_URL = properties.getProperty("mysql_url");
            MYSQL_USERNAME = properties.getProperty("mysql_username");
            MYSQL_PASSWORD = properties.getProperty("mysql_password");
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }

        try {
    
    
            Class.forName(MYSQL_DRIVER);
        } catch (ClassNotFoundException e) {
    
    
            System.err.println("MySQL数据库驱动加载失败!");
        }
    }
 
    /**
     * 执行 DML、DDL语句
     *
     * @param sql
     * @return 是否执行成功
     */
    public static int update(final String sql, Object... args) {
    
    
        try (
                final Connection connection = DriverManager.getConnection(MYSQL_URL, MYSQL_USERNAME, MYSQL_PASSWORD);
                final PreparedStatement preparedStatement = connection.prepareStatement(sql)
        ) {
    
    
            for (int i = 0; i < args.length; i++) {
    
    
                preparedStatement.setObject(i + 1, args[i]);
            }
            return preparedStatement.executeUpdate();
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }

        return 0;
    }

    public interface RowMapper<T> {
    
    
        T generateBean(ResultSet resultSet, int row) throws SQLException;
    }

    /**
     * 执行 DQL语句
     *
     * @param rowMapper 让用户自己创建Bean对象
     * @param sql       sql语句
     * @param args      sql语句中的参数
     * @param <T>       Bean类型
     * @return 查询出的结果
     */
    public static <T> List<T> query(RowMapper<T> rowMapper, String sql, Object... args) {
    
    
        if (null == rowMapper) return null;

        ResultSet resultSet = null;
        try (
                final Connection connection = DriverManager.getConnection(MYSQL_URL, MYSQL_USERNAME, MYSQL_PASSWORD);
                final PreparedStatement preparedStatement = connection.prepareStatement(sql);
        ) {
    
    
            for (int i = 0; i < args.length; i++) {
    
    
                preparedStatement.setObject(i + 1, args[i]);
            }
            resultSet = preparedStatement.executeQuery();

            List<T> list = new ArrayList<>();
            // 表中的数据 行是从0开始的,列是从1开始的
            int row = 0; // 告诉当前正在操纵第几行的数据
            while (resultSet.next()) {
    
    
                list.add(rowMapper.generateBean(resultSet, row++));
            }
            return list;
        } catch (Exception e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            try {
    
    
                if (null != resultSet) resultSet.close();
            } catch (Exception e) {
    
    
                e.printStackTrace();
            }
        }

        return null;
    }

}

③ 引入DAO

什么是DAO

DAO:Data(base) Acces Object

DAO是专门用来操作数据的。

DAO的命名规范

在这里插入图片描述

数据库中一张表就要对应一个JavaBean以及对应一个Dao。

例如数据库下有个customer表,那么就应该有个Customer Bean和CustomerDao与之对应。

实现CustomerDao

public class CustomerDao {
    
    

    //    public List<Customer> customers() {
    
    
//        final String sql = "SELECT id, name, age, height FROM customer";
//
//        return Dbs.query((resultSet, row) -> {
    
    
//            System.out.println("表中的第" + row + "行记录");
//
//            final Integer id = resultSet.getInt("id");
//            final String name = resultSet.getString("name");
//            final Integer age = resultSet.getInt("age");
//            final Double height = resultSet.getDouble("height");
//            return new Customer(id, name, age, height);
//        }, sql);
//    }

    public List<Customer> list() {
    
    
        final String sql = "SELECT id, name, age, height FROM customer";
        return Dbs.query(new Dbs.RowMapper<Customer>() {
    
    
            @Override
            public Customer generateBean(ResultSet resultSet) throws Exception {
    
    
                return new Customer(
                        resultSet.getInt("id"),
                        resultSet.getString("name"),
                        resultSet.getInt("age"),
                        resultSet.getDouble("height")
                );
            }
        }, sql);
    }

    public boolean saveCustomer(Customer customer) {
    
    
        final String sql = "INSERT INTO customer(name, age, height) VALUES(?, ?, ?)";
        return Dbs.update(sql, customer.getName(), customer.getAge(), customer.getHeight()) == 1;
    }
}

④ 创建CustomerSerlvet

  • 将list请求映射到该Servlet的list方法

  • 将addcustomer请求映射到该Servlet的addCustomer方法

在这里插入图片描述

CustomerServlet的实现:

// @WebServlet("/list*"),此时服务器处于根目录(/ 对应 webapp目录)
// @WebServlet("/customer/list") 此时服务器处于根目录下的customer目录(/customer 对应 webapp/customer目录)
@WebServlet("/customer/*")
public class CustomerServlet extends HttpServlet {
    
    

    private final CustomerDao dao = new CustomerDao();

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        req.setCharacterEncoding("utf-8");

        final String requestURI = req.getRequestURI();
        final String[] split = requestURI.split("/");
        final String methodName = split[split.length - 1];
        try {
    
    
            Method method;
            switch (methodName) {
    
    
                case "list":
                case "addcustomer":
                    method = getClass().getMethod(methodName, HttpServletRequest.class, HttpServletResponse.class);
                    method.invoke(this, req, resp);
                    break;
                default:
                    method = getClass().getMethod("error", String.class, HttpServletRequest.class, HttpServletResponse.class);
                    method.invoke(this, "找不到你找的页面", req, resp);
                    break;
            }
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
    }
//        if (requestURI.endsWith("list")) {
    
    
//            list(req, resp);
//        } else if (requestURI.endsWith("addcustomer")) {
    
    
//            addCustomer(req, resp);
//        } else {
    
    
//            error(req, resp, "请求页面不存在");
//        }
//    }

	// 展示用户数据
    public void list(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        List<Customer> list = dao.customers();
        req.setAttribute("customers", list);
        req.setAttribute("customerSize", list.size());
        req.getRequestDispatcher("../pages/list.jsp").forward(req, resp);
    }
	
	// 添加用户数据到数据库
    public void addcustomer(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
    
    
        final String customerName = req.getParameter("customer_name");
        final String customerAge = req.getParameter("customer_age");
        final String customerHeight = req.getParameter("customer_height");
        if (
                null != customerName && !"".equals(customerName) &&
                        null != customerAge && !"".equals(customerAge) &&
                        null != customerHeight && !"".equals(customerHeight)
        ) {
    
    
            dao.saveCustomer(new Customer(
                    customerName, Integer.valueOf(customerAge), Double.valueOf(customerHeight)
            ));
            resp.sendRedirect("/seven_crms_jdbc/customer/list");
        } else {
    
    
            error("用户信息填写错误", req, resp);
        }
    }
	
	// 跳转至出错页面
    public void error(String error, HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        req.setAttribute("error", error);
        req.getRequestDispatcher("../pages/error.jsp").forward(req, resp);
    }

}

调整项目之后的项目结构图

在这里插入图片描述

一些细节和建议

  • 从数据库中查询数据时,最好不要写SELECT * FROM TABLE_XX,而是换成查询具体的字段SELECT name, age, height FROM TABLE_XX

  • 表中的数据,行一般是从0开始的,列一般是从1开始的,自动增长的id也是从1开始的。

  • list.jsp中的a标签可以写为<a href="/seven_again/pages/save.html">添加客户</a>(/context/…/…)

  • Maven项目下的资源文件(例如db.properties)应该放在resource目录下

参考

李明杰: Java从0到架构师②JavaEE技术基石.


本文完,感谢您的关注支持!


猜你喜欢

转载自blog.csdn.net/weixin_44018671/article/details/120804404