【Java Web实战】从零到一打造企业级网上购书网站系统 | 完整开发实录(一)

发布于:2025-08-01 ⋅ 阅读:(30) ⋅ 点赞:(0)

作者:笙囧同学 🧑‍💻
技术栈: Java + JSP + Servlet + MySQL + Bootstrap
项目难度: ⭐⭐⭐⭐⭐


📖 前言

大家好,我是笙囧同学!👋

最近花了一个多月的时间,从零开始设计并实现了一个企业级的网上购书网站系统。这个项目不仅仅是一个简单的CRUD应用,而是一个功能完整、安全可靠、用户体验优秀的电商平台。

在这篇文章中,我将详细分享整个项目的设计思路、技术选型、核心功能实现以及踩过的坑。希望能给正在学习Java Web开发的小伙伴们一些启发和帮助!

💡 温馨提示:文章较长,建议收藏后慢慢阅读。文末会提供完整的源码下载链接!


🎯 项目概览

📊 项目基本信息

项目属性 详细信息
项目名称 网上购书网站系统
项目类型 B2C电子商务平台
开发周期 30天
代码量 8000+ 行
功能模块 5大核心模块
技术栈 Java Web全栈

🏗️ 系统架构总览

数据存储层
数据访问层
业务逻辑层
前端展示层
MySQL数据库
DAO层
数据库连接池
事务管理
用户管理
图书管理
购物车管理
订单管理
权限控制
用户界面
管理界面
移动端适配

🎨 项目亮点

  • 🔐 企业级安全防护:多层安全验证,防SQL注入、XSS攻击
  • 📱 响应式设计:完美适配PC端和移动端
  • 🚀 高性能架构:连接池、缓存优化、分页查询
  • 🛠️ 完善的测试体系:单元测试、集成测试、性能测试
  • 📚 详细的文档:从需求分析到部署运维的完整文档

🎓 核心技术知识点深度解析

在开始介绍技术选型之前,让我先为大家梳理一下这个项目涉及的核心技术知识点,这些都是Java Web开发的精髓所在!作为一名深耕Java Web开发多年的程序员,我将从理论到实践,为大家详细讲解每个技术点的原理、应用场景和最佳实践。

🔍 Java Web技术原理深度剖析

📚 Servlet技术核心原理

Servlet是什么?

Servlet是运行在Web服务器上的Java程序,它是Java Web开发的基石。让我们深入了解Servlet的工作原理:

Servlet生命周期详解
请求处理阶段
加载Servlet类
Web容器启动
创建Servlet实例
调用init方法
Servlet就绪状态
处理客户端请求
继续服务?
调用destroy方法
销毁Servlet实例
接收HTTP请求
解析请求参数
调用service方法
根据请求方法分发
执行业务逻辑
生成HTTP响应

Servlet核心概念详解:

  1. Servlet容器(Container)

    • 负责管理Servlet的生命周期
    • 提供网络服务,解析请求并构造响应
    • 管理Servlet实例的创建、初始化、服务和销毁
  2. ServletConfig对象

    • 包含Servlet的配置信息
    • 在init()方法中传入
    • 可以获取初始化参数和ServletContext
  3. ServletContext对象

    • 代表整个Web应用程序
    • 所有Servlet共享同一个ServletContext
    • 可以用来存储应用级别的数据

实际代码示例:

public class BookServlet extends HttpServlet {
    private BookDAO bookDAO;

    @Override
    public void init() throws ServletException {
        // 初始化阶段,只执行一次
        super.init();
        bookDAO = new BookDAO();

        // 获取初始化参数
        String dbUrl = getInitParameter("dbUrl");
        String dbUser = getInitParameter("dbUser");

        // 初始化数据库连接
        bookDAO.initConnection(dbUrl, dbUser);

        System.out.println("BookServlet初始化完成");
    }

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 每次请求都会调用
        String method = request.getMethod();

        // 根据HTTP方法分发请求
        if ("GET".equals(method)) {
            doGet(request, response);
        } else if ("POST".equals(method)) {
            doPost(request, response);
        } else if ("PUT".equals(method)) {
            doPut(request, response);
        } else if ("DELETE".equals(method)) {
            doDelete(request, response);
        }
    }

    @Override
    public void destroy() {
        // 销毁阶段,释放资源
        if (bookDAO != null) {
            bookDAO.closeConnection();
        }
        System.out.println("BookServlet销毁完成");
    }
}
🌐 HTTP协议深度解析

HTTP请求响应模型:

