JavaWeb购物商城毕业设计全流程:JSP+Servlet+MySQL实战解析
简介基于JavaWeb的购物商城毕业设计项目是一套适合Java初学者和毕业设计学生的完整实战资源。项目遵循MVC分层思想通过Servlet处理请求、JSP生成动态页面并使用JDBC完成数据库操作覆盖用户注册登录、商品展示、购物车与订单管理等核心模块。压缩包内共130个文件包含45张PNG界面截图、17个JSP页面、11个Java源码与对应class文件、10个Jar依赖库以及部署教程、演示图片和数据库脚本整体约19.3MB目录结构清晰。已有233人学习下载借助项目说明和部署文档读者可以快速搭建运行环境深入理解前后台交互与数据持久化流程从环境配置到代码阅读从界面展示到逻辑实现均能获得具体参考。项目内的SQL脚本可直接导入数据库配合部署教程即可完整演示购物流程适合用于毕业设计参考或JavaWeb技术巩固。1. 基于JavaWeb的购物商城毕业设计先搞清这个zip里装的是什么每年答辩季都会有一批“基于JavaWeb的购物商城(毕业设计).zip”在同学之间流转。这类压缩包解压后通常是一个以JSPServletMySQL为技术栈的Maven工程里面包含用户注册登录、商品列表、购物车、下单支付多半是模拟支付这一整条业务链路。它真正的价值不是把界面做得多好看而是用JavaWeb最基础的一套技术把一个商城该有的核心流程完整串起来。适合用它的人也很明确需要交课设或毕设的Java方向学生以及刚学完Servlet、想看看完整项目长什么样的初级开发者。不需要Spring Boot基础不依赖微服务只要会开IDEA和MySQL就能往下走。2. JSPServletMySQL为什么这套组合在毕业设计里依然是主流2.1 选型对比JSPServlet和其他方案差在哪很多同学解压前会先问一句怎么不用Spring Boot这个问题在毕业设计里很常见但答案多半是题目上写着“JavaWeb”验收老师就是按Servlet/JSP这一条线来提问的。你用一个Spring Boot的商城去答“请描述一次完整的HTTP请求处理过程”反而把自己绕进自动配置的黑匣子里问两句就答不上来。JSPServlet的好处是每一层都能在代码里肉眼可见浏览器发请求Servlet接收Service处理DAO查库再回填到JSP。整条链路没有框架帮你偷偷干活的环节这正是答辩现场最好讲的素材。反过来说这套组合的缺点也明显没有自动装配没有声明式事务每个DAO方法都要手写JDBC模板页面还要用JSP标签。但对一个以“检验JavaWeb基础”为目标的毕业设计来说这些缺点恰恰是评分点。如果项目本身已经足够完整导师通常不会要求你强行上Spring Boot。你可以去搜一下市面上的JavaWeb项目完整案例十个里八个是MySQL做持久层因为这套组合资料多、报错好查、任何一个环节卡住了都能搜到帖子。维度JSPServletMySQLSSMSpring Boot学习成本低课本内容中需要理解Spring容器门槛低但黑匣子多答辩讲点每行代码都能讲讲IOC/AOP/Mapper讲自动配置/微服务依赖复杂度一个Tomcat加驱动即可需要Spring全家桶依赖依赖多且版本敏感适合场景JavaWeb课设与毕设框架课课程设计企业实习或项目实训如果你之前跟着黑马JavaWeb笔记敲过代码你会发现这里面的项目分层、SQL脚本、包命名方式基本是一脉相承的。所以这套选型不是什么过时技术而是JavaWeb课设和毕设约定俗成的“标准答案”。2.2 包结构与三层架构按这个结构读代码半天就能理完拿到项目第一件事不是点运行而是先看包名。只要是结构规范的JavaWeb商城包基本逃不出这几个com.shop ├── pojo // 实体类User, Product, Orders, OrderItem ├── dao // 数据访问层UserDao, ProductDao, OrderDao ├── service // 业务层UserService, CartService, OrderService ├── web // 表现层LoginServlet, RegisterServlet, ProductServlet ├── filter // 过滤器LoginFilter, EncodingFilter └── util // 工具类DBUtil, MD5Util, PageBean为什么毕设项目都这么摆因为这正好对应三层架构web负责接收请求和响应service负责业务规则dao负责SQL。你在读代码时要记住一个口诀请求从右上往左下走数据从左下往右上回。用户在index.jsp点“登录”表单提交到LoginServletLoginServlet调UserServiceUserService里调UserDaoUserDao用JDBC查user表查到的User对象再一层层返回最终塞进session页面跳回首页。整个过程没有任何一步是跳层调用的这点在答辩时也是加分项。提示如果工程里没有service层直接在Servlet里写JDBC那这个项目基本属于“能跑但结构差”的范畴自己私底下用可以拿去答辩容易被问倒。反过来如果包里多了controller、mapper这些目录说明项目其实不是标准的Servlet工程导入和配置方式会不一样要按Maven里实际的框架来。2.3 数据库表设计商城最少需要哪几张表购物商城的核心是商品和订单而订单和商品是多对多的关系所以必须拆成订单表和订单明细表。再算上用户最少四张表起步。如果购物车要求“下次登录还在”还得再加一张购物车表很多毕设的购物车直接存在session里那就不需要这张表。一张经典的MySQL库表结构大概是这样的userid、username、password、nickname、phone、create_timeproductid、name、price、stock、image、description、category_idordersid、order_no、user_id、total_price、status、create_timeorder_itemid、order_id、product_id、product_name、price、quantityorders和order_item为什么要拆两张表因为你买三样东西如果塞在一张表里订单号、收货人这些字段就得重复三遍对账和改状态都麻烦。拆开后一张订单对应多行明细order_item里的product_name和price是下单那一刻的快照即使以后商品价格变了历史订单也不受影响。这个细节如果能在答辩时主动讲出来老师会认为你真的理解了这个项目而不是只会点运行。字段命名上建议全部用下划线小写。如果压缩包里带的是.sql文件你先别急着双击导入打开看一眼表名是否和java代码里的一致。我见过不少项目源码和SQL对不上多半是有人改过字段名但忘了同步脚本这种情况后面跑起来必报错。3. IDEA运行JavaWeb项目配置从压缩包到浏览器能访问的四个步骤3.1 解压后先判断工程类型Maven工程还是普通Web工程拿到zip后先解压看根目录有没有pom.xml。有pom.xml就是一个Maven工程用IDEA导入时选pom.xml作为项目文件只有src和web.xml的是普通Web工程需要新建Web项目后把src拷进去。两种方式配置区别不小这里先讲Maven工程这是现在最常见的。IDEA里的导入步骤File → New → Project from Existing Sources选中解压目录选择Maven勾选“Search for projects recursively”一路Next。导入后IDEA会自动下载依赖如果下不动把Maven的settings.xml里镜像切到阿里云这是国内开发环境的基本操作。打开Project Structure快捷键CtrlShiftAltS检查Project SDK是否为1.8或更高Modules里Language level和SDK保持一致。如果项目在别人机器上是用Eclipse写的这里还可能出现Artifact为空的情况需要手动加一个Web Artifact。这一步是idea运行javaweb项目配置里最容易卡住的地方很多人点了运行按钮发现没有可运行的选项就是因为Artifact没建。3.2 初始化MySQL数据导入SQL并改好连接配置找一下压缩包里有没有.sql文件通常叫shop.sql或mall.sql。用Navicat或命令行创建数据库后执行导入mysql -uroot -p123456 -e create database shop default charset utf8mb4; mysql -uroot -p123456 shop shop.sql导入完成后不要着急跑项目先改连接配置。连接信息一般写在src/main/resources下的jdbc.properties或db.properties里jdbc.drivercom.mysql.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/shop?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai jdbc.usernameroot jdbc.password123456注意这四行的写法。前三行都好理解第四行密码一定改成你自己MySQL的密码。URL里的useUnicode、characterEncoding、serverTimezone三个参数现在基本算标配不设编码会中文乱码不设时区在MySQL 8.0下会直接报错“The server time zone value”。驱动类名的坑后面会细说MySQL 8.0的驱动类名是com.mysql.cj.jdbc.Driver如果你的项目里是com.mysql.jdbc.Driver可以先用着但最好确认lib里的jar版本。3.3 配置Tomcat并选择war exploded回到IDEA运行配置。Run → Edit Configurations点号选择Tomcat Server → Local在Deployment选项卡里点击号选择Artifact。这里有两个选项war和war exploded。本地调试一定要选war exploded它的意思是把编译产物直接解压到Tomcat的webapps里改完代码热部署速度极快选war会让Tomcat每次重新解压启动慢还容易因为缓存出莫名其妙的问题。Application context建议设成/shop这样访问地址就是http://localhost:8080/shop。如果你的项目里有会话路径写死过/login这样的绝对路径Application context改掉之后这些路径全部会失效这属于另一个经典坑后面会提。Tomcat的端口默认8080如果被占用在Server选项卡里改HTTP port并把“After launch”的URL对应改掉。这一步不用动系统环境变量IDEA会在Run里自动带上CATALINA_BASE的配置别像以前老教程一样去配CATALINA_HOME。3.4 最小启动步骤从命令行构建到浏览器验证如果是Maven工程建议在启动Tomcat前先手工构建一次这样能把编译错误和依赖缺失暴露在IDE之外cd 你的项目目录 mvn clean package -DskipTests构建成功后target目录下会多出一个war包或war exploded目录。执行这个命令时看最后一段输出出现“BUILD SUCCESS”就说明项目本身能编译通过如果在这里就报错那后面启动Tomcat也必然失败不用继续。接着启动Tomcat看Console日志滚到“Server startup in …”这一行再访问http://localhost:8080/shop。第一次访问看到首页即通关看到报错页面就按第5章的排查清单来。到这里一个JavaWeb购物商城的基础运行链路已经打通。但能打开首页只是第一步真正麻烦的是那几个核心业务流程。4. 把四个核心模块逐个拆开登录、商品、购物车、订单4.1 登录注册与Session用Filter拦住未登录用户购物商城的登录模块表面上是比对用户名密码实际上还有两条隐藏需求密码不能明文存库、未登录不能进后台。密码加密用MD5加盐毕业设计做到这一步就算交代得过去了。// LoginServlet.java 核心逻辑 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding(UTF-8); String username req.getParameter(username); String password req.getParameter(password); UserService userService new UserService(); User user userService.login(username, MD5Util.md5(password shop_salt)); if (user null) { req.setAttribute(msg, 用户名或密码错误); req.getRequestDispatcher(login.jsp).forward(req, resp); } else { HttpSession session req.getSession(); session.setAttribute(user, user); resp.sendRedirect(index.jsp); } }这个方法的逻辑是取请求参数把密码加盐哈希后交给Service层返回User对象就说明数据库里存在这条记录则写入session并重定向返回null则把错误信息带回登录页。注意最后一步我用了sendRedirect而不是forward原因是登录成功后要刷新地址栏为首页地址避免用户按F5时重复提交登录表单。密码加盐的“shop_salt”是写死在本项目里的常量实际产品里应该是随机盐存库但毕业设计用固定盐也比裸存MD5强很多。光改登录还不够要保证未登录用户访问不了购物车和订单页得加一个Filter// LoginFilter.java 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.contains(login) || uri.endsWith(.css) || uri.endsWith(.js)) { chain.doFilter(req, resp); return; } if (request.getSession().getAttribute(user) null) { response.sendRedirect(request.getContextPath() /login.jsp); return; } chain.doFilter(req, resp); }Filter的关键是放行规则。登录本身、css和js静态资源要放行其余所有页面都先检查session里有没有user没有就弹回登录页。这个Filter要在web.xml里配置也可以用注解WebFilter(/*)。我见过很多翻车案例是把静态资源也拦了导致登录页一片裸HTML那就是因为Filter里没做资源放行。4.2 商品列表分页LIMIT和count要分开查商城首页和商品列表页必须分页。分页逻辑分三步查总记录数计算总页数、查当前页数据、封装成PageBean交给JSP渲染。// ProductDao.java public ListProduct findPage(int pageNum, int pageSize) throws SQLException { String sql SELECT id, name, price, stock, image FROM product ORDER BY id LIMIT ?, ?; try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { ps.setInt(1, (pageNum - 1) * pageSize); ps.setInt(2, pageSize); } }LIMIT的两个参数第一个是起始偏移量第二个是每页条数。pageNum是页码从1开始所以偏移量是(pageNum-1)*pageSize。如果第1页你传了0第2页传了10翻页就会少一条或多一条这个公式一定要写在Service层而不是JSP里否则前端改个页码就出错。另一个要注意的地方是count查询需要单独执行public int count() throws SQLException { String sql SELECT COUNT(*) FROM product; }分页条数通常由Servlet从请求参数里取pageSize建议固定12或16不开放给用户传参。原因是你一旦让用户随便传pageSize就能传个10000直接拉走全表数据这在答辩演示时也会让页面卡成假死。4.3 购物车Session实现还是数据库表实现毕设项目里购物车实现方式大致分两派Session派和数据库表派。Session派把购物车对象挂在session上优点是代码少、不需要额外建表、刷新不丢缺点是关浏览器就没。数据库表派把cart_item表持久化用户换设备购物车还在但每次操作都要读写MySQL。从答辩角度来看这两种都能讲但代码量差别很大。Session购物车基本只要两步取session里的购物车Map没有就新建把商品放进去。// CartService.java addToCart HttpSession session request.getSession(); MapInteger, Integer cart (MapInteger, Integer) session.getAttribute(cart); if (cart null) { cart new HashMap(); session.setAttribute(cart, cart); } Integer old cart.get(productId); cart.put(productId, (old null ? 0 : old) 1);这里用MapInteger, Integerkey是商品idvalue是数量。为什么要选Map而不是List因为购物车天然按商品聚合Map的get/put在新增同一商品时只需要覆盖valueList就得先查一遍有没有相同商品再改数量代码至少多一个for循环。页面展示时再遍历Map调ProductDao查出商品信息。这个结构简单到可以从头手写但如果导师明确要求“购物车数据持久化”那就必须走数据库表方案Session方案在答辩时会被一句“重启还在吗”问住。4.4 下单与扣库存一个事务解决两个写操作下单是整个项目里最容易出错的地方因为同时做了两件事插入订单、扣减库存。这两步必须绑在同一个JDBC事务里否则会出现“订单生成了但库存没减”或者反过来。// OrderService.java createOrder Connection conn null; try { conn DBUtil.getConnection(); conn.setAutoCommit(false); // 开启手动事务 OrderDao orderDao new OrderDao(); orderDao.insert(conn, order); // 插入订单表 orderDao.insertItems(conn, items); // 插入订单明细表 productDao.decreaseStock(conn, productId, quantity); // 扣库存 conn.commit(); // 全部成功才提交 } catch (Exception e) { if (conn ! null) conn.rollback(); // 任何一步失败都回滚 } finally { if (conn ! null) conn.setAutoCommit(true); DBUtil.close(conn); }这段代码的关键是把Connection对象当作参数传给了多个DAO方法。很多初学者会写成每个DAO里自己getConnection那样事务就失效了因为每个方法各开各的连接commit和rollback互不相干。正确做法是Service层拿一个Connection往下传保证三个写操作在同一个数据库会话里。扣库存的SQL也要注意不能先查再减应该直接一步到位UPDATE product SET stock stock - ? WHERE id ? AND stock ?;这个UPDATE带上AND stock ?返回值是受影响行数。如果返回0说明库存不足直接抛异常让事务回滚。这一步能避免你写“先查库存再判断再更新”带来的并发问题虽然毕设一般不会真的并发下单但这条SQL写出来在答辩时是实打实的加分项。5. 运行与部署避坑让我熬夜到两点的五个JavaWeb项目问题5.1 页面中文全部变成问号现象JSP页面上的商品名称、用户昵称全是“???”数据库里中文倒是正常。原因三层都容易出问题。最常见的是JSP页面没设pageEncoding或者MySQL连接URL里没带characterEncoding。解决JSP顶部统一加% page contentTypetext/html;charsetUTF-8 pageEncodingUTF-8%连接URL里保证有useUnicodetruecharacterEncodingutf8如果还不行看web.xml里有没有EncodingFilter有就把Filter放在最前面。一条条排90%的乱码是URL或JSP声明丢了。5.2 Tomcat启动成功但访问就404现象Console显示Server startup in 3000ms但浏览器输入http://localhost:8080/shop/index.jsp报404或者连项目名都访问不了。原因Artifact没部署或Application context不对。IDEA里如果Deployment列表为空Tomcat启动时没有webapp可加载另外访问路径要包含contextPath如果你访问的是localhost:8080/index.jsp那只会打到Tomcat自带的ROOT应用自然404。解决Edit Configurations → Deployment先把Artifact加上且选择war explodedApplication context改成/shop访问必须带http://localhost:8080/shop/。如果项目里用了绝对路径/index.jsp这类写法改成request.getContextPath()动态拼接前缀。5.3 启动报 ClassNotFoundException: com.mysql.jdbc.Driver现象点运行后Tomcat报ClassNotFound或者运行到第一次查询数据库时才报异常。原因jar包放在项目的lib目录下但IDEA没有把它视为类库依赖。常见于从别人那里拷来的Eclipse工程lib引入方式不是Maven依赖IDEA不会自动包含进去。解决确认MySQL驱动jar是否存在于lib目录然后Project Structure → Modules → Dependencies点号添加“JARs or directories”把这目录加进去。如果换成了MySQL 8.0驱动还要把配置里的driver改成com.mysql.cj.jdbc.Driver别只换jar不换类名。5.4 端口被占用Port 8080 was already in use现象Tomcat一启动就弹窗说8080被占用。原因之前有别的Tomcat没关或者某个进程占了8080。IDEA里反复Run不停止也会留下残留进程。解决命令行执行netstat -ano | findstr 8080查到占用PID后在任务管理器结束进程或者干脆把Tomcat端口改成8081顺手把访问URL一起改了。Windows下有时候是本地服务占用8080看到PID不确定是什么时优先改IDEA的Tomcat端口快得多。5.5 图片上传成功但刷新后不显示现象商品图片上传时提示成功文件也写到了某个imgs目录但页面刷新后图片裂开。原因上传路径写到了项目编译输出目录target/shop/imgsIDEA每次重新部署时会把target清掉图片随之丢失或者文件写了但访问路径不对浏览器找不到。解决不要往target里写文件把上传目录配置到项目外比如D:/shop_upload/同时用IDEA的External Libraries设置一个虚拟路径映射到Tomcat的webapps。Servlet项目最常见的做法是在Tomcat的server.xml里加Context docBase配置或者创建一个本地用于存上传文件的目录并通过资源映射暴露。这一步属于典型的血泪经验图片上传看似简单实际部署时九成问题都出在路径上。6. 答辩前验证功能一份清单让项目自己开口说话项目能跑通只是开始答辩前要按真实用户路径完整走一遍不能只点开首页就完事。我一般会在答辩前一天做一次“全流程清空重来”清掉浏览器缓存用新的测试账号从头走一遍核心链路。验证步骤操作预期结果注册首页点注册填账号密码提示成功能登录登录用刚注册的账号登录首页右上角显示昵称未登录拦截退出后直接访问购物车URL跳回登录页商品分页翻到第2页URL带page2商品变化加购点“加入购物车”再去购物车数量1修改数量把数量改成3金额联动变化下单提交订单库存减少订单列表出现记录控制台观察IDEA日志无异常SQL报错这个清单里最容易被漏掉的是“未登录拦截”和“库存变化”。很多项目登录后一切正常但一退出直接输入购物车地址就能进去说明Filter没生效还有的下单后库存纹丝不动说明事务或UPDATE SQL写错了。这两条在答辩时最容易暴露问题。如果时间还有富余可以加两个小加分项一是给密码加密的MD5Util类写三行注释说明加盐原因二是把下单接口里的事务边界用注释标出来让老师一眼看到你懂事务。如果导师问“能改成Spring Boot吗”你就说现有三层架构可以直接平移pojo对应entitydao对应Mapperservice原样复用web层换成Controller这样既回答了对框架的理解又不会把现有项目推翻重来。我做毕设那会儿就是靠这个清单答辩前一晚把整个项目重新跑了一遍上场时每个按钮都敢点。毕业设计这件事功能可以不华丽但流程必须闭环数据必须自洽。希望帮到你。本文还有配套的精品资源点击获取