news 2026/9/28 6:05:12

JavaWeb超市系统毕业设计最小可行体实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
JavaWeb超市系统毕业设计最小可行体实战指南

简介:这是一套面向计算机专业本科生毕业设计与JavaWeb初学者实战训练的超市管理系统完整源码包,聚焦B/S架构下的业务管理场景,帮助学习者掌握JSP+Servlet+JDBC全栈开发流程及MySQL数据库设计与操作。资源包含68个文件,涵盖19个核心Java源文件、37个编译后Class字节码、4个建库建表SQL脚本(含员工、商品、进货、销售等关键数据表)、2个系统界面截图及必要Jar依赖与Eclipse项目配置文件(.project/.classpath/.prefs),总大小仅3.5MB,轻量易部署。已有797人学习下载,适合快速搭建本地开发环境并调试运行。读者可直接获取可运行的完整系统:含双角色权限(员工/管理员)、八大功能模块(从系统登录、员工与商品管理到进货销售全流程)、结构清晰的MVC分层目录(src下dao/view/pojo/utils等),以及配套数据库脚本与项目说明文档,显著降低毕设启动门槛与调试成本。

1. 这不是“又一个超市系统”:它是一份能跑通、能改、能答辩的 JavaWeb 毕业设计最小可行体

你搜“JavaWeb 超市管理系统 毕业设计”,页面刷出几百个同名 ZIP 包——点开全是 JSP+Servlet+MySQL 的老三件,目录结构雷同,登录页写着“欢迎来到XX超市”,连验证码都用的Random生成四位数字。但真正卡住你的从来不是“有没有源码”,而是:为什么本地 Tomcat 启动后访问 8080 页面空白?为什么 login.jsp 提交后跳转 404?为什么数据库导入了却提示Unknown column 'user_name' in 'field list'?为什么答辩老师问“事务怎么控制的”,你只能翻着代码说“我用了 conn.setAutoCommit(false)”?

这个标题里的.zip文件,本质是一个被压缩过的“毕业设计最小可行体(MVP)”:它不追求高并发、不带微服务、没用 Spring Boot 自动装配,但它必须满足三个硬约束——能在 JDK 8 + Tomcat 8.5 + MySQL 5.7 环境下 10 分钟内跑起来;所有增删改查逻辑可追踪到具体 Servlet 和 SQL;数据库表结构与 Java 实体类字段严格对齐,没有驼峰/下划线错位。它不是工业级系统,而是专为计算机专业本科生设计的“答辩友好型”载体:功能完整(商品/员工/库存/销售单)、边界清晰(无第三方支付/短信/物流集成)、技术栈透明(JSP 前端 + Servlet 控制层 + JDBC 数据层)。如果你正被开题报告 deadline 追着跑,或刚在 IDEA 里配完 Tomcat 却卡在ClassNotFoundException: com.mysql.jdbc.Driver,这篇笔记就是为你写的——我们不讲 MVC 理论,只拆解从解压 ZIP 到点击“结账”按钮弹出成功提示的每一步真实操作。


2. 解压即启动:环境配置与项目结构破译

2.1 环境版本锁死:为什么必须用 JDK 8 + Tomcat 8.5 + MySQL 5.7

这个 ZIP 包的build.xml(Ant 构建脚本)和web.xml中明确声明了 Servlet 3.0 规范,而 Servlet 3.0 是 JDK 8 的默认支持上限。若你强行用 JDK 17 启动,会直接报错:

java.lang.UnsupportedClassVersionError: com/supermarket/dao/UserDao has been compiled by a more recent version of the Java Runtime (class file version 52.0), this version of the Java Runtime only recognizes class file versions up to 51.0

提示:错误信息里的52.0对应 JDK 8,51.0对应 JDK 7——说明编译时用了 JDK 8,但你运行时用了 JDK 7。反过来,JDK 17 编译的 class 文件版本是 61,Tomcat 10+ 才支持,而本项目web.xml的<web-app>根节点声明的是version="3.0",Tomcat 9+ 才兼容。所以版本链必须闭合:JDK 8 → Tomcat 8.5 → MySQL 5.7。

验证方式:

# 检查 JDK 版本(必须输出 1.8.x) java -version # 检查 Tomcat 版本(必须输出 v8.5.x) $TOMCAT_HOME/bin/version.sh # Linux/Mac %TOMCAT_HOME%\bin\version.bat # Windows # 检查 MySQL 版本(必须输出 5.7.x) mysql --version

2.2 项目结构解剖:识别src、WebContent、lib三大核心区域