客户端浏览器 Web服务器 Servlet应用 数据库 HTTP请求响应完整流程 1. 发送HTTP请求 GET /books?category=java HTTP/1.1 Host: localhost:8080 User-Agent: Mozilla/5.0 Accept: text/html 2. 解析HTTP请求 解析请求行、请求头、请求体 3. 转发给Servlet 根据URL映射找到对应Servlet 4. 解析请求参数 获取查询参数、表单数据等 5. 查询数据库 执行SQL查询 6. 返回查询结果 ResultSet数据 7. 处理业务逻辑 数据转换、业务计算等 8. 生成HTTP响应 HTTP/1.1 200 OK Content-Type: text/html Content-Length: 1234 HTML内容 9. 返回HTTP响应 完整的HTTP响应 10. 渲染页面 浏览器解析HTML并渲染 客户端浏览器 Web服务器 Servlet应用 数据库

HTTP状态码深度理解:

状态码类别 含义 常用状态码 应用场景
1xx 信息性 请求已接收,继续处理 100 Continue 大文件上传
2xx 成功 请求已成功处理 200 OK, 201 Created 正常响应
3xx 重定向 需要进一步操作 301 Moved, 302 Found 页面跳转
4xx 客户端错误 请求有语法错误 400 Bad Request, 404 Not Found 参数错误
5xx 服务器错误 服务器处理错误 500 Internal Error, 503 Unavailable 系统异常
🗄️ JDBC技术深度讲解

JDBC架构原理:

JDBC架构层次
应用层
JDBC API层
JDBC驱动层
数据库层
MySQL数据库
Oracle数据库
PostgreSQL数据库
Type 1: JDBC-ODBC桥
Type 2: 本地API驱动
Type 3: 网络协议驱动
Type 4: 纯Java驱动
DriverManager
Connection
Statement/PreparedStatement
ResultSet
Java应用程序
DAO层
业务逻辑层

JDBC核心接口详解:

  1. DriverManager类

    • 管理数据库驱动程序
    • 建立数据库连接
    • 选择合适的驱动程序
  2. Connection接口

    • 代表与数据库的连接
    • 管理事务
    • 创建Statement对象
  3. Statement接口

    • 执行SQL语句
    • 三种类型:Statement、PreparedStatement、CallableStatement
  4. ResultSet接口

    • 表示查询结果集
    • 提供游标操作
    • 支持不同的滚动类型

JDBC最佳实践代码:

public class BookDAO {
    private static final String DB_URL = "jdbc:mysql://localhost:3306/bookstore";
    private static final String DB_USER = "root";
    private static final String DB_PASSWORD = "password";

    // 使用连接池
    private DataSource dataSource;

    public BookDAO() {
        // 初始化连接池
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl(DB_URL);
        config.setUsername(DB_USER);
        config.setPassword(DB_PASSWORD);
        config.setMaximumPoolSize(20);
        config.setMinimumIdle(5);
        config.setConnectionTimeout(30000);
        config.setIdleTimeout(600000);
        config.setMaxLifetime(1800000);

        this.dataSource = new HikariDataSource(config);
    }

