ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

微信小程序商城系统搭建指南:从数据库设计到环境部署

微信小程序商城系统搭建指南:从数据库设计到环境部署 简介基于微信小程序与NetCore、layui技术构建的多店铺网上购物商城系统面向毕业设计选题、小程序电商开发学习者及需要快速搭建可运行商城的中小型项目团队。项目完整覆盖微信小程序端、管理后台、插件管理及WebApi接口层源码中可见订单处理、商品管理、用户与导出管理等核心业务模块便于理解多店铺商城的整体架构与实现思路。资源共1915个文件以C#后端代码798个cs、小程序页面wxml/wxss、JavaScript脚本、HTML视图及数据库文件为主压缩包约10.34MB文件类型覆盖前后端与配置目录结构清晰。包内提供MySQL数据库脚本、数据连接配置及插件配置示例并附带安装使用说明可辅助完成从环境配置到功能验证的全流程。已有3592人学习下载适合需要完整商城系统参考或作为毕业设计方案的开发者使用。1. 为什么这套商城源码让你卡在启动而不是卡在功能看到“基于微信小程序的在线网上购物商城系统”这个标题很多人的第一反应是代码都齐了导入就能跑。但我带过的毕设项目里真正把时间耗进去的从来不是写功能而是环境。数据库导不进、接口连不上、图片加载不出来查到最后问题全出在 MySQL 版本、小程序白名单和配置文件这几处。这套项目的架构其实不复杂小程序端负责展示和交互后端对着几张表做增删改查数据库把用户、商品、订单串起来。真正值钱的是那份安装使用说明背后的环境思维。下面我按自己平时的做法把从零跑通这套商城系统的完整路径讲一遍也把最容易让人翻车的几个坑点列清楚。适合正在做毕设选题、想快速搭出一个能演示的商城或者想拿这套代码改造成个人项目的同学。2. 拆解商城系统的三层结构先看数据库怎么设计2.1 小程序端、后端接口、MySQL 三层怎么配合常见做法就是前后端分离小程序原生框架负责页面后端用 Spring Boot 或者 Node.js 提供接口数据落在 MySQL。小程序端不是一个常规的 Web 应用它没有 cookie 这套东西登录状态靠自定义 token。后端只做一件事接收请求、校验参数、查库、返回 JSON。数据库则是整套系统的地基表没建好后面接口怎么写都不顺手。这套系统按照毕设标准最少要覆盖六个界面首页、分类、购物车、订单列表、个人中心、商品详情。后端接口大概十个左右登录、商品列表、商品详情、加入购物车、购物车列表、修改数量、结算下单、订单列表、取消订单、模拟支付。功能不多但足够把数据库设计、接口封装、状态机、事务这些点讲全。如果你把它当成商业项目缺少售后、物流、营销这些模块但作为毕设或课程设计结构是完整的。我先说为什么选 MySQL。毕设场景下MySQL 安装简单、资料多、Workbench 和命令行都能操作导出 .sql 文件给导师也方便。后端选 Spring Boot 是因为它自带连接池和事务管理不用自己造轮子。小程序端用原生 WXML/WXSS/JS不去碰 uniapp 那种跨端框架。毕设答辩时你把原生小程序的项目结构讲清楚比讲框架封装更有说服力。2.2 按“用户、商品、订单、购物车”四张核心表建库我一般会把表分成两类一类是基础数据表用户、商品、分类一类是流程数据表购物车、订单、订单明细。下面这套 SQL 是一个可运行的最小集关键字段我都做了注释。-- 用户表存储微信用户与本地用户信息 CREATE TABLE t_user ( id int(11) NOT NULL AUTO_INCREMENT, openid varchar(64) NOT NULL COMMENT 微信openid唯一, nickname varchar(50) DEFAULT COMMENT 昵称, avatar varchar(255) DEFAULT COMMENT 头像url, phone varchar(20) DEFAULT COMMENT 手机号, create_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_openid (openid) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT用户表;-- 分类表商品分类sort_order 控制前端排序 CREATE TABLE t_category ( id int(11) NOT NULL AUTO_INCREMENT, name varchar(50) NOT NULL COMMENT 分类名, sort_order int(11) DEFAULT 0 COMMENT 排序权重, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT分类表;-- 商品表status 控制上下架price 用 decimal CREATE TABLE t_product ( id int(11) NOT NULL AUTO_INCREMENT, category_id int(11) NOT NULL COMMENT 所属分类, name varchar(100) NOT NULL COMMENT 商品名称, subtitle varchar(200) DEFAULT COMMENT 副标题, main_image varchar(255) DEFAULT COMMENT 主图路径, price decimal(10,2) NOT NULL COMMENT 单价保留两位小数, stock int(11) NOT NULL DEFAULT 0 COMMENT 库存, status tinyint(4) NOT NULL DEFAULT 1 COMMENT 1上架 0下架, create_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_category (category_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT商品表;-- 购物车表同一用户同一商品只保留一条记录 CREATE TABLE t_cart ( id int(11) NOT NULL AUTO_INCREMENT, user_id int(11) NOT NULL, product_id int(11) NOT NULL, quantity int(11) NOT NULL DEFAULT 1 COMMENT 数量, checked tinyint(1) NOT NULL DEFAULT 1 COMMENT 是否选中1选中 0未选, update_time datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_user_product (user_id,product_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT购物车表;-- 订单主表一笔订单对应多个商品明细 CREATE TABLE t_order ( id int(11) NOT NULL AUTO_INCREMENT, order_no varchar(32) NOT NULL COMMENT 订单编号业务上唯一, user_id int(11) NOT NULL, total_amount decimal(10,2) NOT NULL COMMENT 商品总额, pay_amount decimal(10,2) NOT NULL COMMENT 实付金额, status tinyint(4) NOT NULL DEFAULT 0 COMMENT 0待付款 1已付款 2已发货 3已完成 4已取消, receiver_name varchar(50) DEFAULT , receiver_phone varchar(20) DEFAULT , receiver_address varchar(255) DEFAULT , create_time datetime DEFAULT CURRENT_TIMESTAMP, pay_time datetime DEFAULT NULL, PRIMARY KEY (id), UNIQUE KEY uk_order_no (order_no) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT订单主表;-- 订单明细表商品价格必须做快照不能实时读商品表 CREATE TABLE t_order_item ( id int(11) NOT NULL AUTO_INCREMENT, order_id int(11) NOT NULL, product_id int(11) NOT NULL, product_name varchar(100) NOT NULL, product_image varchar(255) DEFAULT , price decimal(10,2) NOT NULL COMMENT 下单时的快照价格, quantity int(11) NOT NULL, PRIMARY KEY (id), KEY idx_order (order_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT订单明细表;为什么 t_order_item 里要冗余 product_name 和 price因为商品价格和名称会改订单明细必须保存下单那一刻的快照否则对账对不上。关于这个设计答辩时导师常会追问你把“快照”两个字说出来基本不会被问死。2.3 订单状态流转和字段细节这是答辩时的加分点status 我用了 tinyint 而不是 varchar因为枚举状态在程序里更好处理默认值 0 表示待付款。推荐状态机0 待付款 → 1 已付款 → 2 已发货 → 3 已完成任何状态下都可以有 4 已取消。取消的时机要单独说待付款时取消直接改状态已付款想取消就要走退款逻辑毕设里一般简化为直接改状态但你要能说清楚“这里实际项目中会对接退款接口”。字段类型有四个细节直接影响系统能不能稳定跑起来。第一价格用 decimal(10,2) 而不是 float 或 doublefloat 做精度计算会出问题比如 0.1 加 0.2 不等于 0.3。第二库存用 int下单时用乐观锁更新防止库存变负数具体 SQL 写在第 4 章。第三所有表默认 utf8mb4用 utf8 会在用户填 emoji 时直接写入失败。第四t_cart 里加唯一索引 uk_user_product这是很多人翻车的地方。如果不用唯一索引前端连点两次加入购物车会生成两条重复记录结算时商品数量永远对不上。3. 把源码跑起来数据库导入与项目安装使用说明3.1 需要准备的环境清单我按“最小可运行”的原则列一下这份清单组件推荐版本用途JDK8 或 11后端运行环境Maven3.6 以上后端依赖管理MySQL5.7 或 8.0数据库微信开发者工具稳定版即可小程序调试小程序 AppID注册后即可获得联调登录功能如果后端是 Node.js 版本对应装 Node 16 以上就行。不过毕设选择 Spring Boot 的更多后面的命令和配置我按 Spring Boot 讲。3.2 导入数据库与修改后端连接参数拿到 .sql 文件后用命令行导入。Windows 上要先确认 MySQL 的 bin 目录加了环境变量否则命令会提示“mysql 不是内部或外部命令”。注意在 cmd 里执行PowerShell 对重定向的支持不一致。mysql -uroot -p shop.sql导入完成后验证一下表是否齐全。mysql -uroot -p -e use shop; show tables;看到 t_user、t_category、t_product、t_cart、t_order、t_order_item 这六张表说明数据库导入成功。然后修改后端配置文件文件名是 application.yml 或 application.properties按项目说明改这三处就够。server: port: 8080 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/shop?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrue username: root password: 123456这里至少有三个坑。第一driver-class-name 在 MySQL 5.7 和 8.0 里不一样8.0 必须写 com.mysql.cj.jdbc.Driver写老的 com.mysql.jdbc.Driver 启动直接报错。第二连接串里的 characterEncodingutf8 是 JDBC 驱动的兼容写法你不用改成 utf8mb4表结构用 utf8mb4 就行。第三serverTimezone 不配的话日期字段会差 8 个小时导出来的订单时间全都不对。3.3 小程序端 AppID、合法域名与请求封装导入小程序项目到微信开发者工具先用测试号也能预览页面但登录功能要测 openid 就必须用自己的 AppID。在 project.config.json 里改{ appid: 你的小程序AppID, projectname: shop-mall, setting: { urlCheck: false } }本地调试阶段把 urlCheck 设为 false这样请求 http://localhost:8080 不会被拦截。这是开发阶段的做法上线前必须把这项关掉并在小程序后台配置 https 合法域名。接口请求我习惯统一封装新建一个 utils/request.js。下面这段是核心const BASE_URL http://localhost:8080/api function request(path, method GET, data {}) { return new Promise((resolve, reject) { wx.request({ url: BASE_URL path, method: method, data: data, header: { Content-Type: application/json, token: wx.getStorageSync(token) || }, success(res) { if (res.statusCode 200 res.data.code 0) { resolve(res.data.data) } else { wx.showToast({ title: res.data.msg || 请求失败, icon: none }) reject(res) } }, fail(err) { reject(err) } }) }) } module.exports { request, BASE_URL }逻辑说明把公共部分全部收敛到 request 函数里每个页面只需要传 path、method、data不需要自己拼 URL。token 从本地存储读取每次请求自动带上后端再统一做鉴权。这里和后端约定返回结构是 { code, msg, data }code 为 0 表示成功这样前端处理逻辑可以统一不用每个页面写重复的错误提示。4. 核心功能代码怎么对接登录、商品、购物车到下单4.1 微信登录换 openid本地 session 的完整链路小程序不能把用户的 openid 直接暴露给前端正确流程是前端 wx.login 拿临时 code传给后端后端拿 code 换 openid再生成 token 返回前端把 token 存缓存。后端 Controller 大致如下RestController RequestMapping(/api/user) public class UserController { PostMapping(/login) public Result login(RequestBody LoginRequest req) { // 1. 调用微信接口用 code 换取 openid String openid wxService.code2Session(req.getCode()); // 2. 查库没有则注册新用户 User user userMapper.findByOpenid(openid); if (user null) { user new User(); user.setOpenid(openid); user.setNickname(微信用户); userMapper.insert(user); } // 3. 生成 token 并保存后续请求靠 token 辨认身份 String token UUID.randomUUID().toString().replace(-, ); tokenService.save(user.getId(), token); return Result.success(token); } }逻辑说明code2Session 是后端调用微信接口不是前端直接调。token 用 UUID 生成存到一张 token 表或 Redis 里有效期一般设 7 天。每次请求经过拦截器校验 token查不到就返回 401前端收到 401 就跳回登录页重新 wx.login。4.2 商品列表和首页图片地址与缓存的细节商品列表接口是整套系统里最简单的但有两个细节容易出问题。第一个是图片地址开发阶段用相对路径比如 /upload/1.jpg小程序端再拼上后端地址。第二个是缓存2019 年后小程序对 request 并发有限制商品列表这种不常变的数据适合做本地缓存设置缓存过期时间。async function getProducts(categoryId) { const cacheKey products_ categoryId const cached wx.getStorageSync(cacheKey) if (cached Date.now() - cached.time 5 * 60 * 1000) { return cached.data } const data await request(/product/list?categoryId categoryId) wx.setStorageSync(cacheKey, { time: Date.now(), data: data }) return data }逻辑说明缓存时间设 5 分钟避免每次进首页都打后端。换分类时 categoryId 不同缓存 key 不同不会串数据。也可以把缓存时间做成参数不同接口自己控制比如轮播图缓存 10 分钟购物车列表不缓存。4.3 购物车到订单事务与乐观锁购物车选中商品后点“去结算”后端要做三件事生成订单主表、生成订单明细、扣库存。中间任何一步失败整个操作必须回滚。用 Transactional 注解最省事。Transactional(rollbackFor Exception.class) public Long createOrder(OrderCreateDTO dto) { // 1. 生成订单主表状态为待付款 Order order new Order(); order.setOrderNo(generateOrderNo()); order.setUserId(dto.getUserId()); order.setStatus(0); order.setPayAmount(calculateAmount(dto.getItems())); orderMapper.insert(order); // 2. 插入订单明细价格取商品快照 for (ItemDTO item : dto.getItems()) { orderItemMapper.insert(buildItem(order.getId(), item)); } // 3. 乐观锁扣库存只有库存充足才更新成功 int rows productMapper.deductStock(item.getProductId(), item.getQuantity()); if (rows 0) { throw new RuntimeException(item.getProductName() 库存不足); } return order.getId(); }注意最后一步的 deductStock对应 SQL 是:UPDATE t_product SET stock stock - #{quantity} WHERE id #{productId} AND stock #{quantity}这段 SQL 是防止超卖的关键。先查库存再减库存的写法在并发下必翻车两条请求同时查到库存是 1然后都执行减 1库存就变 -1 了。用 UPDATE 语句里带 stock quantity 条件数据库行锁会保证只有一条更新成功影响行数为 0 就说明库存不足。5. 本地部署避坑记录这五个问题占了八成交付事故5.1 请求一直 fail没有配置合法域名现象模拟器里页面能打开但所有 wx.request 都报 fail控制台提示 url not in domain list。原因小程序正式环境只允许请求配置过的 https 域名http://localhost 不在白名单里。解决开发阶段在微信开发者工具右上角“详情→本地设置”勾选“不校验合法域名”。上线前必须在小程序后台配置服务器域名而且必须是备案过的 https 域名。我见过有人把 urlCheck 关掉后直接打包上传体验版结果测试同学手机上一片空白就是这个原因。5.2 数据库连接报错Public Key Retrieval is not allowed现象后端启动时报错提示 Public Key Retrieval is not allowed。原因MySQL 8.0 默认使用 caching_sha2_password 认证JDBC 客户端默认不允许获取公钥。解决在 JDBC URL 末尾加 allowPublicKeyRetrievaltrue。如果不想改连接串也可以把用户改成 mysql_native_password 认证方式部署从简的话直接改连接串更快。注意这个参数只影响连接建立不影响数据安全。5.3 中文和 emoji 写不进库现象用户昵称带表情时插入报错提示 Incorrect string value: \xF0\x9F\x98\x80。原因表或字段是 utf8 编码。utf8 最多存 3 字节emoji 占 4 字节直接写入失败。解决建表用 utf8mb4同时注意整库、表和连接的字符集保持一致。已经建好的表执行 ALTER TABLE t_user CONVERT TO CHARACTER SET utf8mb4。这里有个容易漏的点如果只改表不改连接参数写入时还是会报错连接 URL 里 characterEncodingutf8 是驱动兼容写法不用改成 utf8mb4。提示在答辩现场演示导入数据时临时改字符集非常被动建表 SQL 一开始就统一写成 utf8mb4。5.4 订单重复提交库存变成负数现象快速点两次提交订单生成了两笔订单库存出现负数。原因前端没有做按钮防抖后端扣库存也只判断了查询出来的库存大于 0不是原子操作。解决前端在提交按钮上做 loading 状态禁止重复点击。后端扣库存改成 UPDATE ... WHERE stock quantity 这种乐观锁写法。另外给 t_order 的 order_no 加唯一索引即使前端并发请求也只能生成一笔订单。5.5 模拟支付跑不通现象点击微信支付没反应后端报 mch_id 不存在。原因真实微信支付需要商户号个人主体小程序没有资格申请。解决毕设方案常见的做法是模拟支付。点击支付按钮直接把订单状态改成已付款同时记录支付时间。答辩时主动说明这里是模拟支付实际项目会对接微信支付统一下单接口该接口需要商户号和 API 密钥。千万不要为了过演示硬接真实支付流程走不通不说还容易泄露密钥。6. 上线前和答辩前的验证技巧我每一套毕设项目交付前都会做一轮“从零还原”测试删掉本地数据库重新执行一遍安装使用说明确认每一步都能复现。因为答辩现场用的机器环境和你开发机不一样能复现才叫交付完成。第一一定要用真机扫码预览不要只在模拟器里演示。模拟器底部导航栏高度、iPhone 安全区、网络请求行为都和真机不同。特别是顶部导航栏不同机型胶囊按钮位置不一样可以用 wx.getMenuButtonBoundingClientRect 动态计算页面顶部占位高度。第二给后端加一个健康检查接口启动后先访问 /api/health 确认服务活着再打开小程序页面能省很多排查时间。第三提交代码前把日志级别调到 debug现场出问题能最快定位答辩完再改回 info。第四把模拟支付那段逻辑讲清楚这是导师最关心的“真实性和简化点”主动说比被问到好。这套系统做得值不值我自己的判断标准很简单建表时顺手把订单明细快照和库存扣减做成规范写法就已经超过大多数毕设了。很多人跑不起来不是代码不行是懒得看安装使用说明连 MySQL 版本都没核对。别做那种人。希望帮到你。本文还有配套的精品资源点击获取
返回列表