解压 ZIP 后,典型目录结构如下:

supermarket/ ├── build.xml # Ant 构建脚本(非 Maven,勿用 IDEA 自动导入) ├── src/ # Java 源码根目录(注意:不是 Maven 的 src/main/java) │ ├── com/supermarket/dao/ # 数据访问层(UserDao.java, GoodsDao.java) │ ├── com/supermarket/service/ # 业务逻辑层(UserService.java, GoodsService.java) │ └── com/supermarket/servlet/ # 控制层(LoginServlet.java, SaleServlet.java) ├── WebContent/ # Web 资源根目录(等价于传统 WAR 包的 webapp) │ ├── WEB-INF/ │ │ ├── web.xml # 核心配置:Servlet 映射、过滤器、监听器 │ │ └── lib/ # 依赖 JAR 包(mysql-connector-java-5.1.47.jar 必须存在) │ ├── index.jsp # 首页入口 │ ├── login.jsp # 登录页 │ └── admin/ # 后台页面(goods_list.jsp, employee_add.jsp) ├── database/ # 数据库脚本目录 │ └── supermarket.sql # 建库建表+初始数据(UTF8MB4 字符集!) └── README.txt # 关键提示:如默认账号密码、端口配置

关键动作:将整个supermarket/目录复制到$TOMCAT_HOME/webapps/下(不要嵌套子文件夹),启动 Tomcat 后访问http://localhost:8080/supermarket/。若看到登录页,说明部署成功;若 404,请检查WebContent/WEB-INF/web.xml中<display-name>是否为supermarket,且webapps/下文件夹名是否与之完全一致(大小写敏感)。

2.3 数据库初始化:supermarket.sql的三处致命细节

database/supermarket.sql不是简单CREATE DATABASE,它包含三个易被忽略的硬编码细节:

  1. 字符集强制声明:

    CREATE DATABASE IF NOT EXISTS supermarket DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE supermarket;

    为什么必须是 utf8mb4?因为商品名称可能含 emoji(如 🍎🍎),MySQL 5.7 默认utf8实际是utf8mb3,无法存储四字节 Unicode。若漏掉mb4,插入商品时会报Incorrect string value错误。

  2. 外键约束显式关闭:

    SET FOREIGN_KEY_CHECKS = 0; -- 关键!否则建表顺序错导致失败 DROP TABLE IF EXISTS `goods`; CREATE TABLE `goods` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(100) NOT NULL, `price` decimal(10,2) NOT NULL, `stock` int(11) NOT NULL DEFAULT '0', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; SET FOREIGN_KEY_CHECKS = 1;

    现象:若未加SET FOREIGN_KEY_CHECKS = 0,且employee表引用了department表,但department表建在后面,则employee表创建失败。

  3. 初始管理员账号明文写死:

    INSERT INTO `user` (`username`, `password`, `role`) VALUES ('admin', 'e10adc3949ba59abbe56e057f20f883e', 'ADMIN');

    密码e10adc3949ba59abbe56e057f20f883e是"123456"的 MD5 值(32 位小写)。答辩时务必修改此密码,否则老师用admin/123456直接登录后台,会质疑安全性。

执行命令:

# 进入 MySQL 命令行(确保已创建 supermarket 数据库) mysql -u root -p > source /path/to/supermarket/database/supermarket.sql

3. 从登录到结账:核心业务链路的手动调试法

3.1 登录流程逆向追踪:login.jsp→LoginServlet→UserDao

当输入admin/123456点击登录,实际发生以下调用链:

  1. login.jsp表单提交到/login(查看<form action="login" method="post">)
  2. web.xml中映射LoginServlet处理/login请求:
    <servlet> <servlet-name>LoginServlet</servlet-name> <servlet-class>com.supermarket.servlet.LoginServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>LoginServlet</servlet-name> <url-pattern>/login</url-pattern> </servlet-mapping>
  3. LoginServlet.java的doPost()方法:
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String username = request.getParameter("username"); // 获取表单值 String password = request.getParameter("password"); UserDao userDao = new UserDao(); // 实例化 DAO User user = userDao.login(username, MD5Util.md5(password)); // 注意:密码已 MD5 加密 if (user != null) { request.getSession().setAttribute("user", user); // 存入 Session response.sendRedirect("admin/index.jsp"); // 重定向到后台首页 } else { request.setAttribute("msg", "用户名或密码错误"); request.getRequestDispatcher("login.jsp").forward(request, response); // 返回登录页 } }

    参数说明:request.getParameter()获取 HTML 表单字段名;MD5Util.md5()是项目自定义工具类,位于src/com/supermarket/util/MD5Util.java;request.getSession().setAttribute()将用户对象存入 Session,后续页面通过session.getAttribute("user")获取。