    public List<Book> getBooksByCategory(String category, int page, int size) {
        List<Book> books = new ArrayList<>();

        // 使用PreparedStatement防止SQL注入
        String sql = "SELECT book_id, title, author, price, stock " +
                    "FROM books WHERE category = ? " +
                    "ORDER BY created_at DESC " +
                    "LIMIT ? OFFSET ?";

        try (Connection conn = dataSource.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {

            // 设置参数
            pstmt.setString(1, category);
            pstmt.setInt(2, size);
            pstmt.setInt(3, page * size);

            try (ResultSet rs = pstmt.executeQuery()) {
                while (rs.next()) {
                    Book book = new Book();
                    book.setBookId(rs.getInt("book_id"));
                    book.setTitle(rs.getString("title"));
                    book.setAuthor(rs.getString("author"));
                    book.setPrice(rs.getBigDecimal("price"));
                    book.setStock(rs.getInt("stock"));

                    books.add(book);
                }
            }

        } catch (SQLException e) {
            // 记录详细的错误信息
            logger.error("查询图书失败: category={}, page={}, size={}",
                        category, page, size, e);
            throw new DAOException("查询图书失败", e);
        }

        return books;
    }

    // 事务处理示例
    public boolean transferStock(int fromBookId, int toBookId, int quantity) {
        Connection conn = null;
        try {
            conn = dataSource.getConnection();
            conn.setAutoCommit(false); // 开启事务

            // 减少源图书库存
            String sql1 = "UPDATE books SET stock = stock - ? WHERE book_id = ? AND stock >= ?";
            try (PreparedStatement pstmt1 = conn.prepareStatement(sql1)) {
                pstmt1.setInt(1, quantity);
                pstmt1.setInt(2, fromBookId);
                pstmt1.setInt(3, quantity);

                int affected1 = pstmt1.executeUpdate();
                if (affected1 == 0) {
                    throw new BusinessException("源图书库存不足");
                }
            }

            // 增加目标图书库存
            String sql2 = "UPDATE books SET stock = stock + ? WHERE book_id = ?";
            try (PreparedStatement pstmt2 = conn.prepareStatement(sql2)) {
                pstmt2.setInt(1, quantity);
                pstmt2.setInt(2, toBookId);

                pstmt2.executeUpdate();
            }

            conn.commit(); // 提交事务
            return true;

        } catch (Exception e) {
            if (conn != null) {
                try {
                    conn.rollback(); // 回滚事务
                } catch (SQLException ex) {
                    logger.error("事务回滚失败", ex);
                }
            }
            logger.error("库存转移失败", e);
            return false;

        } finally {
            if (conn != null) {
                try {
                    conn.setAutoCommit(true); // 恢复自动提交
                    conn.close();
                } catch (SQLException e) {
                    logger.error("关闭连接失败", e);
                }
            }
        }
    }
}
🎨 JSP技术深度解析

JSP(JavaServer Pages)工作原理:

JSP本质上是Servlet的一种简化形式,让我们深入了解JSP的编译和执行过程:

flowchart TD
    A[JSP页面] --> B[JSP引擎]
    B --> C{首次访问?}
    C -->|是| D[JSP编译阶段]
    C -->|否| H[直接执行Servlet]

    D --> E[解析JSP语法]
    E --> F[生成Java源码]
    F --> G[编译成Servlet字节码]
    G --> H[执行Servlet]

    H --> I[生成HTML响应]
    I --> J[返回给客户端]

    subgraph "JSP编译详细过程"
        D1[解析指令标签 <%@ %>]
        D2[解析脚本片段 <% %>]
        D3[解析表达式 <%= %>]
        D4[解析声明 <%! %>]
        D5[解析动作标签 <jsp:>]
        D6[解析EL表达式 ${}]
    end

    E --> D1 --> D2 --> D3 --> D4 --> D5 --> D6

    style A fill:#e3f2fd
    style J fill:#c8e6c9

JSP核心语法详解:

  1. 指令标签(Directive)
<%-- 页面指令:设置页面属性 --%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
         pageEncoding="UTF-8" import="java.util.*"
         errorPage="error.jsp" isErrorPage="false" %>

<%-- 包含指令:静态包含其他文件 --%>
<%@ include file="header.jsp" %>

<%-- 标签库指令:引入标签库 --%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
  1. 脚本元素详解
<%-- 声明:定义变量和方法 --%>
<%!
    private int visitCount = 0;

    public String formatPrice(double price) {
        return String.format("¥%.2f", price);
    }
%>

<%-- 脚本片段:Java代码块 --%>
<%
    visitCount++;
    List<Book> books = (List<Book>) request.getAttribute("books");
    String currentUser = (String) session.getAttribute("username");
%>

<%-- 表达式:输出值 --%>
<p>访问次数:<%= visitCount %></p>
<p>当前用户:<%= currentUser != null ? currentUser : "游客" %></p>
  1. EL表达式深度应用
<%-- 基本语法 --%>
<p>用户名:${sessionScope.username}</p>
<p>图书数量:${requestScope.books.size()}</p>

<%-- 运算符使用 --%>
<p>总价:${book.price * book.quantity}</p>
<p>是否有库存:${book.stock > 0 ? '有货' : '缺货'}</p>

<%-- 集合操作 --%>
<c:forEach items="${books}" var="book" varStatus="status">
    <tr class="${status.index % 2 == 0 ? 'even' : 'odd'}">
        <td>${book.title}</td>
        <td>${book.author}</td>
        <td>${book.price}</td>
    </tr>
</c:forEach>
🔧 Maven构建工具深度讲解

Maven核心概念:

Maven核心概念
项目对象模型 POM
生命周期 Lifecycle
仓库 Repository
插件 Plugin
编译插件
测试插件
打包插件
部署插件
本地仓库
中央仓库
私有仓库
默认生命周期
清理生命周期
站点生命周期
项目信息
依赖管理
构建配置
插件配置

Maven生命周期详解:

阶段 描述 主要任务
validate 验证项目 检查项目结构和必要信息
compile 编译源码 编译src/main/java下的源码
test 运行测试 执行src/test/java下的测试
package 打包项目 创建JAR/WAR文件
verify 验证包 运行集成测试验证包的有效性
install 安装到本地 将包安装到本地仓库
deploy 部署到远程 将包部署到远程仓库

实际项目的pom.xml配置详解:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <!-- 项目基本信息 -->
    <groupId>com.shengjiongtongxue</groupId>
    <artifactId>bookstore-web</artifactId>
    <version>1.0.0</version>
    <packaging>war</packaging>

