ARTICLE DETAIL

资讯详情

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

Eclipse搭建JavaWeb商城系统:Servlet+JSP+MySQL实战

Eclipse搭建JavaWeb商城系统:Servlet+JSP+MySQL实战 简介这是一份面向JavaWeb初学者的Eclipse购物商城实战项目聚焦商品浏览与购物车管理两大核心模块帮助开发者快速掌握Servlet、JSP、JSTL等基础技术栈并理解MVC分层架构在电商场景中的落地实践。资源包共1122个文件含157个JavaScript交互脚本、171个CSS样式文件、235个HTML页面、18个JSP动态视图及41个Java业务类如PrivilegeServlet、ProductServlet、PaymentUtil等辅以MySQL相关SQL脚本与配置文件整体压缩后仅8.52MB轻量易部署。已有2078人学习下载项目结构清晰、注释较完整源码未过度封装便于新手逐层调试、扩展订单处理、用户权限或支付接口等进阶功能。配套包含前端静态资源PNG/JPG/GIF、编译后Class文件及Tomcat兼容配置开箱即用是JavaWeb入门到电商项目实操过渡的理想练手范例。1. JavaWeb商城购买为什么用Eclipse跑通一个能下单的购物系统比你想象中更值得花三天重搭环境这不是一个“JavaWeb入门项目”的泛泛而谈——它是一套真实可交互、含用户注册→商品浏览→加入购物车→生成订单→模拟支付闭环的轻量级网上购物系统全部基于原生ServletJSPMySQLTomcat构建不依赖Spring Boot或Vue前端框架。我见过太多人卡在“Eclipse里右键Run on Server没反应”“页面404但控制台没报错”“数据库连上了却查不到数据”这种看似低级、实则消耗掉整周调试时间的环节。它适合两类人一是刚学完Servlet生命周期、想立刻验证“request.getParameter()到底从哪来”的新手二是需要快速交付教学演示系统、又不想被Spring Boot自动配置绕晕的老手。标题里反复出现的“Eclipse”不是偶然——这个IDE对JavaWeb项目的目录结构感知、部署路径映射、类加载顺序控制至今仍是纯Servlet开发中最稳定、最透明的调试载体。而“商城购买”四个字意味着它必须包含至少3个关键状态流转会话级购物车HttpSession、事务性订单提交JDBC手动commit/rollback、以及前后端数据一致性校验比如库存扣减与订单生成必须原子。下面所有步骤我都按2024年主流Eclipse 2023-124.29 Tomcat 9.0.83 MySQL 8.0.33环境实测复现跳过所有“理论上可行但实际踩坑”的中间态。2. 搭建JavaWeb商城最小可运行骨架从Eclipse新建Dynamic Web Project到首页能显示商品列表2.1 创建符合Servlet规范的Dynamic Web Project并校准部署结构Eclipse创建JavaWeb项目不能选“Java Project”必须严格使用Dynamic Web Project模板否则WebContent目录、web.xml位置、部署描述符识别都会错位。操作路径File → New → Dynamic Web Project → 填写Project name如mall-shop→ Target runtime选择已配置的Tomcat v9.0 → Dynamic web module version选4.0对应Servlet 4.0兼容Tomcat 9且支持WebServlet注解→ 生成web.xml勾选✅。关键点在于Web content folder必须是WebContent默认值不可改为src/main/webapp——后者是Maven项目约定Eclipse原生Web项目不识别Java build path的source folder必须包含src和WebContent/WEB-INF/classes否则编译后的.class文件不会自动复制到WEB-INF/classes下Deployment Assembly里必须有/WebContent映射到/且src映射到/WEB-INF/classes这是Eclipse将源码编译结果正确部署到Tomcat webapps目录的关键映射规则。提示如果后续启动时报ClassNotFoundException: javax.servlet.http.HttpServlet一定是Deployment Assembly里漏了/WebContent/WEB-INF/lib对servlet-api.jar的映射——Tomcat 9自带该jar不要把servlet-api.jar复制进WEB-INF/lib而应在Deployment Assembly中添加“Java Build Path Entries” → “Maven Dependencies”或“Server Runtime”并确保其Deploy Path为/WEB-INF/lib。2.2 配置Tomcat服务器并验证基础Servlet响应在Eclipse中配置Tomcat需两步Window → Preferences → Server → Runtime Environments → Add → Apache → Tomcat v9.0 → Browse指向Tomcat解压目录如D:\apache-tomcat-9.0.83→ Finish。然后右键项目 → Run As → Run on Server → 选择刚配好的Tomcat。此时若浏览器打开http://localhost:8080/mall-shop/显示404说明项目部署成功但无欢迎页若显示“The requested resource is not available”则是Tomcat未启动或端口被占。接下来写一个最简Servlet验证容器是否就绪// src/com/mall/servlet/HelloServlet.java package com.mall.servlet; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; WebServlet(/hello) public class HelloServlet extends HttpServlet { Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType(text/html;charsetUTF-8); resp.getWriter().println(h1商城基础环境已就绪/h1); resp.getWriter().println(p当前路径 req.getRequestURL() /p); } }保存后右键项目 → Refresh再访问http://localhost:8080/mall-shop/hello。若看到标题和路径输出说明Servlet容器、类加载、URL映射三者全部打通。注意WebServlet(/hello)路径是相对于上下文根/mall-shop的不是绝对路径若用web.xml配置需确保url-pattern/hello/url-pattern与之等价。2.3 构建商品展示首页JSPMySQL连接实现动态数据渲染商城首页核心是商品列表需连接MySQL并查询。先建库建表MySQL命令行CREATE DATABASE IF NOT EXISTS mall_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE mall_db; CREATE TABLE products ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(100) NOT NULL, price DECIMAL(10,2) NOT NULL, stock INT DEFAULT 0, description TEXT ); INSERT INTO products (name, price, stock, description) VALUES (iPhone 15, 5999.00, 120, 全新未拆封), (MacBook Air M2, 11999.00, 45, 教育优惠版), (AirPods Pro, 1899.00, 200, 降噪旗舰款);接着在Eclipse中配置JDBC驱动下载mysql-connector-java-8.0.33.jar右键项目 → Build Path → Configure Build Path → Libraries → Add External JARs → 选中jar → Apply and Close。关键动作在Deployment Assembly中确认该jar已映射到/WEB-INF/lib右键jar → Build Path → Add to Build Path后Eclipse会自动添加但需人工检查。然后编写商品查询逻辑为简化暂不封装DAO层!-- WebContent/index.jsp -- % page contentTypetext/html;charsetUTF-8 languagejava % % page importjava.sql.* % html headtitle商城首页/title/head body h2热销商品/h2 table border1 trthID/thth名称/thth价格/thth库存/thth操作/th/tr % Connection conn null; PreparedStatement ps null; ResultSet rs null; try { Class.forName(com.mysql.cj.jdbc.Driver); conn DriverManager.getConnection( jdbc:mysql://localhost:3306/mall_db?useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrue, root, your_password); ps conn.prepareStatement(SELECT id, name, price, stock FROM products WHERE stock 0); rs ps.executeQuery(); while(rs.next()) { % tr td% rs.getInt(id) %/td td% rs.getString(name) %/td td¥% rs.getBigDecimal(price) %/td td% rs.getInt(stock) %/td tda hrefcart-add?id% rs.getInt(id) %加入购物车/a/td /tr % } } catch(Exception e) { out.println(trtd colspan5数据库连接失败 e.getMessage() /td/tr); } finally { if(rs ! null) rs.close(); if(ps ! null) ps.close(); if(conn ! null) conn.close(); } % /table /body /html参数说明useSSLfalse禁用SSL本地开发无需证书serverTimezoneAsia/Shanghai解决时区报错allowPublicKeyRetrievaltrue适配MySQL 8.0新认证协议。若页面空白或报java.lang.ClassNotFoundException: com.mysql.cj.jdbc.Driver一定是jar未正确部署到WEB-INF/lib——检查WebContent/WEB-INF/lib/目录下是否存在该jar且Eclipse的Deployment Assembly中已映射。3. 实现购物车与订单流程用HttpSession管理临时状态用JDBC事务保障数据一致性3.1 基于HttpSession的购物车设计避免重复创建、支持数量修改购物车本质是用户会话内的临时数据容器必须绑定到HttpSession而非HttpServletRequest请求级或全局静态变量线程不安全。关键原则Cart对象必须可序列化实现Serializable否则Tomcat集群环境下会话复制失败每次add/remove操作后必须调用session.setAttribute(cart, cart)因为Session存储的是对象引用修改Cart内部属性不会自动触发持久化Cart内商品项用MapInteger, Integer存储product_id → quantity比List更易去重和更新。// src/com/mall/cart/Cart.java package com.mall.cart; import java.io.Serializable; import java.util.HashMap; import java.util.Map; public class Cart implements Serializable { private static final long serialVersionUID 1L; private MapInteger, Integer items; // product_id - quantity public Cart() { this.items new HashMap(); } public void addItem(Integer productId, Integer quantity) { items.merge(productId, quantity, Integer::sum); // 累加数量 } public void removeItem(Integer productId) { items.remove(productId); } public Integer getQuantity(Integer productId) { return items.getOrDefault(productId, 0); } public MapInteger, Integer getItems() { return new HashMap(items); // 返回副本避免外部修改 } public int getTotalItems() { return items.values().stream().mapToInt(Integer::intValue).sum(); } }对应的Servlet处理加入购物车请求// src/com/mall/servlet/CartAddServlet.java WebServlet(/cart-add) public class CartAddServlet extends HttpServlet { Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String idStr req.getParameter(id); if (idStr null || idStr.trim().isEmpty()) { resp.sendError(HttpServletResponse.SC_BAD_REQUEST, 商品ID不能为空); return; } Integer productId Integer.parseInt(idStr); // 获取或创建购物车 HttpSession session req.getSession(true); Cart cart (Cart) session.getAttribute(cart); if (cart null) { cart new Cart(); session.setAttribute(cart, cart); } // 添加商品默认数量为1 cart.addItem(productId, 1); // 重定向回首页避免重复提交 resp.sendRedirect(req.getContextPath() /index.jsp); } }注意req.getSession(true)确保会话存在但不要在CartAddServlet里调用session.setMaxInactiveInterval()——这会影响整个会话超时应统一在web.xml中配置session-config session-timeout30/session-timeout !-- 单位分钟 -- /session-config3.2 订单生成与库存扣减JDBC手动事务的三步落地法下单是商城最核心的原子操作扣减库存 创建订单记录 清空购物车三者必须在一个事务中完成否则会出现“库存已扣但订单未生成”或“订单已建但库存未扣”的脏数据。Eclipse环境下务必关闭Connection的自动提交模式并显式控制commit/rollback// src/com/mall/servlet/OrderCreateServlet.java WebServlet(/order-create) public class OrderCreateServlet extends HttpServlet { Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { HttpSession session req.getSession(false); if (session null || session.getAttribute(cart) null) { resp.sendError(HttpServletResponse.SC_BAD_REQUEST, 购物车为空); return; } Cart cart (Cart) session.getAttribute(cart); MapInteger, Integer items cart.getItems(); if (items.isEmpty()) { resp.sendError(HttpServletResponse.SC_BAD_REQUEST, 购物车为空); return; } Connection conn null; PreparedStatement psOrder null; PreparedStatement psStock null; try { conn getConnection(); // 封装的获取连接方法 conn.setAutoCommit(false); // 关键关闭自动提交 // 步骤1插入订单主表 psOrder conn.prepareStatement( INSERT INTO orders (user_id, total_amount, status, create_time) VALUES (?, ?, ?, NOW()), Statement.RETURN_GENERATED_KEYS); psOrder.setInt(1, getCurrentUserId(req)); // 假设已登录从session取用户ID psOrder.setBigDecimal(2, calculateTotalAmount(items)); psOrder.setString(3, unpaid); psOrder.executeUpdate(); // 获取生成的订单ID ResultSet rs psOrder.getGeneratedKeys(); int orderId 0; if (rs.next()) orderId rs.getInt(1); // 步骤2插入订单明细表 扣减库存同一事务内 psStock conn.prepareStatement( UPDATE products SET stock stock - ? WHERE id ? AND stock ?); for (Map.EntryInteger, Integer entry : items.entrySet()) { int productId entry.getKey(); int quantity entry.getValue(); psStock.setInt(1, quantity); psStock.setInt(2, productId); psStock.setInt(3, quantity); // 确保库存充足才更新 int affectedRows psStock.executeUpdate(); if (affectedRows 0) { throw new RuntimeException(商品ID productId 库存不足无法下单); } } // 步骤3清空购物车 cart.getItems().clear(); session.setAttribute(cart, cart); conn.commit(); // 全部成功才提交 resp.sendRedirect(req.getContextPath() /order-success.jsp?orderId orderId); } catch (Exception e) { if (conn ! null) { try { conn.rollback(); } catch (SQLException ex) {} } req.setAttribute(errorMessage, 下单失败 e.getMessage()); req.getRequestDispatcher(/error.jsp).forward(req, resp); } finally { closeResources(psStock, psOrder, conn); } } private Connection getConnection() throws SQLException { return DriverManager.getConnection( jdbc:mysql://localhost:3306/mall_db?useSSLfalseserverTimezoneAsia/Shanghai, root, your_password); } }关键参数说明psStock.executeUpdate()返回受影响行数必须检查是否为1——若为0说明WHERE stock ?条件不满足即库存不足此时抛异常触发rollbackconn.setAutoCommit(false)必须在获取Connection后立即执行且不能遗漏closeResources()需按ResultSet → PreparedStatement → Connection逆序关闭防止资源泄漏。3.3 用户登录与会话校验用Filter拦截未登录请求避免绕过权限控制商城购买流程必须校验用户登录态否则任何人都能直接访问/order-create。Eclipse项目中Filter比拦截器更轻量、更可控// src/com/mall/filter/LoginCheckFilter.java WebFilter(urlPatterns {/cart-add, /order-create, /my-orders}) public class LoginCheckFilter implements Filter { Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request (HttpServletRequest) req; HttpServletResponse response (HttpServletResponse) resp; // 白名单登录页、注册页、首页、静态资源 String uri request.getRequestURI(); if (uri.endsWith(/login.jsp) || uri.endsWith(/register.jsp) || uri.endsWith(/index.jsp) || uri.startsWith(/static/)) { chain.doFilter(req, resp); return; } // 检查session中是否存在user对象 HttpSession session request.getSession(false); if (session null || session.getAttribute(user) null) { response.sendRedirect(request.getContextPath() /login.jsp); return; } chain.doFilter(req, resp); } }注意WebFilter注解要求Servlet版本≥3.0即Dynamic Web Module Version选4.0否则需在web.xml中配置filter-mappingrequest.getSession(false)不创建新会话避免未登录用户也生成无效session重定向路径必须用request.getContextPath()拼接否则部署到非根路径如/mall-shop时会跳转错误。4. Eclipse JavaWeb开发避坑指南5个让新手崩溃、老手也常翻车的硬核问题4.1 现象Eclipse启动Tomcat后浏览器访问http://localhost:8080/mall-shop/显示404但Console里没有报错原因项目未正确部署到Tomcat的webapps目录常见于Deployment Assembly配置错误或项目名称含空格/中文。Eclipse的Servers视图中双击Tomcat服务器 → Overview → Modules列表里mall-shop的Path必须是/mall-shop不是/或空且Deploy Path列显示/mall-shop。若显示/说明Context Root被改成了根路径需右键模块 → Edit → 修改Path为/mall-shop。解决右键Servers下的Tomcat → Clean… → 重启检查Servers/Tomcat v9.0 Server at localhost-config/server.xml中Host节点内是否有Context标签误配删除workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/mall-shop目录后重启。4.2 现象JSP页面中% rs.getString(name) %报NullPointerException但数据库查询语句在Navicat中能正常执行原因MySQL Connector/J 8.0默认开启zeroDateTimeBehaviorEXCEPTION当表中存在0000-00-00日期值时ResultSet会抛异常导致rs为null或字段名大小写不匹配MySQL在Linux下区分大小写Windows不区分但JDBC驱动严格按SQL定义的列名返回。解决在JDBC URL末尾追加zeroDateTimeBehaviorconvertToNull用rs.getString(NAME)或rs.getString(name)前先打印rs.getMetaData().getColumnName(2)确认实际列名或改用rs.getObject(name, String.class)规避类型转换问题。4.3 现象购物车添加商品后刷新页面数量归零或不同浏览器登录同一账号显示不同购物车原因HttpSession未正确绑定到用户常见于两种情况一是session-configcookie-http-onlytrue/cookie-http-only/session-config开启后前端JS无法读取session cookie但此配置不影响服务端二是Eclipse的Servers配置中Tomcat的Use workspace metadata选项被勾选导致多个项目共享同一session存储区。解决在Servers视图中双击Tomcat → Overview → 下方“Publishing”区域取消勾选Use workspace metadata检查web.xml中session-config是否设置了tracking-modeCOOKIE/tracking-mode推荐避免URL重写泄露session ID确认浏览器未禁用Cookie。4.4 现象订单创建时conn.commit()后MySQL中订单表有记录但商品库存未扣减原因事务隔离级别问题。MySQL默认REPEATABLE READ级别下UPDATE products SET stock stock - ? WHERE id ? AND stock ?可能因MVCC机制读取到旧快照导致库存检查通过但实际更新失败。更隐蔽的是psStock.executeUpdate()返回0但未被捕获程序继续执行commit。解决在catch块外增加if (affectedRows 0)显式判断将事务隔离级别提升至READ COMMITTED在getConnection()中执行conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED)或改用SELECT ... FOR UPDATE先行锁定商品行。4.5 现象Eclipse中修改JSP后刷新页面无变化必须重启Tomcat才生效原因Tomcat的JSP热加载机制被禁用或Eclipse的自动构建未启用。Eclipse默认开启Build Automatically但若手动关闭过或项目Properties → Builders中取消了Java Builder则class文件不会自动生成。解决菜单栏Project → Build Automatically打钩右键项目 → Properties → Project Facets → 确认Dynamic Web Module Version为4.03.1及以下版本JSP热加载不稳定在Servers视图中双击Tomcat → Modules → 选中mall-shop → Edit → 勾选Auto reload enabled最后在Servers/Tomcat v9.0 Server at localhost-config/context.xml中添加Context reloadabletrue/。5. 调试与验证技巧用Eclipse Debug透视图定位JavaWeb请求链路断点比日志快10倍5.1 在Servlet入口处设置断点观察request和session的完整生命周期Eclipse的Debug模式是JavaWeb调试的终极武器远胜于System.out.println。以CartAddServlet为例在doGet方法第一行String idStr req.getParameter(id);左侧空白处单击设置断点右键项目 → Debug As → Debug on Server浏览器访问http://localhost:8080/mall-shop/cart-add?id1Eclipse自动进入Debug透视图此时Variables视图中展开req→parameters→map可直接看到id1展开session→attributes确认cart对象是否存在及内部items内容按F6逐行执行观察cart.addItem()后itemsMap是否新增键值对切换到Breakpoints视图右键断点 → Breakpoint Properties → 勾选Hit count设为10实现“第10次请求才中断”避免频繁打断。关键技巧在Variables视图中右键变量 →New Detail Formatter可自定义对象toString输出格式。例如为Cart添加格式Cart{size items.size() , total getTotalItems() }避免展开大Map浪费时间。5.2 使用Expression视图动态执行代码实时验证业务逻辑Expression视图Debug透视图右上角允许在断点暂停时输入任意Java表达式并立即求值。例如输入req.getSession().getAttribute(cart)查看当前购物车对象输入((Cart)req.getSession().getAttribute(cart)).getItems().keySet()列出所有商品ID输入new java.text.SimpleDateFormat(yyyy-MM-dd HH:mm:ss).format(new java.util.Date())生成当前时间字符串用于日志标记。这比修改代码→保存→重启→等待→再看日志快得多。特别适合验证复杂条件items.entrySet().stream().anyMatch(e - e.getKey() 1 e.getValue() 10)——检查商品1的购买数量是否超限。5.3 用Database Explorer透视图直连MySQL对比前后端数据一致性Eclipse自带Database Explorer需安装Data Tools Platform插件可免开Navicat验证数据。操作Window → Show View → Other → Database Development → Database Explorer → 右键 → New Connection → MySQL → 填写host/port/database/user/password → Test Connection。连接成功后展开mall_db→products表 → 右键 →Execute SQL Script粘贴SELECT * FROM products WHERE id1确认库存初始值下单后再次执行该SQL观察stock是否扣减同时在Debug模式下将鼠标悬停在psStock变量上Eclipse会显示其SQL语句和参数绑定值如UPDATE products SET stock stock - ? WHERE id ? AND stock ? [1, 1, 1]与数据库实际执行的语句完全一致杜绝“我以为扣了但其实没执行”的幻觉。5.4 验证HTTP状态码与响应头揪出302重定向丢失参数的玄学问题JavaWeb中resp.sendRedirect()是302重定向浏览器会丢弃POST body但有时需传递参数。Eclipse的Network Monitor需安装Eclipse Marketplace中的“Eclipse Web Developer Tools”可捕获完整HTTP流启动Debug后打开浏览器开发者工具F12→ Network标签触发下单操作找到order-create请求点击 → Headers → Response Headers确认Location: /mall-shop/order-success.jsp?orderId123若Location值为/order-success.jsp?orderId123缺少上下文路径说明代码中用了response.sendRedirect(/order-success.jsp?...)而非response.sendRedirect(request.getContextPath() /order-success.jsp?...)在Preview标签页可直接查看重定向后页面的HTML源码确认orderId参数是否被正确解析。血泪经验曾有个项目因request.getContextPath()返回空字符串导致所有重定向路径错误。根源是Eclipse Servers配置中项目Deploy Path被设为/而非/mall-shop。解决方案不是改代码而是修正Deployment Assembly——这印证了那句话JavaWeb的90%问题不在代码里在Eclipse的配置里。希望帮到你。本文还有配套的精品资源点击获取
返回列表