3.2 商品入库操作:goods_add.jsp→GoodsServlet→GoodsDao.insert()

添加商品时,goods_add.jsp表单提交到/goods/add,由GoodsServlet的doPost()处理:

// GoodsServlet.java protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String name = request.getParameter("name"); String priceStr = request.getParameter("price"); String stockStr = request.getParameter("stock"); // 类型转换(必须捕获 NumberFormatException!) BigDecimal price = new BigDecimal(priceStr); int stock = Integer.parseInt(stockStr); Goods goods = new Goods(); goods.setName(name); goods.setPrice(price); goods.setStock(stock); GoodsDao goodsDao = new GoodsDao(); boolean success = goodsDao.insert(goods); // 执行插入 if (success) { request.setAttribute("msg", "商品添加成功!"); request.getRequestDispatcher("goods_list.jsp").forward(request, response); } else { request.setAttribute("msg", "商品添加失败,请重试"); request.getRequestDispatcher("goods_add.jsp").forward(request, response); } }

关键点:

  • BigDecimal用于价格,避免float精度丢失(如0.1 + 0.2 != 0.3);
  • Integer.parseInt()可能抛出NumberFormatException,但原代码未 try-catch——这是答辩时老师最爱问的“异常处理漏洞”;
  • goodsDao.insert()最终执行 SQL:INSERT INTO goods (name, price, stock) VALUES (?, ?, ?),使用PreparedStatement防止 SQL 注入。

3.3 销售单生成:事务控制的实操验证

结账时,需同时更新goods表(扣减库存)和插入sale_record表(记录销售)。SaleServlet.java中的关键代码:

