首页 / 资讯中心 / 文章详情

JavaWeb校园二手交易系统:基于状态机的完整业务闭环实现

JavaWeb校园二手交易系统:基于状态机的完整业务闭环实现 ★ FEATURED ARTICLE
简介这是一套完整的基于JavaWeb技术栈开发的校园二手交易网站源码面向计算机专业本科生、毕设开发者及JavaWeb初学者旨在解决高校学生闲置物品流通难、交易缺乏可信平台的问题。资源包含786个文件以210个JavaScript脚本实现前端交互、74个HTML页面构成用户界面、36个JSP动态页面承载业务逻辑、28个CSS样式文件统一视觉风格及73个JPG/PNG图片资源含界面图标与示例图为主干辅以MySQL数据库支持整体压缩包仅14.22MB轻量易部署。已有71人学习下载适合快速上手项目实践、理解MVC分层结构与前后端协同流程。读者可直接运行系统完整体验学生注册登录、二手商品发布/搜索/下单、管理员后台分类管理、用户与商品审核、助手协同运维等核心功能并通过预览中涉及的FCKeditor富文本编辑、ASP/CFM等多类型模板文件了解早期Web系统兼容性设计思路。1. 校园二手交易网不是“小商城”而是学生真实行为闭环的最小可行系统你见过毕设答辩现场被问倒最多的点是什么不是登录校验怎么写也不是 MySQL 索引怎么建——而是“你这个‘二手交易’到底完成了几笔真实订单”很多同学用 Spring Boot 搭个 CRUD 页面商品列表一刷就出来购物车一点就跳转但后台没有订单状态流转、没有买家确认收货动作、没有卖家发货标记、甚至没有“已下架”和“已售罄”的状态隔离。结果导师一句“这系统能跑通一笔从发布→浏览→下单→确认→完成的全流程吗”当场卡壳。这套基于 JavaWeb 的校园二手交易网源码恰恰是为解决这个“伪闭环”问题而生它不追求高并发或微服务架构但强制落地了学生发布物品 → 同学搜索浏览 → 加入购物车 → 提交订单 → 卖家后台确认 → 订单完成六步不可跳过的业务链路所有状态变更都写进数据库字段如item_status、order_status所有关键操作都有日志留痕如user_id,operate_time,operate_type连管理员回复留言都做了“已读/未读”标记。它适合计算机专业做毕设或课设的同学——不是拿来改个包名就交差而是能带着完整流程图、状态机图、三张核心数据表结构、以及至少两笔模拟订单的截图稳稳站在答辩台前说“老师我这个系统真能跑通一次二手交易。”2. 总体架构设计B/S 分层结构与五大核心模块的职责边界这套系统采用经典 JavaWeb 三层架构表现层 JSP 控制层 Servlet 数据访问层 JDBC不引入 Spring 或 MyBatis降低学习门槛的同时把每个环节的控制权牢牢握在开发者手里。整个系统划分为五个逻辑清晰、职责分明的模块用户认证模块、物品管理模块、订单交易模块、消息互动模块、后台管理模块。每个模块对应一组独立的 Servlet 类、JSP 页面和数据库表彼此通过标准 HTTP 请求参数和 session 属性通信避免过度耦合。这种设计不是为了炫技而是为了让答辩时你能指着代码说清楚“登录验证走的是LoginServlet它只管比对账号密码并设置 session而发布物品由PublishItemServlet处理它只负责接收表单、校验图片路径、插入item表——中间不掺和权限判断也不处理订单逻辑。”2.1 用户认证模块Session 驱动的身份识别与角色分流身份识别不靠 token不靠 cookie 加密就靠最朴素的HttpSession。学生登录成功后LoginServlet将用户基本信息user_id,username,role_type存入 session并重定向至首页。后续所有页面如index.jsp、mycenter.jsp顶部统一嵌入一段校验脚本% Object userObj session.getAttribute(user); if (userObj null) { response.sendRedirect(login.jsp); return; } User user (User) userObj; String role user.getRole(); // student or admin %提示role字段值来自数据库user表的role_type列取值为字符串student或admin绝不使用数字 0/1。这是为后期扩展“助手角色”预留语义空间——比如未来加个assistant角色只需改数据库值不用动所有if(role 1)的判断逻辑。角色分流体现在导航栏动态渲染上。header.jsp中根据role值决定显示哪些菜单项% if (admin.equals(role)) { % a hrefadmin/item_list.jsp商品管理/a a hrefadmin/user_list.jsp用户管理/a a hrefadmin/message_list.jsp留言管理/a % } else if (student.equals(role)) { % a hrefstudent/publish_item.jsp发布物品/a a hrefstudent/my_orders.jsp我的订单/a a hrefstudent/leave_message.jsp给管理员留言/a % } %这种写法看似原始但胜在可调试性强你可以在任意 JSP 页面加% session.getAttribute(user) %直接打印当前登录态无需启动 Redis 或查 token 解析日志。对毕设场景而言稳定压倒一切。2.2 物品管理模块带状态机的全生命周期控制物品不是静态展示对象而是有明确生命周期的状态实体。系统定义item表中status字段为 ENUM 类型取值仅限on_sale在售、sold_out已售罄、offline已下架、deleted逻辑删除。注意没有pending_review或audit_pass这类审核状态——校园场景下学生发布即可见管理员仅做事后监管符合“轻运营、重流通”的定位。发布流程强制校验三项图片路径必须以/upload/开头防止路径穿越价格必须为正数且保留两位小数前端用input typenumber 后端BigDecimal解析所属分类必须存在于category表外键约束 下拉框select绑定。关键代码片段PublishItemServlet.java// 获取分类ID并校验是否存在 String categoryIdStr request.getParameter(category_id); int categoryId Integer.parseInt(categoryIdStr); CategoryDao categoryDao new CategoryDao(); if (!categoryDao.existsById(categoryId)) { request.setAttribute(error, 所选分类不存在请刷新页面重试); request.getRequestDispatcher(publish_item.jsp).forward(request, response); return; } // 构建Item对象status默认设为on_sale Item item new Item(); item.setCategoryId(categoryId); item.setTitle(request.getParameter(title)); item.setDescription(request.getParameter(description)); item.setPrice(new BigDecimal(request.getParameter(price))); item.setPicPath(request.getParameter(pic_path)); // 前端JS已拼好/upload/xxx.jpg item.setStatus(on_sale); // 强制初始化为在售 item.setPublisherId(((User)session.getAttribute(user)).getId()); item.setCreateTime(new Date()); new ItemDao().insert(item); // 插入item表注意pic_path不由后端生成而是前端 JS 在文件上传成功后将返回的服务器路径如/upload/20240512_abc123.jpg填入隐藏域。这样既规避了 Servlet 文件上传的复杂解析又确保路径绝对可控——你永远不需要在 Java 里调MultipartRequest或Apache Commons FileUpload。2.3 订单交易模块四状态驱动的真实履约链路订单不是“提交即完成”而是严格遵循created → confirmed_by_seller → delivered → completed四阶段状态机。order表中status字段定义为 VARCHAR(20)取值固定为上述四个字符串之一不允许出现paid、shipped等电商术语——校园二手本质是线下交付不存在支付网关和物流单号。学生提交订单时SubmitOrderServlet系统仅做三件事校验所选物品status on_sale扣减该物品库存item.stock_count字段初始为 1因校园二手多为单件物品插入新订单status created并记录buyer_id和item_id。卖家即物品发布者登录后在my_sold_items.jsp页面看到待处理订单列表点击“确认交易”按钮触发ConfirmOrderServlet// 根据order_id查询订单 Order order new OrderDao().findById(orderId); Item item new ItemDao().findById(order.getItemId()); // 仅当订单状态为created且物品状态为on_sale时才允许确认 if (!created.equals(order.getStatus()) || !on_sale.equals(item.getStatus())) { throw new RuntimeException(订单状态异常无法确认); } // 更新订单状态 order.setStatus(confirmed_by_seller); new OrderDao().updateStatus(orderId, confirmed_by_seller); // 同步更新物品状态为sold_out item.setStatus(sold_out); new ItemDao().updateStatus(item.getId(), sold_out);这个设计的关键在于状态变更必须成对发生。确认订单的同时物品必须下架——否则会出现“同一物品被两个买家同时下单”的竞态问题。虽然没用分布式锁但通过数据库行级锁InnoDB 默认 显式事务包裹Connection.setAutoCommit(false)在单库场景下完全够用。3. 数据库设计三张核心表与外键约束的务实落地系统共 7 张表但真正承载业务主干的是user、item、order这三张。它们之间通过外键强关联且所有外键均启用ON UPDATE CASCADE杜绝因 ID 变更导致的数据断裂。设计原则就一条宁可多查一次表也不冗余存储字段。比如订单表不存商品名称、价格只存item_id用户表不存角色名称只存role_type字符串。3.1user表角色字段语义化 注册时间自动填充CREATE TABLE user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(100) NOT NULL, -- 存BCrypt加密后的密文 real_name VARCHAR(30), phone VARCHAR(20), email VARCHAR(100), role_type ENUM(student, admin, assistant) DEFAULT student, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, last_login_time DATETIME NULL ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;注意role_type使用ENUM而非TINYINT是为了让 SQL 查询和代码逻辑一眼可读。例如SELECT * FROM user WHERE role_type admin比WHERE role_type 1更不易出错。last_login_time允许为 NULL首次登录后由LoginServlet更新方便统计活跃用户。3.2item表状态字段驱动前端展示逻辑CREATE TABLE item ( id INT PRIMARY KEY AUTO_INCREMENT, category_id INT NOT NULL, publisher_id INT NOT NULL, title VARCHAR(100) NOT NULL, description TEXT, price DECIMAL(10,2) NOT NULL, pic_path VARCHAR(200) NOT NULL, stock_count INT DEFAULT 1, status ENUM(on_sale, sold_out, offline, deleted) DEFAULT on_sale, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, FOREIGN KEY (category_id) REFERENCES category(id) ON UPDATE CASCADE, FOREIGN KEY (publisher_id) REFERENCES user(id) ON UPDATE CASCADE ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;关键设计点stock_count默认为 1符合校园二手“单件寄售”特性若需支持多件只需在发布页加数量输入框后端校验非负整数即可status的ENUM值顺序按业务流转排列on_sale→sold_out→offline方便ORDER BY FIELD(status, ...)排序update_time自动更新用于前台“最新上架”排序ORDER BY update_time DESC LIMIT 10。3.3order表状态机字段 关联信息懒加载CREATE TABLE order ( id INT PRIMARY KEY AUTO_INCREMENT, item_id INT NOT NULL, buyer_id INT NOT NULL, seller_id INT NOT NULL, status ENUM(created, confirmed_by_seller, delivered, completed) DEFAULT created, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, confirm_time DATETIME NULL, complete_time DATETIME NULL, FOREIGN KEY (item_id) REFERENCES item(id) ON UPDATE CASCADE, FOREIGN KEY (buyer_id) REFERENCES user(id) ON UPDATE CASCADE, FOREIGN KEY (seller_id) REFERENCES user(id) ON UPDATE CASCADE ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;为什么不在订单表存商品名称和价格因为商品可能被修改如降价但历史订单价格必须锁定若冗余存储每次改商品名都要遍历所有相关订单更新违背单一职责实际查询时JOIN item ON order.item_id item.id一次搞定MySQL 优化器对这种简单关联极其高效。4. 关键功能实现从发布物品到订单完成的四段真实代码链这里不贴“Hello World”式伪代码只呈现四段在真实运行环境中被反复验证过的核心逻辑。每段代码都来自项目源码中的.java文件经过脱敏但保留全部业务语义。你可以直接复制进自己的 Eclipse 工程稍作路径调整即可运行。4.1 学生发布物品前端表单 后端双重校验前端publish_item.jsp中图片上传区域使用标准input typefile配合一个隐藏域pic_pathform actionservlet/PublishItemServlet methodpost input typetext nametitle required textarea namedescription/textarea input typenumber nameprice step0.01 min0.01 required select namecategory_id required !-- 由CategoryDao.findAll()动态生成option -- /select input typefile idpicFile acceptimage/* input typehidden namepic_path idpicPathInput button typesubmit发布/button /form script document.getElementById(picFile).onchange function(e) { const file e.target.files[0]; if (!file) return; const formData new FormData(); formData.append(file, file); fetch(servlet/UploadImageServlet, { method: POST, body: formData }).then(r r.json()).then(data { document.getElementById(picPathInput).value data.path; // 如 /upload/20240512_xxx.jpg }); }; /script后端UploadImageServlet.java仅做安全校验和保存protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Part filePart request.getPart(file); String fileName Paths.get(filePart.getSubmittedFileName()).getFileName().toString(); // 严格校验文件类型仅允许jpg/jpeg/png String contentType filePart.getContentType(); if (!image/jpeg.equals(contentType) !image/png.equals(contentType)) { response.getWriter().write({\error\:\仅支持 JPG/PNG 格式\}); return; } // 生成唯一文件名时间戳随机数原后缀 String ext fileName.substring(fileName.lastIndexOf(.)); String newFileName System.currentTimeMillis() _ RandomStringUtils.randomAlphanumeric(6) ext; String uploadPath request.getServletContext().getRealPath(/upload); File uploadDir new File(uploadPath); if (!uploadDir.exists()) uploadDir.mkdirs(); filePart.write(uploadPath File.separator newFileName); // 返回JSON前端用path字段填入隐藏域 response.setContentType(application/json); response.getWriter().write(String.format({\path\:\/upload/%s\}, newFileName)); }这段代码的价值在于它把“文件上传”这个高频翻车点压缩成一个可独立测试的单元。你可以在浏览器直接 POST 一个图片到/servlet/UploadImageServlet看是否返回/upload/xxx.jpg—— 成功了再联调发布逻辑失败了问题一定在路径、权限或 MIME 类型上不会污染主业务流。4.2 管理员回复留言异步更新 已读标记管理员在admin/message_list.jsp查看留言列表每条记录旁有“回复”按钮和“已读”标签c:forEach items${messageList} varmsg tr td${msg.id}/td td${msg.content}/td tdc:if test${msg.isRead 1}✓ 已读/c:if/td td a hrefjavascript:void(0) onclickshowReplyForm(${msg.id})回复/a /td /tr /c:forEach点击“回复”弹出表单提交至ReplyMessageServletprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { int messageId Integer.parseInt(request.getParameter(message_id)); String replyContent request.getParameter(reply_content); // 1. 先标记为已读即使还没回复 new MessageDao().markAsRead(messageId); // 2. 插入回复记录到 reply 表 Reply reply new Reply(); reply.setMessageId(messageId); reply.setContent(replyContent); reply.setAdminId(((User)request.getSession().getAttribute(user)).getId()); reply.setCreateTime(new Date()); new ReplyDao().insert(reply); response.sendRedirect(message_list.jsp?success1); }MessageDao.markAsRead()执行 SQLUPDATE message SET is_read 1 WHERE id ?。这个“先标记后回复”的设计解决了管理员打开列表却忘记标记的遗漏问题——只要点了回复就代表他已看过这条留言。4.3 学生查看我的订单状态驱动的卡片式布局student/my_orders.jsp不用复杂表格而是用 Bootstrap 卡片按状态分组div classrow div classcol-md-4 h5待卖家确认/h5 c:forEach items${createdOrders} varorder div classcard mb-3 div classcard-body h6 classcard-title${order.itemTitle}/h6 p classcard-text¥${order.price} | ${order.createTime}/p span classbadge bg-warning等待确认/span /div /div /c:forEach /div div classcol-md-4 h5已确认交易/h5 c:forEach items${confirmedOrders} varorder div classcard mb-3 div classcard-body h6 classcard-title${order.itemTitle}/h6 p classcard-text卖家${order.sellerName}/p span classbadge bg-success已确认/span /div /div /c:forEach /div /div对应的MyOrdersServlet.java中DAO 层按状态分页查询// 查询学生所有订单并按status分组 ListOrder allOrders new OrderDao().findByBuyerId(buyerId); MapString, ListOrder grouped allOrders.stream() .collect(Collectors.groupingBy(Order::getStatus)); request.setAttribute(createdOrders, grouped.getOrDefault(created, Collections.emptyList())); request.setAttribute(confirmedOrders, grouped.getOrDefault(confirmed_by_seller, Collections.emptyList())); request.setAttribute(completedOrders, grouped.getOrDefault(completed, Collections.emptyList()));这种写法让前端极度轻量后端逻辑也一目了然状态就是分组依据无需额外字段。4.4 后台商品管理分类树形结构 状态筛选联动admin/item_list.jsp顶部有两个筛选控件分类下拉框和状态单选按钮。它们联动过滤商品列表form idfilterForm select namecategory_id onchangethis.form.submit() option value全部分类/option c:forEach items${categoryList} varcat option value${cat.id} ${param.category_id cat.id ? selected : } ${cat.name} /option /c:forEach /select select namestatus onchangethis.form.submit() option value全部状态/option option valueon_sale ${param.status on_sale ? selected : }在售/option option valuesold_out ${param.status sold_out ? selected : }已售罄/option option valueoffline ${param.status offline ? selected : }已下架/option /select /formItemDao.findByCondition()方法接收categoryId和status参数构建动态 SQLpublic ListItem findByCondition(Integer categoryId, String status) { StringBuilder sql new StringBuilder(SELECT * FROM item WHERE 11); ListObject params new ArrayList(); if (categoryId ! null categoryId 0) { sql.append( AND category_id ?); params.add(categoryId); } if (status ! null !status.trim().isEmpty()) { sql.append( AND status ?); params.add(status); } sql.append( ORDER BY update_time DESC); return query(sql.toString(), params.toArray(), Item.class); }这段 SQL 构建逻辑是毕设答辩高频考点。导师常问“如果用户不选分类、只选状态SQL 是什么”——答案是SELECT * FROM item WHERE 11 AND status ? ORDER BY ...11保证后续AND语法合法。这种写法比拼接字符串更安全也比 MyBatis 的if标签更贴近底层适合教学演示。5. 避坑指南JavaWeb 二手交易网开发中最容易翻车的 4 个点做毕设最怕什么不是功能写不出来而是写完了跑不起来或者跑起来了但导师一问就露馅。下面这四点是我带过十几届学生、看过上百份毕设代码后总结出的最高频“翻车现场”。每一条都附带真实现象、根本原因和可立即执行的解决方案照着做能省下至少三天调试时间。5.1 现象登录后跳转首页但导航栏不显示“我的中心”F12 看 Network 发现 session 为空原因web.xml中未配置session-config导致 Tomcat 默认 session 超时时间为 30 分钟而开发调试时经常隔几分钟才点一下页面session 已失效更隐蔽的是某些浏览器如 Safari在跨域或 iframe 场景下会拒绝发送 Cookie导致JSESSIONID无法回传。解决在web.xml顶部显式声明 session 超时为 60 分钟session-config session-timeout60/session-timeout /session-config所有跳转链接统一用response.sendRedirect(request.getContextPath() /xxx.jsp)绝不用相对路径如response.sendRedirect(index.jsp)避免因部署路径ROOT 或 /campus不同导致重定向失败在LoginServlet登录成功后手动调用session.setMaxInactiveInterval(3600)单位秒双重保险。5.2 现象上传图片后页面显示 404检查发现/upload/xxx.jpg路径下文件存在但浏览器打不开原因Tomcat 默认不提供upload目录的静态资源服务。/upload/是 Web 应用目录下的子文件夹但 Tomcat 只认webapp下的images/、css/等标准路径对自定义文件夹默认 404。解决在web.xml中添加 servlet-mapping将/upload/*请求交给DefaultServlet处理servlet-mapping servlet-namedefault/servlet-name url-pattern/upload/*/url-pattern /servlet-mapping这是 JavaWeb 项目的“后悔药”。没有这行配置你永远无法在浏览器直接访问上传的图片加上它http://localhost:8080/campus/upload/20240512_xxx.jpg就能正常显示。别信网上那些“改 Tomcat conf/server.xml”的方案太重且毕业答辩环境未必允许你动服务器配置。5.3 现象管理员修改商品价格后学生端订单详情页仍显示旧价格原因订单详情页order_detail.jsp直接从order表查数据而order表里根本没有price字段它只存item_id但 DAO 层OrderDao.findById()方法错误地写了SELECT o.*, i.price FROM order o JOIN item i ON o.item_id i.id导致查出来的 price 是当前 item 表的最新值而非下单时的快照。解决立刻删掉所有JOIN item的订单查询订单详情页改为两次查询先查order表获取item_id再用item_id单独查item表——这样你就能在 DAO 层ItemDao.findById()方法里加一行日志“查询商品ID123的价格”方便调试如果真要存快照就在order表加snapshot_price DECIMAL(10,2)字段在SubmitOrderServlet插入订单时从item表查一次价格并写死进去而不是依赖 JOIN。5.4 现象MySQL 中文乱码数据库显示????但 Navicat 里能看到正确汉字原因不是数据库编码问题而是 JDBC 连接 URL 缺少useUnicodetruecharacterEncodingUTF-8参数。MySQL 服务端编码utf8mb4和客户端连接编码默认 latin1不一致导致 Java 程序写入时被转码丢失。解决检查db.properties或JDBCUtil.java中的连接字符串必须包含jdbc.urljdbc:mysql://localhost:3306/campus?useUnicodetruecharacterEncodingUTF-8serverTimezoneAsia/Shanghai注意serverTimezoneAsia/Shanghai也必须加上否则new Date()写入时间可能比实际晚 8 小时。这个参数和字符集一样是 JavaWeb 项目上线前必检项漏掉一个整个系统中文和时间全乱。6. 答辩验收 checklist用这 7 个动作证明你的系统真的能跑通答辩不是讲 PPT是现场演示。导师最想看到的是你能用鼠标点出一套完整的业务闭环。我带过的某高校毕设答辩要求学生必须在 5 分钟内完成从注册、发布、搜索、下单到后台确认的全流程演示。做不到直接扣分。所以别等答辩当天才练现在就按这份 checklist 过一遍。每一项都对应一个可截图、可复述、可解释的技术点做完你就知道哪里还缺火候。6.1 动作一登录两个账号分别扮演学生和管理员打开两个浏览器窗口Chrome 和 Firefox避免 session 冲突窗口 A用student1/password1登录进入学生首页窗口 B用admin/admin123登录进入后台首页。验证点窗口 A 的导航栏应显示“发布物品”“我的订单”窗口 B 应显示“商品管理”“用户管理”。如果窗口 A 出现“商品管理”菜单说明role_type字段值写错了比如存成了1而非student立刻查user表。6.2 动作二学生发布一件物品并在首页搜索到它在窗口 A进入“发布物品”页填写标题“二手《数据结构》教材第三版”价格填25.00选择分类“教材”确保category表里有这条记录上传一张本地图片建议用 100x100 像素的测试图上传快点击发布跳转回首页。然后在首页搜索框输入“数据结构”回车。验证点搜索结果页必须出现刚发布的那本书且图片能正常显示检查浏览器地址栏 URL 是否为/upload/xxx.jpg。如果图片 404立刻回去检查web.xml的servlet-mapping是否生效。6.3 动作三学生下单后台立即看到新订单在窗口 A找到刚发布的书点击“立即购买” → “提交订单”。切换到窗口 B管理员点击左侧菜单“我的出售”或“订单管理”。验证点订单列表中必须出现一条新记录status为createdbuyer_name显示学生用户名。如果列表为空立刻去数据库查order表——有没有新记录如果没有说明SubmitOrderServlet的 insert 语句没执行如果有但 status 不对说明ItemDao.updateStatus()把物品状态改错了。6.4 动作四管理员确认订单学生端订单状态实时更新在窗口 B找到那条created状态的订单点击“确认交易”。立刻切回窗口 A刷新“我的订单”页。验证点“待卖家确认”分组里那本书应该消失同时“已确认交易”分组里出现它且状态 badge 变成绿色“已确认”。如果没变打开浏览器开发者工具看 Network 选项卡里my_orders.jsp的响应 HTML搜索confirmed_by_seller—— 如果没搜到说明MyOrdersServlet没把状态分组对立刻检查groupingBy(Order::getStatus)的 key 值是否拼写正确是confirmed_by_seller不是confirmed。6.5 动作五导出三张核心表结构现场解释字段设计意图打开 MySQL 客户端如 Navicat 或命令行执行SHOW CREATE TABLE user; SHOW CREATE TABLE item; SHOW CREATE TABLE order;截图这三段 DDL 语句放在答辩 PPT 的“数据库设计”页。验证点你能指着item.status字段说“我用 ENUM 是为了防止非法值写入比如有人手抖输成onsale数据库会直接报错而不是默默存个空字符串”指着order.seller_id说“这个外键不是为了性能是为了数据一致性——如果卖家账号被删订单还能查到是谁卖的因为ON DELETE RESTRICT会阻止删除操作”。6.6 动作六用 Postman 模拟一次留言验证异步回复流程在 Postman 中新建请求MethodPOSTURLhttp://localhost:8080/campus/servlet/LeaveMessageServletBodyraw JSON内容为{content:测试留言请回复}Headers加Cookie: JSESSIONIDxxx从浏览器复制发送后去窗口 B管理员的“留言管理”页确认出现新留言。验证点这条留言的is_read字段值必须为0未读。然后点击“回复”再查数据库is_read应变为1且reply表有新记录。这个动作证明你理解了“异步交互”不是 AJAX而是 HTTP 请求服务端状态更新的完整链路。6.7 动作七关闭 Tomcat清空数据库重新部署5 分钟内恢复全部功能这是终极压力测试。关掉所有服务执行TRUNCATE TABLE user; TRUNCATE TABLE item; TRUNCATE TABLE order; INSERT INTO user (username, password, role_type) VALUES (admin, $2a$10$xxx, admin), (student1, $2a$10$yyy, student);然后重启 Tomcat用两个账号重新登录重复动作一到四。验证点整个过程不超过 5 分钟。如果超时说明你依赖了某个没写进 SQL 初始化脚本的表比如category表忘了 INSERT或者db.properties的密码写错了。从那以后我每次写完数据库脚本都强制走一遍“清库→重插→重启→登录”流程雷打不动。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站