恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
JSP超市管理系统开发全解析:从数据库设计到部署避坑
首页
资讯中心
/
JSP超市管理系统开发全解析:从数据库设计到部署避坑
JSP超市管理系统开发全解析:从数据库设计到部署避坑
发布时间:2026/10/4 11:09:04
简介JSP超市管理系统是一套B/S模式的Java Web完整项目基于JSP、Servlet与MySQL实现开发环境为MyEclipse8.5和Tomcat7.0适合正在学习JSP编程、需要课程设计或毕业设计参考的读者。系统覆盖人事、销售、进货、库存、客户五大管理模块人事方面可查询和更新职工、供货商信息销售模块支持销售信息查询与商品盘点进货与库存模块均提供信息查询及增删改查客户管理可添加、删除用户并修改密码功能划分清晰贴近中小超市真实运营流程。压缩包约1.06MB文件总数平台标注为0文件类型明细暂未提供包内配有完整Java源代码与MySQL数据库脚本数据库配置信息已在代码中标注部署后使用管理员账号admin/admin登录即可运行。目前已有1023人学习读者通过阅读源码和库表脚本可理解JSP页面到后台Servlet/DAO的调用链路、MySQL表结构设计以及基础CRUD写法并能在现有模块上继续扩展作为实训或二次开发起点。1. 这篇文章写给谁被“JSP超市管理系统”这个题目卡住的人如果你手上正拿着“JSP超市管理系统”这类题目多半是课程设计或者毕业设计的档期到了。这个题目的本质是用 JSP 做页面、Servlet 写控制逻辑、MySQL 存数据、MyEclipse 当开发工具最后凑出一个能在 Tomcat 里跑的 Web 项目。它不算新但每年都有大量学生和转行新手栽在环境配置和数据库连接这些环节上。这篇文章就把从建表到部署的完整路径拆给你看包括每一段代码为什么这样写以及那些不跑一遍就根本发现不了的坑。这套技术栈在今天依然值得做原因很实际学校验收看的是“能不能跑、代码是不是自己写的、答辩能不能说清楚”而这套组合的每一层都简单到可以逐行解释。你不用去追 Spring Boot先把 JSP Servlet MySQL 这条链路跑通后面理解任何 Java Web 框架都会快很多。适合三类人正在做课程设计的学生、想补 Java Web 基础课的新手、以及需要快速搭一个内部小系统的在职开发者。虽然是老技术但逻辑一点没老。2. MyEclipse 里的技术选型为什么这套组合在课程设计里经久不衰2.1 先搞清楚 JSP、Servlet、JavaBean 在项目里分别干什么很多人拿到题目就四处找源码结果下载一个压缩包导入 MyEclipse 后一堆红叉根本跑不起来。问题不在于项目本身而在于没弄清楚这套 Web 结构里每个部件的位置。JSP 是展示层它的本质是一个会被容器翻译成 Servlet 的页面文件你在上面写 HTML嵌入 Java 代码片段Scriptlet或者 JSTL 标签浏览器最终拿到的是它生成的纯 HTML。Servlet 是控制层负责接收请求、调用业务方法、决定跳转到哪个 JSP。JavaBean或者现在更常用的普通 POJO是数据模型对应数据库里的表结构。超市管理系统的“管理”二字落在代码上就是增删改查。商品要增加、修改、下架类别要维护销售单要记录。这些操作全部可以归纳成“请求到达 Servlet → Servlet 调用 DAO → DAO 执行 SQL → 返回结果给 JSP 展示”。MyEclipse 在这个链条里的作用是帮你生成项目骨架它建出来的 Web Project 自带src目录和WebRoot也叫webapp目录前者放 Java 类后者放 JSP 和静态资源。你不需要手动配置太多东西但得知道WebRoot/WEB-INF/web.xml是整条链路的入口。2.2 MyEclipse 自带 JDK 和 Tomcat 的匹配关系容易埋雷MyEclipse 版本不同自带的 JDK 和 Tomcat 版本也不一样。比如 MyEclipse 2014 左右常配 JDK 1.7而它在 Tomcat 8 下就需要对应版本的 Servlet 3.1 规范。很多新手拿到项目就点 Run on Server发现 404 或者启动报错原因往往是 MyEclipse 默认绑定的 Tomcat 目录和项目编译级别不一致。我一般会先看项目的 Java Compiler 级别再确认 Tomcat 版本两者至少保证一个大版本内的兼容代码里用到javax.servlet的 API 才不会被 IDE 标红。另外一个容易忽视的问题是 MySQL 驱动 jar 应该放在哪里。很多教程说要把mysql-connector-java-x.x.x-bin.jar放到WEB-INF/lib目录下这是对的因为 Tomcat 启动 Web 应用时会加载这个目录下的所有 jar。但不少人会顺手把它也放进 JDK 的jre/lib/ext或 MyEclipse 的common/lib这会导致版本冲突——多个类加载器同时加载同名驱动类时第 12 章 ClassNotFound 的报错就出来了。我的习惯是只在WEB-INF/lib放一份并且在项目的 Java Build Path 里也加上这个 jar让 IDE 编译时能识别com.mysql.jdbc.Driver这个类。2.3 建项目的第一个动作New Web Project 之后的目录调整打开 MyEclipseFile → New → Web Project输入项目名SupermarketMS。注意 MyEclipse 会问你要不要自动生成web.xml一定要选生成因为后面配置 Servlet 映射全靠它。建完以后立刻做三件事一是检查src目录是否被标记为源代码根目录否则新建的包会跑到别的地方去二是把默认的index.jsp删掉或者改写成登录页三是在WEB-INF/lib下放好 MySQL 驱动。这些动作做完项目骨架才算立住了不要急着写代码。项目结构最好按包名分层建com.supermarket.servlet放控制器com.supermarket.dao放数据库访问对象com.supermarket.model放实体类com.supermarket.util放 DBUtil 工具类。这样分层的好处是答辩时老师问“你这个项目架构是什么样的”你可以直接指着包结构讲清楚也方便后续加功能。很多下载来的项目之所以乱就是把所有类都堆在src根包下面一搜几十个 java 文件全在默认包里连包名都没有。提示如果你不确定项目是用 JDK 1.7 还是 1.8 编译的检查.classpath文件里的container配置或者直接看项目属性里的 Java Build Path。这决定了你的代码能不能用 lambda 表达式和 try-with-resources。3. 超市管理系统的数据库设计5 张表和不能省的外键约束3.1 先画清楚业务再建表商品、类别、销售、供应商、用户数据库设计是这类题目的分水岭。优秀的答辩现场老师一定会问“表和表之间的关系是什么、为什么这样设计”。超市管理系统的核心表我会拆成 5 张用户表负责登录类别表负责商品分类商品表是主资产销售记录表是流水账供应商表补充商品来源。前 4 张必须建供应商表看题目要求但建上会显得业务模型更完整。每张表的主键统一用自增id商品表的数量字段要极其谨慎后面会细说。先写出建表 SQL。注意 MySQL 的存储引擎要选 InnoDB因为事务和外键是这套系统后面保证数据一致性的基础。MyISAM 在旧教程里出现频率很高但它不支持事务销售记录一旦写入失败库存和流水就对不上了。字符集统一utf8排序规则用utf8_general_ci就够不追 utf8mb4除非商品名要存 emoji超市项目里几乎没有这个需求。-- 用户表管理员/收银员共用 CREATE TABLE t_user ( id INT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(64) NOT NULL, real_name VARCHAR(50) COMMENT 真实姓名用于显示收银员, role TINYINT DEFAULT 1 COMMENT 1管理员, 2收银员, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB DEFAULT CHARSETutf8; -- 商品类别表 CREATE TABLE t_category ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50) NOT NULL, sort INT DEFAULT 0 COMMENT 排序权重小的在前 ) ENGINEInnoDB DEFAULT CHARSETutf8; -- 供应商表 CREATE TABLE t_supplier ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100) NOT NULL, contact VARCHAR(50) COMMENT 联系人, phone VARCHAR(20) ) ENGINEInnoDB DEFAULT CHARSETutf8; -- 商品表 CREATE TABLE t_product ( id INT AUTO_INCREMENT PRIMARY KEY, category_id INT NOT NULL, supplier_id INT DEFAULT NULL, name VARCHAR(100) NOT NULL, price DECIMAL(10,2) NOT NULL COMMENT 售价, cost DECIMAL(10,2) DEFAULT NULL COMMENT 进价利润统计用, stock INT NOT NULL DEFAULT 0, status TINYINT DEFAULT 1 COMMENT 1上架, 0下架, CONSTRAINT fk_product_category FOREIGN KEY (category_id) REFERENCES t_category(id), CONSTRAINT fk_product_supplier FOREIGN KEY (supplier_id) REFERENCES t_supplier(id) ) ENGINEInnoDB DEFAULT CHARSETutf8; -- 销售记录表 CREATE TABLE t_sale ( id INT AUTO_INCREMENT PRIMARY KEY, product_id INT NOT NULL, user_id INT NOT NULL COMMENT 操作人, sale_price DECIMAL(10,2) NOT NULL COMMENT 成交单价防止改价后对不上, quantity INT NOT NULL COMMENT 数量, total_amount DECIMAL(10,2) NOT NULL, sale_time DATETIME DEFAULT CURRENT_TIMESTAMP, CONSTRAINT fk_sale_product FOREIGN KEY (product_id) REFERENCES t_product(id), CONSTRAINT fk_sale_user FOREIGN KEY (user_id) REFERENCES t_user(id) ) ENGINEInnoDB DEFAULT CHARSETutf8;这段 SQL 里有几个细节不是随便写的。t_sale表里的sale_price是冗余字段——它把成交时的单价单独存了一份而不是查询时关联商品表拿当前价因为商品改价之后历史销售记录不能被影响。这是系统设计里的一个经典陷阱列出来是想告诉你数据表设计不能只满足“能查出来”。外键约束有人觉得麻烦但在这个项目里必须留着商品删不掉的时候实际上是外键在保护历史销售记录比你在业务代码里一层层判断要可靠得多。3.2 初始化数据管理员账号和测试商品怎么给建完表之后要写data.sql否则项目一跑登录页面就报“用户不存在”查了半天发现忘了做这一步。初始数据至少需要一条管理员账号密码在真实项目中存 MD5 或加盐哈希但课程设计阶段很多人直接明文。为了答辩时少被挑刺我建议你至少用 MD5 存密码Java 标准库MessageDigest就能算不需要引第三方依赖。为什么不用更高级的 BCrypt因为这个项目里你没有注册功能密码只在初始化 SQL 里写一次MD5 足够说明你意识到明文不安全这件事。商品数据要提前造 10 条左右类别 3 个供应商 2 个。不然登录进去商品列表空空如也JSP 页面上那个c:forEach循环一行都渲染不出来你都不知道是页面写错了还是数据没插进去。造数据的 SQL 不要用随机数固定写死几样东西饮料、零食、日用的类别具体的比如可乐、薯片、纸巾。这类数据贴近超市场景答辩时好讲。INSERT INTO t_category (name, sort) VALUES (饮料, 1), (零食, 2), (日用品, 3); INSERT INTO t_supplier (name, contact, phone) VALUES (本地食品批发, 王经理, 13800001111), (日用百货商行, 李经理, 13800002222); INSERT INTO t_user (username, password, real_name, role) VALUES (admin, e10adc3949ba59abbe56e057f20f883e, 系统管理员, 1); INSERT INTO t_product (category_id, supplier_id, name, price, cost, stock) VALUES (1, 1, 可口可乐 500ml, 3.50, 2.60, 120), (1, 1, 农夫山泉 550ml, 2.00, 1.20, 200), (2, 1, 乐事薯片 原味, 8.90, 6.50, 80);e10adc...这串就是123456的 MD5 值你不需要找一个在线工具去现算直接拿来初始化就行。如果你想让答辩更稳可以在工具类里写一个MD5Util登录时对用户输入的密码先加密再比对数据库代码量不大但可以看出你考虑了安全。数据库这层设计到这里其实已经可以了但前提是你建表时想清楚一个问题库存扣减到底在哪一层完成我放在下一章讲因为这个问题决定了你看待整个代码结构的方式。3.3 为什么说销售表和商品表不能合并成一张表一个很多人会踩的设计坑是把销售记录写成商品表里的“销量”字段每卖一次就UPDATE t_product SET sold sold 1。这样做的问题很严重——你失去了所有历史细节谁买的、谁操作的、什么时候买的、当时多少钱。超市管理系统的价值恰恰在这些流水数据上将来做日报表、按月统计、商品排行全依赖记录表。所以t_sale必须单独存在t_product只保留当前库存永远不要试图用一条 update 去记录历史。聚合查询要用到 SUM 和 GROUP BY这也是答辩必问题。拿“每天的销售额是多少”来说SQL 写法是SELECT DATE(sale_time), SUM(total_amount) FROM t_sale GROUP BY DATE(sale_time)。这里用DATE()函数把 DATETIME 截断成日期是 MySQL 里很常见的做法。排行类的统计也依赖这张表比如“销量前十的商品”用ORDER BY SUM(quantity) DESC LIMIT 10就能取到。可以说把t_sale剥离出来整个系统的统计功能都有了下脚的地方。4. 用 JSP Servlet DAO 把登录和商品管理跑通三段核心代码4.1 DBUtil连接 MySQL 的 JDBC 代码是每个页面的前置条件代码要从工具类写起这个说法可能你已经听腻了但它真的决定了后面所有功能能不能跑。DBUtil 类只需要做两件事从配置文件读连接参数、返回一个 Connection。Java 世界里的老牌写法是DriverManager.getConnection(url, user, password)课程设计阶段够用。不需要上连接池因为验收项目没有高并发压力连接池反而会成为引入新问题的来源——比如 C3P0 的配置文件写错账没还上等问题会莫名其妙地冒出来。package com.supermarket.util; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; /** * JDBC 工具类加载驱动、获取连接 */ public class DBUtil { private static final String URL jdbc:mysql://localhost:3306/supermarket_db?useUnicodetruecharacterEncodingutf8; private static final String USER root; private static final String PASSWORD 123456; static { try { Class.forName(com.mysql.jdbc.Driver); } catch (ClassNotFoundException e) { throw new ExceptionInInitializerError(MySQL 驱动加载失败检查 WEB-INF/lib 下是否有 mysql-connector-java.jar); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection(URL, USER, PASSWORD); } }这段代码有两个参数值得你记住。一是useUnicodetruecharacterEncodingutf8它保证中文字段从数据库到页面的编码链路是通的不加它会出现“商品名变成问号”这种让人抓狂的问题。二是Class.forName(com.mysql.jdbc.Driver)虽然新版 JDBC 驱动支持 SPI 自动注册但写静态初始化块是最兼容的写法——它能覆盖 MyEclipse 内置 Tomcat 和外部 Tomcat 的差异。static代码块保证了驱动只加载一次不会因为多次加载而报警告。4.2 登录过滤Servlet 里写判断不如在 Filter 里一劳永逸登录功能每个人都能写出来登录页提交表单到LoginServlet查数据库用户名密码对上了就把用户信息放 session。但“未登录时能不能直接访问商品管理页”这个问题决定你被答辩老师追问的深度。最省事的做法是在每个 JSP 页面顶部写if (session.getAttribute(user) null) response.sendRedirect(login.jsp)。这确实防住了但是代码重复严重而且一旦漏掉一个 JSP这条防线就破了。更稳的做法是写一个LoginFilter注册在web.xml里所有/admin/*的请求过一层检查。package com.supermarket.filter; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; public class LoginFilter implements Filter { public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request (HttpServletRequest) req; HttpServletResponse response (HttpServletResponse) res; HttpSession session request.getSession(false); // 不创建新 session boolean loggedIn (session ! null session.getAttribute(user) ! null); String requestPath request.getRequestURI(); if (loggedIn || requestPath.endsWith(login.jsp) || requestPath.endsWith(LoginServlet)) { chain.doFilter(req, res); // 放行 } else { response.sendRedirect(request.getContextPath() /login.jsp); } } }这段代码里注意request.getSession(false)这个细节——传false表示如果当前没有 session 就返回 null而不是新建一个空的。很多教程写成getSession()不加参数问题在于它会为每一个未登录的请求创建一个 session 对象白白占内存。过滤器的落地方式是最常规的写法通过web.xml配置filter-mapping把/admin/*路径交给它管理。配完之后你的商品管理页面全部放在/admin目录下面拦截逻辑就生效了。4.3 商品列表和新增商品一个完整的 DAO JSP 循环商品管理是这套系统的核心功能先看列表怎么呈现。做法是ProductServlet收到请求后调用ProductDao.findAll()把结果 List 放进 request 域再forward到product_list.jsp。JSP 里用 JSTL 的c:forEach遍历这个套路基本是固定搭配。值得写给你的是 DAO 里的查询方法它决定了你的数据库操作是规规范范每行都关闭了的还是留了一堆连接泄漏的。package com.supermarket.dao; import com.supermarket.model.Product; import com.supermarket.util.DBUtil; import java.sql.*; import java.util.ArrayList; import java.util.List; public class ProductDao { public ListProduct findAll() throws SQLException { String sql SELECT * FROM t_product ORDER BY id DESC; ListProduct list new ArrayList(); // try-with-resources 保证 Connection/PreparedStatement/ResultSet 全部关闭 try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql); ResultSet rs ps.executeQuery()) { while (rs.next()) { Product p new Product(); p.setId(rs.getInt(id)); p.setName(rs.getString(name)); p.setPrice(rs.getBigDecimal(price)); p.setStock(rs.getInt(stock)); list.add(p); } } return list; } public int insert(Product p) throws SQLException { String sql INSERT INTO t_product (category_id, supplier_id, name, price, cost, stock) VALUES (?,?,?,?,?,?); try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { ps.setInt(1, p.getCategoryId()); ps.setInt(2, p.getSupplierId()); ps.setString(3, p.getName()); ps.setBigDecimal(4, p.getPrice()); ps.setBigDecimal(5, p.getCost()); ps.setInt(6, p.getStock()); return ps.executeUpdate(); // 返回受影响行数 } } }这段代码里请务必用PreparedStatement而不是Statement。原因有两个一是拼字符串 SQL 容易出错商品名里有单引号直接就把语句折断了轻则报语法错误重则被 SQL 注入把表删了二是?占位符让代码读起来清晰别人接手也容易看懂。try-with-resources是 JDK 7 引入的语法MyEclipse 里创建项目时如果把编译级别设成 1.6 会直接报语法错误所以你得在项目属性里确认 Java Compiler 至少是 1.7。放在 WEB-INF/lib 下的那些旧 jar 不用管编译级别才是关键。5. JSP 超市管理系统开发中绕不开的高频 Bug现象、原因、解法5.1 MyEclipse 内置 Tomcat 启动慢或直接启动失败现象在 MyEclipse 里点 Run on ServerConsole 卡在“Deployment”或者报出java.lang.OutOfMemoryError: PermGen space。原因MyEclipse 自带 Tomcat 的 JVM 参数默认较小而你的项目部署后需要加载多个 jar 和大量 JSP 编译产物内存不够用。还有一个常见原因是web.xml里的display-name或servlet-mapping写错导致部署文件释放时卡住。解决打开 MyEclipse 的 Servers 视图双击已有的 Tomcat 实例在 Args 里加一行-XX:MaxPermSize256mJDK 8 不需要但还是建议把初始堆调大点。另外把你自己的项目从部署列表里移除重新 Add Deployment很多时候是上次残留的半部署状态卡住了服务器。如果还不行删掉 Tomcat 实例重新建一个5 分钟解决不用花时间研究底层。5.2 登录页提交后跳转不过去URL 路径 404现象login.jsp 输入账号密码点登录浏览器地址栏变成http://localhost:8080/SupermarketMS/LoginServlet然后显示 404 或者直接下载了一个文件。原因表单的 action 写的是相对路径LoginServlet缺少/开头的项目上下文路径context path。解决JSP 顶部引入 JSTL 的c:url处理或者直接写${pageContext.request.contextPath}/LoginServlet。这个表达式会自动把/SupermarketMS补上是 JSP 页面写链接最不容易出错的写法。别用相对路径“../”只要目录结构一调整全盘就乱套了。5.3 数据库插入中文变成问号???或被截断现象商品名称“可口可乐”插入后变成“???”或者报Incorrect string value异常。原因编码链路断裂。这条链有四环MySQL 表字符集、JDBC 连接 URL 的characterEncoding、JSP 页面本身的pageEncoding、以及 Servlet 里对 request 设置的编码。任何一环不是 UTF-8中文就妥妥出问题。解决建表时用CHARSETutf8见上文建表语句JDBC 的 URL 上带useUnicodetruecharacterEncodingutf8在所有 Servlet 处理 POST 请求时调用request.setCharacterEncoding(UTF-8)JSP 文件头写上% page languagejava contentTypetext/html; charsetUTF-8 pageEncodingUTF-8%。四样全配齐才算是把这条链路锁死。注意 MySQL 版本如果装了 8.x表默认字符集是 utf8mb4JDBC 连接参数里的characterEncodingutf8依然有效但如果之前建库时用了latin1光改连接参数救不回来必须ALTER TABLE t_product CONVERT TO CHARACTER SET utf8mb4。5.4 MySQL 驱动版本不匹配JDBC 连接时报 No suitable driver现象点登录按钮后报java.sql.SQLException: No suitable driver found for jdbc:mysql://localhost:3306/...。原因两个最常见驱动 jar 不在WEB-INF/lib下或者 jar 是 MySQL 8.x 的com.mysql.cj.jdbc.Driver而你的代码里写的还是老式驱动类。MyEclipse 2014 时代对应的驱动 jar 通常是 5.1.x 系列加载类名是com.mysql.jdbc.Driver。如果你下载的是新版mysql-connector-java-8.0.x.jar这个类名已经改了需要同时修改 DBUtil 里的Class.forName(com.mysql.cj.jdbc.Driver)并且 URL 上追加serverTimezoneAsia/Shanghai。解决优先检查 jar 位置其次核对驱动类名最后确认 MySQL 服务端口确实是 3306 而没有被本机占用。命令行里netstat -ano | findstr 3306Linux 用ss -lntp | grep 3306一看便知。5.5 JSP 页面报错 The method getParameter() is undefined for the type HttpServletRequest现象代码明明没错但 MyEclipse 里一片红。原因这个最诡异——项目没有把 Tomcat 的 runtime 库关联上导致 IDE 找不到javax.servlet接口。解决右键项目 → Properties → Targeted Runtimes勾上你的 Tomcat 版本点 Apply。如果 Runtimes 列表是空的先去 Window → Preferences → Server → Runtime Environments 把 Tomcat 路径配好。这类环境问题占了这类项目报错的一大半代码本身反而是最不需要担心的部分。6. 从能跑到像样的项目三个细节让答辩局面完全不一样把商品 CRUD 跑通、登录拦截做好这已经达到“及格线”。但如果想从“能跑”进阶到“能讲、经得起追问”我建议你再补三个能力点全部落在现有代码结构上不需要大改。第一个是把销售额统计做成一个简单的报表页第二个是把密码从明文改为 MD5 加盐校验第三个是商品删除改成逻辑删除而不物理删行。三件事的代码量都不大但每件都能在答辩时成为展示系统设计意识的证据。报表页的工程量其实很小新增一个SaleServlet查询SELECT DATE(sale_time) AS d, SUM(total_amount) AS total FROM t_sale GROUP BY d ORDER BY d DESC把结果放在 request 域里转给report.jsp。这个功能可以证明你“会用 GROUP BY 聚合”比在 SQL 语法层面被老师提问要主动得多。逻辑删除的做法是给t_product加一个status字段删除时更新状态。查询商品列表时 SQL 条件带上WHERE status 1这样历史销售记录里的外键关联不会断裂你也顺便解释了为什么建表时外键是必要的。最后说一个很多人忽略的习惯项目里留一份README.md或部署说明.txt把 JDK 版本、Tomcat 版本、MySQL 初始化脚本路径、默认管理员账号写清楚。这个文件在提交作业、换电脑继续开发、发给同学帮忙看 bug 这三个场景里都是救命稻草。我自己在带学生的过程中注意到能写清楚部署文档的人对项目的理解至少扎实一层——毕竟当你用文字把“怎么跑起来”写给别人时你自己对每个环节都会更敏感。希望这篇拆解能帮你少走几段弯路顺利把项目交掉。作为一个带过不少课程设计的人我最后想提醒你一句不要拿到题目就急着找现成源码这年头下载来的“源码”不是缺数据库脚本就是有路径写死的绝对地址改起来比从零写还痛苦这种亏我是吃过的。希望这篇文章里给到你的方法和坑位能让你避免再踩类似的坑一次把项目真正做出来。本文还有配套的精品资源点击获取