1. 这个毕设项目到底在做什么
如果你也在为计算机毕业设计选题发愁,或者已经选了一个电商方向的题目但心里没底,那这篇文章应该能帮到你。我要拆解的是一个真实可落地的项目:基于微信小程序实现优购电商管理系统。这个名字听起来挺常规,但里面涉及的链路其实非常完整——从前端小程序的页面交互,到后端接口的权限控制,再到数据库的表结构设计、订单状态流转、微信支付对接,最后还要写出一篇能过盲审的毕业论文。它不是那种只做一两个页面糊弄答辩的“玩具项目”,而是按生产级电商系统的骨架去设计的,只是把规模控制在本科生能完成、能讲清楚的范围内。
先说结论:这个项目适合谁?适合三类人。第一类是计算机、软件工程相关专业的毕业生,想找一个不烂大街、有技术深度、又能快速上手的电商方向毕设题目;第二类是自学小程序开发但没有完整项目经验的人,想拿一个全栈案例练手;第三类是想做校园周边电商、小范围线上商城的人,可以把这套系统改改直接用。项目本身的技术栈不算激进,但每一条链路都是真实的——这很重要,因为答辩时老师最常问的就是“这个功能是怎么实现的”“为什么这么设计”,而不是听你背概念。
从产品形态上看,“优购电商管理系统”可以拆成两个端:用户端(微信小程序) 和 管理端(Web后台)。用户端是消费者能看到的:浏览商品、搜索、加购物车、下单、支付、查看订单状态、申请售后;管理端是运营人员和商家用的:商品上架下架、库存管理、订单发货、处理退款、查看销售统计。两端的业务数据是打通的,用户在小程序下单,后台能实时看到订单并处理,整个闭环才算完整。
这类系统最大的价值在于,它不是一个孤立的前端页面,而是把电商业务里的核心痛点都覆盖了:怎么识别用户、怎么保证订单状态不乱、怎么和微信支付安全交互、怎么在一套商品体系下支持用户端和管理端的不同权限视角。把这些点吃透,你的毕设从开题到答辩都会顺畅很多,而且面试时也能把这些经验讲成“项目亮点”。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术选型与整体架构思路
2.1 为什么选微信小程序而不是H5或App
这几乎是每年毕设选题时被问得最多的问题。我的建议很直接:如果你想做电商类项目,小程序是性价比最高的载体。原因有几点。
第一,微信小程序的用户触达成本极低,不需要下载App、不需要注册账号,扫码或用微信搜索就能打开,这对电商场景太重要了。第二,小程序自带微信生态的登录体系,调用 wx.login 拿到 code,后端再通过 code2Session 换取 openid,天然就是用户在微信里的唯一身份标识,你不用自己搓一套复杂的注册登录流程,省下大量时间。第三,微信支付、订阅消息、地理位置这些能力直接以API的形式暴露给开发者,接入门槛比App低得多。
相比之下,H5在微信里打开虽然也方便,但支付体验依赖微信JS-SDK,每次要处理签名配置,而且无法使用小程序原生的订阅消息和收货地址能力;App就更不用说了,要单独做安卓和iOS两端,光打包上架、兼容性测试就能耗尽毕设周期。所以选小程序的本质,是用一个确定的平台能力,换一套完整可跑通的业务闭环。
2.2 前端架构:小程序原生框架的基础结构
小程序原生开发虽然听起来“基础”,但它反而是最适合毕设的,因为你不需要额外引入 UniApp、Taro 这类跨端框架的学习成本。原生框架的核心由四类文件组成:.json 负责页面配置(导航栏标题、窗口背景色等),.wxml 负责页面结构,.wxss 负责样式,.js 负责逻辑与数据绑定。
在一个典型的“优购”小程序项目里,目录结构通常是这样的:
code复制miniprogram/
├── app.js # 小程序全局逻辑,初始化全局数据
├── app.json # 全局配置,注册页面、配置tabBar
├── app.wxss # 全局样式
├── utils/
│ ├── request.js # 封装wx.request请求,统一携带token
│ └── util.js # 工具函数,如格式化时间、价格计算
├── pages/
│ ├── index/ # 首页:轮播图、商品分类、推荐商品
│ ├── category/ # 分类页:左侧分类列表 + 右侧商品列表
│ ├── goods_list/ # 商品列表页
│ ├── goods_detail/ # 商品详情页
│ ├── cart/ # 购物车
│ ├── order_confirm/ # 确认订单页
│ ├── order_list/ # 订单列表
│ ├── order_detail/ # 订单详情
│ ├── user/ # 个人中心
│ └── address/ # 收货地址管理
└── components/ # 自定义组件:商品卡片、数字输入框等
这里有个容易被忽略的点:app.json 里的 tabBar 配置决定了底部导航有哪些入口。一般电商小程序会设置四个:首页、分类、购物车、我的。tabBar 页面必须是已注册的页面,而且你至少需要一个 tab 页,否则小程序会直接报错。
2.3 后端架构:单体应用就够了,别过度设计
后端我强烈建议用 Spring Boot + MyBatis Plus + MySQL 的单体架构。不少学生一上来就想搞微服务、Redis、消息队列,结果把简单的事情复杂化了。毕设阶段要展示的是你对业务逻辑的掌握,而不是堆砌一堆中间件名字。单体应用的好处是:一个项目启动、一个数据库、一套接口,所有模块之间的调用都在进程内完成,调试方便,部署也简单,写论文时模块划分反而更清晰。
如果没有任何Java基础,也可以用 Node.js(Express/Koa)或 Python(Flask/Django)来写后端,思路完全一致——核心是设计清晰的RESTful接口。但如果你之后的职业方向偏Java后端,Spring Boot一定是更稳妥的选择,因为Spring生态中MyBatis Plus、Spring Security等组件能帮你省掉大量重复代码。
后端模块划分建议这样拆:
code复制com.yougou.admin # 管理端接口模块
com.yougou.api # 小程序端接口模块
com.yougou.common # 公共配置、工具类、常量、异常处理
com.yougou.entity # 数据库实体类
com.yougou.mapper # MyBatis Plus的Mapper层
com.yougou.service # 业务逻辑层
com.yougou.controller # 控制层,接收前端请求
我特意把管理端和小程序端的接口分到两个包,这样在Swagger文档里可以分组展示,写论文时也能明确说明“接口按权限域划分”。实际开发中,管理端接口通常加上 /admin 前缀,小程序端接口加上 /api 前缀,后面做权限拦截时只需要对这两个前缀分别配置不同的校验规则。
2.4 为什么选择MySQL:你的数据量根本不需要NoSQL
电商系统里最核心的数据关系是“商品—分类—订单—用户”,这是非常典型的二维表结构,MySQL的关联查询、事务支持、外键约束配合MyBatis Plus使用起来非常顺手。有些人觉得用MongoDB听起来更“高级”,但电商订单、金额计算这类强一致性的业务,最适合的永远是关系型数据库。
表设计时只需要覆盖电商业务核心实体:用户表、商品分类表、商品表、商品SKU表(可选)、购物车表、订单表、订单明细表、收货地址表、轮播图表。每一张表之间用主外键关联,保证数据一致性。具体表结构后面有专门一节展开讲。
2.5 微信小程序云开发 vs 自建后端
这是这两年学生们常问的一个岔路口。微信云开发确实很省事——不用买服务器、不用自己写后端登录逻辑,直接用云函数操作云数据库,前端调用 wx.cloud.callFunction 就能完成业务。但如果你选择云开发,要注意一个现实问题:论文里关于“系统架构”的章节会很难写,因为大量后端逻辑被平台封装了,你说不清楚“自己的后端到底做了什么”。
而且,云开发有免费额度限制,如果做毕设演示时流量较大,费用虽然不高但终究是个麻烦。我的建议是:如果选题偏“快速实现、重前端展示”,云开发完全够用;但如果你的题目里包含“管理系统”三个字,答辩老师大概率会追问管理后台、权限、数据统计是怎么实现的,这时候自建后端能讲的内容要丰富得多。
3. 数据库设计:电商系统的地基
3.1 核心表结构设计与字段解析
数据库结构是整个项目的灵魂。很多同学先写代码再改表,最后代码和表结构对不上,越改越乱。我建议倒过来:先花三天时间把表结构定下来,再动手写代码。下面是我在实际开发中反复打磨过的一套核心表结构,可以直接参考。
用户表(user):
| 字段名 | 类型 | 说明 |
|---|---|---|
| id | bigint(20) | 主键自增 |
| openid | varchar(64) | 微信openid,用户唯一标识 |
| nickname | varchar(64) | 昵称 |
| avatar_url | varchar(255) | 头像URL |
| phone | varchar(20) | 手机号 |
| gender | tinyint | 性别:0未知 1男 2女 |
| status | tinyint | 状态:1正常 0禁用 |
| create_time | datetime | 注册时间 |
商品分类表(category):
| 字段名 | 类型 | 说明 |
|---|---|---|
| id | bigint | 主键 |
| name | varchar(32) | 分类名称 |
| parent_id | bigint | 父分类ID,0为顶级 |
| sort | int | 排序值,越小越靠前 |
| icon | varchar(255) | 分类图标 |
商品表(product)是整个系统的核心,字段设计上要注意区分“规格维度”和“销售维度”:
| 字段名 | 类型 | 说明 |
|---|---|---|
| id | bigint | 主键 |
| category_id | bigint | 所属分类ID |
| name | varchar(128) | 商品名称 |
| subtitle | varchar(255) | 副标题/卖点 |
| main_image | varchar(255) | 主图URL |
| sub_images | text | 子图URL列表,JSON数组格式 |
| price | decimal(10,2) | 商品价格 |
| original_price | decimal(10,2) | 划线价(用来展示折扣) |
| stock | int | 库存量 |
| sales | int | 销量(用于排序和展示) |
| status | tinyint | 状态:1上架 0下架 |
| detail | text | 商品详情(富文本) |
| create_time | datetime | 创建时间 |
| update_time | datetime | 更新时间 |
订单表(order)是另一个核心,它承担了电商系统最复杂的业务规则:
| 字段名 | 类型 | 说明 |
|---|---|---|
| id | bigint | 主键 |
| order_no | varchar(64) | 订单编号(唯一) |
| user_id | bigint | 下单用户ID |
| total_amount | decimal(10,2) | 订单总金额 |
| pay_amount | decimal(10,2) | 实付金额 |
| pay_type | tinyint | 支付方式:1微信支付 |
| status | tinyint | 订单状态:0待支付 1待发货 2待收货 3已完成 4已取消 5售后中 |
| address_info | text | 收货地址快照(JSON字符串) |
| remark | varchar(255) | 用户备注 |
| pay_time | datetime | 支付时间 |
| ship_time | datetime | 发货时间 |
| finish_time | datetime | 完成时间 |
| create_time | datetime | 下单时间 |
订单明细表(order_item)记录订单中包含的商品快照:
| 字段名 | 类型 | 说明 |
|---|---|---|
| id | bigint | 主键 |
| order_id | bigint | 订单ID |
| product_id | bigint | 商品ID |
| product_name | varchar(128) | 商品名称快照 |
| product_image | varchar(255) | 商品图片快照 |
| price | decimal(10,2) | 成交单价 |
| quantity | int | 购买数量 |
| total_price | decimal(10,2) | 小计 |
购物车表(cart_item):
| 字段名 | 类型 | 说明 |
|---|---|---|
| id | bigint | 主键 |
| user_id | bigint | 用户ID |
| product_id | bigint | 商品ID |
| quantity | int | 数量 |
| checked | tinyint | 是否选中:1选中 0未选 |
| create_time | datetime | 加入时间 |
| update_time | datetime | 更新时间 |
收货地址表(address):字段包括用户ID、收货人姓名、手机号、省份、城市、区县、详细地址、是否默认地址。
轮播图表(banner):字段包括图片URL、跳转链接、排序值、状态。
3.2 为什么订单表要存“地址快照”而不是关联地址表
这里我想重点说一个设计细节,它经常被当成“加分项”在答辩中展开。
很多学生设计订单表时,直接用一个 address_id 外键去关联地址表,下单的时候记录地址ID,发货时再查地址表获取收货人信息。这在逻辑上看似没问题,但实际上是错的——如果用户在下单之后修改了收货地址,甚至删除了地址记录,那么这笔历史订单的配送信息就会跟着变,这在电商业务里是绝对不能发生的。
正确答案是:在下单那一刻,把收货地址的完整信息拷贝一份,以JSON或独立字段的方式存进订单表。这样即使之后用户改了地址,历史订单仍保留下单时的收货信息,保证履约的准确性。这个细节在论文里用一段话来强调“快照模式保证历史数据不可变”,效果远好于堆砌一堆功能列表。
3.3 外键索引怎么加才合理
另一个数据库设计上的实务点:索引不是乱加的。用户表要按 openid 建唯一索引,因为用户登录时需要用 openid 查用户;订单表要按 user_id 建普通索引,因为用户查自己的订单列表是最频繁的查询;订单明细表要按 order_id 建索引,因为查订单详情肯定会查明细。商品表要按 category_id 建索引,按分类查商品时用得上。
外键约束我建议在实体关系上保留,但在实际建表时可以不加物理外键,只保留逻辑关联。原因很简单:物理外键在插入、更新时会产生额外的约束检查,影响性能,而且后续如果要分库分表会很麻烦。面试或答辩时可以解释为“逻辑外键 + 应用层保证一致性”,这是很多互联网公司实际采用的做法。
4. 小程序前端实现:从登录到下单的完整闭环
4.1 登录授权流程:并不是直接弹窗“授权登录”
小程序登录是很多新手第一个卡住的地方。不少初学者以为登录就是写一个按钮,弹窗让用户授权昵称头像,然后这个用户就“登录”了。实际上,微信小程序的登录流程分为两层:静默登录 和 用户信息完善。
静默登录是用户打开小程序时就自动触发的:前端 wx.login 拿到临时凭证 code,传给后端,后端拿着 code 调微信接口 https://api.weixin.qq.com/sns/jscode2session,换取 openid 和 session_key。拿到 openid 后,后端查数据库,如果用户不存在就自动创建一条用户记录,然后签发一个自定义登录态(比如JWT令牌)返回给前端。前端把令牌存到 wx.setStorageSync('token', token) 里,后续所有需要身份的请求都在请求头里带上这个token。
这一步不需要用户做任何操作,用户甚至感知不到,但系统已经完成了身份识别。有了这层静默登录,用户的购物车、订单都从第一次打开小程序起就和他绑定了。
代码实现大概是这样的:
javascript复制// 前端发起登录
wx.login({
success: (res) => {
const code = res.code;
wx.request({
url: 'https://your-domain.com/api/auth/login',
method: 'POST',
data: { code },
success: (response) => {
const { token, userInfo } = response.data.data;
wx.setStorageSync('token', token);
// 更新全局用户信息
getApp().globalData.userInfo = userInfo;
}
});
}
});
对应的后端接口逻辑:
java复制@RestController
@RequestMapping("/api/auth")
public class AuthController {
@Autowired
private UserService userService;
@PostMapping("/login")
public Result login(@RequestBody LoginRequest request) {
String openid = wechatService.getOpenid(request.getCode());
User user = userService.findOrCreateByOpenid(openid);
String token = jwtUtils.generateToken(user.getId());
return Result.success(new LoginResponse(token, user));
}
}
findOrCreateByOpenid 这个方法的逻辑值得展开:先按 openid 查库,查到就直接返回;查不到就创建一个新用户,默认昵称为“微信用户”,头像用默认占位图,然后返回。这样用户第一次打开小程序就已经“注册”好了,体验非常顺滑。
至于用户想改头像昵称,那是在“个人中心”里主动操作的,可以调用 wx.getUserProfile 获取用户头像昵称后更新到后端。注意这里有个历史坑:早期可以直接调 wx.getUserInfo 弹窗授权,2021年后微信调整了策略,必须通过用户主动点击才能弹出授权框,所以现在统一的方案是“静默登录 + 引导完善资料”。
4.2 配置合法的服务器域名才能 wx.request
小程序有一个经常被忽略但极其致命的规定:wx.request 发起的网络请求,必须指向已经在微信公众平台配置过的合法域名。开发时可以在开发者工具里勾选“不校验合法域名”来跳过,但真机预览一关,请求就全部失败,提示 url not in domain list。
所以如果你自己买了云服务器,上线前一定要在微信公众平台(mp.weixin.qq.com)的“开发管理—开发设置—服务器域名”里,把 https://api.yougou.com 这类域名加进 request 合法域名列表。注意:必须是HTTPS协议,而且证书要有效,不能用IP地址(除非是开发阶段)。如果暂时没有备案域名,也可以用云开发的环境ID来请求,或者用内网穿透工具在真机调试时临时顶一阵子,但这些只能作为开发期方案,不能作为正式交付。
4.3 首页和商品列表:数据怎么来、交互怎么设计
首页是用户对小程序的第一印象,也是几乎每个毕设答辩时会被问到“为什么这样设计”的页面。首页至少包含三个区块:顶部搜索框、轮播图、商品分类导航、下方推荐商品流。
商品列表的数据加载,分页是必须考虑的。不要一次性把数据库里所有商品都查出来返回给前端,而是用分页参数:前端传 pageNum 和 pageSize,后端返回当前页数据和总条数。小程序端的实现方式是使用 onReachBottom 生命周期函数,滚动到底部时自动加载下一页。
javascript复制Page({
data: {
goodsList: [],
page: 1,
pageSize: 10,
hasMore: true
},
onReachBottom() {
if (!this.data.hasMore) return;
this.loadGoods(this.data.page + 1);
},
async loadGoods(page) {
const res = await request({
url: '/api/goods/list',
data: { page, pageSize: this.data.pageSize, categoryId: this.data.categoryId }
});
const newList = page === 1 ? res.list : this.data.goodsList.concat(res.list);
this.setData({
goodsList: newList,
page,
hasMore: res.list.length > 0
});
}
});
这里有一个我从开发中总结出来的细节:分页加载后新数据要和旧数据合并,而不是直接 setData 替换。否则每次滚动加载都会丢掉之前的内容。很多新手在这一步踩坑,页面滚动几次后只剩最后一页的数据,就是因为把列表整体赋值了。
商品详情页相对简单,核心是展示多图、价格、库存、详情富文本,底部有两个固定按钮:加入购物车、立即购买。加入购物车本质是向后端 cart 表插入或更新一条记录,立即购买则直接跳转到确认订单页,把商品参数通过URL传过去,而不是经过购物车中间层。
4.4 购物车:看似简单,其实要注意“选中状态”
购物车页面在电商里是个业务逻辑较重的模块,它不只是展示一个列表,还涉及复杂的联动计算。页面需要展示每个商品的数量、价格、选中状态,底部实时计算“已选商品总金额”。
购物车的数据结构在前端是一个数组,每个元素包含商品信息、数量、checked字段。核心交互有四个:
- 勾选/取消勾选单个商品:更新该商品的checked状态,并重新计算总金额。
- 全选/取消全选:遍历所有商品,批量更新checked状态。
- 修改数量:调用后端接口更新数据库中的quantity,同时重新计算单个商品小计和总金额。
- 删除商品:从购物车列表移除并调用后端接口删除记录。
这里有个细节:每次计算总金额时,前端只计算 checked === 1 的商品价格之和。进入确认订单页时,也要遍历后端传过来的购物车商品,过滤掉未选中的。如果你在开发中发现“结算金额和购物车显示的不一致”,八成是前端没过滤未选中项,或者后端接口把全部购物车商品都带上了。
4.5 确认订单页:把价格算清楚再下单
确认订单页常见的设计是:展示收货地址(可点击跳转到地址选择)、商品列表(不可编辑数量,只读)、金额明细(商品总价、运费、优惠金额、实付金额)。这里最容易被忽视的是金额计算的一致性。
前端展示的金额和后端计算出的金额必须一致。如果前端只是用购物车里的价格自行计算,而后端在下单时重新按数据库中的商品价格计算,就会有数据库价格和前端展示价格不一致的风险。解决办法是确认订单页的数据本身就从后端获取——前端把选中的购物车商品ID数组传给后端,后端根据当前数据库价格重新计算金额并返回,前端只负责任展示。
这么做还有一个好处:后端可以在确认订单时做一次库存预校验,如果某些商品库存不足,直接返回错误提示,前端就能拦截住用户不下单,避免提交订单时才发现缺货的尴尬。
4.6 提交订单:后端事务保证数据一致
提交订单是整套系统里技术含量最高的一个接口,因为涉及多张表的写入和库存扣减。后端在同一个事务里依次执行以下操作:
- 根据请求中的地址ID,查询地址并生成地址快照。
- 遍历商品列表,计算订单总价。
- 扣减商品库存:
UPDATE product SET stock = stock - #{num} WHERE id = #{id} AND stock >= #{num}。 - 插入订单主表记录,状态为“待支付”。
- 插入订单明细表记录。
- 清空购物车中对应的已下单商品。
为什么必须在事务里?因为如果在扣减库存之后、插入订单记录之前程序崩溃了,库存就白白减少了,用户却没有订单,账就对不上。用 @Transactional 注解包住整个方法,任何一个步骤失败,所有操作回滚,数据回到初始状态。
库存扣减的SQL写成 stock >= num 这个条件也很关键,它利用了数据库行锁的特性保证并发安全。两个用户同时下单同一件商品,数据库串行执行更新语句,第二个用户就可能因为 stock < num 而更新失败,然后抛出异常,事务回滚,就不会出现“超卖”问题。这个点在论文里写清楚,绝对是技术加分项。
4.7 微信支付:不是只能听听,毕设也可以接入
很多毕设项目对支付模块避而不谈,只做“模拟支付”——点击按钮直接把订单状态改成已支付。如果时间充裕,我强烈建议你接入微信支付的真实沙箱或真实支付流程,哪怕只跑通一次。因为支付是电商系统里最核心的一环,能跑通真实支付,整个项目的含金量立刻不一样。
微信支付的完整流程是这样的:
- 前端用户点击“去支付”,调用后端接口
/api/order/pay,传入订单号。 - 后端生成一个微信支付订单号(prepay_id),调用微信支付统一下单API,请求参数包括
appid、mch_id、out_trade_no(你系统的订单号)、total_fee(金额,单位是分)、notify_url(支付结果回调地址)。 - 微信支付返回预支付交易会话标识
prepay_id。 - 后端把这个参数以及签名信息返回给前端。
- 前端调用
wx.requestPayment,弹出微信支付界面。 - 用户输入密码完成支付,微信服务器异步向
notify_url发送支付结果通知。 - 后端收到通知后验签,确认支付成功后,把订单状态从“待支付”改成“待发货”,返回处理结果给微信。
需要注意的坑有两个。第一,total_fee 单位是“分”,如果你在后端用 BigDecimal 计算金额,要在传给微信之前转换成int类型的分数,不然差一位小数点就是十倍的价格,测试时直接扣错钱。第二,notify_url 必须是公网可访问的HTTPS地址,本机 localhost 是收不到回调的。开发时可以用内网穿透工具把本机端口映射到公网,微信服务器才能回调到你的接口。
有一点要说明清楚:个人主体的微信小程序,微信支付接口默认是不开放的,必须是企业主体(个体工商户也可以)才能申请。毕设阶段如果实在没有商户号,也可以做一个“模拟支付”版本,在论文中明确说明“由于毕业设计使用个人主体账号,支付环节以模拟支付替代,接口设计已预留真实支付扩展”。这个替代方案完全可以接受,重点是你在代码中预留了支付接口的抽象层。
4.8 订阅消息:订单状态变更主动触达用户
订阅消息是微信小程序特有的消息触达能力,电商系统里典型场景是:用户下单并支付后,商家发货时向用户推送一条“订单发货通知”。
但这里有一个“坑”很容易劝退新手:一次性订阅消息只能在下单时请求一次用户授权,而且授权只对下一次消息有效。也就是说,你必须在用户下单时引导他“订阅发货通知”,他点了同意,商家发货时才有资格发一条消息。如果双方在下单后再请求授权,即使同意了,当次也发不出消息,因为授权必须先于发送存在。
所以常见的做法是:在确认订单页或支付成功页放一个“订阅消息”按钮(或弹窗),调用 wx.requestSubscribeMessage 请求订阅权限,把返回的 accept 状态传给后端。后端存下这个订阅状态,发货时调用微信订阅消息的API发送模板消息。
技术实现本身不复杂,比较麻烦的是模板管理——你需要在微信公众平台申请订阅消息模板,拿到模板ID,然后按模板要求填参。不过如果这里卡住了,也可以简化成“不接入订阅消息”,因为核心业务闭环已经通过订单状态展示完成了,订阅消息属于锦上添花。
5. 管理后台:如何把“管理”二字坐实
5.1 管理后台技术选型:Vue + Element Plus + Spring Boot
“管理系统”四个字如果只体现在小程序端,答辩时很容易被老师挑战:“你这个管理体现在哪?”所以管理后台不是可选项,而是必选项。它负责管理商品、订单、用户,并提供数据统计图表。
管理后台的前端我建议用 Vue 3 + Element Plus + Vite,这部分不用花太多心思,照搬成熟的管理后台模板就行(比如vue-element-admin)。它和小程序端复用同一个后端,只是接口前缀不同,权限控制也不同。
管理后台的页面至少包括:登录页(账号密码登录)、仪表盘(销售统计图表)、商品管理(列表、新增/编辑表单、上架下架)、分类管理、订单管理(列表、详情、发货操作)、用户管理(查看用户列表、禁用用户)、轮播图管理。
5.2 权限控制:JWT + 拦截器,区分用户端和管理端
如果小程序端的登录是 openid 自动注册,那么管理端的登录应该是账号密码。这个账号体系可以单独建一张管理员表(admin_user),不在用户表里混。管理员登录成功后同样签发JWT,但需要在JWT中声明角色类型是 “admin”。
后端通过拦截器(HandlerInterceptor)按路径前缀区分权限校验方式:
java复制// WebMvcConfig中注册拦截器
registry.addInterceptor(adminAuthInterceptor)
.addPathPatterns("/admin/**")
.excludePathPatterns("/admin/login");
registry.addInterceptor(userAuthInterceptor)
.addPathPatterns("/api/**")
.excludePathPatterns("/api/auth/login", "/api/goods/**", "/api/banner/**");
管理员拦截器校验请求头中JWT的角色是否为admin,用户端拦截器只校验token是否有效。这种设计在答辩时非常好讲:你实现了“按角色颗粒度划分接口权限”的通用方案。
5.3 订单发货与售后处理流程
管理后台最重要的业务操作就是“订单发货”。流程是:运营人员在订单列表里看到“待发货”状态的订单,点击“发货”,填写物流公司和运单号,提交后后端把订单状态更新为“待收货”,并记录 ship_time。如果对接了订阅消息,同时触发订阅消息推送。
售后退款的处理稍微复杂一些。用户在小程序端申请退款,订单状态进入“售后中”,管理后台的售后列表会显示申请记录,管理员可以选择同意或拒绝。同意退款后,后端需要调用微信支付“退款API”,把订单金额原路退回。这个接口在真实环境中需要微信商户平台证书和密钥,毕设阶段同样可以用“模拟退款”代替,在后端只更新退款状态。
6. 部署上线、论文写作与答辩准备
6.1 服务器部署:从零到可以真机访问的完整流程
毕设系统做完以后,总要部署到服务器上给老师演示或让同学体验。如果你买的是一台Linux云服务器(学生机认准轻量应用服务器,一年才几杯奶茶钱),部署步骤基本是固定的:
- 安装JDK 8+ 和 Maven。
- 安装MySQL,创建数据库,导入初始化SQL脚本。
- 用Maven打包Spring Boot项目:
mvn clean package -DskipTests,生成可执行jar包。 - 用
nohup java -jar yougou.jar > app.log 2>&1 &启动后端服务。 - 部署前端管理后台:本地执行
npm run build,把 dist 目录下的静态文件上传到 Nginx 的静态资源目录。 - 部署小程序:小程序前端不需要自己部署,直接在微信开发者工具中上传代码,然后在微信公众平台提交审核发布。开发期间可以用“预览”功能在真机上测试。
如果不想自己买服务器,也可以在后端接口测试阶段直接用内网穿透工具(如cpolar、natapp)把本机映射到公网,让小程序真机可以访问到你的后端接口。这个方法适合开发调试,但正式演示前还是建议部署到云服务器,万一电脑休眠或断网,演示就翻车了。
6.2 论文结构:从开题到答辩的时间线安排
每年都有不少学生因为论文进度焦虑到失眠,其实论文和代码是同步推进的,不是最后一个月才动笔。我把整个毕设周期按周拆开,按这个节奏走,基本不会出现手忙脚乱的情况:
- 第1-2周:需求分析,确定功能列表,画用例图、流程图。写开题报告。
- 第3-4周:数据库设计,完成表结构。开始搭后端框架。
- 第5-6周:后端核心接口(商品、登录、购物车、订单)。前端小程序同步开发。
- 第7-8周:管理后台开发,联调前后端。
- 第9-10周:部署测试,修复bug,补充数据统计图表。
- 第11-12周:写论文初稿,重点是系统设计和核心实现章节。
- 第13-14周:论文修改、查重、准备答辩PPT。
论文的正文结构可以参考:
- 第一章 绪论:研究背景、国内外研究现状、研究目标与意义。
- 第二章 相关技术介绍:微信小程序开发框架、Spring Boot、MyBatis Plus、MySQL。每项技术写清楚你用在哪个模块。
- 第三章 系统分析:需求分析、可行性分析、功能需求、非功能需求。
- 第四章 系统设计:总体架构设计、功能模块设计、数据库设计。
- 第五章 系统实现:每个核心模块的核心代码和截图,重点写坑和解决方案。
- 第六章 系统测试:功能测试用例、性能测试结果。
- 第七章 总结与展望。
每一章写3000字左右,整篇论文控制在1.5万字左右就很稳了。注意重点是第四章和第五章,占整篇论文一半以上的篇幅,因为这是老师最喜欢翻的部分。
6.3 答辩展示的3个加分演示路径
答辩现场看的是逻辑和表达。我个人建议你在演示环节按以下三条路径走,最能体现系统完整性:
首先从“用户视角”演示:打开小程序 → 自动登录 → 首页浏览 → 搜索商品 → 查看详情 → 加入购物车 → 提交订单 → 模拟支付 → 在“我的订单”里看到订单状态变化。这个过程展示了完整的用户操作闭环。
然后切到“管理视角”演示:打开管理后台 → 登录 → 看到仪表盘统计数据 → 查看用户刚下的订单 → 点击发货 → 回小程序刷新订单状态,发现已经变为“待收货”。这一步直接把用户端和管理端的数据联动展示出来,是答辩最出彩的时刻。
最后展示“代码与技术细节”:用IDE打开后端项目的核心Service类,找到 createOrder 方法,展示 @Transactional 注解和事务操作,同时打开数据库,查到刚才生成的订单记录和扣减后的库存。如果时间允许,还可以展示一下异常处理逻辑,比如故意把库存改成0,再走一次下单流程,看看系统是否会正确提示“库存不足”。这种“故意出错”的演示比单纯展示正常流程更能证明你没有死记硬背。
6.4 代码仓库与源码组织建议
最后给一个很实际的建议:所有代码(小程序端、后端、管理后台、数据库SQL脚本)整理到同一个Git仓库里,根目录放一份README,写上系统简介、目录结构、部署步骤、测试账号。这样做的好处有三个:方便自己在不同电脑上同步;方便写论文时引用代码路径;如果后续要投简历,可以直接以项目仓库的形式展示给面试官。
README的格式大概是这样:
code复制# 优购电商管理系统
## 项目简介
基于微信小程序 + Spring Boot 的电商管理系统,包含用户端小程序和管理端Web后台。
## 技术栈
- 前端:微信小程序原生框架
- 后台:Spring Boot + MyBatis Plus + MySQL
- 管理端:Vue 3 + Element Plus
## 目录结构
...
## 部署步骤
...
## 测试账号
- 管理端 admin / admin123
这段经历在面试讲到“项目亮点”时,可以非常有条理地说清楚。比如“用事务保证订单和库存的一致性”“用JWT实现用户端和管理端的权限隔离”“订单地址采用快照模式保证历史数据不可变”,每个亮点背后都有一行代码和一个场景支撑。
我在带学生做这类项目时反复说过一句话:电商系统看起来遍地都是,但能把它讲明白,本身就是一份不错的能力证明。优购电商管理系统不是让你去颠覆什么,而是让你在一个真实业务场景里,把需求分析、数据库设计、前后端联调、部署测试这一整条链路完整走一遍。走完这一遍,你不会再怕类似的项目,也更清楚自己适合做前端还是后端。选题确定了,就走下去,代码不一定多完美,但每一步都要能讲出为什么。
