1. 从毕设题目到能跑通的系统:这个项目到底在做什么
先别急着看代码,把这个题目拆开看一遍:基于 Spring Boot 加微信小程序做的在线文创产品订购平台。说白了,就是给文创商品做一个独立的微信小程序商城,用户在小程序里逛商品、加购物车、下单、支付、查看订单,管理员在后台管理商品、处理订单、统计数据。整个系统分两端,小程序端面向普通用户,服务端用 Spring Boot 提供接口,管理后台通常搭配 Vue 这类前端框架来做。
这个选题在计算机毕业设计里属于"经典但不容易做砸"的类型。经典是因为电商类系统的业务链路完整,从用户登录、商品浏览到订单状态流转,能覆盖 Spring Boot 和微信小程序开发的大部分核心知识点;不容易做砸是因为业务模型清晰,领域边界明确,不会像"基于深度学习的某系统"那样,算法模型跑不通就整个项目直接崩溃。文创产品这个细分方向又比普通商品多了一层设计感和差异化,在论文写作和答辩展示时容易出彩。
很多同学拿到这类题目后最容易犯的错是:一上来就写代码,写完代码再补文档,最后发现论文里写的技术方案和实际代码完全对不上。我见过不少同学答辩时被老师问"你这个购物车是用 Redis 存的还是数据库存的",结果自己都说不清楚,因为代码是抄的。所以这篇博文我不会只贴一堆代码片段,而是把整个系统的设计思路、关键实现、踩坑点全部串起来讲,目标是你照着这个思路能自己写出来,而不是只会复制。
适合谁来参考?三类人:第一类是正在做 Spring Boot 小程序类毕设的学生,第二类是想接私活但没做过微信小程序商城的开发者,第三类是产品经理或独立开发者想快速验证文创电商想法。下面所有内容都基于一个假设:你在用 Spring Boot 2.7 + MyBatis Plus + Redis + 微信小程序原生开发(或 uniapp),这个组合是当前中小型项目最主流也最不容易出问题的搭配。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 功能拆分:先画清楚边界,再谈技术实现
2.1 小程序端:用户能干什么
用户端的核心链路是:打开小程序 —— 浏览首页文创产品 —— 查看商品详情 —— 加入购物车/立即购买 —— 下单 —— 支付 —— 查看订单状态 —— 确认收货。围绕这条主链路,还有几个必要功能:用户登录、个人中心、收货地址管理、收藏夹。
首页一般包含轮播图、分类导航、热门商品推荐。文创类商品比较特殊的一点是"故事性",每一件商品通常有设计理念、IP背景、尺寸材质等描述,所以商品详情页要做得比普通电商更丰富,多图展示、细节图、设计故事这些内容不能省。
购物车和订单模块建议做成两种模式:普通购物车流程(多商品合并下单)和立即购买模式(单商品直达下单)。后者在很多毕设里被忽略,但它实际使用频率非常高,尤其是单价较高、决策链路短的文创产品。
支付这块是很多人的心理障碍,实际上毕设项目可以不真正对接微信支付,用一个模拟支付接口代替,前端调起"确认支付"弹窗,后端直接把订单状态改成已支付。但前提是你得把接口设计得和真实微信支付一致,这样将来真要接支付时改动最小。
2.2 管理后台:管理员能干什么
管理后台的核心是商品管理和订单管理。商品管理包括:新增/编辑/下架商品、设置分类、上传商品图片、填写库存和价格、配置商品规格(如颜色、尺寸)、设置是否上架热门推荐。
订单管理除了查看订单列表,还要实现订单状态流转:待付款、待发货、已发货、已完成、已取消。管理员在后台点击发货时需要填写物流单号。
另外一个容易被忽略但很加分的功能是数据看板:展示今日订单数、今日销售额、总用户数、热销商品排行。用简单的 ECharts 柱状图和折线图就能实现,不需要多复杂,但答辩时展示效果非常好。
2.3 角色权限模型
这个系统涉及三个角色:普通用户、管理员、超级管理员。用户角色通过微信小程序的 openid 区分,首次登录时自动注册;管理员账号在数据库里预置,不支持自助注册。
权限控制用 Spring Boot 的拦截器或注解实现即可,不需要引入 Spring Security 这么重的东西,除非你的选题要求。我的建议是:小程序端所有需要用户身份的接口都用一个注解标识,管理员接口单独拦截,管理端接口加上简单的 Token 校验。毕设项目里把权限模型做清楚即可,过度设计反而是负担。
3. 核心技术选型:每一层为什么这么做
技术选型部分直接决定你项目能不能顺利跑通、答辩时能不能扛住追问,所以这一部分值得花点心思逐层说明。
3.1 Spring Boot 版本选择:不要盲目追新
Spring Boot 版本问题在热搜词里反复出现,比如"springboot版本太高",这是毕设翻车的高频原因。我的建议是:直接用 Spring Boot 2.7.x 系列,搭配 JDK 1.8,这是目前最稳定、网上资料最全的组合。
为什么不用 Spring Boot 3.x?Spring Boot 3.x 最低要求 JDK 17,很多同学本机装的是 JDK 8,换版本本身就有门槛;更重要的是,网上能找到的教程、视频、博客,绝大多数都是基于 Spring Boot 2.x 写的,遇到问题搜答案时,2.x 的解决方案一搜一大把,3.x 的则少得多。毕设的核心目标是顺利做出来,不是追求最新技术栈。
Maven 依赖里需要注意的一点是,Spring Boot 2.7 版本下 MyBatis Plus 要用 3.5.x,不要用太老的 3.4,否则某些新写法不支持;同时要注意 MyBatis Plus 和 Spring Boot 的兼容性,建议在 pom.xml 里显式指定版本号,不要只写 starter 不写版本。
3.2 数据库选型:MySQL 5.7 或 8.0 都可以
数据库直接用 MySQL。5.7 和 8.0 我都用过,两者差别不大,建议根据你本机环境来,哪个方便装哪个。数据库表的设计是整个系统的地基,表的数量一般在 8 到 12 张左右,我下面给出一个最常用的表结构清单:
- 用户表(user):id, openid, nickname, avatar_url, phone, create_time
- 分类表(category):id, name, sort_order, create_time
- 商品表(product):id, category_id, name, subtitle, description, main_image, detail_images, price, original_price, stock, sales, is_hot, status, create_time
- 商品规格表(product_spec):id, product_id, spec_name(如"颜色"), spec_value(如"红色"), price, stock
- 购物车表(cart):id, user_id, product_id, spec_id, quantity, checked, create_time
- 订单表(orders):id, order_no, user_id, total_amount, pay_amount, status, address_info, receiver_name, receiver_phone, create_time, pay_time, ship_time, finish_time
- 订单明细表(order_item):id, order_id, product_id, product_name, product_image, spec_desc, price, quantity
- 收货地址表(address):id, user_id, name, phone, province, city, district, detail, is_default
- 轮播图表(banner):id, image_url, product_id, sort_order, status
- 收藏表(favorite):id, user_id, product_id, create_time
订单和订单明细为什么要分成两张表?因为一单可以包含多个商品,如果所有的商品信息都塞进 order 表里,字段设计会非常别扭;拆成明细表后,订单主表只负责记录订单整体信息(金额、状态、收货人),明细表记录具体买了哪些商品、每个商品什么价格、多少数量。这也是电商系统最经典的"主从表"结构,答辩时老师大概率会问,你能把这个逻辑讲清楚就很加分。
3.3 Redis 的定位:缓存购物车和 Token,别什么都往里放
Redis 在这个系统里的使用范围我建议控制在两个地方:存储小程序端登录后生成的 Token,以及缓存首页轮播图和热门商品数据。购物车也可以放 Redis,但这里有一个取舍问题需要考虑清楚。
用 Redis 存购物车的好处是读写快,不用频繁操作数据库;坏处是 Redis 数据是易失性的,如果 Redis 重启了购物车数据就没了,而且你需要在合适的时候把购物车里的商品信息(快照)落库到订单明细中。用 MySQL 存购物车的好处是数据可靠、逻辑简单,每次增删改查直接操作 cart 表即可,坏处是频繁读写数据库,但毕设这个数据量根本感受不到性能差异。
我的建议是:购物车直接存 MySQL。原因很简单——省事、可靠、不容易出错。Redis 在毕设里是一个加分项,所以还是要用,但把它的职责限定在 Token 存储和数据缓存这两个明确且不会出错的场景上。答辩时被问"为什么购物车不用 Redis",你可以直接回答:考虑到购物车数据的持久化要求和毕设场景的数据量,MySQL 直接存储逻辑更简单可靠,Redis 在这里用于登录凭证和热点数据缓存。
3.4 小程序端技术选择:原生还是 uniapp
小程序端可以用微信小程序原生开发,也可以用 uniapp 开发。两者选择主要看你的编程基础:如果你只会 Vue,选 uniapp 更顺手,因为 uniapp 的语法本身就是 Vue 风格的;如果你对小程序原生开发不陌生,或者愿意花时间学,原生开发调试更直接,微信生态的工具链支持也最完整。
我的建议是优先选择原生小程序开发。原因是配套资料最多、报错信息最直观、微信开发者工具的调试能力最强;uniapp 虽然跨端能力强,但如果你不打算同时发布到支付宝小程序或抖音小程序,uniapp 的跨端优势就发挥不出来,反而多了一层编译转换的中间环节,出了问题排查起来更绕。
小程序的目录结构大致如下:
code复制pages/
index/ # 首页
category/ # 分类页
cart/ # 购物车
user/ # 个人中心
product/ # 商品详情
order/ # 订单列表
order-confirm/ # 确认订单
address/ # 地址列表
address-edit/ # 地址编辑
favorite/ # 我的收藏
utils/
request.js # 封装 wx.request
auth.js # 登录态管理
app.js
app.json
核心的请求封装是必须做的,不要在每个页面里直接调 wx.request,否则后面要改 baseURL、统一处理 Token 过期时会想哭。封装思路很简单:所有请求走同一个方法,自动携带 Token,收到 401 状态码时统一跳转登录。
4. 数据库设计与核心表结构:把地基打牢
设计数据库是这类型系统最关键的一环,表结构一旦定了,后面写代码基本就是按图索骥。但如果表设计不合理,后面改起来就是牵一发动全身。我在这一章把核心表的关键字段和设计理由讲透。
4.1 用户表:openid 是唯一身份标识
微信小程序用户登录后,后端通过 code 换取 openid,这是微信体系内用户在当前小程序下的唯一标识。用户表的核心字段就是 openid,它是唯一索引,不能重复。
用户表不需要一开始就把所有字段都填上。很多用户第一次登录时,微信只返回 openid 和昵称、头像,手机号需要用户主动授权才能获得,所以手机号字段允许为空,在用户下单时再强制绑定更合理。
4.2 商品表和购物车表:关于"库存扣减"的经典问题
商品表里的 stock 字段代表库存,下单时怎么处理库存?这是一个非常经典的面试问题,也是答辩时的常见追问点。
最笨的办法是用户下单时直接 UPDATE product SET stock = stock - 1 WHERE id = ...,但这样做的问题是:如果用户下单后不支付,库存已经被扣掉了;过一会儿订单超时关闭,又要把库存加回来,很容易出错。
稍微好一点的办法是:下单时只检查库存是否足够,不实际扣减;等到用户支付成功后再扣减库存。这样处理的好处是不用担心未支付订单占用库存,坏处是可能"超卖"——多个用户同时看到库存充足,同时下单,付款后却发现库存不够了。不过毕设项目的数据量下,这个问题出现的概率极低,而且真到了大流量场景也需要更复杂的方案(例如 Redis 预减库存),不在这个项目范围内。
我的建议是:在下单接口里做库存校验,支付回调里做库存扣减。这样逻辑清晰,答辩时也能讲出"为什么不在下单时扣库存"的理由,证明你认真思考过这个问题。
4.3 订单表:状态字段用数字还是字符串
订单状态是最容易出乱子的地方。我见过有些项目用字符串存状态,比如 "待付款"、"已付款"、"已发货",看起来直观,但隐患很大:如果哪天你改了前端展示文案,数据库里的旧数据全部对不上;枚举值和业务逻辑代码耦合在一起,改一处就要改多处。
我建议用整数存储订单状态:0 待付款,1 待发货,2 待收货,3 已完成,4 已取消。后端定义枚举类,前端用映射表把数字转成文案,这样状态的定义只维护在一处,改文案时不需要动数据库。
订单号用时间戳加随机数生成即可,保证唯一性:yyyyMMddHHmmss + 4位随机数。不需要用全局唯一的雪花 ID,毕设场景下订单号只要求"看起来不重复"和各种状态流转时按订单号查得到记录就行。
4.4 一个容易忽略的坑:订单里要存商品快照
什么叫商品快照?就是下单那一刻商品的名称、图片、价格、规格,以冗余字段的形式存到订单明细表里。
为什么要这样做?因为用户下单之后,管理员完全可能修改商品价格、库存,甚至删除商品。如果订单明细表里只存了一个 product_id,到时候查订单详情要 join 商品表,一旦商品被删了,订单历史数据就残缺了。把商品名称、图片、单价、规格描述原样存进 order_item 表,订单就能显示"当时买的时候是什么样",这是电商系统的基本素养,也是分表设计的核心理由。
4.5 索引设计:别一张表什么索引都不建
虽然毕设数据量不大,但不建索引的习惯很不好。常用查询必须建索引:
- 订单表的
user_id建普通索引,因为查"我的订单"按用户维度高频查询 - 订单表的
order_no建唯一索引,订单号唯一,查询走索引 - 购物车表的
user_id建普通索引 - 商品表的
category_id建普通索引 - 用户表的
openid建唯一索引
索引不是越多越好,每张表 3 到 5 个索引足够,索引本身也会占用存储空间和维护成本。建索引的标准是:高频查询的 WHERE 条件和排序字段才需要索引。
5. 登录鉴权流程:小程序和后端如何互相确认身份
登录鉴权是毕设里最容易卡住的一个点,也是被问到"springboot 版本太高""小程序获取登录后的微信用户失败"这类高频问题时的主要来源。很多同学卡在:前端调后端接口时提示未登录,或者后端拿不到用户身份。这一章把完整的登录链路拆开讲清楚。
5.1 登录流程全链路
微信小程序端的登录流程是这样的:
- 小程序端调用
wx.login(),获取一个临时凭证code - 小程序端把
code发送给后端 - 后端拿着
code调用微信接口https://api.weixin.qq.com/sns/jscode2session,用 appid 和 secret 换回openid和session_key - 后端根据
openid查询用户表,如果不存在则创建新用户 - 后端生成一个 Token(可以用 UUID 或 JWT),存储到 Redis,设置过期时间(比如 7 天)
- 后端把 Token 返回给小程序端
- 小程序端把 Token 存到本地缓存,后续所有请求都在 header 里带上 Token
- 后端每次收到请求时,从 Redis 里查 Token 是否存在,存在则从 Redis 里取出 userId,不存在则返回未登录
整个链路的关键点在于:小程序端不与微信服务器直接交互,所有敏感操作(appid、secret)都在后端完成。这样 appsecret 不会暴露在小程序代码里,安全性有保障。
5.2 wx.login 的常见坑:静默登录和用户信息授权要分开
很多同学把 wx.login() 和 wx.getUserProfile() 搞混。wx.login() 获取 code 是开发者必备的登录身份凭证,这个过程是无感知的,不需要弹窗;wx.getUserProfile() 是获取用户头像昵称,新版本微信里会弹授权框。
正确做法是:进入小程序时只需要 wx.login 换后端 Token,如果有需要再用 wx.getUserProfile() 补用户头像昵称;如果没有收集用户头像昵称的需求,完全可以不弹窗,用微信的"匿名头像昵称"方案。
"小程序获取登录后的微信用户失败"这个问题,大概率是把 wx.login 和 wx.getUserProfile 搞混了,后端拿不到用户信息。还有一个常见原因是后端请求微信接口时,小程序 appid 和 secret 不匹配,或者服务器时间不对,导致签名错误。
5.3 拦截器:统一管理登录校验
后端我建议用一个拦截器统一校验 Token,不需要每个接口手写判断。下面是核心思路:
- 定义一个拦截器,在 preHandle 里读取 header 中的
token字段 - 从 Redis 按 token 取 userId,取不到就返回 401
- 取到 userId 就放到 request attribute 里,Controller 里直接获取
排除白名单,比如登录接口、首页商品列表接口、商品详情接口不需要登录也能访问;其他接口都拦截。
管理后台的鉴权可以单独做,管理员不依赖微信登录,直接用账号密码登录,登录成功后也发一个 Token,管理端接口校验时区分一下用户角色。
6. 核心接口设计与实现:商品下单到支付这一条链路
本章把系统的主链路代码实现串一遍,重点关注业务逻辑和接口设计,不贴全部代码(全部代码量太大),但是核心思路、关键代码片段都会给出来。
6.1 商品列表接口:分页、分类筛选、关键字搜索
小程序首页和分类页都需要商品列表,一个接口可以通吃:GET /api/product/list?categoryId=1&page=1&size=10&keyword=创意。
后端用 MyBatis Plus 的 LambdaQueryWrapper 做条件查询,categoryId 非空就加等值条件,keyword 非空就加模糊查询,status 默认只查上架状态,按 sort_order 或 create_time 排序,最后用 Page 对象分页。
响应结构建议统一封装,这样前端处理起来非常统一:
json复制{
"code": 200,
"message": "success",
"data": {
"total": 100,
"list": [...]
}
}
6.2 商品详情接口:为什么不能只返回单个表的数据
商品详情页往往需要一次性返回商品基本信息、多张轮播图、规格列表。如果前端分别请求三个接口,逻辑上也能实现,但效率低、代码分散。更好的做法是后端做一次聚合,一次性返回。
这类聚合查询的本质是:单表查询加循环组装。如果是大厂的商城系统,这类接口可能需要做缓存和异步编排;但毕设场景下,直接查数据库组合返回即可,重点是代码结构要清楚。
6.3 创建订单接口:事务和幂等
创建订单是最核心的业务接口,涉及多个表的写操作:
- 创建订单主表记录
- 创建订单明细表记录
- 清空购物车中对应的商品
- 更新商品库存(或校验库存)
这四步必须保证"要么全部成功,要么全部失败",所以要用 @Transactional 事务注解。我在实际项目中遇到过一个问题:同一个订单通过快速点击被提交两次,导致购物车被清空两次、库存扣减两次。解决办法是在前端加"提交中"防重复点击,后端判断当前用户是否有未支付订单先做一次拦截。更严谨的做法是加上一个"唯一订单号"的约束,但毕设做到前端防重复加后端的未支付订单检查已经足够。
下单成功后返回 orderId 或 orderNo,前端拿着订单号去发起支付。支付这块毕设场景用模拟支付即可,后端提供一个"模拟支付接口",前端提交订单后直接在订单详情页显示"确认支付",点击后调用模拟支付接口,后端将订单状态从待付款改为待发货。
6.4 订单列表和详情:按状态分组查询
订单列表是用户查看频率很高的页面,通常要按状态筛选:全部、待付款、待发货、待收货、已完成。后端接口设计时支持 status 参数,为空时查询全部,传入具体状态时精确过滤。
订单列表返回时需要包含每个订单下的商品明细列表,因为小程序前端要在一个订单卡片里展示这个订单有几个商品。这里也要做一次聚合查询:先查订单主表,再根据订单 id 集合批量查订单明细表,然后在 Java 代码里按 orderId 分组组装。
6.5 管理端接口:商品管理和订单处理
管理端接口与用户端接口分开,单独一套 controller 和 service。商品管理包括新增、编辑、上架/下架、删除。删除商品要注意:有订单引用的商品不能物理删除,只能做软删除(通过 status 字段控制),这又是电商系统的一个基本素养。
订单处理接口就是管理员发货:更新订单状态、填物流信息。管理端的数据看板接口建议单独写一个统计接口,用简单的 SQL 聚合完成,不要在前端做统计计算。
7. 环境准备与部署:从本地跑通到答辩演示
环境准备是最容易让新手心态崩溃的环节。这一章把全流程捋一遍,每一处都给出具体的操作建议。
7.1 本机开发环境清单
- JDK 1.8(配置好 JAVA_HOME)
- Maven 3.6+(或直接用 IDEA 内置 Maven)
- MySQL 5.7 或 8.0(启动服务,创建数据库,字符集选 utf8mb4)
- Redis(Windows 版 Redis 直接下载 zip 解压即可,运行 redis-server.exe)
- IDEA 2023 或 2024 版本(社区版够用,专业版更顺手)
- 微信开发者工具(稳定版即可)
- Navicat 或 DBeaver 连接数据库
7.2 后端项目启动的完整步骤
后端项目拿到手之后,第一次启动会遇到的问题是"端口被占用""Redis 连不上""MySQL 连接失败"。我的建议是启动顺序固定下来:先启动 MySQL,再启动 Redis,最后启动 Spring Boot 项目。
配置文件 application.yml 里需要关注的关键项:
yaml复制server:
port: 8080
spring:
datasource:
url: jdbc:mysql://localhost:3306/creative_mall?useUnicode=true&characterEncoding=utf8mb4&serverTimezone=Asia/Shanghai
username: root
password: yourpassword
driver-class-name: com.mysql.cj.jdbc.Driver
redis:
host: localhost
port: 6379
database: 0
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
db-config:
id-type: auto
注意 MySQL 连接串里 serverTimezone=Asia/Shanghai 是必须的,否则会因为时区问题报错。utf8mb4 字符集是为了支持中文和特殊字符(比如 emoji 表情),如果你在商品描述里放 emoji,用 utf8 会报错。
7.3 小程序端运行配置
小程序端在微信开发者工具里导入项目后,需要做两处配置:
第一,把 app.js 里的 baseURL 改成你本机的后端地址。真机测试时不能填 localhost,要改成局域网 IP,比如 http://192.168.1.100:8080。此时后端的 application.yml 如果配置了跨域或拦截器白名单,也要相应调整。
第二,在微信公众平台(小程序后台)配置 request 合法域名。注意,开发调试时可以在开发者工具的"详情-本地设置"里勾选"不校验合法域名",这样本地 IP 调试不会报域名错误。但是真机预览时仍然会校验,所以如果要真机测试,这个域名配置还是要重视。很多同学在"真机测试时出现 net::ERR_CONNECTION_RESET",就是因为开发机上后端端口没有对外开放,或者手机和电脑不在同一个局域网。
7.4 答辩演示时的环境准备清单
答辩是一次性的,设备环境一定要提前演练。建议准备一台备用笔记本电脑,数据库、Redis、后端、小程序开发者工具全部提前启动好,模拟一次完整的演示流程:登录、浏览商品、加购物车、下单支付、后台发货、用户端确认收货。
另外一定要准备一个重要备份方案:如果有现场网络环境不稳定的情况,提前把核心演示录屏存一份,实在连不上微信开发者工具时直接放录屏,不丢分反而证明你考虑周到。
8. 项目文档与论文写作:系统设计说明书怎么写不虚
很多同学觉得代码写完了就大功告成,结果在文档和论文环节翻车。毕设文档的核心目标是向评审老师说明:你做了什么、为什么这么做、结果怎么样。文档要有技术深度,而不是流水账。这一章重点讲怎么写系统设计说明书。
8.1 系统设计说明书的结构骨架
一份合格的系统设计说明书通常包含以下章节:
- 项目背景与研究意义
- 系统需求分析
- 系统总体设计
- 系统详细设计
- 系统实现与测试
- 总结与展望
核心部分是需求分析和总体设计,这部分决定了论文的技术含量。
8.2 需求分析部分怎么写
需求分析要画出系统的角色图和功能模块图。这一部分建议用思维导图把功能模块展开,再转化为文字描述,重点写清楚两个角色(用户和管理员)各自的功能需求和非功能需求。
非功能需求容易被忽略,例如系统的性能要求(接口响应时间不超过 X 秒)、安全性要求(用户密码加密存储、Token 过期机制)、可用性要求(页面操作友好、错误提示明确)。这些写进去之后,论文看起来会专业很多。
8.3 详细设计部分怎么写
详细设计部分要包含:
- 数据库设计:画出 E-R 图,给出每张表的字段说明表
- 接口设计:写出主要接口的请求参数和返回结果
- 核心业务逻辑设计:比如下单流程、登录流程,用文字描述每一步操作
这一部分最忌讳写成纯理论,最好能配合核心代码片段说明。代码不要贴全部,贴关键方法,比如下单接口的事务处理、登录 Token 的生成逻辑。
8.4 测试部分怎么写
测试部分要写清楚测试环境、测试用例和测试结果。测试用例要覆盖主流程和边界情况:正常下单、库存不足、商品不存在、下单后取消、订单超时关闭。每一类测试都要有测试结果截图。
在测试结果里可以讲一个真实发现的问题并给出解决方案。比如我发现快速点击下单按钮会重复下单,于是增加了前端防重复提交和后端未支付订单检查,这部分内容在答辩时是很加分的,证明你做了充分的测试和优化。
9. 踩坑记录与问题排查:那些最容易让人崩溃的瞬间
这一部分我根据经验整理了几个出现频率最高的坑,也是热搜词里反复出现的问题。每一条都是我自己或者我指导过的同学真实踩过的,建议收藏起来慢慢对照。
9.1 Spring Boot 版本太高导致兼容性问题
"springboot 版本太高"几乎每个学期都要看到几十次。典型表现是:使用 Spring Boot 3.x 创建项目,然后照抄一份 Spring Boot 2.x 的教程代码,结果依赖报错、配置报错、API 报错连环出现。
解决思路就一句话:换用 Spring Boot 2.7.x。在我的方案里这是最稳的版本,所有主流的 MyBatis Plus、Redis、微信开发 SDK 都完美兼容。
9.2 小程序获取登录后的微信用户失败
这类报错最常见的场景是:后端 wx.login 后拿着 code 去换 openid,结果返回 errcode: 40029 或 errmsg: invalid code。原因一般是 code 被使用了两次——前端在同一页面多次调用 wx.login,导致第一次拿到的 code 已经失效;或者开发者工具时间不同步。
还有一种情况是 AppID 配错。自己测试时用的 AppID 和正式环境 AppID 不一致,后端小程序密钥也没有对应调整。检查配置的时候,一定要把前端 appid、后端配置的 appid、微信公众平台的 AppSecret 这三者对齐。
9.3 真机测试时 net::ERR_CONNECTION_RESET
这个问题几乎每天都会有人问。真机测试时,手机访问不到电脑上的后端服务,最常见的原因是手机和电脑不在同一个局域网内,或者电脑防火墙拦截了端口访问。最完整的排查链路是:
- 确认后端程序已经启动,浏览器访问
http://localhost:8080/api/health确认能通 - 查看电脑的局域网 IP,用
ipconfig(Windows)或ifconfig(Mac)命令 - 手机浏览器直接访问
http://局域网IP:8080/api/health,通不通一目了然 - 如果手机浏览器不通,检查防火墙设置,把 8080 端口加入放行列表
- 如果手机浏览器通了,但小程序真机预览仍报错,大概率是 request 合法域名校验问题,在开发者工具详情设置里勾选"不校验合法域名"
这个问题排查的关键是分层:先排除后端没启动,再排除网络不通,最后才去检查小程序配置。
9.4 MyBatis Plus 分页失效
MyBatis Plus 分页查询需要在配置类里加上分页插件拦截器,否则 Page 对象返回的 total 一直是 0,或者分页不生效。
java复制@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
这个坑非常经典,几乎每个用 MyBatis Plus 的毕设都会遇到一次,因为官方文档里分页插件是可选配置,很多人漏了。
9.5 小程序 request 请求封装:统一处理基础逻辑
小程序的 wx.request 本身比较原始,如果每个页面都写一遍,代码会非常冗余。建议封装在 utils/request.js 里,把 baseURL、请求头 token、超时时间、错误码统一处理。接口返回 401 时自动清除本地登录态并跳转登录页。
这个封装还有一个额外的好处:调试时可以在 request.js 里统一打印请求和响应日志,排查问题效率高很多。
10. 从毕设到实际项目:这个系统还能怎么延伸
做完一个毕设项目,学到的东西不应该停留在"通过答辩"这个层面。从毕设到实际项目之间,还有几条非常自然的延伸路径。
10.1 增加真实微信支付
如果将来想把这个系统真正上线运营,第一步是接入真实微信支付。微信支付需要商户号、API 证书、支付回调接口,流程比模拟支付复杂不少,但在后端已经有"模拟支付"接口的基础上,把模拟逻辑替换成真实调用的改造成本其实不高,前端小程序调用 wx.requestPayment 接口,后端处理支付回调并更新订单状态。
10.2 增加商品评价和用户互动
文创产品非常依赖口碑传播,用户评价、买家秀、点赞、分享,这些功能不仅能提升产品的用户体验,也能在功能上增加社交属性。评价功能的核心是订单完成后的评价入口、评价列表、评价图片上传,扩展起来很自然。
10.3 增加数据库读写分离或 Redis 缓存优化
如果数据量增长后,每次查商品列表、首页数据都直接查数据库,压力会越来越大。此时可以在 Redis 里缓存商品列表和首页数据,设置缓存过期时间,后台修改商品时主动删除缓存。这个路径的核心是理解"缓存一致性",属于进阶技能的范畴,但对想深入了解后端的同学非常有价值。
10.4 管理后台从 Vue 到微服务的演进
如果管理后台的功能越来越多,可以考虑把商品管理、订单管理、数据统计拆成独立的微服务模块,或者引入消息队列来处理订单超时关闭这类异步任务。这类演进在毕设中不需要做,但理解它的方向和动机,对将来做真实项目帮助很大。
我做这类项目比较多,最大的体会是:毕设项目的价值不在于用了多牛的技术,而在于你是否真正理解了业务逻辑和工程化的基础思维。一个能把订单状态流转、库存扣减、登录鉴权讲清楚的人,比一个装了十几个依赖但是说不清每个依赖为什么存在的人强得多。按照我上面这些思路把系统从零推到跑通,答辩时被追问也不会慌,因为每一步你都知道为什么这么做。