    <name>网上购书网站</name>
    <description>基于Java Web的企业级购书平台</description>

    <!-- 属性配置 -->
    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

        <!-- 依赖版本管理 -->
        <servlet.version>4.0.1</servlet.version>
        <jsp.version>2.3.3</jsp.version>
        <jstl.version>1.2</jstl.version>
        <mysql.version>8.0.33</mysql.version>
        <junit.version>5.9.2</junit.version>
        <mockito.version>5.1.1</mockito.version>
    </properties>

    <!-- 依赖管理 -->
    <dependencies>
        <!-- Servlet API -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>${servlet.version}</version>
            <scope>provided</scope>
        </dependency>

        <!-- JSP API -->
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>javax.servlet.jsp-api</artifactId>
            <version>${jsp.version}</version>
            <scope>provided</scope>
        </dependency>

        <!-- JSTL -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>${jstl.version}</version>
        </dependency>

        <!-- MySQL驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>

        <!-- 连接池 -->
        <dependency>
            <groupId>com.zaxxer</groupId>
            <artifactId>HikariCP</artifactId>
            <version>5.0.1</version>
        </dependency>

        <!-- JSON处理 -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.15.2</version>
        </dependency>

        <!-- 日志框架 -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>2.0.7</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.4.8</version>
        </dependency>

        <!-- 测试依赖 -->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-core</artifactId>
            <version>${mockito.version}</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <!-- 构建配置 -->
    <build>
        <finalName>bookstore</finalName>

        <plugins>
            <!-- 编译插件 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.11.0</version>
                <configuration>
                    <source>11</source>
                    <target>11</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>

            <!-- WAR打包插件 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.3.1</version>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>

            <!-- 测试插件 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>3.1.2</version>
                <configuration>
                    <includes>
                        <include>**/*Test.java</include>
                        <include>**/*Tests.java</include>
                    </includes>
                </configuration>
            </plugin>

            <!-- Jetty插件 - 用于开发测试 -->
            <plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>11.0.15</version>
                <configuration>
                    <httpConnector>
                        <port>8080</port>
                    </httpConnector>
                    <webApp>
                        <contextPath>/bookstore</contextPath>
                    </webApp>
                    <reload>manual</reload>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <!-- 配置文件 -->
    <profiles>
        <!-- 开发环境 -->
        <profile>
            <id>dev</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <properties>
                <db.url>jdbc:mysql://localhost:3306/bookstore_dev</db.url>
                <db.username>root</db.username>
                <db.password>password</db.password>
            </properties>
        </profile>

        <!-- 测试环境 -->
        <profile>
            <id>test</id>
            <properties>
                <db.url>jdbc:mysql://test-server:3306/bookstore_test</db.url>
                <db.username>test_user</db.username>
                <db.password>test_password</db.password>
            </properties>
        </profile>

