这次我们来看一个典型的全栈商城项目:基于SpringBoot + Vue3 + 微信小程序的健身器材交易平台。项目分为三端:用户看到的微信小程序端负责商品浏览、购物车、下单支付;运营人员使用的 Vue3 管理后台负责商品管理、订单处理和批量上架;后端统一由 SpringBoot 提供 RESTful API,数据库走 MySQL。标题里出现的“SpringBoot4”多数情况下是项目模板命名习惯,实际技术栈仍然以 Spring Boot 为准,编写代码时先确认pom.xml里的官方版本基线。
这个项目最值得关注的不是健身器材这个垂直领域本身,而是它的电商闭环足够完整:从微信登录、商品分页、购物车、生成订单、支付回调,到后台发货和状态流转,几乎覆盖了“小程序电商系统”的所有核心节点。如果你正在做课程设计、毕业设计,或者需要一套前端后台都能用的商城脚手架,这个项目可以作为直接改造的起点。
本文会按照“核心能力梳理 -> 使用边界与合规提醒 -> 系统架构与数据库设计 -> 本地环境部署 -> 后端接口实现 -> Vue3 管理后台开发 -> 小程序端对接 -> 接口联调与排错 -> 运维最佳实践”的顺序展开。这篇文章适合已经掌握 Java、Vue 基础,想完整跑通一个多端电商项目的人;也适合只差一个能演示的实训项目、需要快速评估技术方案的人。
1. 核心能力速览
| 能力项 | 说明 |
|---|---|
| 项目类型 | 健身器材电商交易系统,包含用户小程序、管理后台、后端接口三层 |
| 后端框架 | SpringBoot,主流版本为 2.7.x 或 3.x,具体看课程项目基线 |
| 前端框架 | Vue3 + Vite + Element Plus 管理后台 |
| 用户端 | 微信小程序原生开发,也可迁移到 uni-app |
| 数据库 | MySQL 8.x,订单模块可扩展 Redis 缓存 |
| 核心功能 | 用户登录、商品分类、商品详情、购物车、订单结算、支付回调、后台发货 |
| 后台功能 | 商品 CRUD、批量上下架、订单管理、库存管理、用户管理 |
| 接口形式 | RESTful JSON,Token 或 JWT 鉴权 |
| 权限模型 | 普通用户、管理员/商家两种核心角色,课程项目可精简为一种管理员 |
| 典型场景 | 课程设计、毕业设计、小型器材商户私域商城二次开发 |
从材料看,该项目更偏向“完整电商功能演示 + 多端代码组织”,而不是只做静态页面。验证项目是否合格,重点看三件事:订单状态机是否完整、商品管理能否支撑批量操作、移动端接口是否能在微信开发者工具里直接跑通。
2. 适用场景与使用边界
2.1 适合谁用
如果你是需要完成 SpringBoot 全栈项目的在校学生,这类项目最大的价值就是结构清晰:前端调用 API、后端处理业务、数据库落表,每一层都能在答辩时讲明白。如果你是一个小型健身器材商户,想在微信生态里做私域售卖,也可以基于这套代码进行二次开发,替换品牌、价格、分类即可。
2.2 能解决什么问题
健身器材交易与普通服装电商不同,商品重量大、物流费用高、售后服务周期长,因此系统里一般会重点关注商品规格、库存扣减、订单状态和物流发货。一个可用的系统至少包含:商品列表搜索、商品详情展示、加入购物车、选择数量与规格、提交订单、支付回调、后台订单处理。
2.3 使用边界和合规提醒
这里必须提醒几件事。第一,微信小程序上线和微信支付都要求企业主体,个人开发者无法直接使用微信支付原生能力,课程项目通常用模拟支付或沙箱环境演示,接入真实支付需要商户号和产品资质。第二,小程序图片、品牌 Logo、代言人肖像等素材需要获得授权,不能直接抓取商业网站的素材用于演示发布。第三,商品数据可能涉及商标,上架前要进行版权核对。第四,系统应遵循最小化采集,用户手机号、地址属于敏感信息,不要写入日志,接口返回时也要做脱敏处理。
3. 系统架构与功能模块拆解
3.1 整体分层
后端采用经典三层架构:
| 层级 | 模块/作用 |
|---|---|
| Controller 层 | 接收请求,参数校验,统一返回 Result |
| Service 层 | 业务逻辑:订单状态机、库存扣减、支付回调处理 |
| Mapper/Repository 层 | 数据库 CRUD |
| 前端小程序 | 首页、分类、购物车、结算、订单、我的 |
| Vue3 管理后台 | 登录、商品管理、订单管理、数据概览 |
实际开发时建议把跨端公共逻辑放到后端,例如商品状态判断、价格计算、库存校验都只做一次,避免小程序端和管理后台逻辑不一致。
3.2 核心数据表设计
电商系统最少需要以下核心表。字段取名可以根据 MyBatis-Plus 或 JPA 的习惯调整,但逻辑上要完整:
user 用户表 product_category 商品分类表 product 健身器材商品表 product_sku 商品规格表,比如颜色、重量 cart_item 购物车表 order_info 订单主表 order_item 订单明细表 payment_record 支付流水表商品表建议字段:id, category_id, title, cover_image, image_list, price, original_price, stock, sales, status, detail, create_time, update_time。订单表建议字段:id, order_no, user_id, total_amount, pay_amount, status, receiver_name, receiver_phone, receiver_address, pay_time, delivery_time, finish_time。
3.3 订单状态设计
课程项目最容易出问题的是订单状态不清晰。建议统一用枚举或固定字符串维护状态,不要把“待付款”“已付款”这类展示文字直接存库:
CREATED:已创建,待支付 PAID:已支付,待发货 DELIVERED:已发货,待收货 FINISHED:已完成 CLOSED:已取消/超时关闭 REFUNDING:退款中后端做状态流转时,核心代码应该使用状态校验。比如订单状态从“待付款”变为“已付款”时,不允许从“已发货”状态直接改为“已完成”,这部分可以用简单的 switch 判断,也可以引入状态机框架,但课程项目没有必要过度设计。
4. 本地部署环境准备与工程启动
4.1 环境清单
部署前先确认环境。下面的版本是通用参考,具体以项目pom.xml和package.json里的锁定版本为准:
| 工具 | 建议版本 |
|---|---|
| JDK | 8 / 11 / 17,取决于 SpringBoot 大版本 |
| Maven | 3.6+ |
| MySQL | 5.7 / 8.0 |
| Node.js | 16 或 18 |
| IDE | IntelliJ IDEA + VS Code |
| 微信开发者工具 | 最新稳定版 |
如果项目使用 Spring Boot 3.x,JDK 必须是 17 以上,并且代码中的javax.*要换成jakarta.*。如果项目还在用 Spring Boot 2.7,JDK 8/11 即可。不要盲目升级 JDK,避免依赖不兼容。
4.2 初始化数据库
先创建数据库并导入 SQL 初始化脚本:
CREATE DATABASE IF NOT EXISTS fitness_mall DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;执行完建表 SQL 后,再确认数据库账号、密码和项目配置一致。
4.3 后端配置示例
使用 SpringBoot 时,核心配置集中在application.yml:
server: port: 8080 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/fitness_mall?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: your-password jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: Asia/Shanghai mybatis-plus: mapper-locations: classpath*:mapper/**/*.xml configuration: map-underscore-to-camel-case: true global-config: db-config: logic-delete-field: deleted logic-delete-value: 1 logic-not-delete-value: 0 jwt: secret: your-project-jwt-secret-key expire-minutes: 1440注意,真实项目中 MySQL 地址、账号密码、JWT Secret 不能直接提交到公开仓库。课程作业提交时可以保留默认配置,但商用项目建议放到环境变量或配置中心。
4.4 打包并启动
后端启动命令:
mvn clean package -DskipTests java -jar target/fitness-mall.jar如果项目没有安装 Maven 也可以使用 Maven Wrapper:
mvnw spring-boot:run管理后台启动命令:
npm install npm run dev微信小程序端用微信开发者工具导入miniapp目录,修改utils/config.js里的接口域名后直接编译预览。
5. SpringBoot 后端核心链路实现
5.1 统一返回结构与异常处理
接口返回建议使用统一格式,否则小程序、管理后台都要各自处理数据格式错误:
public class Result<T> { private Integer code; private String message; private T data; public static <T> Result<T> success(T data) { Result<T> result = new Result<>(); result.code = 200; result.message = "success"; result.data = data; return result; } public static <T> Result<T> failed(String message) { Result<T> result = new Result<>(); result.code = 500; result.message = message; return result; } }建议在 Controller 里不要直接返回实体类,而是返回Result<T>。这样接口返回报文稳定,前端可以统一拦截错误状态。
5.2 微信登录与 Token 签发
小程序获取用户身份的标准流程是:小程序端调用wx.login拿到临时code,再将code发送给后端,后端调用微信接口换取openid。课程项目如果不想每次请求都访问微信接口,可以只在登录时换取,然后签发自己的 JWT Token。后端接口大致如下:
@PostMapping("/api/auth/login") public Result<String> login(@RequestBody LoginRequest request) { // 1. 用 code 调用微信 jscode2session 接口,得到 openid // 2. 根据 openid 查找用户,不存在则创建 // 3. 生成 JWT Token,返回给小程序端 String token = userService.login(request.getCode()); return Result.success(token); }小程序端拿到 Token 后,需要把 Token 放到请求头的Authorization字段里。后端使用拦截器或 Spring Security 解析 Token,并将 userId 设置到请求上下文。
5.3 商品列表分页查询
商品接口需要支持关键字搜索、分类筛选、排序。代码如下:
@GetMapping("/api/products") public Result<PageResult<ProductVO>> pageProduct(@RequestParam(defaultValue = "1") int page, @RequestParam(defaultValue = "10") int size, @RequestParam(required = false) Long categoryId, @RequestParam(required = false) String keyword, @RequestParam(required = false) String sort) { Page<Product> productPage = productService.pageProduct(page, size, categoryId, keyword, sort); return Result.success(PageResult.of(productPage)); }数据库查询时重点关注:根据status=1只查上架商品;库存为 0 的商品不下发到小程序;图片字段返回相对路径,由前端拼接域名,减少数据流量。
5.4 购物车与库存预扣
加入购物车本身不扣库存,只是记录用户选择的商品和数量。真正的库存扣减放在下单时,而且要使用数据库乐观锁或唯一约束避免超卖。核心逻辑:先查商品当前库存,再使用UPDATE ... SET stock = stock - #{count} WHERE id = #{productId} AND stock >= #{count},用更新行数判断是否扣减成功。
5.5 订单创建与支付回调
创建订单的关键操作是:生成订单号、计算订单金额、扣减库存、清空对应购物车项。支付模块在商业项目里应走微信支付 V3,但课程演示可以先做一个“模拟支付”接口:
@PostMapping("/api/pay/mock") public Result<String> mockPay(@RequestBody MockPayRequest request) { // 1. 根据订单号查询订单 // 2. 校验订单未支付 // 3. 调用微信支付统一下单,或演示时直接进入回调逻辑 // 4. 更新订单状态为 PAID // 5. 记录支付流水 return Result.success("支付成功"); }在真实微信支付流程里,后端只负责生成 prepay 参数,小程序通过wx.requestPayment拉起收银台,微信服务器回调后端通知接口,后端再把订单状态改为已支付。这个回调接口必须校验签名,不能只凭订单号就改订单状态。
5.6 库存与订单状态一致性
课程项目常见的隐藏问题是:用户下单后不支付,库存却被扣掉。更合理的方案是:订单创建时不立即扣库存,而是“预占库存”,超时未支付后释放;在简化版本里,可以直接在用户提交订单支付成功后扣减库存。无论采用哪种方式,都要保证订单表和库存表的数据一致。建议为订单增加expire_time字段,任务调度定时扫描超时未支付订单并关闭。
6. Vue3 管理后台与批量运营操作
6.1 管理后台初始化
Vue3 环境建议使用 Vite 创建项目:
npm create vite@latest admin-web -- --template vue cd admin-web npm install npm install element-plus vue-router pinia axios npm run dev管理后台目录建议:
src ├── api │ ├── product.js │ └── order.js ├── router │ └── index.js ├── store │ └── user.js ├── views │ ├── Login.vue │ ├── Dashboard.vue │ ├── product/ProductList.vue │ └── order/OrderList.vue6.2 登录与路由权限
管理后台不是小程序端,不能使用微信登录,通常采用账号密码 + Token 方式。登录成功后在 Pinia 中保存用户信息和 Token。路由守卫判断没有 Token 时跳转登录页:
router.beforeEach((to, from, next) => { const token = localStorage.getItem('admin-token'); if (!token && to.path !== '/login') { next('/login'); } else { next(); } });如果角色不止一种,可以在路由 meta 上标记roles,再结合用户角色过滤路由。
6.3 商品列表页与上传
商品列表页是后台最高频操作。表格里最好展示商品图、标题、价格、库存、销量、上下架状态。常规页面结构是:搜索表单 + 批量操作按钮 + 表格 + 分页 + 新建/编辑弹窗。
批量操作接口可以设计为:
export function batchUpdateProductStatus(data) { return request({ url: '/api/admin/products/batch-status', method: 'put', data }); }请求体示例:
{ "ids": [1001, 1002, 1003], "status": 1 }这个接口能够一次上架或下架多个商品,后台调用时先校验权限,再逐条更新,并返回最终成功条数。对于几千条商品的批量改价、批量设库存,也建议使用类似结构,不要用循环前端请求单个接口。
6.4 图片上传与回显
健身器材图片不适合很小的压缩图,详情页通常会使用多图展示。管理后台保存商品图片时可以上传到本地服务器目录,也可以接入对象存储。上传接口返回图片 URL,前端再将该 URL 和其他商品字段一起提交。后端建议限制图片类型和大小,避免把可执行文件上传到服务器。
6.5 订单管理
订单管理页需要完成:订单查询、详情查看、发货。发货时填写物流公司和物流单号后,将订单状态改为DELIVERED。为了展示完整,还需要一个小型操作日志表记录“谁在什么时间改了什么状态”,这比把管理员操作过程硬编码在前端要可靠得多。
7. 微信小程序端接口对接与购物流程
7.1 请求封装
小程序端建议封装统一的request方法,每次请求自动携带 Token,遇到 401 时跳转登录页:
const BASE_URL = 'http://127.0.0.1:8080'; function request({ url, method = 'GET', data = {} }) { return new Promise((resolve, reject) => { wx.request({ url: BASE_URL + url, method, data, header: { 'Content-Type': 'application/json', 'Authorization': wx.getStorageSync('token') || '' }, success(res) { if (res.data.code === 200) { resolve(res.data.data); } else { wx.showToast({ title: res.data.message, icon: 'none' }); reject(res.data); } }, fail(err) { reject(err); } }); }); } module.exports = { request };这种封装能显著减少每个页面的重复代码。在小程序真机预览时,BASE_URL 不能写localhost或127.0.0.1,要改为局域网 IP 或线上域名,并且需要在微信公众平台配置域名白名单。
7.2 小程序登录流程
小程序首页加载前可以先检测本地 Token 是否存在,如果不存在就执行静默登录:
async function login() { const code = await new Promise((resolve, reject) => { wx.login({ success: (res) => resolve(res.code), fail: reject }); }); const token = await request({ url: '/api/auth/login', method: 'POST', data: { code } }); wx.setStorageSync('token', token); }7.3 首页与商品列表
首页由轮播图、分类导航、推荐商品列表组成。轮播图和分类数据来自后端接口,商品列表可以带“加载更多”或“上拉触底加载下一页”的逻辑。小程序使用scroll-view或页面自带的onReachBottom实现分页时,注意设置page和size参数,并把hasMore保存到 data 中。
7.4 购物车页面
购物车页面在本地操作体验更流畅,但提交订单时必须以服务端数据为准。本地购物车数据结构至少要保存skuId、商品 ID、数量、选中状态。用户点击结算时,把选中的商品列表传给后端,后端重新计算价格并返回订单确认信息。
7.5 下单与支付
下单按钮触发POST /api/orders,返回订单号。支付时进入模拟支付或微信支付,支付成功后跳转订单详情。整个流程涉及多个异步状态,建议用一个状态变量控制按钮,防止用户重复点击导致重复下单:
if (this.submitting) return; this.submitting = true; try { const order = await createOrder(this.selectedItems); await mockPay(order.orderNo); wx.redirectTo({ url: '/pages/order/detail?orderNo=' + order.orderNo }); } finally { this.submitting = false; }7.6 个人中心与订单列表
个人中心展示用户头像、昵称、待付款、待发货、待收货等入口。订单列表页面按照状态分类,用户可以取消待付款订单、确认收货。确认收货后再次提示用户,避免误操作。商家管理操作应该在管理后台完成,不在小程序端暴露。
8. 接口 API、联调与常见问题排查
8.1 核心接口规划
| 功能 | 请求方法 | 路径 | 权限 |
|---|---|---|---|
| 小程序登录 | POST | /api/auth/login | 公开 |
| 商品分页 | GET | /api/products | 公开 |
| 商品详情 | GET | /api/products/{id} | 公开 |
| 加入购物车 | POST | /api/cart/items | 用户 |
| 查看购物车 | GET | /api/cart/items | 用户 |
| 创建订单 | POST | /api/orders | 用户 |
| 模拟支付 | POST | /api/pay/mock | 用户 |
| 我的订单 | GET | /api/orders/mine | 用户 |
| 确认收货 | PUT | /api/orders/{orderNo}/confirm | 用户 |
| 后台商品列表 | GET | /api/admin/products | 管理员 |
| 后台批量上下架 | PUT | /api/admin/products/batch-status | 管理员 |
| 后台发货 | PUT | /api/admin/orders/{orderNo}/delivery | 管理员 |
调用方式统一为 JSON,时间字段统一为字符串格式。小程序端和 Vue3 管理后台都读取同一个后端接口,可以避免同一业务逻辑重复实现。
8.2 curl 调试示例
后端启动后,先用 curl 验证接口是否正常:
curl -X GET "http://127.0.0.1:8080/api/products?page=1&size=10" \ -H "Content-Type: application/json"如果返回:
{ "code": 200, "message": "success", "data": { "records": [], "total": 0 } }说明商品列表接口链路正常,接下来再排查数据填充问题。
8.3 常见问题与排查方法
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 后端无法启动 | 端口被占用或数据库连接失败 | 查看控制台日志,检查 8080 端口 | 换端口或修改 application.yml |
| 小程序接口 404 | BASE_URL 配错或者路径不一致 | 打开开发者工具 Network 面板 | 对照后端 RequestMapping 修正路径 |
| 小程序连不上本地后端 | 真机无法访问 localhost | 改用电脑局域网 IP 或用云服务器调试 | 在 config.js 修改接口域名 |
| 接口返回“请先登录” | 未传 Token 或 Token 过期 | 查看请求头是否带 Authorization | 重新登录刷新 Token |
| 新增商品后小程序看不到 | 商品状态不是上架状态 | 查询数据库 status 字段 | 后台改为上架状态 |
| 订单支付后状态未改变 | 支付回调未触发或签名校验失败 | 查看后端支付日志和回调请求 | 检查回调路径和签名算法 |
| Vue3 请求跨域 | 后端没有放开 CORS | 观察浏览器控制台 CORS 报错 | 后端配置跨域过滤器 |
| 页面白屏 | JS 报错或依赖缺失 | 打开浏览器控制台 | 根据报错重新安装依赖 |
| 商品图片不显示 | 图片路径错误或静态资源被拦截 | 直接访问图片 URL | 配置静态资源映射路径 |
| 批量操作只成功一部分 | 中间某条数据异常 | 查看批量接口返回明细 | 增加事务,失败时整体回滚 |
8.4 前后端联调流程
推荐顺序:先调登录接口,再调商品接口,再调购物车,最后调订单和支付。每一步都要以数据库实际变化为准,不要只看前端页面是否“看起来成功”。例如创建订单后,应该去数据库order_info和order_item表核对金额、用户、商品明细;支付接口调用后,要核对订单状态是否从CREATED变成PAID。
因为本项目没有内置音视频、大模型等复杂推理场景,对 CPU 和显存没有特殊要求。部署时关注的是 JVM 内存、MySQL 连接数和前端静态资源的带宽,而不是显卡资源消耗。本地开发电脑 8GB 内存即可正常跑后端和数据库,16GB 会更宽松。
9. 性能观察、最佳实践与后续扩展
9.1 本地资源占用观察
后端启动后,可以通过以下命令检查 Java 服务的资源占用:
jps -l jstat -gc <pid> 1000如果出现内存溢出,通常是查询返回数据量过大或 JVM 堆设置过小。可以在启动命令中显式指定内存:
java -Xms512m -Xmx1024m -jar target/fitness-mall.jar9.2 代码与工程最佳实践
项目二次开发时,建议先做一次全面检查:
- 数据库密码、JWT Secret 不要使用默认值。
application.yml中的配置可以拆成application-dev.yml和application-prod.yml两套。- 商品价格使用整数分存储,避免浮点数造成金额误差。
- 删除商品使用逻辑删除,不要直接物理删除,否则历史订单明细会找不到商品快照。
- 小程序端和管理后台不要共用一套登录接口,后台必须限制访问来源并增加验证码。
- 接口层做参数校验,至少校验商品数量不能为负数、收货电话格式是否正确。
- 支付类操作要记录流水号,方便对账。
9.3 像“练手项目”一样验证一遍
任何类似商城项目拿到手,都建议按下面的检查清单验证一遍:
- 注册或登录是否能在数据库生成对应用户数据。
- 商品上下架状态是否能影响小程序端展示。
- 库存为 0 的商品是否还能被加入购物车。
- 下单时库存是否会被正确扣减。
- 订单支付后,后台“待发货”列表是否出现新订单。
- 管理后台发货后,小程序端订单状态是否变为“待收货”。
- 用户确认收货后,订单是否能正常结束。
- 取消订单后库存是否回补。
- 一个账号能否看到自己的订单,而看不到别人的订单。
- 未登录用户能否直接调用需要登录的接口。
如果这十条都能跑通,这套商城可以继续在此基础上扩展秒杀、优惠券、会员积分、物流查询等功能。
9.4 可扩展方向
当前项目核心是“健身器材电商”。如果希望它更像一个能实际运营的平台,可以从三个方向扩。第一,增加会员体系,比如按消费金额划分普通用户与 VIP 用户,VIP 用户享受不同折扣。第二,增加多商户入驻,健身器材厂商直接在自己的店铺后台上传商品,平台只做审核和订单分账,这会涉及更复杂的权限与结算设计。第三,增加运动内容板块,器材销售不是一次性交易,可以结合训练计划、使用教程视频等提升复购率,相当于把商城做成“器材销售 + 内容服务”结合体。
这次的健身器材交易小程序本身并不复杂,真正值得吸收的是“SpringBoot 后端怎么把商品、订单、支付状态管理好,Vue3 管理后台怎么做运营操作,小程序怎么跟后端完成一次电商闭环”这条完整链路。建议先跑通后端连接 MySQL,再打开 Vue3 管理后台造一批测试商品,最后在微信开发者工具里完成一次从浏览到支付的演示。最容易踩的坑集中在三处:数据库账号密码不匹配、小程序接口地址不是局域网 IP、订单状态没有实现闭环。搭建完这套项目后,直接把它当成自己后续写电商、写后台管理系统时的脚手架,会节省大量重复搭框架的时间。