JavaWeb商城项目实战拆解:Servlet+JSP+JDBC从购物车到支付回调
简介基于Eclipse开发的JavaWeb在线购物商城项目源码面向初级Java开发者适合系统学习Servlet、JSP、JSTL、JDBC以及MVC分层设计也可作为毕业设计或课程项目的二次开发起点。资源包共1122个文件压缩后约8.52MB除Java类与JSP页面外还包含大量HTML、CSS、JavaScript前端文件以及GIF、PNG、JPG图片素材同时提供配置文件、SQL数据库脚本和Eclipse工程文件整体结构覆盖商品后台管理、前台展示与购物车交互等典型模块。目前已有2078人学习参考。项目当前重点实现了商品浏览、购物车管理、用户登录注册等基础电商功能代码按Model、View、Controller分层组织注释清晰目录划分明确在Eclipse内置Tomcat环境下即可直接部署运行。通过阅读源码可熟练掌握JavaWeb请求处理流程、数据库访问封装、会话状态管理以及简单的安全编码实践在此基础上还可进一步扩展订单处理、支付接口、后台权限控制等功能非常适合作为电商项目的实战练手与功能完善的蓝本。1. JavaWeb商城到底值不值得拆一口能从Servlet啃到支付回调的实战锅JavaWeb商城在Eclipse里跑通之后你会发现自己突然能看懂网上那些花里胡哨的电商系统了——商品列表、商品详情、购物车、下单、模拟支付回调这一整条链路全是ServletJSPJDBC的老三样在扛。它最值钱的地方恰恰是没上Spring Boot这些现代框架请求怎么进Tomcat、Servlet怎么转发、Dao怎么查库、JSP怎么渲染每一步都摆在明面上。对刚学完JavaWeb基础、准备做毕设起步的人来说把它从Eclipse里导进来跑一遍比抱着SSM教程空看三个月都顶用。适合谁适合手里有一堆零散知识点、想串成一条完整业务线的人也适合想拿真实项目练二次开发手感的初级开发者。核心就一句话用它把网上购物系统从概念变成能点能买的东西。2. 从class文件反推项目结构Servlet、Dao、工具类各自守哪块阵地拿到这份资源你第一眼看到的不是源码而是一堆编译后的class文件和几个css备份文件。这反而是好事——文件名把项目骨架全暴露了。我从这些名字里挑几条典型的出来拆给你看讲清楚这套商城是怎么分层、怎么流转的。2.1 文件清单暴露出的技术栈与分层方式清单里值得先注意的是三类文件。第一类是PrivilegeServlet.class、ProductServlet.class、AdminProductServlet.class这仨是典型的Servlet控制器命名方式。PrivilegeServlet管权限判断ProductServlet管前台商品查询和详情AdminProductServlet管后台商品管理一个Servlet对应一类业务动作非常传统的MVC写法。第二类是PrivilegeDaoImpl.class和ProductDaoImpl.class命名后缀Impl说明接口和实现分离这是从JDBC操作里抽出来的数据访问层但注意——项目里没有出现Service层说明这套代码是早年常见的Servlet直接调Dao结构少一层抽象对新手来说反而是优点调用链短好跟。第三类是PaymentUtil.class、CheckImgServlet.class、CallbackServlet.class这三个名字一露出来项目的功能边界就清楚了不仅支持商品浏览和购物车还带验证码和模拟支付回调。MVC分层在Eclipse里的物理结构也跟这些文件一一对应。ProductServlet.class和PrivilegeServlet.class编译后进WEB-INF/classes对应Controller层ProductDaoImpl.class对应Model层的数据访问实现JSP页面放在WebContent根目录下对应View层。没有Service层、没有XML配置的Spring容器连web.xml都是最朴素的Servlet映射方式。这套结构放到现在看确实老但它把一个请求从浏览器到Servlet再到Dao再回JSP的完整路径压到了最短对想搞清楚黑匣子里到底是什么的初学者来说这种直白正是它最大的教学价值。2.2 购物车链路Session临时存储与Dao层持久化的分界购物车是这套商城的核心功能实现方式在清单里也有迹可循。没有出现CartServlet这种独立控制器但结合常见的JavaWeb商城写法加购动作一般走ProductServlet或专门的购物车Servlet用户点加入购物车Servlet从Session里取出购物车对象没有就新建一个放进Session然后往购物车对象里塞商品条目。这里判断加购的逻辑就是看Session里有没有一个叫cart的属性有就更新数量和金额没有就session.setAttribute(cart, new Cart())。这样做的好处是天然隔离用户每个会话的购物车互不干扰坏处也明显——用户一关浏览器Session结束购物车就没了。在这样一套教学项目里购物车数据放Session不算偷懒而是刻意为之目的是把状态存储这件事讲清楚。等你后面做二次开发再决定要不要把购物车内容拆到Cookie或数据库里。清单里ProductDaoImpl.class干的是另一件事从数据库把商品表的数据捞出来填进商品对象再放进购物车条目。也就是说商品的静态信息走Dao层从MySQL里取购物车的临时状态走Session在内存里存两层各管一段改数据源的时候不会互相污染。这也是这套代码值得照着写一遍的关键它能让你分清哪些数据需要持久化哪些数据临时放会话里就够了。// 购物车在Session中的典型存取逻辑对应ProductServlet中的加购动作 HttpSession session request.getSession(); Cart cart (Cart) session.getAttribute(cart); // 从Session拿购物车 if (cart null) { cart new Cart(); // 第一次加购新建购物车 session.setAttribute(cart, cart); // 存回Sessionkey必须统一 } // 根据商品id查商品信息这里省略Dao层调用细节 Product product productDao.findById(productId); // 商品信息走Dao层不走Session cart.addItem(product, count); // 把商品塞进购物车条目这段逻辑有三个点值得记一下。第一Session的key别写乱cart这个字符串在存和取的地方必须完全一致大小写错了就出现购物车明明加了东西下一页就没影了的玄学问题。第二加购时从Session取、从Dao查两个数据源分工明确商品详情宁可每次都查库也不放Session是为了保证商品价格和库存是最新的。第三购物车对象放Session里存的是引用所以同一会话的多个请求之间是共享的这是Session机制本身保证的不需要你额外做同步。2.3 支付与回调PaymentUtil和CallbackServlet的前后端配合这套商城能跑通购买闭环靠的不是真的接第三方支付而是PaymentUtil和CallbackServlet配合出来的模拟支付回调。教学项目里这是标配用户下单后跳到一个支付页面页面提交参数给一个模拟支付网关通常是写死的一个Servlet地址网关处理完以后回调CallbackServlet回调里带着订单号、支付金额、签名这些参数项目拿到参数后验签验签通过就把订单状态改成已支付。PaymentUtil这个类干的就是签名生成和校验的脏活它接收一个装着订单参数和密钥的Map按约定的规则拼接成一个字符串再对这个字符串做HmacSHA1运算得出一个签名串。回调那边收到同样的参数重新算一遍签名两个串一致就说明参数没被人动过。// PaymentUtil中签名生成的核心逻辑参数拼串 HMAC运算 public static String buildHmac(String[] params, String secretKey) { StringBuilder sb new StringBuilder(); for (String param : params) { if (param ! null param.trim().length() 0) { // 空值不参与签名 sb.append(param); } } return DigestUtils.hmacSha1Hex(secretKey, sb.toString()); // 工具类封装返回十六进制签名 }这里最容易看蒙的是参数顺序。签名拼接时参数顺序必须和支付网关那边约定好前后端任意一边换了拼接顺序签名就对不上回调就验签失败订单就一直停留在待支付状态。实际排查的时候最快的办法是在CallbackServlet里把收到的参数原样打印出来跟支付页提交的参数顺序逐一比对。另外一个值得注意的点是这种教学模拟支付里密钥通常是写死在常量类或配置里的二次开发接真实支付时密钥一定要挪到服务端配置文件里绝不能让前端页面接触到这是安全底线。回调验签通过后的动作也简单拿订单号更新订单表的支付状态字段再重定向到支付成功页面整个购买闭环就走完了。3. Eclipse导入到浏览器跑通建库、配Tomcat、调上下文路径项目结构看明白了下一步就是把它在Eclipse里跑起来。这一步翻车率不低但大多是环境配置问题不是代码问题。这一章给你一套能一次跑通的步骤每一步都带参数说明。3.1 环境对齐JDK、Tomcat、Eclipse三者的版本匹配导入前先确认三件套的版本别上来就配。这个项目不是Maven工程是传统的Dynamic Web Project所以它对Eclipse版本不挑但Tomcat和JDK的匹配关系必须注意。JDK用8或者11都行关键是Tomcat的版本要和JDK对应JDK 8配Tomcat 8.5或者9.0JDK 11配Tomcat 9.0别上来就装Tomcat 10因为Tomcat 10把包名从javax.*换成了jakarta.*这套代码里的Servlet和JSP全是老的javax.servlet开头装Tomcat 10跑起来直接一片404或者ClassNotFound属于最常见的环境和代码不匹配翻车。Eclipse方面用Eclipse IDE for Enterprise Java and Web Developers版本别用基础的Java SE版那里面没有Web工具插件新建Dynamic Web Project的入口都没有。Eclipse自带的和Tomcat的集成方式是通过Server视图添加一个Tomcat运行时把项目添加到Server上再启动这样Eclipse会在内部把项目部署到wtpwebapps目录下而不是你手工往Tomcat的webapps里拷。这个区别很重要因为很多人习惯把项目文件夹直接丢进webapps然后去访问localhost:8080/项目名结果页面出来了但样式全丢——因为它没经过Eclipse的部署机制上下文路径和资源路径对不上。3.2 从零导入先建空项目再把源码合并进来导入这份项目有个建议步骤不要用Eclipse的Import菜单直接选文件夹因为这套资源里只有class文件和部分配置文件源码文件、JSP、CSS是不是齐全你一眼看不出来直接Import一个残缺结构进来后面报错会非常难查。我一般习惯这样干先新建一个干净的Dynamic Web Project把项目名定成shop然后把这套资源里的src目录、WebContent目录内容分别拷进新项目的对应目录里。拷完以后再让Eclipse重新编译一遍而不是直接信任那批class文件。# 以Windows环境为例把资源里的源码目录和页面目录合并进新建的项目 # 新建Dynamic Web Project时项目名填 shop不要填带空格的名称 # WebContent目录对应Eclipse项目里的src/main/webapp老项目结构就是WebContent xcopy /E /Y 资源目录\src D:\workspace\shop\src xcopy /E /Y 资源目录\WebContent D:\workspace\shop\WebContent这样做的目的是强迫Eclipse用源码重新编译把原来那批class文件覆盖掉。需要注意拷完以后要立刻在Eclipse里对着项目根目录按F5刷新让Eclipse感知到新增文件然后Project - Clean...清理一次让全部Java文件重新编译。如果你直接沿用旧class文件会出现一个特别坑的现象你改了Java源码Tomcat跑的还是class文件里那套老逻辑页面怎么动都没反应。这也是这套资源带了一堆class文件最容易埋的坑手工拷入后必须走一遍重新编译千万别省。3.3 数据库建表与JDBC连接参数落到哪项目跑起来前数据库必须先建好。这套商城至少需要商品表、用户表、订单表、订单项表、分类表这几张核心表数据源配置一般写在JDBCUtils工具类或者c3p0-config.xml配置文件里。如果你在源码里找不到配置文件那就去src目录下翻一个工具类里面通常硬编码了连接地址、用户名、密码三项配置。建表SQL不用多复杂字段齐了就行下面给你一份最能满足这套代码查询逻辑的最小表结构。-- 商品表商品id、名称、价格、库存、图片路径 CREATE TABLE product ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(100) NOT NULL, price DECIMAL(10,2) NOT NULL, pnum INT DEFAULT 0, imgurl VARCHAR(200) DEFAULT NULL, cid INT NOT NULL ) ENGINEInnoDB DEFAULT CHARSETutf8; -- 订单表订单id、下单用户、总金额、订单状态 CREATE TABLE orders ( id VARCHAR(36) PRIMARY KEY, uid INT NOT NULL, money DECIMAL(10,2) NOT NULL, status INT DEFAULT 0 ) ENGINEInnoDB DEFAULT CHARSETutf8; -- 订单项表订单和商品的关联数量与单价 CREATE TABLE orderitem ( id INT PRIMARY KEY AUTO_INCREMENT, oid VARCHAR(36) NOT NULL, pid INT NOT NULL, count INT DEFAULT 1 ) ENGINEInnoDB DEFAULT CHARSETutf8;建完表以后JDBC连接串的参数是另一个高频翻车点。MySQL 5.7和8.0的配置不一样如果数据库是MySQL 8.0连接串里必须带serverTimezoneAsia/Shanghai和useSSLfalse否则驱动报时区错误。连接串的完整长相是这样String url jdbc:mysql://localhost:3306/shop?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai;这段里characterEncodingutf8是保页面中文不乱码的关键useSSLfalse是避开MySQL 8.0的SSL握手告警serverTimezone是指定时区。这三个参数缺一个轻则告警刷屏重则直接连接超时。驱动jar包别放错位置必须丢到WebContent/WEB-INF/lib目录下Eclipse会自动把它加进部署清单。你要是图省事把它扔到Tomcat的lib目录里本地能跑但项目一换机器部署类就找不到了报ClassNotFoundException属于给自己埋雷。3.4 部署启动与访问路径验证全部配置完成后在Eclipse的Servers视图里启动Tomcat然后在浏览器访问http://localhost:8080/shop/index.jsp。注意这里项目名是shop上下文路径默认就是项目名。如果访问localhost:8080/看到的是Tomcat默认首页说明项目没部署上或者上下文路径不对。项目成功启动的标志是首页能加载出CSS样式和商品图片而不是一片裸HTML。验证第二个入口是验证码访问http://localhost:8080/shop/checkImg浏览器里应该能直接看到一张图片如果看到404去web.xml里查CheckImgServlet的url-pattern是不是写的/checkImg路径不匹配就是这个现象。第三个入口是后台管理访问AdminProductServlet映射的URL能进后台说明权限过滤器没把你的IP拦掉。这三个入口逐个能开这套商城就跑通了。4. 避坑指南跑这套JavaWeb商城最常见的五处翻车点资源本身没问题但跑这套东西的时候我见过太多人在同一个坑里反复横跳。挑五个高频翻车点按现象、原因、解决的顺序写清楚你照着对号入座。4.1 404爆一片编译class与源码不同步现象是浏览器访问某个Servlet路径直接404但代码里明明有这个Servlet。这种情况十有八九是Tomcat加载的还是旧的class文件源码改了没重新编译或者你直接把资源里的class文件拷进了项目覆盖了Eclipse刚编译出来的版本。解决的办法是Project菜单点 Clean选你这个项目让它把所有class删掉重新编译然后在Servers视图里对Tomcat右键Clean一次把部署目录清掉最后再重新启动。这套动作的顺序不能乱先清项目编译产物再清Tomcat部署目录否则旧class还会被拷回去。4.2 样式全崩占位CSS文件里的.bak备份被当成了宝现象是页面能打开但所有样式全军覆没字体、颜色、布局全裸奔控制台里一片404。翻资源清单你会发现有两个文件叫shop_header.css.bak和shop_common.css.bak这两个是样式表的备份。很多人图省事把JSP里link标签的地址从.css改成了.css.bak或者CSS目录下原有的.css文件丢失了JSP引用的地址解析不到浏览器就直接放弃加载样式。解决的办法把.bak后缀去掉恢复成shop_header.css和shop_common.css然后进JSP检查link标签的href是不是用了绝对路径。正确写法是href${pageContext.request.contextPath}/css/shop_common.css别写死成/shop/css/...上下文路径一换项目名就404。4.3 验证码点烂了也不出图CheckImgServlet被路径坑了现象是登录页和注册页的验证码图片是个裂图标右键图片属性能看到地址但访问就是404。原因基本锁定在web.xml里Servlet映射和页面img标签的src对不上。很多教学项目里图片的src直接写死成/checkImg但你的项目上下文路径是/shop正确src是/shop/checkImg。另外一个隐蔽原因如果项目里有权限过滤器过滤器拦截了所有路径但没放行/checkImg验证码请求会被拦下来也会出现这个现象。解决先把图片src改成带上下文路径的形式再看过滤器有没有排除这个URL。4.4 JDBC连不上驱动jar放错目录的典型症状现象是点商品列表或者登录的时候页面卡一会儿然后报ClassNotFoundException或Communications link failure。第一行报错如果是ClassNotFoundException: com.mysql.jdbc.Driver说明驱动jar没在classpath里如果是Communications link failure说明连接参数或者网络有问题。解决驱动jar必须放在WebContent/WEB-INF/lib下放src目录里不会被打包进部署目录。MySQL 8.0的驱动类名是com.mysql.cj.jdbc.Driver不是老版的com.mysql.jdbc.Driver这个换版本的时候最容易踩。还有一个隐蔽坑如果你在Eclipse里改了lib目录必须重启Tomcat因为Web应用在启动时才会加载jar运行时往lib里扔jar是不会生效的。4.5 订单支付一直停在待支付回调验签对不上现象是模拟支付页面跳转正常但支付完回到商城订单状态还是未支付数据库里看订单表的status字段一直是0。原因有两点第一是支付请求里的参数顺序跟PaymentUtil里签名拼接的顺序不一致验签失败后代码直接return不更新订单状态第二是回调参数里某个字段为null比如订单号在Session里丢了回调拿不到正确的关联id更新操作就落空。解决的办法在CallbackServlet的入口处加一行日志把收到的所有参数打出来跟支付页提交的参数对比重点看参数顺序和空值。签名算法本身不用改多数情况是参数顺序乱套。5. 进阶把骨架改造成淘宝式商城的三步硬操作跑通只是起点这套源码真正的价值是当跳板。三个最值得动手的方向购物车持久化、订单状态机、支付回调日志化。先从购物车动手这是改动性价比最高的部分。// 从Session购物车迁移到Cookie购物车的核心思路把Json数据塞进Cookie String cartJson new ObjectMapper().writeValueAsString(cart); Cookie cookie new Cookie(cart, URLEncoder.encode(cartJson, UTF-8)); cookie.setMaxAge(7 * 24 * 3600); // 7天有效期用户关浏览器购物车还在 cookie.setPath(request.getContextPath() /); response.addCookie(cookie);迁移的原理一句话就能讲清Session购物车的生命周期绑定在服务端会话上用户清缓存换设备就没影了Cookie购物车把数据写在浏览器端设置setMaxAge以后即使浏览器关掉再打开购物车也能通过Cookie里的Json恢复。代价是Cookie有4KB的大小限制放二十个商品没问题再多就得截断或者升级成数据库方案。Cookie方案的优势是服务端不存购物车数据多台服务器部署时不需要做Session共享这在本地练习时没感觉但如果你以后部署到多节点环境你会发现这一步提前帮你绕开了最大的分布式坑。订单状态机改造是第二个突破口。现在代码里status字段是int0待支付、1已支付、2已发货、3已收货你得在订单表上加个时间字段记录下来每个状态变更的时刻然后在CallbackServlet里支付成功后不仅更新状态还写一条流水日志。这个流水日志以后就是你排查纠纷的最强证据也是商城类项目面试时能拿出手的亮点。回调日志化更简单在CallbackServlet里把收到的完整参数加上时间戳写进日志文件做二次开发接真实支付时你就会感激这一步的救命之恩。最后一个动手点是把硬编码的数据库连接串和支付密钥抽到配置文件里。在src目录新建db.properties和pay.properties用Properties工具类加载别让密码散落在Java代码里。这一步做完你才算真正理解了资源文件在JavaWeb里的作用。从那以后我每次拿到新项目第一件事不是跑起来而是先把配置文件翻一遍确认数据库和密钥没有硬编码在代码里这个习惯帮我省掉了无数个换台电脑就崩的尴尬希望帮到你。本文还有配套的精品资源点击获取