        <!-- 生产环境 -->
        <profile>
            <id>prod</id>
            <properties>
                <db.url>jdbc:mysql://prod-server:3306/bookstore_prod</db.url>
                <db.username>prod_user</db.username>
                <db.password>prod_password</db.password>
            </properties>
        </profile>
    </profiles>
</project>

📚 Java Web核心技术栈

mindmap
  root((Java Web技术栈))
    前端技术
      HTML5
        语义化标签
        表单验证
        本地存储
        响应式设计
      CSS3
        Flexbox布局
        Grid布局
        动画效果
        媒体查询
      JavaScript
        DOM操作
        事件处理
        Ajax异步
        ES6语法
      Bootstrap
        栅格系统
        组件库
        响应式工具
        主题定制
    后端技术
      Java基础
        面向对象
        集合框架
        异常处理
        多线程
      Servlet
        生命周期
        请求处理
        会话管理
        过滤器
      JSP
        指令标签
        动作标签
        EL表达式
        JSTL标签库
      JDBC
        连接管理
        预编译语句
        事务控制
        连接池
    数据库技术
      MySQL
        存储引擎
        索引优化
        查询优化
        事务机制
      SQL语言
        DDL语句
        DML语句
        DCL语句
        存储过程
    开发工具
      Maven
        依赖管理
        生命周期
        插件机制
        多模块项目
      Git
        版本控制
        分支管理
        协作开发
        代码回滚

🏗️ MVC架构模式深度剖析

MVC架构详解
Model层 - 数据模型
View层 - 视图展示
Controller层 - 控制逻辑
支撑组件
过滤器 Filter
监听器 Listener
工具类 Util
配置文件 Config
Servlet控制器
请求分发器
参数验证器
响应处理器
JSP页面
HTML模板
CSS样式
JavaScript脚本
实体类 Entity
数据访问对象 DAO
业务逻辑 Service
数据传输对象 DTO
🎯 设计模式在Java Web中的应用

在企业级Java Web开发中,设计模式的合理运用能够大大提高代码的可维护性和扩展性。让我详细讲解几个核心设计模式:

1. MVC模式(Model-View-Controller)

MVC模式详细结构
View层 - 视图
Controller层 - 控制器
Model层 - 模型
数据流向
用户请求
数据处理
视图渲染
响应返回
实体类 Entity
业务逻辑 Service
数据访问 DAO
数据传输 DTO
Servlet控制器
请求分发
参数验证
异常处理
JSP页面
HTML模板
JSON响应
XML响应

实际代码实现:

// Model层 - 实体类
public class Book {
    private int bookId;
    private String title;
    private String author;
    private BigDecimal price;
    private int stock;

    // 构造方法、getter、setter省略

    // 业务方法
    public boolean isAvailable() {
        return stock > 0;
    }

    public BigDecimal calculateDiscountPrice(double discountRate) {
        return price.multiply(BigDecimal.valueOf(1 - discountRate));
    }
}

// Model层 - 业务逻辑
public class BookService {
    private BookDAO bookDAO;

    public BookService() {
        this.bookDAO = new BookDAO();
    }

    public List<Book> searchBooks(String keyword, String category, int page, int size) {
        // 参数验证
        if (keyword == null || keyword.trim().isEmpty()) {
            throw new IllegalArgumentException("搜索关键词不能为空");
        }

        // 业务逻辑处理
        List<Book> books = bookDAO.searchBooks(keyword, category, page, size);

        // 数据后处理
        return books.stream()
                   .filter(Book::isAvailable)
                   .collect(Collectors.toList());
    }
}

// Controller层 - 控制器
@WebServlet("/books")
public class BookController extends HttpServlet {
    private BookService bookService;

    @Override
    public void init() throws ServletException {
        this.bookService = new BookService();
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        String action = request.getParameter("action");

        try {
            switch (action) {
                case "search":
                    handleSearch(request, response);
                    break;
                case "detail":
                    handleDetail(request, response);
                    break;
                default:
                    handleList(request, response);
            }
        } catch (Exception e) {
            handleError(request, response, e);
        }
    }

    private void handleSearch(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        String keyword = request.getParameter("keyword");
        String category = request.getParameter("category");
        int page = Integer.parseInt(request.getParameter("page"));
        int size = Integer.parseInt(request.getParameter("size"));

        List<Book> books = bookService.searchBooks(keyword, category, page, size);

        request.setAttribute("books", books);
        request.setAttribute("keyword", keyword);
        request.setAttribute("category", category);

        RequestDispatcher dispatcher = request.getRequestDispatcher("/books.jsp");
        dispatcher.forward(request, response);
    }
}

2. DAO模式(Data Access Object)

DAO模式架构
业务层
DAO接口层
DAO实现层
数据库层
MySQL数据库
连接池
事务管理
BookDAOImpl
UserDAOImpl
OrderDAOImpl
BookDAO接口
UserDAO接口
OrderDAO接口
BookService
UserService
OrderService

DAO模式实现:

// DAO接口定义
public interface BookDAO {
    // 基本CRUD操作
    void save(Book book);
    void update(Book book);
    void delete(int bookId);
    Book findById(int bookId);
    List<Book> findAll();

    // 业务查询方法
    List<Book> findByCategory(String category);
    List<Book> searchByKeyword(String keyword);
    List<Book> findPopularBooks(int limit);

