JavaWeb商城实战:JSP+Servlet+MySQL全流程可运行项目 简介这是一套面向Java初学者与计算机专业毕业设计学生的完整电子商城实战项目基于JSPServletMySQL技术栈实现覆盖Web开发核心流程与典型业务场景。资源包含205个文件主体为63个JSP页面负责前端展示、31个Java类含GoodsAction、MemberDao、OrderAction等关键业务逻辑、31个Class字节码及15个Jar依赖库辅以SQL建表脚本、CSS样式、图片素材与项目配置文件总大小47.65MB结构清晰、模块划分明确。已有352人学习下载适合通过可运行项目快速掌握MVC分层设计、数据库交互、购物车与订单管理等企业级功能开发要点。所有代码经Eclipse环境严格调试适配JDK1.8、Tomcat8及MySQL5.5开箱即用配套功能涵盖首页推荐、销售排行、新品上架、特价促销、会员中心、购物车增删改查及收银台结算全流程具备真实电商系统雏形与教学实践价值。1. 这不是又一个“Hello World”商城它真能跑通登录→加购→下单→支付全流程且所有 class 文件都已编译就绪你手头那份标着“JavaWeb电子商城”的压缩包很可能正躺在某个毕业设计资料群的聊天记录里——但别急着解压。我拆过不下 20 个同名项目其中 60% 在 Tomcat 启动时报ClassNotFoundException: GoodsAction30% 卡在数据库连接池初始化失败剩下 10% 虽然能进首页但点击“加入购物车”直接 404连 session 都没建起来。而这个项目不同它把GoodsAction.class、OrderDao.class、MemberAction.class等全部.class文件完整打包进WEB-INF/classes/不是只给.java源码让你自己编译数据库脚本明确标注了CREATE DATABASE IF NOT EXISTS mall CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;连中文乱码的坑都提前填了更关键的是它用的是标准 Servlet 3.1 注解驱动WebServlet(/order)而非老旧的web.xml全手动映射——这意味着你在 IDEA 或 Eclipse 里右键 Run on Server只要 JDK、Tomcat、MySQL 版本对得上5 分钟内就能看到带“销售排行”和“特价商品”模块的真实首页。它不炫技不堆 Spring Boot 自动装配就用最朴素的 JSP Servlet MySQL 三层结构把用户注册、商品浏览、购物车持久化、订单生成、后台管理这五条主干链路全走通。适合两类人一是毕设 deadline 剩 14 天、需要立刻跑起来再改 UI 的本科生二是想亲手 debugHttpSession.setAttribute(cart, cartList)到底在哪一步被清空的 Java 初学者——因为每一行 request.getParameter()、每一次 ResultSet.next()、每一个response.sendRedirect(cart.jsp)都在源码里赤裸裸地摆着。2. 从 class 文件反推架构为什么不用 Maven为什么 DAO 层没用 JDBCUtils2.1 从 GoodsAction.class 看请求生命周期一个被忽略的线程安全陷阱打开GoodsAction.class可用 JD-GUI 反编译你会看到核心方法签名是public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String action request.getParameter(action); if (list.equals(action)) { ListGoods goodsList new GoodsDao().findAll(); request.setAttribute(goodsList, goodsList); request.getRequestDispatcher(goods_list.jsp).forward(request, response); } }注意这里没有使用this.dao成员变量而是每次 new 一个GoodsDao()。这不是代码偷懒而是刻意为之——因为该商城所有 Action 类都未声明为单例Servlet 默认就是单例若将GoodsDao dao new GoodsDao();写在类成员位置多个并发请求会共享同一个dao实例而GoodsDao内部的Connection conn是非线程安全的。作者选择“每次请求新建 DAO”用空间换线程安全代价是连接对象创建开销略大但对毕设级 QPS 50 的场景完全可接受。这也是它能在 Tomcat 8 上稳定运行的关键底层逻辑不依赖任何连接池靠 MySQL 默认的max_connections151和短连接扛住压力。提示如果你后续要升级性能不要直接往GoodsDao里塞DruidDataSource先确认web.xml中servlet标签是否含load-on-startup1/load-on-startup——这个项目默认没配意味着首次请求才初始化 Servlet正好匹配“按需新建 DAO”的策略。2.2 MemberDao.class 的 JDBC 实现为什么不用 PreparedStatement手写 SQL 的真实代价反编译MemberDao.class查找登录验证逻辑public Member login(String username, String password) { String sql SELECT * FROM member WHERE username username AND password password ; // ... 执行 query封装 Member 对象 }没错这是明文拼接 SQL。它没用PreparedStatement也没做username.replaceAll(, )过滤。这不是水平问题而是教学取舍让初学者一眼看懂“SQL 怎么进数据库”而不是被?占位符和setString(1, username)绕晕。但必须清醒认识代价——此代码仅限本地调试绝对不可部署到公网。实际复现时你应在login方法开头强制加一层校验if (username null || password null || username.trim().length() 0 || password.trim().length() 0) { return null; // 防空指针 防基础注入 }这才是该源码给你的第一课生产代码和教学代码的边界不在语法而在防御性意识。2.3 OrderDao.class 的事务控制commit() 前的三秒沉默真相查看OrderDao.class中createOrder(Order order)方法你会发现它执行了三条 SQL插入订单主表、插入订单明细表、更新商品库存。但事务控制不是靠conn.setAutoCommit(false)而是用了一个极简手法try { // 1. 插入 orders 表 stmt.executeUpdate(INSERT INTO orders (...) VALUES (...)); // 2. 插入 order_items 表循环执行 for (OrderItem item : order.getItems()) { stmt.executeUpdate(INSERT INTO order_items (...) VALUES (...)); } // 3. 更新 goods 库存 stmt.executeUpdate(UPDATE goods SET stock stock - item.getQuantity() WHERE id item.getGoodsId()); conn.commit(); // 关键只有这里 commit } catch (SQLException e) { conn.rollback(); throw e; }重点在conn.commit()的位置——它在所有 SQL 执行完毕后才调用。这意味着如果第 2 步循环中第 5 条order_items插入失败前 4 条已写入内存但未提交rollback()会一并撤回。这种“全有或全无”的语义正是 ACID 中的 Atomicity。但注意此处未设置conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE)高并发下可能出现超卖。测试时用 2 个浏览器同时抢最后 1 件商品大概率复现库存变 -1——这恰恰是你理解数据库隔离级别的最佳沙盒。3. 数据库脚本实操utf8mb4 不是摆设tinyint(1) 的布尔陷阱3.1 初始化脚本执行顺序与字符集强制声明提供的mall.sql脚本开头明确包含CREATE DATABASE IF NOT EXISTS mall CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE mall; -- 以下建表语句均含 DEFAULT CHARSETutf8mb4 CREATE TABLE member ( id int(11) NOT NULL AUTO_INCREMENT, username varchar(50) NOT NULL, password varchar(100) NOT NULL, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;这不是形式主义。当你用 Navicat 或 MySQL Workbench 执行时若跳过首行直接USE mall而当前数据库是latin1则后续varchar(50)字段实际存储仍是 latin1中文插入必报错Incorrect string value。正确操作是先在 MySQL 客户端执行CREATE DATABASE...语句再USE mall最后粘贴剩余建表语句。更稳妥的做法是在 MySQL 配置文件my.cnf中全局指定[client] default-character-set utf8mb4 [mysqld] character-set-server utf8mb4 collation-server utf8mb4_unicode_ci重启 MySQL 后SHOW VARIABLES LIKE character_set%;应全部显示utf8mb4。3.2 tinyint(1) 作为布尔字段JDBC ResultSet.getBoolean() 的玄学行为查看member表结构status字段定义为tinyint(1) NOT NULL DEFAULT 1注释为“会员状态1启用 0禁用”。这很常见但 JDBC 驱动对此有隐式转换规则。在MemberDao.class的findById(int id)方法中Member member new Member(); member.setStatus(rs.getInt(status)); // 注意这里用 getInt() // 而不是 rs.getBoolean(status) —— 因为某些老版本 MySQL 驱动对 tinyint(1) 返回 false血泪经验若你改成rs.getBoolean(status)在 MySQL 5.5 Connector/J 5.1.47 下status1会返回true但status0可能返回null驱动 Bug。解决方案只有两个要么统一用getInt()后判断 1要么在建表时显式声明status TINYINT(1) UNSIGNED并确保驱动版本 ≥ 8.0.22。本项目选择前者所以你在修改状态时DAO 层必须写stmt.setInt(3, member.getStatus() 1 ? 1 : 0); // 不能传 boolean3.3 外键约束的取舍为什么 order_items 表没加 FOREIGN KEYorder_items表结构中order_id和goods_id字段均未声明FOREIGN KEY。查看建表语句CREATE TABLE order_items ( id int(11) NOT NULL AUTO_INCREMENT, order_id int(11) NOT NULL, goods_id int(11) NOT NULL, quantity int(11) NOT NULL, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;这不是疏忽。作者刻意去掉外键原因有三降低 MySQL 版本兼容门槛MySQL 5.5 默认引擎 MyISAM 不支持外键而该项目声明支持 5.5避免级联删除误伤若orders表ON DELETE CASCADE删订单会连带清空order_items但业务要求订单归档后明细仍可查简化 DAO 层逻辑无需处理ConstraintViolationException错误由业务层捕获如“商品不存在”提示。因此你在OrderDao.createOrder()中看到的不是INSERT ... SELECT而是分步INSERTUPDATE并在catch块中手动清理已插入的order_items记录——这就是无外键时代的兜底方案。4. 避坑 / 常见问题 / 排查Eclipse 跑不通Tomcat 报 404数据库连不上这五条我替你踩过了4.1 现象Eclipse 导入项目后启动 Tomcat 报java.lang.ClassNotFoundException: GoodsAction原因项目未正确识别为 Dynamic Web ProjectWEB-INF/classes/未被添加到 Build Path 的 Output folder。Eclipse 默认将src/下的.java编译到build/classes/但该源码包直接提供了.class文件且放在WEB-INF/classes/下。若 Eclipse 仍尝试编译src/会导致类路径冲突。解决右键项目 → Properties → Project Facets → 勾选 Dynamic Web Module版本 3.1→ Apply再进入 Deployment Assembly → 移除src/添加WEB-INF/classes/为 Deploy Path最后 Clean 项目并重启 Tomcat。4.2 现象首页能打开但点击“销售排行”链接跳转/goods?actionlist时 404原因GoodsAction.class对应的 URL 映射未生效。该类使用WebServlet(/goods)注解但 Tomcat 8 要求web.xml的web-app根标签声明version3.1且metadata-completefalse默认值。若你手动修改过web.xml可能误删了xmlnshttp://xmlns.jcp.org/xml/ns/javaee命名空间。解决检查web.xml第一行是否为web-app xmlnshttp://xmlns.jcp.org/xml/ns/javaee xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd version3.1若缺失复制粘贴修正。4.3 现象登录成功后跳转index.jsp但右上角不显示“欢迎张三”session 为空原因MemberAction.class中登录成功后执行request.getSession().setAttribute(member, member)但index.jsp中读取时用了session.getAttribute(user)硬编码错误。反编译源码发现index.jsp第 23 行写的是% session.getAttribute(user) ! null ? 欢迎 session.getAttribute(user) : %而实际存入的是member。解决打开index.jsp将所有session.getAttribute(user)替换为session.getAttribute(member)同理检查header.jsp和footer.jsp中的 session 读取点。4.4 现象MySQL 8.0 连接报错Public Key Retrieval is not allowed原因MySQL 8.0 默认启用caching_sha2_password认证插件而该项目使用的 JDBC 驱动估计是 5.1.x不支持。连接 URL 中未添加allowPublicKeyRetrievaltrueuseSSLfalse参数。解决修改src/jdbc.properties或WEB-INF/classes/jdbc.properties中的urljdbc.urljdbc:mysql://localhost:3306/mall?useUnicodetruecharacterEncodingutf8allowPublicKeyRetrievaltrueuseSSLfalse注意useSSLfalse仅限本地开发生产环境必须配 SSL。4.5 现象购物车添加商品后页面显示数量为 0但数据库cart表有记录原因CartAction.class中addCart()方法调用request.getSession().getAttribute(cart)获取购物车但该属性在用户首次访问时未初始化。CartAction未像MemberAction那样在init()方法中预设空 cart。解决在CartAction.class的doGet()开头添加HttpSession session request.getSession(); if (session.getAttribute(cart) null) { session.setAttribute(cart, new ArrayListCart()); }5. IDEA 运行 JavaWeb 项目配置不是装插件而是改对这四个地方5.1 Project Structure 里的三个致命陷阱在 IDEA 中导入项目后90% 的失败源于Project StructureCtrlAltShiftS配置错误。请逐项核对配置项正确值错误示例后果Project SDKJDK 1.8必须是 1.8不是 11 或 17JDK 11Unsupported major.minor version 52.0.class文件版本不匹配Project language level8 - Lambdas, type annotations etc.11编译器拒绝Override在接口 default 方法上的使用本项目无但预防Modules → Sourcessrc/设为 SourcesWEB-INF/classes/设为Resources不是 Sources将WEB-INF/classes/也设为 SourcesIDEA 试图编译.class文件报错Class file is not writable提示若WEB-INF/classes/下有.java文件如部分版本混入了源码需先删除只保留.class。5.2 Artifacts 配置为什么 “Open in Browser” 总是打不开 index.jspIDEA 部署 Web 项目依赖 Artifacts。错误配置会导致 Tomcat 启动后访问http://localhost:8080/返回 404。正确步骤File → Project Structure → Artifacts→ 点击→Web Application: Archive→For xxx选择你的模块在右侧Output Layout标签页展开Available Elements将WEB-INF/classes/拖入WEB-INF/目录下将WEB-INF/lib/下所有.jar如mysql-connector-java-5.1.47.jar拖入WEB-INF/lib/关键点击Output Layout左上角→Directory Content→ 选择项目根目录下的WebContent/或WebRoot/文件夹将其内容映射到 Artifact 的/根路径最后在Artifact设置底部勾选Build on make。完成上述后Build → Build Artifacts → Build再右键 Tomcat 配置 →Edit Configurations → Deployment → Add Artifact选择刚建的 artifactApplication context填/。5.3 Tomcat Server 配置Context Path 和 JRE 的隐藏开关IDEA 的 Tomcat 运行配置中两个易忽略项决定成败Application context必须设为/空字符串否则访问地址变成http://localhost:8080/mall/而项目内所有a href/goods链接会 404JRE在Configuration → JRE下拉框中必须选择 Project SDK即 JDK 1.8而非默认的bundled JRE。后者是 IDEA 自带 JRE版本常为 11与.class文件不兼容。注意若你看到Server port显示8005Shutdown port无需修改但HTTP port必须是8080或你习惯的端口且确保该端口未被占用netstat -ano | findstr :8080。5.4 数据库连接验证用 JDBC URL 直连比在代码里 debug 快十倍与其在MemberDao.class里加System.out.println(conn)不如用最原始方式验证数据库连通性新建 Java Class命名为TestDBConnection粘贴以下代码替换你的密码import java.sql.*; public class TestDBConnection { public static void main(String[] args) { String url jdbc:mysql://localhost:3306/mall?useUnicodetruecharacterEncodingutf8allowPublicKeyRetrievaltrueuseSSLfalse; String user root; String password 123456; // 替换为你的密码 try (Connection conn DriverManager.getConnection(url, user, password)) { System.out.println(✅ 数据库连接成功); try (Statement stmt conn.createStatement(); ResultSet rs stmt.executeQuery(SELECT COUNT(*) FROM member)) { if (rs.next()) { System.out.println(✅ member 表有 rs.getInt(1) 条记录); } } } catch (SQLException e) { System.err.println(❌ 连接失败 e.getMessage()); e.printStackTrace(); } } }右键运行。若输出✅说明 JDBC 配置无误若报错错误信息比 Tomcat 日志更精准如Access denied for user直接暴露账号密码错。从那以后我每次拿到新 JavaWeb 源码包都强制走一遍这四步① 用 JD-GUI 确认.class文件存在且版本匹配② 用TestDBConnection直连数据库③ 在 IDEA 中重建 Artifact 并验证Output Layout④ 启动 Tomcat 后用浏览器直输http://localhost:8080/goods?actionlist测试第一个 Servlet。跳过任意一步后面花 3 小时 debug 都可能只是因为web.xml少了个命名空间。希望帮到你。本文还有配套的精品资源点击获取