Connection conn = null; try { conn = JDBCUtil.getConnection(); // 获取连接 conn.setAutoCommit(false); // 关闭自动提交,开启事务 // 1. 更新商品库存 String updateSql = "UPDATE goods SET stock = stock - ? WHERE id = ?"; PreparedStatement ps1 = conn.prepareStatement(updateSql); ps1.setInt(1, quantity); // 购买数量 ps1.setInt(2, goodsId); ps1.executeUpdate(); // 2. 插入销售记录 String insertSql = "INSERT INTO sale_record (goods_id, quantity, total_price, sale_time) VALUES (?, ?, ?, NOW())"; PreparedStatement ps2 = conn.prepareStatement(insertSql); ps2.setInt(1, goodsId); ps2.setInt(2, quantity); ps2.setBigDecimal(3, totalPrice); ps2.executeUpdate(); conn.commit(); // 提交事务 request.setAttribute("msg", "结账成功!"); } catch (SQLException e) { if (conn != null) { try { conn.rollback(); // 回滚事务 } catch (SQLException ex) { ex.printStackTrace(); } } request.setAttribute("msg", "结账失败:" + e.getMessage()); } finally { JDBCUtil.close(conn); // 关闭连接 }

为什么必须手动 commit/rollback?若只更新库存成功、插入销售记录失败,不回滚会导致库存虚减。此处conn.setAutoCommit(false)是事务起点,conn.commit()是终点,conn.rollback()是异常兜底——答辩时演示“故意让插入失败”,观察库存是否恢复,即可证明事务生效。


4. 避坑指南:五个让答辩前夜崩溃的真实问题

4.1 现象:Tomcat 启动后访问http://localhost:8080/supermarket/报 404

原因:web.xml中<display-name>值为supermarket,但webapps/下文件夹名是supermarket-master或SuperMarket(大小写不一致)。Tomcat 严格区分大小写,且 WAR 包解压后文件夹名必须与display-name完全一致。
解决:重命名webapps/下文件夹为supermarket(全小写),重启 Tomcat。

4.2 现象:登录页提交后跳转http://localhost:8080/login报 404

原因:login.jsp表单的action属性写成绝对路径/login,但项目上下文路径不是 ROOT。例如,若项目放在webapps/supermarket/,则正确路径应为supermarket/login。
解决:将<form action="/login" ...>改为<form action="login" ...>(相对路径),或使用 JSTL<c:url value="/login"/>。

4.3 现象:goods_list.jsp显示java.lang.ClassNotFoundException: com.mysql.jdbc.Driver

原因:MySQL 5.1+ 驱动类名已从com.mysql.jdbc.Driver变更为com.mysql.cj.jdbc.Driver,但JDBCUtil.java中仍用旧类名,且lib/mysql-connector-java-5.1.47.jar未放入WebContent/WEB-INF/lib/。
解决:

  1. 确认WebContent/WEB-INF/lib/下存在mysql-connector-java-5.1.47.jar;
  2. 修改JDBCUtil.java中Class.forName("com.mysql.cj.jdbc.Driver");
  3. URL 改为jdbc:mysql://localhost:3306/supermarket?useSSL=false&serverTimezone=UTC(添加serverTimezone=UTC防止时区报错)。

4.4 现象:添加商品时中文名称显示为??,数据库中存为乱码

原因:MySQL 服务端字符集未设为utf8mb4,或JDBC URL未指定characterEncoding=utf8mb4。
解决:

  1. MySQL 配置文件my.cnf添加:
    [client] default-character-set = utf8mb4 [mysqld] character-set-server = utf8mb4 collation-server = utf8mb4_unicode_ci
  2. JDBCUtil.java中 URL 改为:
    jdbc:mysql://localhost:3306/supermarket?useSSL=false&serverTimezone=UTC&characterEncoding=utf8mb4

4.5 现象:sale_record表插入成功,但goods表库存未减少

原因:SaleServlet.java中conn.setAutoCommit(false)后未执行conn.commit(),或catch块中conn.rollback()未生效(因conn为 null)。
解决:

  1. 检查conn.commit()是否在try块末尾;
  2. 确保JDBCUtil.getConnection()返回的conn不为 null;
  3. 在finally块前添加日志:System.out.println("Transaction committed");验证执行路径。

5. 答辩加分项:三步让老师眼前一亮的定制化改造

5.1 第一步:给登录页加验证码(5 分钟实现防暴力破解)

原系统无验证码,易被脚本爆破。只需三步:

  1. 生成验证码图片:在src/com/supermarket/util/VerifyCodeUtil.java中添加:
    public static String generateVerifyCode(HttpServletRequest request) { String code = RandomStringUtils.randomNumeric(4); // 生成4位数字 request.getSession().setAttribute("verifyCode", code); // 存入 Session return code; }
  2. 添加验证码图片 Servlet:新建VerifyCodeServlet.java:
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String code = VerifyCodeUtil.generateVerifyCode(request); BufferedImage image = new BufferedImage(80, 30, BufferedImage.TYPE_INT_RGB); Graphics2D g = image.createGraphics(); g.setColor(Color.WHITE); g.fillRect(0, 0, 80, 30); g.setColor(Color.BLACK); g.setFont(new Font("Arial", Font.BOLD, 20)); g.drawString(code, 10, 25); response.setContentType("image/png"); ImageIO.write(image, "png", response.getOutputStream()); }
    并在web.xml中映射/verifyCode。
  3. 修改login.jsp:
    <img src="verifyCode" onclick="this.src='verifyCode?'+Math.random()" alt="验证码"/> <input type="text" name="verifyCode" placeholder="请输入验证码"/>
    在LoginServlet中增加校验:
    String inputCode = request.getParameter("verifyCode"); String sessionCode = (String) request.getSession().getAttribute("verifyCode"); if (!inputCode.equalsIgnoreCase(sessionCode)) { request.setAttribute("msg", "验证码错误"); request.getRequestDispatcher("login.jsp").forward(request, response); return; }

    答辩话术:“老师,我增加了图形验证码,防止暴力破解。点击图片可刷新,且验证码区分大小写,提升了基础安全。”

5.2 第二步:销售单导出 Excel(用 Apache POI 实现)

老师常问“数据怎么导出分析?”,原系统无此功能。添加ExportSaleServlet.java:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { List<SaleRecord> records = new SaleRecordDao().findAll(); // 查询全部销售记录 HSSFWorkbook workbook = new HSSFWorkbook(); HSSFSheet sheet = workbook.createSheet("销售记录"); // 表头 HSSFRow headerRow = sheet.createRow(0); String[] headers = {"ID", "商品ID", "数量", "总价", "时间"}; for (int i = 0; i < headers.length; i++) { headerRow.createCell(i).setCellValue(headers[i]); } // 数据行 for (int i = 0; i < records.size(); i++) { SaleRecord r = records.get(i); HSSFRow row = sheet.createRow(i + 1); row.createCell(0).setCellValue(r.getId()); row.createCell(1).setCellValue(r.getGoodsId()); row.createCell(2).setCellValue(r.getQuantity()); row.createCell(3).setCellValue(r.getTotalPrice().doubleValue()); row.createCell(4).setCellValue(r.getSaleTime().toString()); } response.setContentType("application/vnd.ms-excel"); response.setHeader("Content-Disposition", "attachment; filename=sales.xls"); workbook.write(response.getOutputStream()); }

依赖添加:下载poi-3.17.jar放入WebContent/WEB-INF/lib/。

价值点:导出功能体现数据闭环能力,且 POI 是 JavaWeb 常用工具,展示技术广度。

5.3 第三步:用 Filter 统一处理中文乱码(一劳永逸)

每次request.setCharacterEncoding("UTF-8")太重复。新建EncodingFilter.java:

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse resp = (HttpServletResponse) response; req.setCharacterEncoding("UTF-8"); resp.setCharacterEncoding("UTF-8"); resp.setContentType("text/html;charset=UTF-8"); chain.doFilter(req, resp); }

并在web.xml中配置:

<filter> <filter-name>EncodingFilter</filter-name> <filter-class>com.supermarket.filter.EncodingFilter</filter-class> </filter> <filter-mapping> <filter-name>EncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>

玄学经验:Filter 必须在web.xml中置于所有 Servlet 映射之前,否则无效。这是血泪教训——曾因位置放错,导致goods_add.jsp提交的中文始终乱码。

最后想说:这个超市系统不是要你造轮子,而是让你亲手拧紧每一颗螺丝。我当年答辩时,老师指着销售单页面问:“如果同时两人结账同一商品,库存会超卖吗?” 我当场打开SaleServlet,指出conn.setAutoCommit(false)和synchronized未加——然后快速补上synchronized块,并解释“高并发需 Redis 锁,但本设计聚焦事务一致性”。老师笑了,说:“这才是工程思维。” 希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/28 6:05:10

JavaWeb超市管理系统:Servlet+JSP+JDBC毕设实战指南

简介&#xff1a;本资源是一套完整的基于JavaWeb技术栈开发的超市管理系统毕业设计项目&#xff0c;面向计算机专业本科生、Java初学者及毕设实践者&#xff0c;解决课程设计与项目实战中缺乏可运行全栈案例的痛点。压缩包共68个文件&#xff0c;含19个核心Java源码、37个编译后…

作者头像 李华
网站建设 2026/9/28 6:05:04

做网站需要域名还需要什么:避开5个隐形坑,搞懂建站报价

做网站需要域名还需要什么:避开5个隐形坑,搞懂建站报价 改个需求建站公司拖一周,这种憋屈感谁懂?你只想要个简单的企业官网,结果对方说域名没备案、服务器要重新调、SSL证书要等审批。更坑的是,当初那份 建站报价 单上,只写了“网站开发费”,其他全是隐形消费。…

作者头像 李华
网站建设 2026/9/28 6:04:43

PHP+HTML实现流式输出效果的示例详解

效果演示后端代码12345678910111213141516171819202122232425262728293031323334353637383940<?php// 关闭输出缓冲ini_set(output_buffering, off);ini_set(zlib.output_compression, false);while (ob_get_level()) ob_end_clean(); // 清除所有缓冲层// 设置HTTP头&…

作者头像 李华
网站建设 2026/9/28 6:04:42

多平台大文件上传兼容性实战:分片、Worker与S3协议

1. 兼容性问题到底藏在哪些环节&#xff1a;从浏览器到对象存储的完整链路做上传模块这些年&#xff0c;我最大的感受是&#xff1a;大文件上传的多平台兼容性问题&#xff0c;真正难的地方往往不是某一段代码写不出来&#xff0c;而是你根本说不清问题卡在哪一段。同一个 2GB …

作者头像 李华
网站建设 2026/9/28 6:04:43

3步搞定wordpress中文在线字体 图解步骤解决访问慢

3步搞定wordpress中文在线字体 图解步骤解决访问慢 网站做好了没人访问,是不是特别扎心?很多老板觉得代码写完、页面点亮就算完工,结果打开浏览器转圈半天,用户早就跑了。别急,这往往不是内容问题,而是加载速度在拖后腿。特别是中文网站,字体文件动辄几MB,首屏白屏时间直接翻倍。…

作者头像 李华
网站建设 2026/9/28 6:04:18

微星B350M BIOS重置原理与实操避坑指南

1. 为什么BIOS重置不是“按个键就完事”——从B350M实战看微星主板的底层逻辑你手里的那块微星B350M迫击炮&#xff0c;或者任何一块微星主板&#xff0c;它的BIOS不是Windows桌面右下角那个可以双击关闭的程序。它是一段固化在主板南桥附近SPI Flash芯片里的固件&#xff0c;是…

作者头像 李华