    // 分页查询
    List<Book> findWithPagination(int page, int size);
    int getTotalCount();
}

// DAO接口实现
public class BookDAOImpl implements BookDAO {
    private DataSource dataSource;

    public BookDAOImpl() {
        this.dataSource = DataSourceFactory.getDataSource();
    }

    @Override
    public void save(Book book) {
        String sql = "INSERT INTO books (title, author, publisher, price, stock, category) " +
                    "VALUES (?, ?, ?, ?, ?, ?)";

        try (Connection conn = dataSource.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {

            pstmt.setString(1, book.getTitle());
            pstmt.setString(2, book.getAuthor());
            pstmt.setString(3, book.getPublisher());
            pstmt.setBigDecimal(4, book.getPrice());
            pstmt.setInt(5, book.getStock());
            pstmt.setString(6, book.getCategory());

            int affectedRows = pstmt.executeUpdate();

            if (affectedRows == 0) {
                throw new DAOException("保存图书失败,没有行被影响");
            }

            // 获取生成的主键
            try (ResultSet generatedKeys = pstmt.getGeneratedKeys()) {
                if (generatedKeys.next()) {
                    book.setBookId(generatedKeys.getInt(1));
                }
            }

        } catch (SQLException e) {
            throw new DAOException("保存图书失败", e);
        }
    }

    @Override
    public List<Book> searchByKeyword(String keyword) {
        String sql = "SELECT * FROM books WHERE " +
                    "(title LIKE ? OR author LIKE ? OR description LIKE ?) " +
                    "AND stock > 0 ORDER BY created_at DESC";

        List<Book> books = new ArrayList<>();
        String searchPattern = "%" + keyword + "%";

        try (Connection conn = dataSource.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {

            pstmt.setString(1, searchPattern);
            pstmt.setString(2, searchPattern);
            pstmt.setString(3, searchPattern);

            try (ResultSet rs = pstmt.executeQuery()) {
                while (rs.next()) {
                    books.add(mapResultSetToBook(rs));
                }
            }

        } catch (SQLException e) {
            throw new DAOException("搜索图书失败", e);
        }

        return books;
    }

    // 结果集映射方法
    private Book mapResultSetToBook(ResultSet rs) throws SQLException {
        Book book = new Book();
        book.setBookId(rs.getInt("book_id"));
        book.setTitle(rs.getString("title"));
        book.setAuthor(rs.getString("author"));
        book.setPublisher(rs.getString("publisher"));
        book.setPrice(rs.getBigDecimal("price"));
        book.setStock(rs.getInt("stock"));
        book.setCategory(rs.getString("category"));
        book.setCreatedAt(rs.getTimestamp("created_at"));
        return book;
    }
}

3. 工厂模式(Factory Pattern)

// 数据源工厂
public class DataSourceFactory {
    private static DataSource dataSource;
    private static final Object lock = new Object();

    public static DataSource getDataSource() {
        if (dataSource == null) {
            synchronized (lock) {
                if (dataSource == null) {
                    dataSource = createDataSource();
                }
            }
        }
        return dataSource;
    }

    private static DataSource createDataSource() {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl(ConfigManager.getProperty("db.url"));
        config.setUsername(ConfigManager.getProperty("db.username"));
        config.setPassword(ConfigManager.getProperty("db.password"));
        config.setMaximumPoolSize(20);
        config.setMinimumIdle(5);

        return new HikariDataSource(config);
    }
}

// DAO工厂
public class DAOFactory {
    public static BookDAO getBookDAO() {
        return new BookDAOImpl();
    }

    public static UserDAO getUserDAO() {
        return new UserDAOImpl();
    }

    public static OrderDAO getOrderDAO() {
        return new OrderDAOImpl();
    }
}

🔄 HTTP请求处理生命周期

浏览器 Web服务器 过滤器链 Servlet容器 JSP引擎 数据库 1. 发送HTTP请求 2. 请求进入过滤器链 3. 字符编码过滤 4. 登录验证过滤 5. 权限检查过滤 6. 转发到目标Servlet 7. 参数解析和验证 8. 数据库操作 9. 返回查询结果 10. 转发到JSP页面 11. 页面渲染处理 12. 返回HTML内容 13. 响应通过过滤器 14. 响应处理完成 15. 返回HTTP响应 完整的请求-响应生命周期 浏览器 Web服务器 过滤器链 Servlet容器 JSP引擎 数据库

下篇的链接为:https://editor.csdn.net/md/?articleId=149720198