尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
JavaEE网上书店实战项目:Servlet+JSP+JDBC全链路实现
简介这是一份面向计算机专业本科生及Java初学者的JavaEE全栈实践项目资源适用于课程设计、毕业设计或Web开发入门实战帮助学习者系统掌握企业级B/S架构应用的开发流程与关键技术。资源包含88个文件以40个JSP页面负责前端展示与交互、11个Java源码涵盖Servlet、DAO、Service等分层逻辑、1个SQL建库脚本完整MySQL表结构与初始化数据为核心辅以CSS样式、XML配置、JPG素材及MyEclipse工程元数据文件整体压缩包仅519KB轻量易部署。已有3144人学习下载说明其结构清晰、开箱即用是少有的兼顾教学性与工程规范性的中小型项目范例。学习者可直接导入IDE运行完整体验用户注册登录、图书浏览搜索、购物车管理、订单提交及后台基础管理等全流程功能并通过源码深入理解MVC分层、JDBC/JPA数据操作、会话控制与前后端协同机制。1. 一个能跑通、能改、能交差的JavaEE网上书店从登录页到订单生成全链路可调试课程设计/毕设直接套用不翻车你是不是也经历过老师布置“基于JavaEE的网上书店”课程设计网上搜了一堆“完整源码”下载解压后发现——Tomcat启动报错、MySQL连不上、首页空白、后台管理进不去、连注册按钮都点不动更糟的是代码里全是中文变量名、没注释、SQL写在JSP里、Servlet里塞了300行业务逻辑……最后硬着头皮改到凌晨三点只为了把“购物车数量显示为0”改成“显示实际数量”。这个项目不是Demo玩具它是一套真正能跑起来的、结构清晰、分层合理、数据库脚本完备的JavaEE实战工程。它用标准ServletJSPJDBC非Spring全家桶适配Tomcat 8.5/9.xMySQL 5.7所有页面响应式适配用户端含图书浏览、搜索、加入购物车、下单、订单查询管理员端含图书CRUD、订单状态管理、用户信息查看。适合课程设计快速交付、毕设基础框架搭建、或作为JavaEE分层架构教学的实操蓝本——不是教你“Hello World”而是带你走完“用户点击购买→库存扣减→订单落库→页面跳转”的真实闭环。2. 环境准备与项目结构解析看清目录骨架才能不被“找不到类”和“404”反复暴击2.1 运行环境最低要求与验证清单这不是一个“下载即用”的傻瓜包但每一步都可控。我建议你用以下组合这是我在某高校实验室带学生跑通率最高的配置JDK必须是 JDK 8u202 或 JDK 11注意JDK 17 会因Tomcat版本兼容问题导致javax.servlet类找不到别踩这个坑Tomcat推荐 Apache Tomcat 8.5.99 或 9.0.85不要用10.xServlet API 5.0会导致JSP编译失败MySQL5.7.32 或 8.0.33若用8.0需在连接URL中显式添加?serverTimezoneGMT%2B8useSSLfalseIDEIntelliJ IDEA 2022.3 或 Eclipse 2023-06Eclipse需安装“Web Developer Tools”插件提示验证JDK是否生效不要只看java -version务必执行javac -version并确认输出与java -version主版本号一致Tomcat启动后访问http://localhost:8080能看到Apache欢迎页才算真正就绪。2.2 项目根目录结构5大核心文件夹各司其职解压后你会看到如下结构已去除无关文档和临时文件bookstore/ ├── src/ # Java源码根目录标准Maven结构但本项目未用pom.xml直接编译 │ ├── main/ │ │ ├── java/ # 所有Servlet、DAO、Bean类 │ │ │ └── com/bookstore/ │ │ │ ├── servlet/ # 核心控制器LoginServlet、AddToCartServlet、OrderServlet等 │ │ │ ├── dao/ # 数据访问层BookDao、UserDao、OrderDao纯JDBC封装 │ │ │ ├── bean/ # 实体类Book.java、User.java、Order.java、CartItem.java │ │ │ └── util/ # 工具类DBUtil.java单例DataSource、PageUtil.java分页封装 │ │ └── webapp/ # Web资源根目录等同于传统WebContent │ │ ├── css/ # Bootstrap 4.6定制样式已精简仅保留book-list、cart-table等关键class │ │ ├── js/ # 原生JS交互cart.js购物车增删改、order.js表单校验 │ │ ├── images/ # 图书封面占位图jpg/png路径硬编码在book_list.jsp中 │ │ ├── WEB-INF/ │ │ │ ├── web.xml # 关键Servlet映射、Filter、welcome-file-list全在此 │ │ │ └── lib/ # 仅2个jarmysql-connector-java-5.1.47.jar jstl-1.2.jar │ │ ├── index.jsp # 用户首页图书列表搜索框 │ │ ├── login.jsp # 登录页含验证码图片生成逻辑 │ │ ├── cart.jsp # 购物车页AJAX局部刷新非整页跳转 │ │ └── admin/ # 后台管理模块独立路径需admin权限访问 │ │ ├── admin_login.jsp │ │ └── book_manage.jsp │ └── test/ # 空文件夹预留单元测试位置当前未实现 ├── sql/ # 数据库脚本重点 │ ├── bookstore_db.sql # 创建数据库字符集utf8mb4 │ ├── bookstore_table.sql # 建表语句user, book, order, order_item, cart_item │ └── bookstore_data.sql # 初始化数据10本样例图书2个测试账号 └── README.md # 极简说明仅含数据库导入命令和默认账号这个结构没有花哨的Maven多模块但严格遵循JavaEE Web应用分层规范servlet层只做请求分发与跳转dao层专注SQL执行与结果映射bean层纯粹POJOutil提供可复用基建。所有JSP页面只负责展示零Java代码scriptlet已全部移除用JSTLEL表达式替代。2.3 web.xml核心配置拆解为什么你的Servlet总404很多同学卡在第一步——访问/login返回404。根本原因往往出在web.xml的servlet-mapping配置。我们来看关键片段!-- web.xml 片段 -- servlet servlet-nameLoginServlet/servlet-name servlet-classcom.bookstore.servlet.LoginServlet/servlet-class /servlet servlet-mapping servlet-nameLoginServlet/servlet-name url-pattern/login/url-pattern !-- 注意这是相对路径不是绝对路径 -- /servlet-mapping welcome-file-list welcome-fileindex.jsp/welcome-file /welcome-file-list filter filter-nameEncodingFilter/filter-name filter-classcom.bookstore.util.EncodingFilter/filter-class init-param param-nameencoding/param-name param-valueUTF-8/param-value /init-param /filter filter-mapping filter-nameEncodingFilter/filter-name url-pattern/*/url-pattern /filter-mapping这段代码决定了访问http://localhost:8080/bookstore/login会触发LoginServlet注意上下文路径/bookstore由Tomcat部署时决定非代码硬写所有请求先过EncodingFilter强制设置request.setCharacterEncoding(UTF-8)解决中文参数乱码比如搜索“Java编程思想”传参变“Java?????”index.jsp是默认首页直接访问http://localhost:8080/bookstore/就加载它注意如果你把项目部署为ROOT应用即去掉/bookstore路径url-pattern无需修改但浏览器地址栏要访问http://localhost:8080/login。初学者常误以为url-pattern要加项目名这是典型误区。2.4 SQL脚本执行顺序与关键约束别让外键把你锁死sql/目录下三个.sql文件必须严格按顺序执行否则建表会失败bookstore_db.sql创建数据库并指定字符集CREATE DATABASE IF NOT EXISTS bookstore_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE bookstore_db;提示utf8mb4是必须的否则图书标题里的emoji如或生僻字会存成??且后续建表若用utf8会报错。bookstore_table.sql建表含外键依赖链-- 先建user表被其他表引用 CREATE TABLE user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) UNIQUE NOT NULL, password VARCHAR(100) NOT NULL, email VARCHAR(100), role ENUM(user,admin) DEFAULT user ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 再建book表无外键依赖 CREATE TABLE book ( id INT PRIMARY KEY AUTO_INCREMENT, title VARCHAR(200) NOT NULL, author VARCHAR(100), price DECIMAL(10,2) NOT NULL, stock INT DEFAULT 0 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 最后建order表依赖user.id CREATE TABLE order ( id VARCHAR(50) PRIMARY KEY, -- 格式ORD_20240520_0001 user_id INT NOT NULL, total_price DECIMAL(10,2) NOT NULL, status ENUM(pending,paid,shipped,completed) DEFAULT pending, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES user(id) ON DELETE CASCADE ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;关键点ON DELETE CASCADE表示删除用户时自动清空其所有订单避免孤儿数据。bookstore_data.sql插入初始化数据含密码BCrypt加密INSERT INTO user (username, password, email, role) VALUES (testuser, $2a$10$ZzZzZzZzZzZzZzZzZzZzZuQZzZzZzZzZzZzZzZzZzZzZzZzZzZzZz, testdemo.com, user), (admin, $2a$10$ZzZzZzZzZzZzZzZzZzZzZuQZzZzZzZzZzZzZzZzZzZzZzZzZzZzZz, admindemo.com, admin);密码是BCrypt加密后的密文$2a$10$...开头不是明文。登录时LoginServlet调用BCrypt.checkpw()校验安全性达标。3. 核心模块代码逐行剖析从用户登录到订单生成看懂每一行在干什么3.1 LoginServlet一次登录请求的完整生命周期这是整个系统的入口代码虽短但涵盖了请求接收、参数校验、数据库查询、会话管理、重定向全流程// src/main/java/com/bookstore/servlet/LoginServlet.java WebServlet(/login) public class LoginServlet extends HttpServlet { private static final long serialVersionUID 1L; protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 1. 获取请求参数已由EncodingFilter保证UTF-8 String username request.getParameter(username).trim(); String password request.getParameter(password); // 2. 基础校验空值、长度 if (username.isEmpty() || password.isEmpty()) { request.setAttribute(error, 用户名或密码不能为空); request.getRequestDispatcher(/login.jsp).forward(request, response); return; // 阻止后续执行 } // 3. 查询用户调用DAO层 UserDao userDao new UserDao(); User user userDao.findByUsername(username); // 4. 校验密码BCrypt比对非明文equals if (user ! null BCrypt.checkpw(password, user.getPassword())) { // 5. 登录成功存入session区分角色跳转 request.getSession().setAttribute(user, user); if (admin.equals(user.getRole())) { response.sendRedirect(request.getContextPath() /admin/admin_login.jsp); } else { response.sendRedirect(request.getContextPath() /index.jsp); } } else { request.setAttribute(error, 用户名或密码错误); request.getRequestDispatcher(/login.jsp).forward(request, response); } } }关键逻辑说明WebServlet(/login)替代web.xml中servlet-mapping更直观Servlet 3.0特性request.getSession().setAttribute(user, user)将用户对象存入Session后续所有页面可通过${sessionScope.user.username}获取response.sendRedirect(...)客户端重定向URL会变避免F5刷新重复提交而forward是服务器端跳转URL不变用于错误提示页密码校验用BCrypt.checkpw()而非password.equals(user.getPassword())这是安全底线3.2 AddToCartServlet购物车状态如何跨请求保持购物车是Web开发经典难点——HTTP无状态如何记住用户加了哪几本书本项目采用Session存储购物车对象简洁高效// src/main/java/com/bookstore/servlet/AddToCartServlet.java WebServlet(/addtocart) public class AddToCartServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 1. 获取当前用户必须已登录 User user (User) request.getSession().getAttribute(user); if (user null) { response.sendRedirect(request.getContextPath() /login.jsp); return; } // 2. 获取图书ID和数量 int bookId Integer.parseInt(request.getParameter(bookId)); int quantity Integer.parseInt(request.getParameter(quantity)); // 3. 从Session中获取或创建购物车 ListCartItem cart (ListCartItem) request.getSession().getAttribute(cart); if (cart null) { cart new ArrayList(); request.getSession().setAttribute(cart, cart); } // 4. 检查是否已存在该图书合并数量非重复添加 boolean found false; for (CartItem item : cart) { if (item.getBookId() bookId) { item.setQuantity(item.getQuantity() quantity); found true; break; } } if (!found) { // 5. 新增购物车项需先查图书信息填充 BookDao bookDao new BookDao(); Book book bookDao.findById(bookId); if (book ! null) { CartItem newItem new CartItem(); newItem.setBookId(bookId); newItem.setBookTitle(book.getTitle()); newItem.setPrice(book.getPrice()); newItem.setQuantity(quantity); cart.add(newItem); } } // 6. 重定向回商品页避免重复提交 response.sendRedirect(request.getContextPath() /book_detail.jsp?id bookId); } }参数说明与设计意图bookId前端通过input typehidden namebookId value${book.id}传递确保唯一性quantity默认为1但支持用户在详情页输入自定义数量如买3本《算法导论》CartItem是轻量级VO只存必要字段id、标题、单价、数量不存Book实体避免Session膨胀合并逻辑第4步是用户体验关键同一本书多次点击“加入购物车”应累加数量而非新增行3.3 OrderServlet订单生成的事务边界与库存扣减下单是最敏感操作必须保证“库存扣减”和“订单创建”原子性。本项目用JDBC手动事务实现不依赖Spring// src/main/java/com/bookstore/servlet/OrderServlet.java WebServlet(/createorder) public class OrderServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { User user (User) request.getSession().getAttribute(user); if (user null) { response.sendRedirect(request.getContextPath() /login.jsp); return; } // 1. 从Session获取购物车 ListCartItem cart (ListCartItem) request.getSession().getAttribute(cart); if (cart null || cart.isEmpty()) { request.setAttribute(error, 购物车为空无法下单); request.getRequestDispatcher(/cart.jsp).forward(request, response); return; } Connection conn null; try { conn DBUtil.getConnection(); // 获取连接来自DBUtil单例 conn.setAutoCommit(false); // 关闭自动提交开启事务 // 2. 创建订单主表记录 String orderId ORD_ new SimpleDateFormat(yyyyMMdd).format(new Date()) _ String.format(%04d, System.currentTimeMillis() % 10000); BigDecimal totalPrice calculateTotal(cart); Order order new Order(); order.setId(orderId); order.setUserId(user.getId()); order.setTotalPrice(totalPrice); order.setStatus(pending); new OrderDao().insert(conn, order); // 传入conn确保同一事务 // 3. 扣减库存 创建订单明细循环执行 BookDao bookDao new BookDao(); for (CartItem item : cart) { // 先查当前库存防止超卖 Book book bookDao.findById(item.getBookId()); if (book.getStock() item.getQuantity()) { throw new RuntimeException(图书《 book.getTitle() 》库存不足仅剩 book.getStock() 本); } // 扣减库存UPDATE ... WHERE stock ? int updated bookDao.updateStock(conn, item.getBookId(), item.getQuantity()); if (updated 0) { throw new RuntimeException(库存扣减失败请重试); } // 创建订单明细 OrderItem orderItem new OrderItem(); orderItem.setOrderId(orderId); orderItem.setBookId(item.getBookId()); orderItem.setQuantity(item.getQuantity()); orderItem.setPrice(item.getPrice()); new OrderItemDao().insert(conn, orderItem); } // 4. 提交事务 conn.commit(); request.getSession().removeAttribute(cart); // 清空购物车 request.setAttribute(success, 订单创建成功订单号 orderId); request.getRequestDispatcher(/order_success.jsp).forward(request, response); } catch (Exception e) { // 5. 回滚事务 if (conn ! null) { try { conn.rollback(); } catch (SQLException ex) { ex.printStackTrace(); } } request.setAttribute(error, 下单失败 e.getMessage()); request.getRequestDispatcher(/cart.jsp).forward(request, response); } finally { DBUtil.closeConnection(conn); } } private BigDecimal calculateTotal(ListCartItem cart) { BigDecimal total BigDecimal.ZERO; for (CartItem item : cart) { total total.add(item.getPrice().multiply(BigDecimal.valueOf(item.getQuantity()))); } return total; } }事务关键点conn.setAutoCommit(false)是起点conn.commit()是终点中间所有DAO操作必须复用同一个conn对象库存检查book.getStock() item.getQuantity()和扣减UPDATE book SET stock stock - ? WHERE id ? AND stock ?必须在同一事务内否则有竞态条件DBUtil.closeConnection(conn)在finally块中执行确保连接不泄露这是血泪经验漏关连接会导致Tomcat连接池耗尽后续所有请求卡死4. 常见问题排查那些让你怀疑人生的404、500、空白页其实都有固定解法4.1 现象访问http://localhost:8080/bookstore/显示404但Tomcat欢迎页正常原因项目未正确部署到Tomcat或web.xml中welcome-file配置错误或index.jsp不在webapp/根目录解决检查Tomcatwebapps/目录下是否存在bookstore/文件夹非压缩包确认bookstore/WEB-INF/web.xml中welcome-file-list包含welcome-fileindex.jsp/welcome-file确认bookstore/index.jsp文件物理存在注意大小写Linux下Index.jsp≠index.jsp4.2 现象登录时输入正确账号密码仍提示“用户名或密码错误”原因数据库密码是BCrypt加密密文但你手动INSERT时用了明文或UserDao.findByUsername()方法未查到数据用户名大小写敏感、表名拼写错误解决用bookstore_data.sql初始化数据勿手写INSERT在UserDao.java的findByUsername方法中加日志System.out.println(Querying username: username);确认SQL执行检查MySQL用户表user的username字段是否为VARCHAR(50)且UNIQUE约束生效4.3 现象购物车页面cart.jsp显示为空但Session里明明有cart数据原因JSP中EL表达式未启用或web.xml的web-app根标签未声明Servlet 3.0版本解决检查web.xml第一行是否为?xml version1.0 encodingUTF-8?第二行为web-app xmlnshttp://xmlns.jcp.org/xml/ns/javaee在cart.jsp顶部添加指令% page isELIgnoredfalse %虽然Servlet 3.0默认开启但某些旧Tomcat需显式声明确认cart.jsp中遍历代码为c:forEach items${sessionScope.cart} varitem而非${cart}后者作用域不对4.4 现象下单成功后数据库order表有记录但order_item表为空原因OrderServlet中事务未正确传播OrderItemDao.insert()使用了新连接DBUtil.getConnection()脱离了主事务解决查看OrderItemDao.java的insert方法签名必须是public void insert(Connection conn, OrderItem item)且内部使用conn.prepareStatement()而非DBUtil.getConnection().prepareStatement()在OrderServlet中所有DAO调用必须传入同一个conn对象如new OrderItemDao().insert(conn, orderItem)4.5 现象后台管理页admin_login.jsp能打开但输入admin账号后跳转到/bookstore/404.jsp原因admin/目录下的页面未配置安全约束或web.xml中security-constraint规则错误或admin_login.jsp中表单action指向了错误URL解决检查admin_login.jsp中登录表单form action${pageContext.request.contextPath}/admin/login methodpost确认web.xml中是否有针对/admin/*的security-constraint本项目未配置故应为普通Servlet在admin/目录下新建LoginAdminServlet.javaWebServlet(/admin/login)并确保web.xml无冲突映射5. 二次开发实战3个高频改造需求附可直接粘贴的代码与验证步骤5.1 需求为图书列表页增加按价格区间筛选功能如¥50-¥100这是课程设计中最常被要求的扩展点。核心思路在index.jsp加筛选表单 →BookServlet接收参数 → DAO层动态SQL查询。Step 1修改index.jsp在搜索框下方添加价格筛选!-- index.jsp 中位于 form actionsearch methodget 下方 -- div classform-group label价格区间/label input typenumber nameminPrice placeholder最低价 classform-control stylewidth:120px; display:inline; span stylemargin:0 10px;—/span input typenumber namemaxPrice placeholder最高价 classform-control stylewidth:120px; display:inline; /divStep 2修改BookServlet.java原处理图书列表的Servlet支持价格参数// src/main/java/com/bookstore/servlet/BookServlet.java WebServlet(/books) public class BookServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 获取分页参数 int page 1; int size 12; if (request.getParameter(page) ! null) { page Integer.parseInt(request.getParameter(page)); } // 获取价格筛选参数 BigDecimal minPrice null; BigDecimal maxPrice null; if (request.getParameter(minPrice) ! null !request.getParameter(minPrice).isEmpty()) { minPrice new BigDecimal(request.getParameter(minPrice)); } if (request.getParameter(maxPrice) ! null !request.getParameter(maxPrice).isEmpty()) { maxPrice new BigDecimal(request.getParameter(maxPrice)); } // 调用DAO查询支持价格区间 BookDao bookDao new BookDao(); PageBook bookPage bookDao.findPageByPrice(page, size, minPrice, maxPrice); request.setAttribute(bookPage, bookPage); request.getRequestDispatcher(/index.jsp).forward(request, response); } }Step 3修改BookDao.java增加findPageByPrice方法// src/main/java/com/bookstore/dao/BookDao.java public PageBook findPageByPrice(int page, int size, BigDecimal minPrice, BigDecimal maxPrice) { String sql SELECT * FROM book WHERE 11; ListObject params new ArrayList(); if (minPrice ! null) { sql AND price ?; params.add(minPrice); } if (maxPrice ! null) { sql AND price ?; params.add(maxPrice); } sql ORDER BY id DESC LIMIT ?,?; params.add((page - 1) * size); params.add(size); // 执行查询使用DBUtil.query()已封装PreparedStatement ListBook list DBUtil.query(sql, Book.class, params.toArray()); // 查询总记录数复用相同WHERE条件 String countSql SELECT COUNT(*) FROM book WHERE 11; ListObject countParams new ArrayList(); if (minPrice ! null) { countSql AND price ?; countParams.add(minPrice); } if (maxPrice ! null) { countSql AND price ?; countParams.add(maxPrice); } Long total DBUtil.querySingle(countSql, Long.class, countParams.toArray()); return new Page(list, total, page, size); }验证步骤重启Tomcat访问http://localhost:8080/bookstore/books?minPrice50maxPrice100检查页面是否只显示价格在50-100之间的图书修改URL参数确认筛选实时生效5.2 需求为订单详情页增加“取消订单”按钮仅限“pending”状态这是提升系统完整性的关键动作。需新增Servlet、更新数据库、修改JSP。Step 1在order_detail.jsp添加按钮仅对pending订单显示!-- order_detail.jsp 中订单状态下方 -- c:if test${order.status pending} form action${pageContext.request.contextPath}/cancelorder methodpost styledisplay:inline; input typehidden nameorderId value${order.id} button typesubmit classbtn btn-sm btn-danger onclickreturn confirm(确定取消此订单)取消订单/button /form /c:ifStep 2创建CancelOrderServlet.java// src/main/java/com/bookstore/servlet/CancelOrderServlet.java WebServlet(/cancelorder) public class CancelOrderServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String orderId request.getParameter(orderId); if (orderId null || orderId.trim().isEmpty()) { request.setAttribute(error, 订单号无效); request.getRequestDispatcher(/order_list.jsp).forward(request, response); return; } try { OrderDao orderDao new OrderDao(); // 仅允许取消pending状态订单 int updated orderDao.cancelOrder(orderId); if (updated 0) { request.setAttribute(error, 取消失败订单不存在或状态不可取消); } else { request.setAttribute(success, 订单已取消); } } catch (Exception e) { request.setAttribute(error, 系统错误 e.getMessage()); } request.getRequestDispatcher(/order_list.jsp).forward(request, response); } }Step 3在OrderDao.java中添加cancelOrder方法// 更新 order 表状态 public int cancelOrder(String orderId) { String sql UPDATE order SET status cancelled WHERE id ? AND status pending; return DBUtil.update(sql, orderId); }验证步骤创建一个新订单确保状态为pending进入该订单详情页点击“取消订单”刷新页面确认状态变为“cancelled”尝试取消已支付订单确认提示“状态不可取消”5.3 需求将MySQL连接改为Druid连接池提升并发性能原项目用DBUtil单例DriverManager高并发下易成为瓶颈。Druid是阿里开源的高性能连接池替换只需3步。Step 1添加Druid依赖替换原mysql-connector-java下载druid-1.2.20.jar和mysql-connector-java-8.0.33.jar放入WEB-INF/lib/删除旧版mysql-connector-java-5.1.47.jar。Step 2创建druid.properties配置文件放在src/main/resources/# druid.properties driverClassNamecom.mysql.cj.jdbc.Driver urljdbc:mysql://localhost:3306/bookstore_db?serverTimezoneGMT%2B8useSSLfalseallowPublicKeyRetrievaltrue usernameroot password123456 initialSize5 minIdle5 maxActive20 maxWait60000 timeBetweenEvictionRunsMillis60000 minEvictableIdleTimeMillis300000 validationQuerySELECT 1 testWhileIdletrue testOnBorrowfalse testOnReturnfalse poolPreparedStatementstrue maxPoolPreparedStatementPerConnectionSize20 filtersstat,wall,log4j2Step 3重写DBUtil.java使用DruidDataSource// src/main/java/com/bookstore/util/DBUtil.java public class DBUtil { private static DataSource dataSource; static { try { Properties props new Properties(); props.load(DBUtil.class.getClassLoader().getResourceAsStream(druid.properties)); dataSource DruidDataSourceFactory.createDataSource(props); } catch (Exception e) { throw new RuntimeException(Druid DataSource init failed, e); } } public static Connection getConnection() throws SQLException { return dataSource.getConnection(); } public static void closeConnection(Connection conn) { if (conn ! null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } // 其他query/update方法保持不变仅修改getConnection()调用方式 }验证步骤启动Tomcat观察控制台是否打印Druid初始化日志使用JMeter模拟100并发用户访问首页对比替换前后TPSTransactions Per Second访问http://localhost:8080/druidDruid监控页默认账号admin/admin查看连接池状态从那以后我每次接手JavaEE老项目第一件事就是打开web.xml确认Servlet映射和Filter链第二件事是直奔sql/目录看建表语句的字符集和外键第三件事是用Postman发一个最简单的GET请求测通路——而不是急着改代码。这套网上书店项目它不炫技但每一步都踩在JavaEE教学和工程落地的交界线上足够简单让你看懂又足够完整让你交差。它证明了一件事不用Spring Boot用原生ServletJDBC一样能做出健壮、可维护、能上线的系统。希望帮到你。本文还有配套的精品资源点击获取
RELATED

