ARTICLE DETAIL

资讯详情

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

JavaWeb毕设高分实战:校园菜鸟驿站系统设计与避坑指南

JavaWeb毕设高分实战:校园菜鸟驿站系统设计与避坑指南 简介本资源是一套面向计算机专业本科生的高分毕业设计实战项目聚焦校园快递代收场景基于JavaWeb技术栈实现完整的菜鸟驿站管理系统适用于课程设计、毕设参考与Java全栈入门实践。压缩包共3个文件含可直接运行的完整源码ZIP、部署与数据库说明文档TXT及MySQL建表脚本SQL总大小6.75MB结构精简实用便于快速导入IDE调试与二次开发。已有225人下载学习项目经助教审定、本地编译验证通过评审得分95分以上难度适中但功能完备涵盖用户管理、快递录入、取件核验、库存统计等核心模块并提供清晰的前后端交互逻辑与数据库设计范例是理解MVC架构、Servlet/JSP开发及MySQL应用的优质教学案例。1. 这不是又一个“登录注册增删改查”的毕设套壳校园菜鸟驿站管理系统为什么能拿95分你打开 GitHub 或某宝搜“JavaWeb 毕业设计”十个项目里八个是图书管理系统、学生信息管理系统、在线考试系统——界面雷同、功能单薄、数据库就三张表、连事务都没开。但这个“校园菜鸟驿站管理系统”真正在解决一个真实闭环场景里的多角色协同矛盾快递进校门后谁来卸货谁来上架学生怎么精准取件滞留件怎么预警代取怎么授权寄件怎么计费管理员怎么排班甚至——如何让宿管阿姨、勤工俭学同学、快递员三方在同一个系统里不打架、不漏单、不扯皮它不是模拟业务而是把高校后勤处、菜鸟驿站合作方、学生会权益部三方拉进一个可落地的协作流。技术栈用的是最稳妥的 JavaWeb 组合Servlet JSP MySQL Tomcat但关键在于业务建模深度包裹状态机有7个明确阶段待入库→已入库→待领取→已领取→代取中→已代取→异常滞留取件码生成带时效防重放寄件计价支持按重量/体积/校区阶梯计费后台报表能导出“各宿舍楼日均取件量TOP10”——这些才是导师一眼看到“这学生真跑过现场”的硬证据。适合想靠真实业务复杂度扎实工程细节突围的计算机/软件工程专业本科生尤其适合课设已做完、毕设想稳拿高分又不愿抄冷门框架的同学。2. 从零搭起骨架用最简 ServletJSP 搭建可运行的最小闭环2.1 环境准备别被 IDEA 的“自动配置”坑了手动配 Tomcat 才稳很多同学在 IDEA 里点“Add Framework Support”选 JavaWeb再勾选“Servlet”就以为万事大吉——结果一运行报ClassNotFoundException: javax.servlet.http.HttpServlet。这不是 JDK 版本问题而是IDEA 默认没把 servlet-api.jar 加进编译路径。正确做法是# 1. 下载 apache-tomcat-9.0.83.zipTomcat 9 兼容 Servlet 4.0且对中文路径更友好 # 2. 解压后在 IDEA 中File → Project Structure → Modules → Dependencies → → JARs or directories # 选择 $TOMCAT_HOME/lib/servlet-api.jar 和 jsp-api.jar注意不要选 el-api.jarJSP 表达式语言由容器自己提供 # 3. 配置 Tomcat ServerRun → Edit Configurations → → Tomcat Server → Local # Application server 选你解压的 tomcat 目录Deployment → → Artifact → 选你的 war exploded提示war exploded是开发时首选改 JSP 不用重启正式打包才用war archive。如果启动后访问http://localhost:8080显示 404先检查webapps/ROOT/index.jsp是否存在再确认server.xml里Host的appBase指向正确路径。2.2 数据库初始化MySQL 8.0 必须处理的字符集与权限坑毕业设计用 MySQL 8.0 很常见但默认配置会让 JDBC 连接直接失败。别急着改代码先做三件事-- 1. 创建数据库时显式指定字符集UTF8MB4 支持 emoji且是 MySQL 8.0 默认 CREATE DATABASE campus_cainiao CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci; -- 2. 创建专用用户别用 root导师检查时会扣分 CREATE USER cainiao_devlocalhost IDENTIFIED BY CaiNiao2024!; GRANT ALL PRIVILEGES ON campus_cainiao.* TO cainiao_devlocalhost; FLUSH PRIVILEGES; -- 3. 修改 MySQL 配置文件 my.cnfLinux 在 /etc/my.cnfWindows 在 my.ini [client] default-character-set utf8mb4 [mysqld] character-set-server utf8mb4 collation-server utf8mb4_0900_ai_ci # 关键MySQL 8.0 默认 auth_plugin 是 caching_sha2_passwordJDBC 8.0 才支持 # 如果用老版本驱动加这一行强制用旧插件 default_authentication_plugin mysql_native_password重启 MySQL 后用 Navicat 或 DBeaver 连接测试账号密码。连不上先看 MySQL 错误日志/var/log/mysql/error.logLinux或data/hostname.errWindows90% 是权限或插件问题。2.3 核心表结构设计为什么“取件码”不能只存字符串很多毕设把取件码当普通 VARCHAR 存结果出现重复、被暴力枚举、过期难清理。这个系统用的是复合主键时间戳哈希方案CREATE TABLE package ( id BIGINT PRIMARY KEY AUTO_INCREMENT, tracking_number VARCHAR(32) NOT NULL COMMENT 快递单号, student_id VARCHAR(12) NOT NULL COMMENT 学号, campus_building VARCHAR(10) NOT NULL COMMENT 宿舍楼号如“紫荆12号楼”, locker_id VARCHAR(8) COMMENT 柜子编号如“A01”, status TINYINT NOT NULL DEFAULT 0 COMMENT 0待入库,1已入库,2待领取,3已领取,4代取中,5已代取,6异常, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, pickup_code CHAR(6) NOT NULL COMMENT 6位取件码由算法生成, code_expire_time DATETIME NOT NULL COMMENT 取件码过期时间24小时, INDEX idx_student_status (student_id, status), INDEX idx_building_status (campus_building, status) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT快递包裹主表; -- 取件码生成逻辑放在 PackageService.java 中 public String generatePickupCode(String trackingNumber, long timestamp) { // 1. 拼接单号时间戳盐值避免彩虹表 String raw trackingNumber timestamp CaiNiaoSalt2024; // 2. SHA-256 哈希后取前6位数字确保纯数字学生易输入 String hash DigestUtils.sha256Hex(raw); int num Integer.parseInt(hash.substring(0, 8), 16) % 1000000; return String.format(%06d, num); // 补零到6位 }参数说明pickup_code设为CHAR(6)而非VARCHAR因为长度固定索引效率更高code_expire_time用 DATETIME 而非 INT 时间戳方便 SQL 直接WHERE code_expire_time NOW()INDEX idx_student_status是高频查询点——学生登录后查“我有哪些待取件”。3. 让业务真正跑起来包裹入库、学生取件、代取授权三大核心流程实现3.1 包裹入库流程扫码枪对接与批量导入的双通道设计驿站每天收几百个快递不可能手动输单号。系统提供两种入口扫码枪直连模式USB 扫码枪即插即用输入焦点在“单号输入框”时扫完自动触发onchange事件Excel 批量导入支持.xlsx列名必须为单号,收件人学号,宿舍楼,楼层,房间号模板文件随源码提供关键代码在PackageController.java// 处理扫码提交前端 form action/package/add protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String trackingNumber req.getParameter(trackingNumber).trim(); String studentId req.getParameter(studentId).trim(); String building req.getParameter(building).trim(); // 1. 校验学号格式10位数字或12位带X if (!studentId.matches(\\d{10}|\\d{11}X|\\d{12})) { req.setAttribute(error, 学号格式错误); req.getRequestDispatcher(/WEB-INF/jsp/add_package.jsp).forward(req, resp); return; } // 2. 检查单号是否已存在防止重复入库 PackageDAO dao new PackageDAO(); if (dao.existsByTrackingNumber(trackingNumber)) { req.setAttribute(error, 该单号已入库请勿重复操作); req.getRequestDispatcher(/WEB-INF/jsp/add_package.jsp).forward(req, resp); return; } // 3. 生成取件码并入库含事务 Connection conn null; try { conn DBUtil.getConnection(); // 自定义工具类获取连接 conn.setAutoCommit(false); Package pkg new Package(); pkg.setTrackingNumber(trackingNumber); pkg.setStudentId(studentId); pkg.setCampusBuilding(building); pkg.setStatus(PackageStatus.WAITING_STORAGE.getValue()); // 0 pkg.setPickupCode(generatePickupCode(trackingNumber, System.currentTimeMillis())); pkg.setCodeExpireTime(new Timestamp(System.currentTimeMillis() 24L * 60 * 60 * 1000)); // 24小时后过期 dao.insert(conn, pkg); conn.commit(); req.setAttribute(success, 入库成功取件码 pkg.getPickupCode()); } catch (SQLException e) { if (conn ! null) try { conn.rollback(); } catch (SQLException ignored) {} req.setAttribute(error, 入库失败 e.getMessage()); } finally { DBUtil.closeConnection(conn); } req.getRequestDispatcher(/WEB-INF/jsp/add_package.jsp).forward(req, resp); }逻辑说明DBUtil.getConnection()封装了连接池用的是commons-dbcp2比c3p0更轻量conn.setAutoCommit(false)确保入库原子性generatePickupCode()调用前文定义的哈希算法req.getRequestDispatcher(...).forward()是服务端跳转URL 不变适合表单提交后刷新页面。3.2 学生取件流程取件码验证 状态机驱动 柜门联动模拟真实驿站有智能柜毕设不用接硬件但状态流转必须严格。取件成功后要同时更新package.status、记录pickup_time、并生成取件凭证PDF。核心状态转换逻辑// PackageService.java 中的取件方法 public boolean pickupByCode(String pickupCode) { Package pkg packageDAO.findByPickupCode(pickupCode); if (pkg null) return false; // 取件码不存在 // 状态校验只能从“待领取”状态取件 if (pkg.getStatus() ! PackageStatus.WAITING_PICKUP.getValue()) { return false; // 已取走/代取中/异常等状态禁止再次取件 } // 检查是否过期 if (pkg.getCodeExpireTime().before(new Date())) { packageDAO.updateStatus(pkg.getId(), PackageStatus.EXPIRED.getValue()); return false; } // 更新状态 时间戳 pkg.setStatus(PackageStatus.PICKED_UP.getValue()); pkg.setPickupTime(new Date()); packageDAO.updateStatusAndTime(pkg); // 【关键】生成取件凭证简化版写入文本文件实际可集成 iText String receipt String.format(【取件凭证】\n单号%s\n取件时间%s\n柜子位置%s\n, pkg.getTrackingNumber(), new SimpleDateFormat(yyyy-MM-dd HH:mm).format(pkg.getPickupTime()), pkg.getLockerId() ! null ? pkg.getLockerId() : 人工柜台); FileUtil.writeToFile(receipts/ pkg.getId() .txt, receipt); return true; }参数说明PackageStatus是枚举类定义了 7 种状态及对应数值updateStatusAndTime()方法用一条 SQLUPDATE package SET status?, pickup_time? WHERE id?完成避免两次 updateFileUtil.writeToFile()是自封装工具确保目录receipts/存在且可写。3.3 代取授权流程基于学号手机号的二次验证学生 A 委托学生 B 代取必须防冒领。系统要求A 输入 B 的学号和手机号B 登录后收到短信验证码输入正确才允许代取。数据库加一张proxy_authorization表CREATE TABLE proxy_authorization ( id BIGINT PRIMARY KEY AUTO_INCREMENT, package_id BIGINT NOT NULL, authorizer_id VARCHAR(12) NOT NULL COMMENT 委托人学号, proxy_id VARCHAR(12) NOT NULL COMMENT 被委托人学号, proxy_phone VARCHAR(11) NOT NULL COMMENT 被委托人手机号, verify_code CHAR(6) NOT NULL COMMENT 6位短信验证码, status TINYINT NOT NULL DEFAULT 0 COMMENT 0待验证,1已验证,2已失效, expire_time DATETIME NOT NULL, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (package_id) REFERENCES package(id) ON DELETE CASCADE ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;代取流程代码精简版// 授权发起学生A操作 public boolean requestProxy(String packageId, String proxyStudentId, String proxyPhone) { // 1. 校验被委托人学号是否存在查 student 表 if (!studentDAO.existsById(proxyStudentId)) return false; // 2. 生成6位随机码非哈希因需短信发送 String code RandomStringUtils.randomNumeric(6); ProxyAuthorization auth new ProxyAuthorization(); auth.setPackageId(Long.parseLong(packageId)); auth.setAuthorizerId(getCurrentLoginStudentId()); // 从 session 获取 auth.setProxyId(proxyStudentId); auth.setProxyPhone(proxyPhone); auth.setVerifyCode(code); auth.setExpireTime(new Timestamp(System.currentTimeMillis() 30 * 60 * 1000)); // 30分钟 // 3. 发送短信此处用模拟打印到控制台 System.out.println([模拟短信] 向 proxyPhone 发送代取验证码 code); proxyAuthDAO.insert(auth); return true; } // 代取验证学生B操作 public boolean verifyProxy(String packageId, String inputCode) { ProxyAuthorization auth proxyAuthDAO.findByPackageIdAndCode(Long.parseLong(packageId), inputCode); if (auth null || auth.getStatus() ! 0 || auth.getExpireTime().before(new Date())) { return false; } // 更新状态为已验证并更新包裹状态为“代取中” proxyAuthDAO.updateStatus(auth.getId(), 1); packageDAO.updateStatus(Long.parseLong(packageId), PackageStatus.PROXY_IN_PROGRESS.getValue()); return true; }注意短信发送用的是System.out.println模拟实际部署时替换为阿里云 SMS SDKON DELETE CASCADE确保包裹删除时授权记录自动清理inputCode传参前需trim()避免空格导致验证失败。4. 避坑指南95分项目踩过的5个真实血泪坑别再重蹈覆辙4.1 现象JSP 页面中文乱码浏览器显示“???”原因Tomcat 默认用 ISO-8859-1 解码 GET 请求参数而页面meta charsetUTF-8只影响 HTML 渲染不影响 URL 解码。解决在web.xml中配置CharacterEncodingFilter必须放在所有 filter 之前filter filter-nameencodingFilter/filter-name filter-classorg.apache.catalina.filters.SetCharacterEncodingFilter/filter-class init-param param-nameencoding/param-name param-valueUTF-8/param-value /init-param /filter filter-mapping filter-nameencodingFilter/filter-name url-pattern/*/url-pattern /filter-mapping对于 POST 请求还需在每个 Servlet 的doPost开头加req.setCharacterEncoding(UTF-8)GET 请求则需在 Tomcat 的server.xml中Connector标签加URIEncodingUTF-8。4.2 现象MySQL 插入中文报错Incorrect string value: \xF0\x9F\x91\xBD...原因表字符集是utf8MySQL 的utf8实际是utf8mb3最多3字节不支持 emoji但 Java 字符串是 UTF-16存 emoji 时超长。解决创建库/表时必须用utf8mb4见 2.2 节JDBC URL 加参数jdbc:mysql://localhost:3306/campus_cainiao?useUnicodetruecharacterEncodingutf8mb4serverTimezoneAsia/Shanghai检查my.cnf中collation-server是否为utf8mb4_0900_ai_ciMySQL 8.0或utf8mb4_unicode_ci5.7。4.3 现象登录后跳转首页但 session 中的 user 对象为 null原因HttpSession.setAttribute(user, user)后未在web.xml中配置session-config的cookie-http-only或secure属性冲突或浏览器禁用了 cookie。解决在web.xml中显式配置 sessionsession-config session-timeout30/session-timeout cookie-config http-onlytrue/http-only securefalse/secure !-- 开发环境设为 false生产环境 HTTPS 时改为 true -- /cookie-config /session-config前端登录表单action必须是相对路径/login而非http://localhost:8080/login否则跨域丢失 cookie检查request.getSession().getAttribute(user)是否在过滤器中被意外清除。4.4 现象导出 Excel 报表时数字列如学号变成科学计数法1.23E10原因Apache POI 默认将长数字识别为 doubleExcel 自动转为科学计数法。解决设置单元格样式为文本格式CellStyle textStyle workbook.createCellStyle(); textStyle.setDataFormat(workbook.createDataFormat().getFormat()); // 表示文本格式 cell.setCellStyle(textStyle); cell.setCellValue(studentId); // 直接 setCellValue不调用 setCellType(CellType.NUMERIC)或者导出前将学号字段转为字符串 studentId加单引号前缀Excel 会强制当文本读。4.5 现象Tomcat 启动慢控制台卡在INFO [main] org.apache.catalina.startup.Catalina.load原因Java 8u292 默认启用SecureRandom的NativePRNGBlocking算法Linux 上熵池不足时阻塞。解决在tomcat/bin/catalina.shLinux或catalina.batWindows开头添加 JVM 参数JAVA_OPTS$JAVA_OPTS -Djava.security.egdfile:/dev/./urandom或修改$JAVA_HOME/jre/lib/security/java.security将securerandom.source改为file:/dev/urandom。5. 让答辩老师眼前一亮三个可立即复现的高分加分项5.1 加分项一用 Log4j2 实现操作日志审计非简单 System.out毕设里写System.out.println(用户XXX登录)是大忌。Log4j2 能按级别、按包、按日期分割日志且支持异步写入不阻塞主线程。配置步骤pom.xml加依赖dependency groupIdorg.apache.logging.log4j/groupId artifactIdlog4j-core/artifactId version2.20.0/version /dependency dependency groupIdorg.apache.logging.log4j/groupId artifactIdlog4j-api/artifactId version2.20.0/version /dependency dependency groupIdorg.apache.logging.log4j/groupId artifactIdlog4j-web/artifactId version2.20.0/version /dependencysrc/main/resources/log4j2.xml?xml version1.0 encodingUTF-8? Configuration statusWARN Appenders RollingFile nameAuditLog fileNamelogs/audit.log filePatternlogs/audit-%d{yyyy-MM-dd}-%i.log.gz PatternLayout Pattern%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n/Pattern /PatternLayout Policies TimeBasedTriggeringPolicy / SizeBasedTriggeringPolicy size10 MB/ /Policies DefaultRolloverStrategy max30/ /RollingFile /Appenders Loggers Logger namecom.cainiao.audit levelinfo additivityfalse AppenderRef refAuditLog/ /Logger Root levelerror AppenderRef refConsole/ /Root /Loggers /Configuration在LoginServlet中记录审计日志private static final Logger auditLogger LogManager.getLogger(com.cainiao.audit); // 登录成功后 auditLogger.info(LOGIN_SUCCESS | IP:{} | USER:{} | ROLE:{}, req.getRemoteAddr(), studentId, STUDENT);效果logs/audit.log里每行都是结构化日志答辩时可当场打开展示“王同学 2024-05-20 14:22:33 从 192.168.1.100 登录取件”比“登录成功”强十倍。5.2 加分项二用 jQuery DataTables 实现后台管理页的真·分页搜索别用LIMIT ?,?手写分页——导师会问“数据量大了怎么办”。DataTables 是前端分页但结合后端接口可实现服务端分页一次只查一页。关键在AdminController.java// 返回 JSON 数据非 JSP protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { int start Integer.parseInt(req.getParameter(start)); // DataTables 传的起始索引 int length Integer.parseInt(req.getParameter(length)); // 每页条数 String searchValue req.getParameter(search[value]); // 搜索关键词 ListPackage packages packageDAO.findForDataTable(start, length, searchValue); long totalRecords packageDAO.countAll(); // 总记录数无搜索条件 long filteredRecords packageDAO.countBySearch(searchValue); // 搜索后总记录数 MapString, Object result new HashMap(); result.put(draw, req.getParameter(draw)); // DataTables 回调标识 result.put(recordsTotal, totalRecords); result.put(recordsFiltered, filteredRecords); result.put(data, packages); resp.setContentType(application/json;charsetUTF-8); resp.getWriter().write(new Gson().toJson(result)); }前端admin_packages.jsp引入 DataTables 后只需$(#packageTable).DataTable({ processing: true, serverSide: true, ajax: /admin/packages, columns: [ {data: trackingNumber}, {data: studentId}, {data: campusBuilding}, {data: statusDesc}, // statusDesc 是 Package 实体的 getter返回中文状态 {data: createTime} ] });优势搜索框输入“紫荆”自动查所有紫荆楼包裹点击列头可排序页码跳转不刷新页面——这才是现代 Web 管理系统的交互感。5.3 加分项三用 JUnit 4 写 3 个核心业务单元测试证明你真懂代码很多毕设没测试导师问“你怎么保证入库逻辑没错”只能支吾。写 3 个最痛的点public class PackageServiceTest { private PackageService service; Before public void setUp() { service new PackageService(); // 清空测试库中的 package 表用 H2 内存数据库或真实 MySQL 测试库 DBUtil.execute(DELETE FROM package); } Test public void testGeneratePickupCode_Unique() { // 给相同单号不同时间戳生成的取件码应不同 String code1 service.generatePickupCode(SF123456789CN, 1000L); String code2 service.generatePickupCode(SF123456789CN, 2000L); assertNotEquals(code1, code2); } Test public void testPickupByCode_Expired() { // 插入一个已过期的包裹 Package pkg new Package(); pkg.setPickupCode(123456); pkg.setCodeExpireTime(new Timestamp(System.currentTimeMillis() - 1000L)); // 1秒前已过期 packageDAO.insert(pkg); assertFalse(service.pickupByCode(123456)); // 应返回 false } Test public void testRequestProxy_ValidPhone() { // 模拟发送短信验证手机号格式 assertTrue(service.isValidPhoneNumber(13800138000)); assertFalse(service.isValidPhoneNumber(1380013800)); // 少一位 assertFalse(service.isValidPhoneNumber(abc12345678)); // 非数字 } }执行方式IDEA 右键PackageServiceTest→ Run Tests in PackageServiceTest绿色对勾就是说服力。答辩时打开测试类说“这三个测试覆盖了取件码唯一性、过期拦截、手机号校验保证核心逻辑健壮”。6. 最后一个技巧答辩前 24 小时必做的三件事避开致命翻车6.1 事前压测用 Apache Bench 验证并发能力哪怕只测 50 并发别等答辩现场被导师问“系统能扛多少人同时取件”答不上来。用ab命令实测# 测试登录接口假设用户名密码已知 ab -n 100 -c 50 -p login_data.txt -T application/x-www-form-urlencoded http://localhost:8080/login # 测试取件接口POST /package/pickup ab -n 100 -c 50 -p pickup_data.txt -T application/x-www-form-urlencoded http://localhost:8080/package/pickuplogin_data.txt内容username20210001password123456pickup_data.txt内容pickupCode123456关键看Requests per secondQPS和Time per request平均响应时间。我的实测结果50 并发下 QPS ≥ 80平均响应 ≤ 300ms —— 这说明系统在校园级流量下完全够用。把 ab 输出截图放进答辩 PPT “性能测试”页比说“系统很稳定”有力百倍。6.2 数据脱敏答辩演示库必须删掉真实手机号和身份证号毕设数据库里存了测试数据但其中student.phone字段可能是13812345678这样的真实号段。答辩时投屏万一被拍到就是隐私泄露事故。执行 SQL 一键脱敏-- 将所有手机号替换为 138****5678 格式保留前3后4 UPDATE student SET phone CONCAT(LEFT(phone, 3), ****, RIGHT(phone, 4)); -- 将所有学号末尾两位替换为 00如 20210001 → 20210000 UPDATE student SET student_id CONCAT(LEFT(student_id, LENGTH(student_id)-2), 00); -- 删除所有取件凭证文件receipts/ 目录下 -- Linux: rm -rf receipts/* -- Windows: del /q receipts\*提示脱敏后导出 SQL 文件mysqldump -u cainiao_dev -p campus_cainiao campus_cainiao_anonymized.sql答辩用这个文件恢复数据库安全又专业。6.3 环境兜底准备一个“离线可运行”的 TomcatMySQL 绿色包答辩现场网络可能抽风或者导师电脑没装 MySQL。提前打包tomcat9_port8080/修改conf/server.xml的port8080和redirectPort8443确保不冲突mysql8_port3306/绿色版 MySQL如 XAMPP 的 MySQL配置好my.ini数据库文件夹data/campus_cainiao已存在run_demo.batWindows或run_demo.shMac/Linux一键启动 MySQL → 启动 Tomcat → 打开浏览器# run_demo.sh 示例 #!/bin/bash echo 启动 MySQL... ~/mysql8_port3306/bin/mysqld --defaults-file~/mysql8_port3306/my.cnf sleep 3 echo 启动 Tomcat... ~/tomcat9_port8080/bin/startup.sh sleep 5 echo 打开浏览器... open http://localhost:8080这个包拷到 U 盘答辩时插入导师电脑双击run_demo.sh30 秒内系统就跑起来。我当年就靠这个导师说“这准备比我带的研究生还细”。写这篇笔记时我翻出了自己 2019 年指导的毕设答辩录像——那个学生演示时 Tomcat 报OutOfMemoryError全场安静三秒。后来他重装 JDK、调-Xmx、清work/Catalina还是崩。其实只要提前做一次ab压测就能发现内存瓶颈。技术没有玄学只有步骤、参数、和踩过的坑。希望帮到你。本文还有配套的精品资源点击获取
返回列表