“宠物商城”这个题目,在计算机类毕业设计里属于又经典又常青的存在。每年都有人拿来当毕设,每年也都有人做到一半卡壳,停在“登录注册写完了,下一步不知道干吗”的状态。今天把手上这套基于Web的宠物商城平台(编号49149)完整拆一遍——不管你是用Java、PHP、Python做后端,还是配合C#小程序做客户端,业务设计这套东西都是通用的。从需求怎么拆、表怎么建、技术怎么选,到订单事务怎么处理、后端怎么部署,我尽量讲得实在一点,你照着走能少踩不少坑。
先交代一下本篇的适用范围。我默认你有基本编程能力,至少写过循环、建过类、知道SQL是什么。如果你是刚学完JavaSE就被导师扔来写Spring Boot,建议先补一下Maven和HTTP的基础再回来往下看,不然中间的依赖配置就够你懵两天。整篇文章的结构是:先想清楚项目架构,再选好技术路线,然后设计表,最后写代码和排坑。这个顺序也是我建议你实际开发时遵循的顺序。
1. 项目定位与需求拆解:打开IDE之前先把思路理清
1.1 宠物商城本质上是一套电商系统
很多人拿到题目就急着建工程,结果页面还没写两张,数据库表已经改了三遍。正确的姿势是先想明白:宠物商城在业务上跟淘宝、京东没有任何区别,只不过商品是猫、狗、猫粮和狗窝。电商核心链路只有一条——商品展示、加购、下单、支付、发货、收货。你把这个链路在脑子里过一遍,功能清单自然就出来了:
前台要有商品列表、商品详情、购物车、订单确认、模拟支付、个人订单。 后台要有商品管理、分类管理、订单处理、用户管理。 底层要有登录鉴权、文件上传、数据统计这些公共能力。
项目能不能立住,就看这条主链路能不能跑通。好多同学做毕设翻车,不是代码能力差,而是链路里某个环节断了:要么下单不扣库存,要么支付完订单状态没变。所以第一步不是写代码,是把链路拆清楚,每一步对应哪张表、哪个接口,先画出来。
1.2 功能模块按“用户端+后台”两层拆
这里给一个可以直接抄的模块拆分表。
| 模块 | 用户端 | 管理后台 |
|---|---|---|
| 商品模块 | 分类浏览、关键词搜索、商品详情、收藏 | 商品增删改、上下架、分类维护 |
| 购物车模块 | 加入购物车、修改数量、删除、批量结算 | 无 |
| 订单模块 | 创建订单、模拟支付、取消、查看进度 | 订单查询、发货、状态变更 |
| 用户模块 | 注册、登录、个人信息、收货地址 | 用户列表、禁用/启用 |
| 公告模块 | 首页公告展示 | 公告发布与下架 |
| 统计模块 | 首页推荐商品 | 商品数量、订单金额、销量图表 |
这个表的作用不只是开发时的功能规划,它同时就是你论文里“系统功能设计”那一章的素材——画用例图、写功能描述,全都能从表里抄出来。我见过不少同学等到写论文时才回头整理功能,结果发现功能设计得七零八落,连用例图都不知道怎么画。开发之前就把这个表填好,后面舒服很多。
1.3 先做MVP,再谈加分功能
我强烈建议按“最小可用版本”的思路来做。所谓MVP,就是先完成这七个功能:注册登录、商品列表、商品详情、购物车、下单、模拟支付、后台商品管理。这七个做完,系统已经是一个可以拿出手的完整项目了。剩下的功能都属于锦上添花:收藏、评论、销量榜、数据图表、公告、地址管理。
这里我得提个很多人都会犯的错:以为功能越多分越高,于是一股脑加了一堆列表页面,每个功能都只做到“能显示数据”的程度。答辩老师随便一问“这个数据的实时性怎么保证”就答不上来。我的建议是,加分功能宁可少做,但要做闭环。比如收藏功能,不做就算了,要做就做到:详情页可以收藏/取消、收藏按钮有即时反馈、个人中心有收藏列表、点击列表项跳回详情。一个功能自成一环,比十个半成品有用得多。
2. 技术选型:Java、PHP、Python、C#小程序四条路线怎么挑
2.1 四种方案横向对比
| 方案 | 后端框架 | 前端方案 | 开发速度 | 工作量 | 答辩亮点 | 适合人群 |
|---|---|---|---|---|---|---|
| Java | Spring Boot + MyBatis Plus | Vue + Element Plus | 中等 | 偏大 | 工程化、RESTful、JWT鉴权 | 打算找Java后端工作 |
| PHP | ThinkPHP 8 / Laravel | Vue 或 Bootstrap | 快 | 适中 | 上手快、部署简单 | 工期紧、纯应付毕设 |
| Python | Django + DRF | Vue 或模板 | 较快 | 适中 | Django Admin自动后台 | 学Python方向 |
| C#小程序 | ASP.NET Core + EF Core | 微信小程序/uni-app | 中等 | 偏大 | 小程序实战、跨平台 | 想学C#或小程序开发 |
说实话,这四种方案做出来的东西功能上不会有区别,区别全在“你会不会讲亮点”和“代码你能不能自己控制住”。选型的唯一原则是:选你最有把握的,而不是选看起来最高级的。
2.2 Java路线:Spring Boot + MyBatis Plus + Vue 的组合
如果你打算毕业以后走Java后端方向,用Spring Boot做这个项目是当下最优解。我测试过最顺手的一组版本搭配:Spring Boot 2.7.x + MyBatis Plus 3.5.x + MySQL 8.0,前端Vue 3 + Element Plus + Axios,鉴权用JWT,构建工具用Maven。
为什么推荐这套?首先是生态成熟,你搜“Spring Boot 宠物商城”之类的关键词,能找到大量教程,踩过的坑几乎都有答案。其次是工程结构清晰,controller、service、mapper三层各管各的事,答辩时讲“分层设计的好处”会非常顺畅。最后是部署简单,Maven打包成一个jar文件,服务器上一条java -jar就起来了,不需要额外配置Tomcat。核心依赖只需要盯住两个:
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.3</version> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.1</version> </dependency>2.3 PHP和Python方案:让开发速度最大化
PHP这门语言虽然被人黑得很多,但做这类管理系统的效率确实高。以ThinkPHP 8为例,路由、ORM、验证器都是现成的,配合宝塔面板一键部署,从开写原型到在线可访问,一个周末就能搞定。你要做的核心事情就是把Pet模型、Order模型定义好,规则写在模型里,控制器里直接调用模型方法就行。
Python方案我推荐Django + DRF。Django的最大优势在于自带Admin后台,建好model后往admin.py里一注册,后台增删改查页面就有了,等于省出一个完整管理端。前端再用Vue调DRF写的API,开发体验很爽。但要注意一个细节:Django模型外键一定要设on_delete策略。分类表下面有宠物时,如果直接删分类,默认行为可能把宠物一起级联删掉,我在这里丢过一次演示数据,面色相当难看。
2.4 C#小程序方案的理解
标题里的“C#小程序”通常指两种理解。第一种是后端用C#写ASP.NET Core Web API,前端用微信小程序;第二种是直接用C#开发桌面端小程序工具,但做宠物商城显然第一种更合理。ASP.NET Core和Spring Boot是同一个level的框架,EF Core做ORM写起来很优雅。前端微信小程序原生语法加一个登录页、商品列表页、详情页、购物车页,就能覆盖核心场景。
做小程序必须知道的是:真机调试时,小程序要求后端接口必须是HTTPS,开发期间可以在微信开发者工具里勾选“不校验合法域名”来调试,但上线必须准备一个备案域名并配好SSL证书。这个限制不算大坑,但经常有人到答辩前才发现接口调不通,浪费一整天。
3. 数据库设计:一张表一张表地建
3.1 从业务链路推导出数据表
很多新手问“要建几张表”,答案是跟着业务走就行。用户要注册,所以有user表;商品要分类,所以有category和pet两张表;用户要加购,所以有cart表;下单,所以有orders和order_item;收藏、评论、公告、地址这类辅助功能,对应favorite、comment、notice、address。
表与表之间的关系也很清晰:user是核心,延伸出cart、orders、favorite、comment、address;pet挂在category下面;orders和order_item是一对多。设计的时候把关系写清楚,后面所有业务代码都是围绕这些表展开的,根本不会乱。
3.2 核心建表SQL
下面以宠物表pet为例,这是整个系统里最核心的商品表:
CREATE TABLE `pet` ( `id` int(11) NOT NULL AUTO_INCREMENT, `category_id` int(11) NOT NULL COMMENT '分类id', `name` varchar(50) NOT NULL COMMENT '宠物名称', `cover` varchar(255) DEFAULT NULL COMMENT '封面图', `images` text COMMENT '详情图,逗号分隔', `price` decimal(10,2) NOT NULL COMMENT '售价', `original_price` decimal(10,2) DEFAULT NULL COMMENT '原价', `stock` int(11) NOT NULL DEFAULT 0 COMMENT '库存', `sales` int(11) NOT NULL DEFAULT 0 COMMENT '销量', `description` text COMMENT '描述', `status` tinyint(1) NOT NULL DEFAULT 1 COMMENT '1上架 0下架', `create_time` datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `idx_category_id` (`category_id`), KEY `idx_name` (`name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='宠物商品表';其他表结构我列一个字段速查表,方便你照着一一建出来:
| 表 | 关键字段 |
|---|---|
| user | id, username, password, nickname, phone, avatar, create_time |
| category | id, name, icon |
| cart | id, user_id, pet_id, quantity, checked |
| orders | id, order_no, user_id, total_price, receiver, phone, address, status, pay_time, create_time |
| order_item | id, order_id, pet_id, pet_name, price, quantity |
| favorite | id, user_id, pet_id, create_time |
| comment | id, pet_id, user_id, content, rating, create_time |
| notice | id, title, content, create_time |
| address | id, user_id, receiver, phone, detail, is_default |
3.3 订单为什么拆成主表和明细表
我见过有同学图省事把订单信息全塞一张表,用JSON存商品列表,被导师怼到说不出话。拆表的原因很简单:一个订单包含多种宠物,每种的“价格、数量”都不一样,如果塞在同一行里,后面做统计、退款、发货都会很痛苦。所以orders负责存订单整体状态和收货信息,order_item负责存一个个具体商品。查订单详情时,按order_id把明细查出来逐个展示就行。
另外三个细节:金额字段必须用decimal(10,2),坚决不用float,浮点误差在钱上出现就是事故;逻辑外键而不是物理外键,因为物理外键在后续删除和关联操作上会带来无数麻烦,MyBatis Plus的联表查询完全够用;user_id、order_no这种查询高频字段加上索引,论文里也能写一笔“通过索引优化查询效率”。
4. 核心功能实现:从注册到下单的完整代码
4.1 注册登录与JWT鉴权
注册接口的完整逻辑是三件事:校验用户名唯一、密码加密、插入用户。密码加密这个点特别重要,我见过有同学直接明文存user表,答辩老师一打开数据库就笑了。Java里用Spring Security自带的BCrypt即可:
@PostMapping("/register") public Result register(@RequestBody User user) { long count = userMapper.selectCount( new QueryWrapper<User>().eq("username", user.getUsername())); if (count > 0) { return Result.error("用户名已存在"); } user.setPassword(BCrypt.hashpw(user.getPassword(), BCrypt.gensalt())); userMapper.insert(user); return Result.success(); }登录接口则是查出用户、校验密码、签发一个JWT返回给前端。前端把Token存到本地存储,之后每次请求在请求头带上Authorization: Bearer <Token>,后端拦截器统一校验:
@PostMapping("/login") public Result login(@RequestBody User user) { User dbUser = userMapper.selectOne( new QueryWrapper<User>().eq("username", user.getUsername())); if (dbUser == null || !BCrypt.checkpw(user.getPassword(), dbUser.getPassword())) { return Result.error("用户名或密码错误"); } String token = JwtUtil.createToken(dbUser.getId(), dbUser.getUsername()); return Result.success(token); }JWT的好处就是无状态,后端不需要存session。Web端和小程序端共用同一套登录逻辑,将来接移动端也好扩展。
4.2 商品列表、搜索与分页
商品接口是日后的访问热点,三个维度查询要支持:关键词模糊搜名称、分类id过滤、价格排序。用MyBatis Plus的QueryWrapper写起来很直观:
Page<Pet> page = petMapper.selectPage( new Page<>(current, size), new QueryWrapper<Pet>() .eq(StringUtils.isNotBlank(categoryId), "category_id", categoryId) .like(StringUtils.isNotBlank(keyword), "name", keyword) .eq("status", 1) .orderByDesc(sort == null ? "create_time" : sort) );这里有个关键细节:查询时必须固定status=1,只把上架的商品展示给用户。不然后台下架的商品还在前台售卖,会成为一个业务逻辑bug。另外分页插件要在配置类注册一下:
@Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; }4.3 购物车实现逻辑
购物车的核心操作就四个:加入、列表、修改数量、删除。加购时要先判断库存够不够,不能把库存为0的商品加进去;同一用户加同一商品时,如果已存在则累加数量而不是插入新记录。接口大致是:
@PostMapping("/add") public Result add(@RequestBody CartDTO dto) { Pet pet = petMapper.selectById(dto.getPetId()); if (pet == null || pet.getStock() <= 0) { return Result.error("商品已下架或库存不足"); } Cart cart = cartMapper.selectOne(new QueryWrapper<Cart>() .eq("user_id", dto.getUserId()) .eq("pet_id", dto.getPetId())); if (cart == null) { cart = new Cart(); cart.setUserId(dto.getUserId()); cart.setPetId(dto.getPetId()); cart.setQuantity(1); cartMapper.insert(cart); } else { cart.setQuantity(cart.getQuantity() + 1); cartMapper.updateById(cart); } return Result.success(); }这里要提醒的是:购物车的user_id必须从前端传递并校验与Token中的用户一致,绝不能只信前端。很多同学偷懒直接从前端拿user_id,很容易被别人改参数,这也是答辩老师喜欢抓的安全漏洞。
4.4 下单流程:事务和库存是命门
下单是整个项目里最有含金量的一段逻辑,也是答辩时最值得讲的点。完整流程是:接收提交的购物车id列表,查出商品,计算总价,生成订单号,写订单主表和明细表,扣库存,清掉对应购物车记录,然后跳转支付。
这一串操作里只要有一半成功一半失败,数据就全乱了。所以必须用事务保证原子性。Spring里直接在方法上标注@Transactional:
@Transactional public OrderVO createOrder(OrderCreateDTO dto) { List<Cart> carts = cartMapper.selectBatchIds(dto.getCartIds()); if (carts.isEmpty()) { throw new RuntimeException("购物车为空"); } BigDecimal total = BigDecimal.ZERO; String orderNo = System.currentTimeMillis() + "" + (int)((Math.random() * 9 + 1) * 1000); for (Cart cart : carts) { Pet pet = petMapper.selectById(cart.getPetId()); if (pet.getStock() < cart.getQuantity()) { throw new RuntimeException("商品[" + pet.getName() + "]库存不足"); } total = total.add(pet.getPrice().multiply(BigDecimal.valueOf(cart.getQuantity()))); } Orders order = new Orders(); order.setOrderNo(orderNo); order.setUserId(dto.getUserId()); order.setTotalPrice(total); order.setStatus(0); ordersMapper.insert(order); for (Cart cart : carts) { Pet pet = petMapper.selectById(cart.getPetId()); OrderItem item = new OrderItem(); item.setOrderId(order.getId()); item.setPetId(pet.getId()); item.setPetName(pet.getName()); item.setPrice(pet.getPrice()); item.setQuantity(cart.getQuantity()); orderItemMapper.insert(item); petMapper.update(null, new UpdateWrapper<Pet>() .setSql("stock = stock - " + cart.getQuantity()) .setSql("sales = sales + " + cart.getQuantity()) .eq("id", pet.getId())); } cartMapper.deleteBatchIds(dto.getCartIds()); return buildOrderVO(order); }这个方法的亮点,也就是你答辩时可以讲三分钟的东西,在于: 第一,为什么用selectBatchIds而不循环查,是为了减少数据库I/O; 第二,扣库存用的是条件更新SQL而不是先查后改,避免并发时库存变成负数; 第三,所有写操作都在同一个事务里,任何一个环节异常都会整体回滚。
4.5 模拟支付与订单状态机
个人开发拿不到微信/支付宝的企业商户号,所以毕设里统一采用“模拟支付”。支付页放一个“确认支付”按钮,点击后调后端接口把订单状态从0(待付款)改成1(已付款),记录支付时间,就完成了。从业务上这就是一个完整的状态机流转。
订单状态建议定义为:0待付款、1已付款/待发货、2已发货/待收货、3已完成、4已取消。后台每完成一步,前台订单列表的进度条就向前走一格。讲清楚这套状态机,比接一个真的支付通道更能体现你对业务的理解。如果真想接真实支付,答辩前跟导师确认资质是个绕不开的问题,但这已经超出系统设计本身了。
5. 前端与小程序端:让项目完整落地
5.1 管理后台用现成框架还是自己写
管理后台我推荐两种做法,根据你的时间预算来。
第一种,用RuoYi(若依)这类开源框架二次开发。它自带用户权限、菜单管理、代码生成器,你只要定义好数据表,代码生成器就能生成增删改查页面。适合时间紧张或者想要“系统很完整”观感的人。缺点是需要花时间熟悉它的结构。
第二种,自己写一个轻量后台。前端用vue-element-admin的简化版,后端自己起一套简单的增删改查接口,页面不用多,把商品管理、订单管理、用户管理三个页面做精致就够了。对毕设来说,“少而精”的后台其实比堆功能的后台更稳。
我自己更倾向于第二种,因为每个接口都是自己写的,答辩被问时不会露怯。用若依的话,一旦老师问到代码生成器的内部原理,答不上来会比较尴尬。
5.2 用户端核心页面要点
用户端页面有一个原则:主流程页面必须完整,不只停留在UI。我给你列一下每个页面的核心交互:
首页:顶部搜索框、轮播图、宠物分类导航、今日推荐商品卡片。搜索框要能跳转到列表页并带上关键词。 商品列表页:分类tab切换、筛选条件、卡片网格、空状态提示、分页加载。筛选参数要用query参数存到url里,刷新不丢。 商品详情页:图片预览、名称价格、库存/销量信息、收藏按钮、加入购物车和立即购买。库存信息要实时显示,归零时禁用按钮。 购物车页:商品勾选与全选、数量加减组件、合计金额实时计算、“结算”按钮进入下单页。 结算页:收货人信息、商品清单、总价、提交订单按钮。订单提交后跳转模拟支付页。
页面的交互细节能体现你这套系统的完成度。比如购物车数量减到0时给出删除确认,商品缺货时打上“已下架”水印,这些都是加分点。
5.3 小程序端如何复用这套后端
如果选了C#小程序或者微信小程序路线,前端完全复用不了Vue页面,但要调用的后端接口完全一样。小程序端一般只需要做五个页面:登录、首页、商品列表、商品详情、购物车/订单。小程序的登录逻辑和Web略有区别:Web是用户名密码登录,小程序推荐先用wx.login拿到code,再传给后端换取用户信息;或者为了省事,沿用Web的用户名密码登录也行,就是体验差一点。
数据同步方面要注意:小程序和Web如果同时放出去演示,用户数据是共享的,后台看到的数据要一致。域名和HTTPS的问题前面说过,开发阶段记得在开发者工具里关闭域名校验,上线前再改成正式域名。
6. 实战踩坑:这些问题我全都遇到过
6.1 环境搭建问题速查表
| 现象 | 原因 | 解决方案 |
|---|---|---|
| Maven依赖一直下载中 | 默认中央仓库访问慢 | 在settings.xml配阿里云镜像 |
| 启动Spring Boot报端口占用 | 8080被其他进程占用 | netstat -ano|findstr 8080找到PID后kill |
| MySQL连接失败 | 时区参数没配 | jdbc连接串加serverTimezone=Asia/Shanghai |
| Vue安装依赖卡住 | npm源慢 | 设置npm config set registry https://registry.npmmirror.com |
| 前端请求接口404 | 后端路径和前端url没对齐 | 把前后端日志打开,逐一核对请求路径 |
我多说一句,端口占用这个问题,十个人里有九个会遇到。Windows用户用netstat -ano找到8080的PID,然后在任务管理器里结束进程就能解决,不用重启电脑。
6.2 跨域、乱码、图片404三大经典问题
跨域基本是前后端分离项目的必修课。后端加一个CORS配置,几分钟就解决:
@Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOriginPatterns("*") .allowedMethods("GET", "POST", "PUT", "DELETE") .allowCredentials(true); } }注意allowCredentials(true)和allowedOriginPatterns("*")要配套用,如果使用旧版的allowedOrigins("*")配合allowCredentials会直接报错。
中文乱码这个坑,在Spring Boot 2.x时代基本不存在了,重点在数据库。建库时一定写DEFAULT CHARSET=utf8mb4,表也尽量明确字符集,别偷懒。PHP项目则要注意页面文件和数据库连接都是UTF-8,一个环节不一致就乱码。
图片上传后404是另一个高频坑。根本原因是你把文件保存到了本地磁盘,但没有把磁盘路径映射成URL能访问的静态资源。Spring Boot里这样配:
@Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/upload/**") .addResourceLocations("file:" + uploadPath + "/"); }上传的文件URL就能用/upload/xxx.jpg访问了。如果上传接口返回的地址本身就是全路径,那检查一下数据库存的路径字段是否和实际保存路径一致。
6.3 并发扣库存:别让库存变成负数
库存扣成负数这个问题,我用一个生活类比:一只猫库存是1,同时来了10个人下单,如果每个人下单前都先查库存再减,10个人可能都查到“还有1只”,然后10单全成功,库存变成-9。这是经典的并发问题。
解决方案是“条件更新”:把“查库存再减”变成“减库存时检查库存大于0”一条SQL完成:
UPDATE pet SET stock = stock - #{quantity} WHERE id = #{petId} AND stock >= #{quantity}如果更新影响行数为0,说明库存不足,抛出异常让事务回滚。把这句话写进下单方法里,库存负数的问题就杜绝了。对毕设来说,用这条SQL已经足够,不需要上分布式锁。课堂上讲清楚这个思路,老师会觉得你理解了并发的本质。
6.4 部署上线的标准动作
开发完成后,部署到云服务器是很多学校要求的一步。标准动作很简单:
后端:用Maven打成jar包,服务器上执行nohup java -jar pet-mall.jar > app.log 2>&1 &,日志重定向到文件,方便排查。启动前确保MySQL和Redis在运行,防火墙放行8080端口或者用Nginx反代。
前端:Vue项目npm run build生成dist目录,用Nginx托管,配置里把/api开头的请求代理到后端服务的8080端口。
我实测过的缺点是:在本地IDEA里跑得非常顺的应用,到服务器上第一个坑往往是数据库连接。因为本地连的是localhost,服务器上要改成内网/公网地址;或者时区/用户名密码对不上。所以部署前先写一个简单的健康检查接口,放到服务器上先curl一下,确认数据库通了再启动完整项目,能省掉至少半小时的排查时间。
7. 毕设文档与答辩准备:别让论文拖后腿
7.1 文档怎么在开发期间就顺手准备好
很多人的毕设论文是最后半个月赶出来的,质量可想而知。过来人经验是:开发期间顺手把素材攒齐,写论文只是把片段连起来。你要攒的素材包括:每个功能模块的截图、核心代码片段、测试用例表格、遇到的问题与解决记录。
比如每测完一个模块,就顺手填一张测试用例表:
| 测试模块 | 用例描述 | 预期结果 | 实际结果 |
|---|---|---|---|
| 注册 | 输入已存在用户名 | 提示用户名已存在 | 通过 |
| 登录 | 输入正确密码 | 返回Token并跳转首页 | 通过 |
| 商品搜索 | 搜索“猫” | 展示相关宠物 | 通过 |
| 下单-正常 | 库存充足下单 | 生成订单、库存减1 | 通过 |
| 下单-超库存 | 数量大于库存 | 提示库存不足、事务回滚 | 通过 |
| 模拟支付 | 点击确认支付 | 订单状态变为已付款 | 通过 |
论文里“系统测试”这一章,直接拿来用。然后再补几张数据库表结构截图、接口文档截图,论文素材就够了。不用边写边截图,零散时间就能做完,但效果比一个月后临时抱佛脚强得多。
7.2 答辩演示怎么演才不会翻车
答辩演示有个固定剧本:先讲背景和需求,再讲技术选型,第三步直接登录前台走一遍搜索、加购、下单、支付流程,最后打开后台看订单状态和商品管理。这个顺序有讲究,主流程走完,所有功能模块都被覆盖了,听众不会乱。
讲的时候记住三句话:第一句讲“这里解决什么问题”,第二句讲“怎么解决的”,第三句讲“为什么这么做”。以下单为例:“订单提交涉及多张表写入,如果不处理并发,库存可能变负数,所以我用条件更新的SQL配合事务,保证数据一致。”这样讲,比背代码流畅,而且显得你真的干过。
还有一条血的教训:演示前一天把电脑重启一次,所有服务重新启动,确保点击十分钟内不会出环境问题。数据别用测试数据,提前准备几只名猫名犬的商品图片和数据,视觉效果好,答辩观感会直观高一个档次。
把这套项目从0做到跑通,我自己最大的体会是:宠物商城这种“增删改查”系统,真正的难度不在写代码,而在把流程想清楚、把坑提前踩明白。下单要加事务、库存要条件更新、图片路径要映射、跨域要配置,这四件事每件都有人栽过。希望你读完这篇,能少翻几次车。最后再啰嗦一句:不管选Java、PHP还是Python,先把那七个MVP功能完完整整做出来,再谈花活。链路通了,项目就活了。