Servlet+JSP+MySQL网上商城课设:跑通、避坑与答辩

发布时间:2026/10/11 13:23:09

Servlet+JSP+MySQL网上商城课设:跑通、避坑与答辩 简介面向Web程序设计课程学习者的网上商城期末大作业完整项目提供可直接运行的完整商城站点适合课程设计、毕业设计或需要Java Web项目参考的初、中级开发者是Java Web全栈综合练习能将课堂知识串联成完整项目。共207个文件压缩包约4.7MB其中75个Java文件负责后台业务逻辑27个JSP页面处理动态输出21个HTML、18个CSS和18个JavaScript文件搭建前端展示与交互另配有图片素材和XML/Properties配置整体结构清晰便于按模块学习与二次开发。目前已有145人学习下载。资源覆盖网上商城从数据层、业务层到展示层的完整链路可帮助理解请求转发、会话管理、数据库读写等Web开发关键环节前端还基于Bootstrap等样式库优化了用户界面文件分类较清晰便于快速定位后端逻辑、前端页面与样式素材适合作为期末作品或毕业设计参考也便于答辩演示、功能扩展或代码复用。1. 这个网上商城课程作业 zip解压不是重点跑通才是先给一个反直觉结论WEB 程序设计课程的期末大作业挂科的人往往不是因为功能没做完而是把项目做成了“能打开首页的黑匣子”答辩时一被问就翻车。标题里这个网上商城项目 zip核心是一套完整的电商教学闭环用户注册登录、商品列表、购物车、下单、订单管理。它要解决的是“用课堂上学过的 Servlet、JSP、MySQL 把这些页面串成一个能演示的完整流程”这个具体任务。适合期末赶进度的学生、想拿高分答辩的开发者以及拿到别人项目想改成自己的初学者。所以这个 zip 的价值不在解压在于你能顺着下面这条线走一遍看懂骨架、跑通功能、避开坑、答辩有底气。按章节往下做一台装了 MySQL 和 Tomcat 的机器就能完整复现。2. 网上商城的技术骨架先看懂表设计和三层架构再决定怎么改动手改代码之前先花半小时把项目的骨架看清。网上商城这类课程作业的套路非常固定前端是 JSP 加少量 CSS 和 JavaScript后端是 Servlet 做控制器业务逻辑写在 service 包数据库访问写在 dao 包数据库用 MySQL容器用 Tomcat。搞清楚这一层后面所有调试才有方向。2.1 课程作业的通用选型ServletJSP 为什么仍是主流一个网上商城作业包打开后端是 ServletJSP 的概率非常高。原因很简单课程考核点落在“HTTP 请求怎么进 Servlet、Session 怎么保持登录、SQL 怎么写”这层基础功上而不是框架的自动装配。Spring Boot 这类框架把连接池、事务、参数绑定都藏起来了表面开发快但答辩时被追问一句“你的事务注解底层做了什么”很多人直接卡住。所以拿到 zip 后第一件事不是急着改代码先确认技术栈。常见的形态是JSP 做页面Servlet 做控制器业务逻辑在 service 包数据库操作在 dao 包数据库 MySQL部署容器 Tomcat。这种分层看起来土但它是一条能从头讲到尾的链路。如果包里的代码把 SQL 全部写在 JSP 里那你拿到的是“能跑但不好答辩”的版本后面会单独说怎么改。方案课程适配度答辩追问难度改造空间Servlet JSP MySQL高中大Spring Boot Thymeleaf低高中PHP MySQL中中小2.2 数据库四张表用户、商品、订单、订单明细网上商城的表设计四张表是下限user、goods、orders、order_item。很多作业只建三张表把商品名称和单价直接冗余在 orders 表里理由是下订单查询方便。问题在于后台一旦改商品价格历史订单跟着变答辩老师一条 SQL 就把你问住了。正确做法是 orders 只记录订单号和用户商品维度全部落在 order_item 里明细表保存下单那一刻的名称和价格快照。CREATE DATABASE IF NOT EXISTS shop DEFAULT CHARSET utf8mb4; CREATE TABLE user ( id INT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(32) NOT NULL UNIQUE, password VARCHAR(64) NOT NULL, phone VARCHAR(11), create_time DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE goods ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(64) NOT NULL, price DECIMAL(10,2) NOT NULL, stock INT NOT NULL DEFAULT 0, cover VARCHAR(255), status TINYINT NOT NULL DEFAULT 1 COMMENT 1上架 0下架 ); CREATE TABLE orders ( id INT AUTO_INCREMENT PRIMARY KEY, order_no VARCHAR(32) NOT NULL UNIQUE, user_id INT NOT NULL, total_amount DECIMAL(10,2) NOT NULL, status TINYINT NOT NULL DEFAULT 0 COMMENT 0待支付 1已支付 2已发货 3已完成, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE order_item ( id INT AUTO_INCREMENT PRIMARY KEY, order_id INT NOT NULL, goods_id INT NOT NULL, goods_name VARCHAR(64) NOT NULL, price DECIMAL(10,2) NOT NULL, quantity INT NOT NULL );几个参数说明price 用 DECIMAL(10,2) 而不是 FLOAT是为了避免浮点累加时的精度误差计算订单总金额时能少很多玄学问题。password 字段长度给 64给 MD5 或 SHA-256 加盐后的结果留够空间不要用 VARCHAR(20) 存明文。status 用 TINYINT 而不是字符串后面扩展状态机时只改注释不动数据结构。索引方面orders.user_id 和 order_item.order_id 建议各加普通索引不加也能跑但订单列表的 JOIN 查询在数据量稍大时会明显变慢答辩现场容易被追问。2.3 从 zip 到本地服务器的部署路径拿到 zip 解压后先确认工程目录是不是标准 Web 应用结构。常见结构包含 src 目录的 Java 源码、webapp 或 WebContent 目录的页面和静态资源、WEB-INF/web.xml 的 Servlet 映射与过滤器注册、lib 的第三方 jar。如果连 lib 都没有说明驱动用的是 IDE 的 Library 方式引入换机器部署时容易踩驱动找不到的坑。shop-project ├── src/com/demo/shop │ ├── servlet/IndexServlet.java │ ├── servlet/LoginServlet.java │ ├── servlet/CartAddServlet.java │ ├── service/OrderService.java │ ├── dao/UserDao.java │ ├── dao/GoodsDao.java │ └── util/DBUtil.java ├── webapp │ ├── WEB-INF/web.xml │ ├── lib/mysql-connector-java.jar │ ├── jsp/login.jsp │ ├── jsp/register.jsp │ ├── jsp/goods_list.jsp │ └── jsp/cart.jsp └── sql/shop.sql部署我用的是 IDE 内嵌 Tomcat 的方式导入工程为 Web 项目配置本机 Tomcat 安装路径把 artifact 加到 Deployment 里点 Run 就能跑。这里有两个必调参数Tomcat 默认端口 8080被占用时改 conf/server.xml 里 Connector 的 portMySQL 连接 URL 里的 serverTimezoneMySQL 8.x 必须带 serverTimezoneAsia/Shanghai否则连接直接报错。这两个参数属于“换台电脑就翻车”的高频点记住位置后面避坑章还会展开。注意如果工程里同时存在 web.xml 和 WebServlet 注解且 web.xml 的 metadata-complete 设为 true注解会全部失效。遇到 Servlet 映射 404 时先查这一项。3. 从注册登录到商品列表把第一条业务链路跑通这一章的目标是让用户注册、登录、看商品列表这三件事串起来。串起来的关键有两个参数从页面到 Servlet 的传递登录状态从登录页到其他页面的传递。代码能跑是底线更重要的是知道每一行在做什么。3.1 注册和登录密码存储与 Session 登录态注册页收集 username、password、confirmPassword 三个参数前端用 JS 校验一次Servlet 里必须再校验一次。规则和参数说明见代码package com.demo.shop.servlet; WebServlet(/register) public class RegisterServlet extends HttpServlet { Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 编码设置必须放在读取参数之前 req.setCharacterEncoding(UTF-8); String username req.getParameter(username); String password req.getParameter(password); String confirm req.getParameter(confirmPassword); if (username null || username.length() 3 || password null || password.length() 6 || !password.equals(confirm)) { resp.sendRedirect(register.jsp?err1); return; } // 课程作业建议至少用 MD5实际生产必须加盐 UserDao dao new UserDao(); if (dao.exists(username)) { resp.sendRedirect(register.jsp?err2); return; } dao.save(username, MD5Util.md5(password)); // 注册成功直接跳登录页不自动登录流程更清晰 resp.sendRedirect(login.jsp?ok1); } }两个关键点doPost 处理表单提交GET 请求访问这个 URL 时应重定向到注册页不然浏览器地址栏直接输入 /register 会得到 405。编码设置放在读取参数之前是硬性要求放在之后中文参数必乱码。MD5Util 核心就一行MessageDigest.getInstance(MD5) 后按十六进制输出用 Spring 的 DigestUtils 也可以。真实项目必须加盐课程作业做到 MD5 已经能挡住“密码明文存数据库”这个答辩雷点。登录逻辑类似但多了一个 Session 写入WebServlet(/login) public class LoginServlet extends HttpServlet { Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding(UTF-8); String username req.getParameter(username); String password req.getParameter(password); User user new UserDao().findByUsernameAndPassword( username, MD5Util.md5(password)); if (user null) { resp.sendRedirect(login.jsp?err1); return; } // 登录态放 Session 而不放 Cookie后端依赖的会话数据不进浏览器 HttpSession session req.getSession(); session.setAttribute(loginUser, user); session.setMaxInactiveInterval(30 * 60); // 单位秒半小时超时 resp.sendRedirect(index); } }Session 默认超时 30 分钟web.xml 里可以全局覆盖。我习惯把 user 对象整个放进去而不是只放 userId页面用 EL 表达式直接拿用户名省一次查库。前提是 User 对象的 password 属性在 setAttribute 前置空否则调试日志会带出密码这是自己在代码里埋的雷。3.2 商品列表页分页参数与 JSP 渲染商品列表页是访问 /indexServlet 查当前页的商品列表转发给 JSP 渲染。带分页的实现如下WebServlet(/index) public class IndexServlet extends HttpServlet { Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String pageParam req.getParameter(page); int page 1; if (pageParam ! null pageParam.matches(\\d)) { page Integer.parseInt(pageParam); } int pageSize 12; GoodsDao dao new GoodsDao(); ListGoods list dao.findByPage((page - 1) * pageSize, pageSize); int total dao.count(); int totalPage (total pageSize - 1) / pageSize; req.setAttribute(list, list); req.setAttribute(totalPage, totalPage); req.setAttribute(currentPage, page); req.getRequestDispatcher(jsp/goods_list.jsp).forward(req, resp); } }page 参数做了正则过滤防止前端传入非数字导致 NumberFormatException。totalPage 用 (total pageSize - 1) / pageSize 计算避免浮点运算。对应的 JSP 片段% page contentTypetext/html;charsetUTF-8 % % taglib prefixc urihttp://java.sun.com/jsp/jstl/core % html head base href${pageContext.request.contextPath}/ /head body c:forEach varg items${list} div classgoods-card p classname${g.name}/p p classprice${g.price}/p a hrefcart/add?goodsId${g.id}加入购物车/a /div /c:forEach c:forEach vari begin1 end${totalPage} a hrefindex?page${i}${i}/a /c:forEach /body /html两个细节要注意head 里的 解决了 CSS、图片和链接的相对路径问题没有它订单列表页里的链接大概率按 /order/ 前缀解析然后集体 404。c:forEach 依赖 JSTL 核心库如果 webapp/WEB-INF/lib 下没有 jstl.jar 和 standard.jarJSP 会直接报 500。很多作业包解压后首页就打不开十次有八次是缺这两个 jar。3.3 数据库连接抽一个工具类别在每个 Servlet 里连库课程作业最常见的坏味道是每个 Servlet 都写一遍 Class.forName、DriverManager.getConnection结果换数据库密码要改七八个文件。抽一个 DBUtil 是正确起步public class DBUtil { private static final String URL jdbc:mysql://localhost:3306/shop?useUnicodetruecharacterEncodingUTF-8serverTimezoneAsia/Shanghai; private static final String USER root; private static final String PASSWORD 123456; static { try { // MySQL 8.x 驱动类名带 cj老驱动类名已弃用 Class.forName(com.mysql.cj.jdbc.Driver); } catch (ClassNotFoundException e) { throw new ExceptionInInitializerError(e); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection(URL, USER, PASSWORD); } public static void close(AutoCloseable... resources) { for (AutoCloseable r : resources) { if (r ! null) { try { r.close(); } catch (Exception ignored) {} } } } }URL 里三个参数是踩坑重灾区useUnicodetrue 和 characterEncodingUTF-8 保证中文写入不乱码serverTimezoneAsia/Shanghai 是 MySQL 8.x 的强校验不加就报 The server time zone value 异常。数据库连接池比如 Druid课程作业不是必须但答辩时主动提出“这里可以换连接池避免每次请求建立物理连接”是明确加分表达。驱动类名 5.1.x 和 8.x 不一样这也是后面避坑章 5.5 的引子。4. 购物车与下单流程Session 购物车、库存扣减与事务边界购物车是商城作业里最容易做成“能用但挨骂”的部分。有些实现把购物车放 Cookie优点是刷新不丢缺点是数据在浏览器端服务端无法校验数量和价格答辩被问“用户改了 Cookie 里的价格怎么办”就沉默。课程作业更推荐购物车放 Session服务端完全掌控。4.1 购物车的数据结构Map 而不是 ListSession 里购物车字段类型用 MapInteger, CartItemkey 是商品 IDvalue 是购物车条目。为什么不用 List用户反复添加同一商品时Map 只需要 get 出来改数量不用遍历 List 找同一行。CartItem 建议这样设计public class CartItem { private int goodsId; private String goodsName; private BigDecimal price; // 加入购物车那一刻的商品单价 private int quantity; // 购买数量 private boolean checked; // 是否勾选结算时只算勾选项 public BigDecimal getSubtotal() { return price.multiply(BigDecimal.valueOf(quantity)); } }加入购物车的 Servlet 把“购物车不存在就新建、商品已有就累加、没有就 new 一个”三个分支写清楚WebServlet(/cart/add) public class CartAddServlet extends HttpServlet { Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { int goodsId Integer.parseInt(req.getParameter(goodsId)); int quantity 1; if (req.getParameter(quantity) ! null) { quantity Integer.parseInt(req.getParameter(quantity)); } HttpSession session req.getSession(); MapInteger, CartItem cart (MapInteger, CartItem) session.getAttribute(cart); if (cart null) { cart new HashMap(); } CartItem item cart.get(goodsId); if (item ! null) { item.setQuantity(item.getQuantity() quantity); } else { Goods goods new GoodsDao().findById(goodsId); item new CartItem(); item.setGoodsId(goodsId); item.setGoodsName(goods.getName()); item.setPrice(goods.getPrice()); item.setQuantity(quantity); cart.put(goodsId, item); } session.setAttribute(cart, cart); // 重定向而不是转发防止刷新页面时购物车数量不断累加 resp.sendRedirect(jsp/cart.jsp); } }这里用 resp.sendRedirect 而不是 forward能让浏览器地址栏变成 cart.jsp刷新页面时触发 GET 而不是重新执行 addServlet挡掉很大一部分重复加购的翻车现场。price 取的是加入购物车那一刻的商品表价格而不是结算时再查表保证购物车展示和最终结算口径一致。这个“价格快照”的思路和订单明细表里的 goods_name 快照是同一条设计原则。4.2 创建订单与扣减库存一个事务里完成订单创建牵扯三步生成订单号、写 orders 表、遍历购物车扣库存并写 order_item 明细。中间任何一步失败前面做的要全部撤销所以必须放在一个数据库事务里public boolean createOrder(int userId, MapInteger, CartItem cart) { Connection conn null; try { conn DBUtil.getConnection(); conn.setAutoCommit(false); // 关闭自动提交开启事务 // 1. 生成订单号并插入订单主表 String orderNo S System.currentTimeMillis() userId; BigDecimal total BigDecimal.ZERO; for (CartItem item : cart.values()) { total total.add(item.getSubtotal()); } new OrderDao(conn).insertOrder(orderNo, userId, total); // 2. 遍历购物车验证库存并扣减 PreparedStatement ps conn.prepareStatement( UPDATE goods SET stock stock - ? WHERE id ? AND stock ?); for (CartItem item : cart.values()) { ps.setInt(1, item.getQuantity()); ps.setInt(2, item.getGoodsId()); ps.setInt(3, item.getQuantity()); if (ps.executeUpdate() 0) { throw new SQLException(库存不足商品ID item.getGoodsId()); } // 3. 写订单明细 new OrderDao(conn).insertItem(item); } conn.commit(); return true; } catch (SQLException e) { if (conn ! null) { try { conn.rollback(); } catch (SQLException ignored) {} } return false; } finally { DBUtil.close(conn); } }扣库存的 UPDATE 带了 AND stock ?一条 SQL 同时完成“检查库存并扣减”不需要先 SELECT 再 UPDATE既能减少一次查询也规避了并发下的超卖风险。事务能否回滚的前提是 OrderDao 的全部 SQL 都使用同一个 conn绝不能在 service 层再调 DBUtil.getConnection() 去拿第二个连接这是很多人写了事务代码却不生效的根本原因。订单号用时间戳拼 userId课程作业够用但并发下有可能重复答辩时可以主动说“真实环境建议用 UUID 或雪花算法”这属于能接住追问的加分表达。4.3 订单列表与状态字段用 TINYINT 定义状态机orders.status 建议定义成 TINYINT 并在代码里写常量或枚举不要直接比较字符串。状态流转一般是待支付(0) → 已支付(1) → 已发货(2) → 已完成(3)。课程作业的“模拟支付”就是点一下支付按钮把状态从 0 改成 1真实支付回调不在期末范围内。订单列表页要展示“这个订单包含哪些商品”不要用 N1 查询也就是别在页面循环里逐条查 order_item用一条 GROUP_CONCAT 聚合查询更干净SELECT o.id, o.order_no, o.total_amount, o.status, u.username, GROUP_CONCAT(CONCAT(i.goods_name, x, i.quantity) SEPARATOR 、) AS items_text FROM orders o JOIN user u ON o.user_id u.id JOIN order_item i ON o.id i.order_id GROUP BY o.id ORDER BY o.create_time DESC;GROUP_CONCAT 默认长度上限 1024商品特别多时可能被截断课程作业的量级不会触发但心里有数。order_item 里的 goods_name 是下单快照后台改商品名也不会影响历史订单明细这正是第 2 章建表时强调快照字段的原因。状态字段配合 Java 枚举或者常量类使用页面展示时再用 switch 映射成中文比在 SQL 里写 CASE WHEN 更清晰也更好维护。5. 网上商城作业避坑5 个最容易让页面白屏的细节课程作业的坑往往不在复杂逻辑而在几个偷懒的细节。这一章全是血泪经验每一条都按“现象 → 原因 → 解决”写照着排查能省一晚。5.1 中文乱码回马枪编码设置的位置和顺序现象注册提交后数据库里 username 变成问号或者 JSP 商品名显示乱码。原因设置编码的时机太晚比如先读了 getParameter 再 setCharacterEncoding那一次读取已经按 ISO-8859-1 解码了或者只处理了请求没处理响应输出。MySQL 连接 URL 缺 characterEncodingUTF-8 也会存乱码。解决编码在所有入口统一处理最稳的做法是写一个 CharsetFilter在 doFilter 最靠前的位置设置public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) { HttpServletRequest request (HttpServletRequest) req; // 必须放在读取任何参数之前 request.setCharacterEncoding(UTF-8); resp.setContentType(text/html;charsetUTF-8); chain.doFilter(req, resp); }同时确认 web.xml 里这个 filter 的 url-pattern 是 /* 并且注册顺序在业务 Filter 之前。自己搭工程时把这两行放进 filter比在几十个 Servlet 里各自 set 一遍可靠得多。5.2 Session 重启就丢购物车被清空不算 bug但演示会翻车现象把项目 redeploy 或重启 Tomcat 后重新打开页面发现购物车空空的登录态也没了。原因Session 默认存在 JVM 内存里进程重启就没了。这是正常机制不是项目 bug。解决知道它为什么会丢演示时避开这个时刻即可。常见的做法是把演示顺序设计成“先启动服务器 → 登录 → 逛商品 → 加购 → 下单”中间不去碰 redeploy。如果作业要求“刷新页面购物车还在”这归 Session 管要求“重启后购物车还在”那需要 Cookie 或数据库保存购物车课程作业一般不要求到这层。5.3 刷新页面重复下单PRG 模式解决的经典问题现象下单成功后顺手按 F5订单表里多了两条一模一样的订单。原因下单接口是 POSTServlet 处理完没有重定向响应结束后浏览器刷新会把上一次 POST 再发一遍。解决用 POST-Redirect-GET 模式下单成功后不要 forward 或直接输出内容而是 response.sendRedirect(order/list)让浏览器跳到 GET 请求上。这个习惯适用于所有写操作注册、加购、下单写完之后一律重定向。它能同时解决“返回上一页再刷新”的重复提交问题是成本最低的幂等手段。5.4 图片样式加载 404JSP 相对路径的经典误导现象首页正常点进订单列表页后 CSS 全丢图片裂开控制台一堆 404。原因JSP 里的 hrefcss/style.css 是相对路径浏览器访问 /order/list 时会把基准当成 /order/于是解析成 /order/css/style.css自然找不到。解决在每个 JSP 的 head 里加一行 base 标签 页面里所有相对路径都基于项目根目录解析不会因为 URL 层级变化集体失效。这也是第 3 章 JSP 示例特意放这一行的原因。5.5 换电脑就连不上数据库驱动、时区、密码三个顺序现象别人电脑上能跑拿回来访问首页报 500控制台第一行是 Communications link failure 或 Access denied。原因常见三个MySQL 8.x 驱动类名变了、URL 没带 serverTimezone、数据库密码和本地不一致。解决按顺序排查先看 lib 里 mysql-connector-java 的 jar 版本5.1.x 用老驱动类名8.0.11 起必须写 com.mysql.cj.jdbc.Driver再检查 URL 有没有 serverTimezoneAsia/Shanghai最后用命令行 mysql -u root -p 验证账号密码能连上。三步做完十台机器能解决九台。剩下那一台多半是 MySQL 端口不是默认 3306检查 URL 里的端口号就行。6. 让答辩更有底气的三个小技巧日志、数据核对、下单入口6.1 用一个 Filter 打印请求日志把“我感觉能跑”变成“我测过”答辩被问系统性能时空口说“应该还行”最吃亏。我习惯在所有项目里加一个 AccessLogFilter打印每个请求的方法、URL 和耗时WebFilter(/*) public class AccessLogFilter implements Filter { Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request (HttpServletRequest) req; long start System.currentTimeMillis(); chain.doFilter(req, resp); long cost System.currentTimeMillis() - start; System.out.printf(%s %s 耗时 %dms%n, request.getMethod(), request.getRequestURI(), cost); } }耗时是第一次进入 filter 到响应结束的时间反映一次 HTTP 请求全链路耗时。答辩时打开控制台现场点几个页面把耗时数据亮出来比任何话术都有说服力。耗时稳定在几十毫秒就大方说“列表页平均 XX 毫秒”如果上千毫秒提前自查是不是 SQL 没走索引。6.2 备一条 SQL 自证数据一致性老师问数据一致性不要只解释事务。备一条能现场执行的核对 SQL-- 找出总金额与明细累加不一致的订单正常应返回空结果 SELECT o.order_no, o.total_amount, SUM(i.price * i.quantity) AS real_total FROM orders o JOIN order_item i ON o.id i.order_id GROUP BY o.id, o.order_no, o.total_amount HAVING o.total_amount ! real_total;返回空结果配合下单时开启事务的代码就能证明“金额一致性有代码逻辑和 SQL 双层保障”。如果查出数据正好是答辩的改进素材说明你发现了问题并知道怎么修。这条 SQL 比堆概念扎实得多。6.3 调整演示入口把最顺的流程放在第一屏答辩演示顺序和代码质量同样重要。默认首页如果是注册页评委要找半天入口如果登录后落地页是商品列表整个演示能压缩到十次点击以内。我交课程作业前会写一个一分钟演示脚本从启动服务器到提交订单必须一遍过中间不允许出现“等我找一下这个功能在哪”的空档。另一个习惯是提前主动触发一次“库存不足”确认提示文案。与其让评委问库存为 0 会怎样而现查代码不如演示时就展示边界处理。这个习惯帮我免掉过很多次临时救场。希望帮到你。本文还有配套的精品资源点击获取
延伸阅读

更多相关文章

2026/10/11 13:23:09

图片矢量化实战:从像素到贝塞尔路径的完整指南

简介:这是一份以 Vector Magic 1.15 完美版为核心的图片矢量化工具包,面向需要将位图转为矢量图的平面设计师、电商美工、印刷排版人员及普通办公用户,重点解决图片放大后边缘模糊、轮廓难以二次编辑等常见问题。压缩包共 5 个文件&#xff0…

2026/10/11 13:18:09

Qt文件管理器实战:QFileSystemModel与QTreeView工程解析

简介:这是一份面向QT初学者与C GUI开发入门者的轻量级文件管理器项目源码,基于QT框架实现,帮助读者理解桌面端文件管理工具的基本架构与交互逻辑。压缩包共33个文件,约80KB,包含8个cpp源文件、7个h头文件、4个ui界面文…

2026/10/11 13:18:09

运动想象脑电分类实战:CNN局部特征+Transformer全局注意力

简介:运动想象脑电信号分类项目,基于Transformer框架并结合CNN提取局部时间空间特征,是一份完整的Python毕设源码,面向计算机、人工智能及相关专业的学生与从业者,可用于期末课程设计、大作业或毕业设计等场景。项目由…

2026/10/11 14:23:16

Flutter适配OpenHarmony的Container组件实战指南

1. 项目概述 大概从去年开始,我就在关注 Flutter 在 OpenHarmony 上的适配进展。之前很多团队还停留在“能跑起来”的阶段,页面稍微复杂一点就各种崩溃、布局错乱,尤其是想用基础组件的时候,经常发现行为跟标准 Flutter 不一致。所…

2026/10/11 14:23:16

城市运管服平台下综合办公数字化建设实践与思考

数字政府建设持续向纵深推进,城市运行管理服务平台作为城市治理 的重要载体,除城市事件处置、监测预警、指挥调度等核心业务之外,内部综合办公数字化建设,已经成为提升部门协同效率、规范内部业务流程、实现治理业务与内部管理双向…

2026/10/11 14:23:16

IBM-PC汇编课后习题答案详解:补码、寻址与标志位避坑指南

简介:《IBM-PC汇编语言程序设计》配套习题答案,主要为使用沈美明、温冬婵教材的计算机专业学生和自学者提供课后练习参考。文档按习题解答主线展开,覆盖数制转换、8位补码加减运算、位操作、ASCII码与字符串处理等基础知识点,并对…

2026/10/11 14:23:16

Flutter for OpenHarmony 中 Container 组件核心属性与实战避坑

做客户端开发这些年,我接触过不少跨端方案,Flutter 算是用得最多的一套。前阵子把一个内部工具项目的界面迁移到 OpenHarmony 设备,用的就是社区维护的 Flutter for OpenHarmony 分支。迁移过程中我有个很深的感受:真正让你在真机…

2026/10/11 14:18:16

SpringBoot3+EasyExcel实现复杂Excel一键导入实战指南

1. 项目背景与方案选型1.1 从POI直接操作说起做后端开发的,谁没被Excel导入导出折磨过?我早年用Apache POI直接写导入功能,代码量大不说,最痛苦的是内存。一个几万行的Excel解析下来,整个JVM堆吃紧,频繁Ful…

2026/10/11 0:02:13

Python调用Gemini Structured Outputs实现工单路由门禁

客服工单最怕的不是模型“答错一句话”,而是它给出一段看起来合理的说明,程序却从中猜错优先级。通俗做法是:要求模型只交 JSON(JavaScript Object Notation,轻量数据格式),再让代码验证它。Gem…

2026/10/11 0:02:13

Spring Boot超市进销存系统毕设实战:从需求拆解到答辩通关

最近带的一个学生项目组里,有A同学跑来问我:选什么毕设题目最稳妥,既能让评审老师觉得工作量够,又不会在答辩时被问到语无伦次。我第一反应就是推荐基于Spring Boot的超市仓库管理系统——也就是超市进销存系统。这个题目乍一看平…

2026/10/11 0:02:13

Flutter StatefulWidget 生命周期核心解析

很多刚开始接触 Flutter 的朋友,在看完一堆“Hello World”和基础组件之后,大概率都会撞上同一堵墙:StatefulWidget 里那堆 initState、build、dispose 方法,到底什么时候被调用?为什么顺序是那样?在里面到…

2026/10/11 0:02:13

Python调用Gemini Structured Outputs实现工单路由门禁

客服工单最怕的不是模型“答错一句话”,而是它给出一段看起来合理的说明,程序却从中猜错优先级。通俗做法是:要求模型只交 JSON(JavaScript Object Notation,轻量数据格式),再让代码验证它。Gem…

2026/10/11 0:02:13

Spring Boot超市进销存系统毕设实战:从需求拆解到答辩通关

最近带的一个学生项目组里,有A同学跑来问我:选什么毕设题目最稳妥,既能让评审老师觉得工作量够,又不会在答辩时被问到语无伦次。我第一反应就是推荐基于Spring Boot的超市仓库管理系统——也就是超市进销存系统。这个题目乍一看平…

2026/10/11 0:02:13

Flutter StatefulWidget 生命周期核心解析

很多刚开始接触 Flutter 的朋友,在看完一堆“Hello World”和基础组件之后,大概率都会撞上同一堵墙:StatefulWidget 里那堆 initState、build、dispose 方法,到底什么时候被调用?为什么顺序是那样?在里面到…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