相关推荐

Dify 官方安装包 Docker Compose 部署避坑与验证

Dify 官方安装包 Docker Compose 部署避坑与验证

简介:Dify 官方安装包是从 GitHub 获取的项目主体压缩包,面向希望本地部署、源码研读或二次开发 AI 应用编排平台的开发者,适合用于搭建开发测试环境、了解项目模块组织以及扩展功能。压缩包共 2000 个文件,整体约 20.25MB&#x…

📅 2026/10/28 10:36:19
OSG3.6.5+OSGEarth在VS2019下的3rdParty配置与排错

OSG3.6.5+OSGEarth在VS2019下的3rdParty配置与排错

简介:面向三维渲染、数字地球与GIS可视化方向的C开发者,这套预编译第三方库用于在Visual Studio 2019的64位环境中搭建OSG3.6.5与OSGEarth2.10的编译依赖,帮助避开第三方库版本混杂、逐个从源码编译耗时以及运行库不一致等常见阻碍。压缩包共…

📅 2026/10/28 10:36:19
Dify Docker Compose部署与RAG知识库验证避坑指南

Dify Docker Compose部署与RAG知识库验证避坑指南

简介:面向希望快速获取 Dify 官方安装包的开发者与运维学习者,这份压缩包提供从 GitHub 项目页面整理的工程主体,可用于本地环境验证、源码阅读与二次开发准备。包内共 2000 个文件,以 1337 个 Python 文件承载主要业务逻辑&#…

