ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

JSP网上书店毕设实战:从环境搭建到下单事务的完整实现

JSP网上书店毕设实战:从环境搭建到下单事务的完整实现 简介本资源为基于JSP的网上书店系统毕业设计全套资料面向计算机相关专业需要完成毕业设计的学生及Java Web初学者。内容涵盖从系统开发背景、运行环境选择、功能分析与模块设计到数据库需求分析、概念结构、逻辑结构设计及结构实现的完整过程并详细讲述各功能模块的创建与系统编译发行。压缩包为zip格式大小约23.73MB包含源码、论文与视频等文件可支撑登录、管理员、注册用户、销售主页、图书管理及个人资料修改等页面的开发与调试。论文部分还涉及session与cookie安全性、身份验证机制保护JSP页面及SQL Server数据库安全等章节并附有毕业论文小结。已有121人学习适合需要完整赛题方案、可运行源码、配套论文与演示视频的读者参考帮助快速理解B/S架构管理信息系统的搭建思路与实现细节。1. 从一份 JSP 网上书店毕设说起它到底能跑通什么如果你正在搜「基于 JSP 的网上书店系统 设计与实现」大概率是三种人之一马上要交毕设、被导师催着要能演示的系统、或者想找一个结构完整又不算太难的 JavaWeb 项目练手。这个标题对应的东西其实很明确——一个用 JSP Servlet JDBC 搭起来的 B/S 架构网上书店功能覆盖图书浏览、分类检索、购物车、下单、后台图书与订单管理配套还有论文和演示视频。它不追求高并发也不上微服务核心价值是「结构完整、能本地跑起来、能讲清楚每一层在干什么」。我见过太多人卡在第一步环境搭不起来Tomcat 一启动就报 404 或 500然后开始怀疑人生。其实这类传统 JSP 项目的技术栈非常固定常见做法是 JSP 负责视图、Servlet 处理请求、JavaBean 封装数据、JDBC 直连 MySQL。你只要把这条链路打通剩下的就是照着功能模块填代码。这篇笔记就按「先搞懂结构 → 再动手跑通 → 最后避开那些必踩的坑」的顺序把这份毕设从黑匣子拆成你能复现的步骤。适合新手跟着做也适合熟手快速判断这套方案值不值得投入时间。2. 拆开这套 JSP 网上书店分层结构与选型理由2.1 为什么是 JSP Servlet JDBC 这套老组合先别急着嫌弃它老。毕设场景下这套组合有三个硬优势第一资料多遇到问题几乎都能搜到答案第二不依赖复杂框架IDEA 新建一个 JavaWeb 项目就能开写不需要配 Spring 那一堆 XML 或注解第三答辩时老师问「请求怎么走的」你能从浏览器一路讲到数据库链路清晰。具体分层是这样的JSP 页面负责展示图书列表、购物车、订单等界面Servlet 作为控制器接收表单提交和链接请求调用业务方法DAO 层用 JDBC 操作 MySQL完成增删改查实体类JavaBean在层之间传递数据。这种 MVC 雏形虽然粗糙但对毕设来说足够而且论文里画架构图、写模块设计都很好展开。提示如果你的学校明确要求用 SSM 或 SpringBoot那这套 JSP 方案需要做适配但核心的 DAO 和实体类可以复用。2.2 数据库表设计五张核心表撑起整个书店网上书店的数据模型不复杂但表关系要想清楚。我一般会建这几张表用户表、图书表、分类表、购物车表、订单表含订单明细。图书和分类是多对一订单和用户是多对一订单和图书通过订单明细做多对多。下面是一个精简的建表 SQL字段按毕设常见需求保留你可以直接拿去改-- 用户表 CREATE TABLE user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(50) NOT NULL, email VARCHAR(100), phone VARCHAR(20), address VARCHAR(200), role TINYINT DEFAULT 0 -- 0普通用户 1管理员 ); -- 图书表 CREATE TABLE book ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(100) NOT NULL, author VARCHAR(50), price DECIMAL(10,2) NOT NULL, stock INT DEFAULT 0, category_id INT, cover VARCHAR(200), -- 封面图片路径 description TEXT, FOREIGN KEY (category_id) REFERENCES category(id) ); -- 分类表 CREATE TABLE category ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50) NOT NULL ); -- 购物车表 CREATE TABLE cart ( id INT PRIMARY KEY AUTO_INCREMENT, user_id INT NOT NULL, book_id INT NOT NULL, quantity INT DEFAULT 1, FOREIGN KEY (user_id) REFERENCES user(id), FOREIGN KEY (book_id) REFERENCES book(id) ); -- 订单表 CREATE TABLE orders ( id INT PRIMARY KEY AUTO_INCREMENT, user_id INT NOT NULL, order_no VARCHAR(50) NOT NULL UNIQUE, total_price DECIMAL(10,2), status TINYINT DEFAULT 0, -- 0待付款 1已付款 2已发货 3已完成 create_time DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES user(id) ); -- 订单明细表 CREATE TABLE order_item ( id INT PRIMARY KEY AUTO_INCREMENT, order_id INT NOT NULL, book_id INT NOT NULL, quantity INT, price DECIMAL(10,2), FOREIGN KEY (order_id) REFERENCES orders(id), FOREIGN KEY (book_id) REFERENCES book(id) );建表时注意几个参数price用DECIMAL(10,2)而不是FLOAT避免金额计算出现精度问题order_no加唯一索引防止重复下单status用TINYINT存状态码比存字符串省空间也方便判断。外键约束在毕设里建议加上答辩时能体现数据完整性设计但如果你本地测试时嫌插入数据麻烦可以先不建外键最后再补。2.3 项目目录结构IDEA 里怎么摆才不乱用 IDEA 新建 JavaWeb 项目后目录结构直接决定你后面找文件顺不顺手。我习惯这样组织src/ com.bookstore.entity/ -- 实体类 com.bookstore.dao/ -- 数据库操作 com.bookstore.servlet/ -- 控制器 com.bookstore.util/ -- 工具类DBUtil等 web/ css/ js/ images/ -- 静态资源 WEB-INF/ web.xml -- 部署描述符 lib/ -- 第三方jar包 index.jsp -- 首页 book_list.jsp -- 图书列表 cart.jsp -- 购物车 order.jsp -- 订单页 admin/ -- 后台页面WEB-INF下的文件浏览器不能直接访问必须通过 Servlet 转发这是 JSP 项目的基本安全习惯。lib目录放 MySQL 驱动 jar 包记得在 IDEA 的 Project Structure 里把依赖加进去否则运行时报ClassNotFoundException。2.4 一个最小可跑的 Servlet JSP 链路光看结构没感觉我们跑一条最简单的链路浏览器请求图书列表 → Servlet 查数据库 → 转发给 JSP 渲染。先写 DBUtilpublic class DBUtil { private static final String URL jdbc:mysql://localhost:3306/bookstore?useSSLfalseserverTimezoneUTC; private static final String USER root; private static final String PASSWORD 你的密码; static { try { Class.forName(com.mysql.cj.jdbc.Driver); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection(URL, USER, PASSWORD); } }注意serverTimezoneUTC这个参数MySQL 8 以上不写会报时区错误。驱动类名用com.mysql.cj.jdbc.Driver旧版是com.mysql.jdbc.Driver写错了一样连不上。接着写 BookServletWebServlet(/bookList) public class BookServlet extends HttpServlet { protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ListBook books new ArrayList(); String sql SELECT * FROM book; try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql); ResultSet rs ps.executeQuery()) { while (rs.next()) { Book b new Book(); b.setId(rs.getInt(id)); b.setName(rs.getString(name)); b.setPrice(rs.getBigDecimal(price)); books.add(b); } } catch (SQLException e) { e.printStackTrace(); } req.setAttribute(books, books); req.getRequestDispatcher(/book_list.jsp).forward(req, resp); } }JSP 页面里用 JSTL 遍历% taglib prefixc urihttp://java.sun.com/jsp/jstl/core % c:forEach items${books} varb div classbook-item h3${b.name}/h3 p价格${b.price}/p /div /c:forEach这条链路跑通说明你的数据库连接、Servlet 映射、JSP 转发都没问题。后面加购物车、下单无非是在这个模式上多写几个 Servlet 和 DAO 方法。3. 从零跑通环境搭建与核心功能实现步骤3.1 环境版本怎么选JDK、Tomcat、MySQL 的搭配版本不匹配是新手翻车重灾区。我建议这套组合JDK 8 或 11、Tomcat 8.5 或 9、MySQL 5.7 或 8.0。别一上来就 JDK 17 Tomcat 10Tomcat 10 把javax.servlet改成了jakarta.servlet老代码直接编译不过你会花大量时间在改包名上。IDEA 里配置 Tomcat 的步骤Run → Edit Configurations → 加一个 Tomcat Server → Local → 在 Deployment 里加 Artifact选 war exploded→ Application context 设成/bookstore。这样你访问http://localhost:8080/bookstore/就能进首页。MySQL 驱动版本也要对MySQL 8 用mysql-connector-java-8.0.xMySQL 5.7 用5.1.x。驱动 jar 放进WEB-INF/lib后别忘了在 IDEA 的 Modules 里也加一遍依赖否则编译能过但运行报错。3.2 用户注册登录Session 与密码处理的正确姿势注册逻辑接收表单 → 校验用户名是否已存在 → 插入数据库。登录逻辑查用户 → 比对密码 → 把用户信息存进 Session。// 登录 Servlet 核心代码 String username req.getParameter(username); String password req.getParameter(password); UserDao dao new UserDao(); User user dao.findByUsername(username); if (user ! null user.getPassword().equals(password)) { req.getSession().setAttribute(currentUser, user); resp.sendRedirect(index.jsp); } else { req.setAttribute(msg, 用户名或密码错误); req.getRequestDispatcher(login.jsp).forward(req, resp); }密码这里有个坑毕设里很多人直接存明文答辩时老师一问就露馅。至少做个 MD5 或 SHA-256 哈希代码量不大但能体现安全意识。Session 超时时间在web.xml里配session-config session-timeout30/session-timeout /session-config单位是分钟。购物车和订单页面都要判断currentUser是否为空为空就跳登录页否则会空指针。3.3 购物车实现存 Session 还是存数据库两种做法各有场景。存 Session 简单不用建表但用户换浏览器购物车就没了存数据库持久化好但每次增删改都要读写库。毕设里我一般推荐存数据库因为论文里可以写「购物车数据持久化设计」而且订单模块本来就要读购物车表。加购的 Servlet 逻辑int userId ((User) req.getSession().getAttribute(currentUser)).getId(); int bookId Integer.parseInt(req.getParameter(bookId)); CartDao cartDao new CartDao(); Cart exist cartDao.findByUserAndBook(userId, bookId); if (exist ! null) { cartDao.updateQuantity(exist.getId(), exist.getQuantity() 1); } else { cartDao.insert(new Cart(userId, bookId, 1)); } resp.sendRedirect(cartList);参数说明bookId从图书列表页的链接传过来userId从 Session 取。注意加购前要判断库存库存为 0 时前端直接禁用按钮后端也要再校验一次防止绕过前端直接调接口。3.4 下单流程事务处理与订单号生成下单是整套系统里最需要小心的地方。它涉及三件事写订单主表、写订单明细、扣减库存。这三步必须在一个事务里完成否则会出现订单写了但库存没扣或者扣了库存订单没写。public boolean createOrder(int userId, ListCart cartList) { Connection conn null; try { conn DBUtil.getConnection(); conn.setAutoCommit(false); // 开启事务 String orderNo ORD System.currentTimeMillis(); BigDecimal total BigDecimal.ZERO; for (Cart c : cartList) { total total.add(c.getPrice().multiply(new BigDecimal(c.getQuantity()))); } // 插入订单主表 String sql1 INSERT INTO orders(user_id, order_no, total_price, status) VALUES(?,?,?,0); PreparedStatement ps1 conn.prepareStatement(sql1, Statement.RETURN_GENERATED_KEYS); ps1.setInt(1, userId); ps1.setString(2, orderNo); ps1.setBigDecimal(3, total); ps1.executeUpdate(); ResultSet rs ps1.getGeneratedKeys(); int orderId 0; if (rs.next()) orderId rs.getInt(1); // 插入明细并扣库存 for (Cart c : cartList) { String sql2 INSERT INTO order_item(order_id, book_id, quantity, price) VALUES(?,?,?,?); PreparedStatement ps2 conn.prepareStatement(sql2); ps2.setInt(1, orderId); ps2.setInt(2, c.getBookId()); ps2.setInt(3, c.getQuantity()); ps2.setBigDecimal(4, c.getPrice()); ps2.executeUpdate(); String sql3 UPDATE book SET stock stock - ? WHERE id ? AND stock ?; PreparedStatement ps3 conn.prepareStatement(sql3); ps3.setInt(1, c.getQuantity()); ps3.setInt(2, c.getBookId()); ps3.setInt(3, c.getQuantity()); if (ps3.executeUpdate() 0) { throw new SQLException(库存不足图书ID c.getBookId()); } } conn.commit(); return true; } catch (SQLException e) { if (conn ! null) try { conn.rollback(); } catch (SQLException ex) { ex.printStackTrace(); } e.printStackTrace(); return false; } finally { if (conn ! null) try { conn.setAutoCommit(true); conn.close(); } catch (SQLException e) { e.printStackTrace(); } } }关键点setAutoCommit(false)开启事务任何一步失败就rollback扣库存的 SQL 带了AND stock ?防止超卖订单号用时间戳生成简单但够用如果要更规范可以加用户 ID 前缀。下单成功后清空购物车跳转到订单列表页。3.5 后台管理图书增删改查与图片上传后台功能不复杂但图片上传是个小难点。JSP 表单要设enctypemultipart/form-dataServlet 里用MultipartConfig注解接收文件WebServlet(/admin/addBook) MultipartConfig(maxFileSize 1024 * 1024 * 5) public class AddBookServlet extends HttpServlet { protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String name req.getParameter(name); BigDecimal price new BigDecimal(req.getParameter(price)); Part filePart req.getPart(cover); String fileName System.currentTimeMillis() _ filePart.getSubmittedFileName(); String savePath getServletContext().getRealPath(/images/) fileName; filePart.write(savePath); // 后续插入数据库cover 字段存 images/ fileName } }maxFileSize限制 5MB防止传大文件把服务器撑爆。保存路径用getServletContext().getRealPath拿到 web 目录的真实路径存数据库时只存相对路径方便迁移。后台页面记得加权限过滤普通用户不能访问/admin/下的任何页面。4. 避坑与排查JSP 网上书店最常见的五个翻车点4.1 中文乱码从请求到响应全链路排查现象表单提交后数据库里存的是问号或者页面显示乱码。原因JSP 页面编码、请求编码、数据库连接编码三者不一致。解决JSP 顶部加% page contentTypetext/html;charsetUTF-8 %Servlet 里在取参数前设req.setCharacterEncoding(UTF-8)数据库连接 URL 加characterEncodingutf8MySQL 建库时指定DEFAULT CHARSETutf8mb4。四个地方都对齐乱码基本消失。4.2 404 错误路径和映射对不上现象访问某个 Servlet 或 JSP 报 404。原因WebServlet的路径写错、web.xml里没配、或者 JSP 放在WEB-INF下直接访问了。解决先看 Tomcat 控制台有没有部署成功再检查访问 URL 是否带了 Application context比如/bookstore/bookListWEB-INF下的 JSP 只能通过 Servlet 转发访问不能直接在浏览器输路径。4.3 数据库连接失败驱动、URL、权限三连问现象启动后第一次查库就报Communications link failure或Access denied。原因驱动 jar 没放进lib、URL 端口写错、密码不对、MySQL 没启动。解决先确认 MySQL 服务在跑再检查lib下有没有驱动 jar 并且 IDEA 依赖里也加了URL 格式jdbc:mysql://localhost:3306/库名端口默认 3306密码注意大小写和特殊字符。如果报时区错误URL 末尾加serverTimezoneUTC。4.4 事务不回滚自动提交没关掉现象下单时库存不足抛了异常但订单主表已经写进去了。原因conn.setAutoCommit(false)没执行或者异常被 catch 后没有 rollback。解决确认在事务开始前关了自动提交catch 块里必须调conn.rollback()finally 里恢复setAutoCommit(true)再关闭连接。建议把事务代码单独抽成一个方法别和普通查询混在一起。4.5 Session 失效购物车数据莫名丢失现象用户登录后加了购物车过一会儿刷新页面购物车空了。原因Session 超时、Tomcat 重启、或者浏览器禁用了 Cookie。解决web.xml里把session-timeout设大一点比如 60 分钟Tomcat 重启会导致内存中的 Session 丢失这是正常现象如果要求持久化可以把购物车存数据库浏览器 Cookie 问题在毕设演示时少见但可以用 URL 重写做兜底。5. 让这套毕设更耐问论文映射与演示技巧5.1 论文里怎么把代码讲成设计答辩老师不会逐行看你的代码但会问「你这个模块怎么设计的」。所以论文里的模块设计章节要和代码结构对应上。比如你写了BookDao论文里就写「图书数据访问层负责图书信息的增删改查采用 JDBC 实现通过 PreparedStatement 防止 SQL 注入」。你写了事务处理论文里就写「订单模块采用数据库事务保证订单创建与库存扣减的原子性」。我一般会建议学生画三张图系统架构图展示 JSP、Servlet、DAO、MySQL 的层次、E-R 图展示六张表的关系、流程图展示下单的完整步骤。这三张图能把论文的技术部分撑起来而且画起来不费劲。5.2 演示视频怎么录才不翻车录屏前先清空测试数据重新注册一个干净的用户按「注册 → 登录 → 浏览图书 → 加购物车 → 下单 → 后台管理」的顺序走一遍。每一步停留两秒让看的人能看清页面。别在录屏时开一堆无关窗口也别用太花哨的鼠标特效。如果演示时数据库突然连不上提前准备一个备份 SQL 文件现场重新导入。Tomcat 启动慢的话提前启动好再录。视频长度控制在 5 到 8 分钟太长没人看太短说不清功能。5.3 这套方案值不值得投入我的真实判断如果你时间紧、只想顺利毕业这套 JSP 网上书店是性价比很高的选择。技术栈成熟、资料多、功能模块清晰改一改就能变成「基于 JSP 的图书管理系统」「基于 JSP 的在线商城」复用率很高。但如果你想让毕设更有竞争力可以在它基础上加一两个亮点比如用 ECharts 做个销售数据看板或者加个简单的推荐算法按分类推荐同类图书。改动量不大但答辩时能多讲几分钟。我自己带过几届学生最后悔的情况是有人非要在毕设里上微服务结果环境搭了两周还没跑通最后匆匆换回 JSP 方案时间全浪费了。先把这套跑通再考虑加东西这是最稳的路径。希望帮到你。本文还有配套的精品资源点击获取
返回列表