
1. 从毕设题目看本质商品预购平台到底在考什么每年到了毕设季总有学弟学妹拿着类似“基于JavaWeb的商品预购平台的设计与实现【完整源码LW部署说明演示视频】”这样的题目来问我第一句话通常是“学长这个题难吗我能不能直接拿来改一改交上去”我的回答一直很直接这个题目不难但它是一道门槛很隐蔽的综合题。表面上它只要求你“做一个能预购商品的网站”实际上它把JavaWeb课程里最核心的东西全部串进来了——JSP/Servlet、数据库设计、会话管理、Maven或传统Web工程结构、Tomcat部署、甚至一点并发和状态机思维。你如果只是把源码跑起来那是零收获但如果你愿意从需求反推设计一点点把代码读透这个项目能帮你把大学四年学得稀碎的Java知识全部理顺。先说清楚这个平台要解决的业务问题。商品预购和普通电商下单最大的区别在于“时间窗口”和“限量逻辑”。普通网购是“有货就卖下单扣库存”预购则是平台提前放出商品信息、设定一个开始预购的时间点和总名额用户在指定时间内提交预购意向并支付定金或全款平台在预定时间点再统一处理后续发货。所以这个系统的核心不是CRUD而是三件事时间判断、库存保护、状态流转。你要保证同一件商品不会超卖要在预购开始前后切换不同的页面状态要能处理“预购成功但未支付”“支付后等待发货”这些中间状态——这才是评审老师真正想看的东西。另外标题里那个“完整的LW部署说明演示视频”其实点明了毕设交付的标准形态LW指论文即开题、绪论、需求分析、系统设计、测试这些章节部署说明是给评审老师一个能跑起来的环境记录演示视频是为了证明系统真实可运行。作为学长我强烈建议你哪怕拿到了全套东西也要自己把环境装一遍、把代码读一遍、把视频录一遍。为什么因为答辩现场老师最爱问的就是“这个模块怎么实现的”“这个Bug你怎么排查的”你如果只会按F5启动然后点两下页面很容易被追问到崩溃。适合谁来学这个题目一类是自己写了代码想找参考的初学者另一类是已经拿到源码但完全看不懂思路的同学。我下面的内容会按“业务设计—技术架构—数据库—功能实现—部署排错—答辩准备”这条线展开尽量把关键代码思路和最容易踩的坑讲透句句都是我在实际带毕设时见过的问题。2. 技术选型背后的原因为什么JavaWeb一代至今仍是毕设主流聊技术栈之前先放一个很多同学都有的疑问为什么现在外面都是Spring Boot满天飞毕设题目还在写JavaWeb难道不该赶上潮流用Spring Boot Vue吗这里有三个现实原因。第一很多高校的JavaWeb课程大纲仍然以JSP Servlet MySQL Tomcat为主线考试考的是这套毕设题目自然沿用这套。第二传统JavaWeb技术栈的代码写在明面上没有Spring Boot那种“自动配置”和“约定大于配置”的黑盒评审老师能直接看到请求是怎么从浏览器一路跑到数据库再返回的这对答辩来说反而是好事。第三老一代满分项目源码改造成本低网上资料最全你自己复现时翻车概率最小。但这里我要说句实话如果你已经比较熟悉Java基础我建议你在“JavaWeb技术栈”的大前提下把实现方式升级成Servlet JSP MyBatis或者Servlet JSP JDBC封装版而不要硬去套一个笨重的SSH框架。原因后面会讲先记住结论。技术版本的选择上尽量用稳定组合而不是最新组合。我推荐这个搭配JDK 8兼容性最好Tomcat和IDE支持最稳不要去追JDK 17/21毕设项目没必要。Tomcat 8.5或9.x对应Servlet 3.1/4.0规范够用且教程最多。MySQL 5.7或8.08.0注意驱动要换com.mysql.cj.jdbc.Driver并且URL上要带时区参数这个坑下文中细说。IDEA社区版或专业版 Maven用Maven管理依赖会让部署说明好写很多前提是你熟悉传统Web目录结构。JSP JSTL做前端页面渲染少量原生JavaScript/CSS做交互不要引入太重的前端框架。为什么不去碰Spring Boot不是因为Spring Boot不好而是考虑到多数毕设评分标准讲的是“掌握JavaWeb核心技术”。你写一个Spring Boot项目答辩老师想看Servlet生命周期、看Filter过滤器配置、看HttpSession使用这些在Spring Boot里都被封装得看不见了。传统JavaWeb项目里你能清晰地展示过滤器链、监听器、Servlet映射这些“手工感”很强的细节恰恰是拿分的点。当然如果你的开题报告已经定了Spring Boot那就走Spring Boot路线题目和实现保持一致即可这里不抬杠。技术选型上还有一个小细节很多人会忽略前端页面是直接写JSP还是HTMLAjax。我的建议是混合使用。像商品列表、预购详情这种需要动态渲染的页面用JSP JSTL在服务端渲染减少前端调试成本像“提交预购”这种需要局部刷新并提示结果的操作用Ajax发JSON到Servlet返回状态码避免整个页面刷新导致预购状态丢失。这样既体现了JSP技能又展示了前后端交互思路。3. 核心业务与数据模型设计先把表设计好再写代码很多同学拿到源码第一件事是打开IDE跑起来这没错但要真正搞懂系统必须倒过来从数据库设计入手。表结构是整套系统的骨架表之间的关系设计不合理后面写代码全是补丁。商品预购平台至少需要这几张核心表**用户表。**包含用户ID、用户名、密码、真实姓名、手机号、邮箱、注册时间、状态。密码必须存加密后的密文而不是明文哪怕是毕设也要养成这个习惯。可以使用MD5加盐或者用更稳妥的SHA-256加盐项目不大写一个加密工具类即可。**商品表。**包含商品ID、商品名称、主图URL、详情描述、原价、预购价、预购开始时间、预购结束时间、总库存即预购名额、已预购数量、商品状态未开始/预购中/已售罄/已结束/已下架。这里最关键的字段就是“预购开始时间”和“预购结束时间”系统里所有的状态判断都围绕它们展开。**预购订单表。**这张表要关联用户和商品包含预购订单ID、用户ID、商品ID、预购数量、下单时间、预购状态待支付/已支付/已取消/已发货/已完成、支付方式、支付时间、收货地址ID等。严格来说一个用户对同一款商品在预购期内的订单应该做唯一性约束——这是在业务层控制的很多源码里没做导致用户可以反复提交预购订单最终超卖。**收货地址表。**包含地址ID、用户ID、收货人、手机号、省市区、详细地址、是否默认地址。预购成功之后需要填写地址或者提交预购时直接选择一个默认地址这个逻辑看你的业务设计。**管理员表。**用于后台登录包含管理员ID、用户名、密码、角色、最后登录时间。后台和前台用户表不建议共用虽然功能上可以复用但语义上分开更清晰答辩时也更好解释。除了表结构你要理解表之间的一对多、多对一关系。一个用户有多个预购订单一个商品被多个用户预购所以预购订单表同时持有用户ID和商品ID作为外键。商品表和预购订单表是一对多用户表和收货地址表是一对多。把这些关系画成ER图放进论文里就是第二章“数据库设计”的核心素材。接下来是业务上最值得深挖的两个细节。第一个细节是“预购数量限制”。电商里最怕的就是超卖预购场景更是如此。最简单可靠的做法是在商品表里维护一个“已预购数量”字段当用户提交预购请求时先检查已预购数量 本次数量是否超过总库存如果没超过就执行一条带条件更新的SQL去修改已预购数量同时插入预购订单。为什么强调“带条件更新”因为如果分开两步执行先查询再更新两个用户同时提交时就可能都查到“还剩1件”然后都扣成“已预购2件”这就超卖了。用一条UPDATE 商品表 SET 已预购数量 已预购数量 #{num} WHERE 商品ID #{id} AND 已预购数量 #{num} 总库存这种写法数据库自己在更新时判断天然避免并发超卖。这个“先查再改要不得条件更新才是正道”的结论我建议你在论文测试章节里专门写一小段很加分。第二个细节是“预购时间判断”。预购系统的核心就是时间所以所有“能不能下单”“页面显示什么状态”都不能只看前端显示的变量必须以后端服务器时间为准。前端可以拿到预购开始时间做倒计时展示但真正提交预购时Servlet控制层必须重新校验当前时间是否落在预售窗口内。我在评审别人的设计时经常看到一个问题前端隐藏了一个“开始预购”按钮时间没到就不显示但恶意用户直接构造请求一样能提交。所以后端校验是安全底线前端按钮只负责体验。另外建议在商品表里直接冗余一个“状态”字段比如0未开始、1预购中、2已售罄、3已结束。每次商品被管理员发布后系统可以依据当前时间和库存自动更新这个状态。为什么要冗余状态字段而不是每次查询时临时算因为多张表都要显示商品状态列表页、详情页、后台管理页如果都临时算SQL会写得很重复而且不方便统一维护。状态字段的更新逻辑可以放在一个定时刷新方法里也可以在每次查询商品时顺带检查并更新。对于毕设前者足够。4. 工程结构三层的代码该怎么组织现在进到代码层面。贯穿整个JavaWeb毕设最重要的一条经验就是代码结构清晰比代码本身写得花哨更重要。评审老师翻你的工程目录第一眼就看得出一份源码是拼凑的还是用心写的。传统的JavaWeb项目通常分为三层再加一个工具包表现层Web层放Servlet和JSP。Servlet负责接收请求、解析参数、调用业务层、根据结果跳转或返回JSON。JSP负责展示在WebContent或webapp目录下按功能分文件夹前端页面放在front或者直接放在根目录后台管理页面放在admin下面。业务层Service层Service接口 Service实现类一个模块一个Service。比如UserService、ProductService、OrderService、AddressService、AdminService。业务层里写核心的业务判断逻辑比如预购时间校验、库存扣减和订单创建的组合逻辑。数据访问层Dao层/持久层每张表对应一个Dao封装所有对数据库的增删改查。如果用了JDBCDao里就是每次ConnectionPreparedStatement如果用了MyBatisDao变成Mapper接口SQL写在XML里。实际带毕设时我更推荐手写JDBC封装一个BaseDao原因很简单你自己写的代码答辩时能讲清楚每一行而MyBatis的底层如果被追问起来很多人答不好。实体类与工具类实体类对应表结构字段名和数据库列名保持一致。工具类至少要有数据库连接工具类DBUtil、字符编码过滤器CharacterEncodingFilter、MD5工具类、时间格式化工具类、分页工具类。这里必须重点说两个所有JavaWeb新手都会栽跟头的细节。第一个是包名问题。很多破解版或老项目源码的包名是com.xxx.xxx这种带个人标识的跑起来没问题但如果你要当成自己的毕设交建议统一改成自己的包名比如com.shop.preorder。改包名不是面子工程改完包名你必然要手动过一遍所有Java文件里的import和package声明这个过程本身就是一次项目通读。另一个细节是Java文件名里不要出现中文和空格编码统一UTF-8。第二个是编码过滤器。项目统一使用UTF-8通常用一个Filter拦截所有请求设置request.setCharacterEncoding(UTF-8)和response.setContentType(text/html; charsetUTF-8)并且在web.xml里配置filter映射为/或/*。如果你不做这一步前端通过POST表单提交的中文数据到后端会乱码MySQL存进去也是乱码然后你会花一晚上排查为什么用户名变成“???”。这个坑我见得太多了几乎每个第一次做JavaWeb毕设的人都踩过。下面给一个典型的项目目录结构做参考src/ main/ java/ com/shop/preorder/ entity/ -- 实体类 dao/ -- 数据库访问接口 dao/impl/ -- JDBC实现或Mapper实现 service/ -- 业务接口 service/impl/ -- 业务实现 web/ -- Servlet控制器 util/ -- 工具类 filter/ -- 过滤器 resources/ db.properties -- 数据库连接配置 webapp/ WEB-INF/ web.xml -- Web部署描述符 lib/ -- 依赖jar包如果没走Maven css/ js/ images/ admin/ -- 后台管理页面 front/ -- 前台页面 index.jsp -- 首页这个结构看起来平平无奇但它的好处是评审老师看目录就能说出“这是标准的MVC三层架构”你论文里的系统设计章节直接可以对照着写不需要临时编。我个人认为这是整个毕设项目中最值得花时间去清理的部分因为很多二手源码的目录是乱的Servlet全堆在一个包JSP散落在根目录工具类里还有绝对路径写死的内容。你把它整理成上面这个结构项目的“质感”立刻就上来了。5. 功能实现的高频考点前端、后端、状态流转怎么做说完了结构进入功能实现。商品预购平台通常包含前台用户模块和后台管理模块我挑每个模块里最容易在答辩中被提问、也最容易写崩的点展开讲。5.1 用户登录与会话管理用户登录的常规流程是用户提交用户名密码Service层查出用户并比对密码密文比对成功把用户对象放入session同时查询该用户是否有关联地址并放一个默认地址标识到session或临时对象里。这里有两个容易忽略的点。第一个是验证码。登录页面建议加一个图形验证码虽然是老技术但能体现出你对“防止恶意暴力破解”有基本的意识。自己写一个生成随机数字图片的Servlet即可用session存验证码字符串校验的时候忽略大小写。网上很多源码的验证码由于没有刷新容器路径缓存导致每次请求报404这个我放到后面问题排查章节说。第二个是注销和会话超时。退出登录要调用session.invalidate()不仅清理用户对象还要清理验证码、购物车、临时数据等所有会话内容。web.xml里可以配置session超时时间一般30分钟。这里想提醒大家的是千万不要在JSP页面里用session.setAttribute(user, ...)这种方式把密码也存进去有的源码为了图省事把整个User对象放进session密码就在里面裸奔。正确做法是在查询用户时先去掉密码字段再放入session或者单独定义一个不含密码的VO对象。5.2 商品列表与预购状态展示商品列表页是前台的门面。列表通常按首页焦点图、热门预购、即将开始这几个维度展示每个商品卡片上要有封面图、名称、当前状态、预购倒计时。这里涉及到一个前端体验的关键点倒计时。预购开始前显示“距离开始还有XX小时XX分XX秒”预购中显示“距离结束还有XX立即抢购”已结束显示“本场预购已结束”。倒计时的标准做法是页面加载时由JSP输出后端时间戳和状态然后前端用JavaScript开启一个定时器每秒刷新剩余时间到0之后前端把按钮置灰并重新请求后端状态。不要在JSP里输出服务器时间后就放着不动那样页面时间永远不更新也不要在前端用本地时间来做校准本地时间可以手动改会被误判。正确做法是前端拿“服务器时间戳与本地时间戳的差值”作为校准偏移量每秒用当前本地时间 偏移量来计算剩余时间。这是很实用的细节演示的时候也很唬人。状态展示统一用一个工具方法根据“当前时间”、“预购开始时间”、“预购结束时间”、“总库存”、“已预购数量”返回一个枚举或整型状态。列表页用JSTL的c:if或c:choose根据状态显示不同按钮和文案。这里要特别注意SQL查列表时用一条SQL把上面的几个字段都查出来不要在页面里循环查数据库新手经常在c:forEach循环里调Dao方法那叫N1查询页面一卡一卡的数据量大了会非常明显。5.3 预购下单事务和并发是灵魂这块是整个系统最核心的地方也是我前面提到过的“先查再改”最容易踩坑的地方。完整的预购下单流程是后端校验用户是否登录从session取用户。后端校验当前时间是否在预购窗口内。按商品ID查出商品信息再次校验商品状态是否为“预购中”。校验用户是否已对该商品下过待支付或已支付的预购单防止重复预购。执行条件更新库存已预购数量 本次数量判断不超过总库存。创建预购订单记录状态为“待支付”或直接“已支付”如果支持预购时直接付款。如果上面任何一步失败都要回滚不能出现“库存扣了但订单没创建”的情况。第7点最容易被人忽略。在传统JDBC里你需要在Service层手动开启事务把连接传给Dao层在finally里提交或回滚。很多源码为了省事每个Dao自己打开连接、自己关闭连接根本不共享同一个连接结果是库存扣了、订单没插入数据对不上。正确写法是把“更新库存”和“插入订单”放在同一个数据库连接里执行public boolean createPreOrder(int userId, int productId, int num) { Connection conn null; try { conn DBUtil.getConnection(); conn.setAutoCommit(false); // 开启事务 // 1. 条件更新库存 int rows productDao.decreaseStock(conn, productId, num); if (rows 0) { conn.rollback(); return false; } // 2. 插入预购订单 boolean ok orderDao.insert(conn, userId, productId, num); if (!ok) { conn.rollback(); return false; } conn.commit(); return true; } catch (Exception e) { try { if (conn ! null) conn.rollback(); } catch (SQLException ex) {} return false; } finally { DBUtil.close(conn); } }上面这段代码是所有预购系统最重要的骨架你理解它就理解了“保证数据一致性”这句话在JavaWeb里的落地方式。答辩时老师问“这个系统怎么保证用户不会超卖”你就把这段逻辑讲一遍然后补一句“数据库的行级锁保证了并发更新串行化”基本就稳了。至于这里是悲观锁还是乐观锁思路、能不能用分布式锁这些问题属于加分项能说出“单机Tomcat下数据库条件更新就是最稳妥的兜底如果以后拆分微服务再引入Redis分布式锁”这样的演进思路会显得你比单纯背八股文的同学高一个层次。5.4 后台管理简单但要有“操作日志”意识后台模块功能通常是管理员登录、商品管理的增删改查、预购订单列表、用户列表、状态手动修改。这里有两个建议。第一个建议是管理员操作商品上下架或修改预购时间时做一个简单的操作日志表记录谁在什么时间做了什么操作。这不是需求书里必有的但做出来之后论文的“系统特色”章节就不空了同时让后台显得更完整。实现也不复杂一个拦截器或业务方法里插入一行日志就行。第二个建议是后台列表分页。管理员看到订单列表、用户列表时要分页这是最常规的考查点。手写一个分页工具类维护总记录数、当前页、每页条数、总页数然后SQL里用LIMIT #{offset}, #{pageSize}做分页查询。JSP页面上显示上一页、下一页、页码链接。这里有个小细节分页查询最好写两条SQL一条SELECT COUNT(*)查总数一条LIMIT查当前页数据不要试图用一条SQL同时拿总数否则不同数据库兼容性很差而且逻辑混乱。5.5 预购订单的完整生命周期预购订单状态建议用一个枚举或常量类管理常见的有待支付0、已支付1、已取消2、已发货3、已退款4、已完成5。每个状态之间的流转要受规则约束比如待支付状态下用户可以取消或支付。超过一定时间未支付会自动取消可选做用定时任务扫描表。已支付状态下等待管理员后台发货。已发货后用户可以确认收货订单变成已完成。已取消的订单不能再次支付。状态流转看似简单但论文里画一个“订单状态图”是很经典的素材。你只要能在答辩时把每个状态之间的转移条件和触发操作讲清楚老师就觉得你的设计是完整的。另外订单列表页按状态筛选点击订单详情时展示完整的信息和支付时间、发货时间这些都是顺手加分的体验点。6. 部署真正跑起来从源码到浏览器全流程毕设标题里写了“部署说明”这说明部署是整个交付的一部分。很多人以为部署就是把ROOT文件夹丢到Tomcat的webapps下面其实不然。一份合格的部署说明应该包括环境要求、初始化数据库的SQL、如何配置数据库连接、如何打包、如何放到Tomcat、如何访问、常见启动失败的处理。我先推荐一种最稳妥、最适合答辩演示的部署方式用IDEA内置Tomcat来运行因为这样调试方便再补充一种“独立Tomcat部署”方式用于以后写部署文档或线上发布。6.1 IDEA中配置Tomcat运行项目如果你用的IDEA社区版它不自带Tomcat集成插件需要先确认自己能写传统Web项目。如果没有Tomcat集成入口可以用专业版或者直接在本地下载Tomcat压缩包通过“Edit Configurations”添加Tomcat Server。这里只说专业版或Ultimate版本的通用做法打开项目File - Project Structure - Artifacts确认存在一个war exploded类型的artifact。菜单Run - Edit Configurations新增一个Tomcat Server - Local。在Server标签页选择本地Tomcat安装目录设置JRE为项目使用的JDK 8。在Deployment标签页添加那个war explodedApplication context设置为/preorder。启动前确认项目pom.xml如果是Maven工程里的打包方式是war并在Build里勾选了“Build project before run”。这里有个非常常见的错误Application context填成带空格或中文的路径比如/商品预购导致浏览器访问时404。统一用纯英文小写路径比如/preorder。另一个常见错误是Tomcat端口被占用我在章节里单独列出来。6.2 初始化数据库与连接配置数据库初始化只需要执行两件事创建数据库导入建表和测试数据的SQL脚本。很多源码自带的SQL脚本文件是mysql.sql里面可能还包含DROP DATABASE这种危险语句导入前务必小心别把你电脑上现有的数据库清了。推荐改成创建一个以项目命名的数据库比如db_preorder然后执行USE db_preorder;再建表。数据库连接配置要改三处JDBC URL、用户名、密码。如果是MySQL 8URL要写成jdbc:mysql://localhost:3306/db_preorder?useUnicodetruecharacterEncodingUTF-8serverTimezoneAsia/ShanghaiuseSSLfalseserverTimezone这个参数在MySQL 8里是必填的不写会抛The server time zone value ... is unrecognized的异常很多新手卡在这里。MySQL 5.7则通常只需要前面两个参数。驱动类名也要区分MySQL 5.7用com.mysql.jdbc.DriverMySQL 8用com.mysql.cj.jdbc.Driver。你在网上搜“mysql连接失败”的报错一多半都出在这两个地方。配置连接后最好用一个最简单的JDBC测试类验证能连通数据库不要直接点启动Tomcat然后等报错调试效率高得多。我的习惯是写一个TestDBUtil.javamain方法里输出一句“连接成功”跑通了再继续。6.3 打包成WAR包并独立部署如果你想脱离IDEA运行就要打WAR包。Maven项目在项目根目录执行mvn clean package打包成功后target目录下会生成preorder.war。把这个WAR文件名改成ROOT.war或保持原名放到Tomcat的webapps目录下启动Tomcat访问路径取决于文件名。如果你想直接用http://localhost:8080访问首页就把WAR命名为ROOT.war如果访问http://localhost:8080/preorder就保持preorder.war。独立部署的最大好处是脱离IDE后依然能跑适合你录演示视频时保持环境干净。要注意独立部署时Tomcat的JDK版本和编译时一致否则大概率报“UnsupportedClassVersionError”。另外独立部署时数据库连接池或数据库驱动JAR要放到WEB-INF/lib目录下如果WAR包里没打进去启动时会提示找不到驱动类。7. 高频Bug排查与答辩准备掌握这些你就稳了这一部分是我最想给学弟学妹讲清楚的因为代码写对了不代表能顺利演示。现场翻车往往是因为环境问题、路径问题、资源加载问题而不是逻辑问题。7.1 启动失败速查表把常见的启动和访问异常整理成一张表遇到问题先对号入座不要盲目百度、乱改配置。现象原因解决端口被占用Tomcat启动报Address already in use8443/8080被其他程序占用改Tomcat端口或关掉占用程序。cmd执行netstat -ano | findstr 8080查PID。404访问首页找不到文件context路径不对或WAR没有正确部署确认Application context是否为/preorder确认webapps下WAR存在且解压成功一点页面报500Servlet异常或JSP编译错误看Tomcat的catalina日志定位具体异常行。JSP第一行检查pageEncoding是否UTF-8中文乱码编码过滤器缺失或MySQL连接没设置characterEncoding在web.xml配置CharacterEncodingFilterJDBC URL加useUnicodetruecharacterEncodingUTF-8数据库驱动找不到驱动JAR没放进WEB-INF/lib检查lib目录重建WAR包项目里用了不支持的高版本JDK特性编译版本与运行版本不一致pom.xml里maven.compiler.source/target设为1.8确保IDEA的Project SDK及Tomcat的JRE都是JDK8时间格式显示不对服务器时间与本地时区不一致设置JVM时区参数或使用系统默认时区简单方案是serverTimezoneAsia/Shanghai7.2 排查问题的两次精选经历我印象特别深的一个案例有个学弟部署好之后前台页面能打开但一点“管理员登录”就一直404。排查步骤如下先在浏览器按F12看Network里请求的真实URL发现实际请求到了/admin/login但是后台接口写的映射却是/adminLogin路径不一致。这就是JavaWeb最典型的路径错误。解决办法统一在Servlet的WebServlet(/admin/login)和JSP表单的form actionadmin/login methodpost上保持一致并优先使用“相对当前上下文路径”而不是根路径减少部署环境差异。另一个案例是验证码图片加载不出来。排查发现验证码Servlet生成的图片在直接访问URL时正常但在JSP页面里img srccode.jpg却不显示。原因是图片路径没有带上下文路径request.getContextPath()导致浏览器实际请求到了根目录下的code.jpg而Servlet映射在/code或类似路径下。解决办法是在JSP里写成img src${pageContext.request.contextPath}/code。这类问题本质上还是路径不统一导致的。7.3 演示现场的“保命”操作流程答辩演示一般只有5到10分钟时间紧凑。我的建议是提前准备一个“演示脚本”先展示首页和商品列表突出“预购状态”的展示特别说明倒计时的实现。演示注册登录要求演示时用一个测试账号密码尽量短输入体验快。打开商品详情页重点展示“预购中”的状态然后下单。演示库存扣减打开后台订单列表确认刚才的预购单已生成。如有余力演示一下“重复预购被拦截”的逻辑这是全场最亮的点。在演示之前一定把浏览器缓存清一遍、数据库重置干净执行一遍SQL脚本、Tomcat先跑一遍确认无报错。不要现场改代码不要现场改数据库所有操作提前验证。7.4 论文答辩高频问题围绕这个题目老师大概率会问这些问题这个系统架构是什么为什么用JSP不用前后端分离预购怎么防超卖数据库中商品表和订单表是什么关系Session和Cookie的区别MVC各层的职责你个人做了哪些优化这些问题在正文里其实都已经覆盖我建议你把每个问题对应到代码里的具体位置用代码讲而不是背概念。比如老师问“MVC怎么体现的”你就说“JSP是View、Servlet是Controller、ServiceDao是Model”然后翻开目录指给他看比干背定义有说服力得多。8. 源码整理与交付好的毕设给人的第一印象最后聊一个看似不起眼、但很容易拉开档次的事情——交付资料的整理。你交给指导老师的应该是一个干净整洁的文件夹而不是一个随处可见二手源码痕迹的压缩包。我建议按这个结构整理商品预购平台_学号_姓名/ ├── 源码/ │ ├── preorder/ -- 完整工程代码 │ └── 数据库脚本.sql ├── 论文/ │ └── 基于JavaWeb的商品预购平台的设计与实现.docx ├── 部署说明/ │ └── 部署说明.md / 部署说明.pdf ├── 演示视频/ │ └── 演示视频.mp4 └── 答辩PPT/ └── 答辩PPT.pptx源码文件夹里要附一个README.md写清楚环境版本、如何导入IDEA、数据库初始化步骤、账号密码管理员、测试用户。论文里所有截图要重新截不要用二手源码里原有的截图否则查重和老师一眼就能看出来。演示视频不要边操作边说话可以先录操作后期配音或者用字幕注释关键步骤控制在8分钟以内。部署说明文档里一定包含“失败场景”的解决办法。比如我前面整理的启动失败表、路径404问题、中文乱码问题放进部署文档里是极其加分的因为说明你是真的部署过、踩过坑、会解决问题而不是从网上复制来的。这部分我在带学生时特别强调宁可部署说明里多写三个排错问题也不要只写“双击startup.bat即可”。我个人在实际带项目的过程中还有一个体会这些“交付物”表面上是为了应付学校检查实际上是帮你自己把项目从“能跑”升级到“能讲清楚”。当你开始写部署说明时你会被迫重新检查每一个细节当你录演示视频时你会发现自己对某个功能的解释是否含糊。这个过程本身就是一次高质量复习比埋头补十页八股文都有用。如果你准备选这个题目或者手里已经有一套源码但还没彻底读懂我的建议是不要把“完整源码”当成终点而是当成一个可以解剖的标本。顺着数据库表结构读一遍跟着一次预购请求从前端到后端的完整链路走一遍再把超卖这个并发问题亲手复现一次你对该项目的理解深度会和那些只改了个姓名排版的人完全不同。答辩场上这种理解深度是骗不了人的。