📅 2026/10/28 10:36:19
MORE NEWS

更多资讯

📰

VC2010下双向链表实现大整数加乘:进位处理与调试全攻略

简介:面向K12阶段或初学数据结构与算法的学生、开发者,这是一份基于双向链表实现大整数加乘运算的C语言项目,用于解决标准整型变量无法存储超长数值的问题。项目在Visual C 2010环境下编写,采用双向链表存储大整数,每个…

📰

FDTD超表面仿真8.6教程:求解器、网格、材料与脚本避坑

简介:《FDTD Solutions软件教程》面向微纳光学、超表面与光电器件仿真方向的学习者和科研人员,围绕Lumerical时域有限差分法(FDTD)的建模、求解与分析展开,适合希望系统掌握软件操作并理解仿真物理设置的中级读者。资源…

📰

边缘计算任务调度器QPLMTS源码拆解:从DAG生成到调度落地

简介:基于QPLMTS算法的边缘计算场景任务调度器源码,适合高校边缘计算、分布式系统与算法设计课程的学生作为课程设计或期末大作业的完整参考。该实现围绕QPLMTS算法在边缘节点间的任务调度与资源分配展开,核心调度逻辑以C代码编写&#xff0c…

📰

分布式驱动电动汽车状态估计与容积卡尔曼滤波技术

1. 分布式驱动电动汽车状态估计的行业背景与挑战在新能源车快速普及的今天,分布式驱动架构正在重塑电动汽车的控制范式。与传统集中式驱动不同,四个轮毂电机独立控制的布局带来了更灵活的动力分配可能,但同时也让车辆状态估计的复杂度呈指数级…

📰

FDTD微纳光学仿真:从Yee网格到材料建模与避坑

简介:《FDTD Solutions软件教程》面向微纳光学、光学器件与超表面仿真方向的研究人员和工程人员,基于Lumerical时域有限差分法,帮助读者建立从建模、材料设置到结果分析的完整认知。资源包共1个PDF文件,约11.61MB,内容…

📰

计算机组成原理课设实战:从指令集设计到数据通路验证的完整指南

简介:这份资源是山东大学20级计算机组织与结构(计算机组成原理)课程的大课设资料,面向正在学习计组实验、需要完成电路设计与指令系统实现的本科生。内容围绕逻辑门搭建、运算器与控制器设计、存储系统及指令集定义展开&#xff0…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