
简介这是一套基于微信小程序开发的鲜花销售系统完整毕业设计源码包适用于课程设计、毕业设计以及小程序实战进阶。项目包含用户端小程序与后台管理端覆盖商品展示、购物车、订单、会员管理等典型业务模块界面简洁、交互流畅前端代码注释详细零基础开发者也能按图索骥。资源共1341个文件压缩包仅13.86MB其中png图片与svg图标构成前端视觉资源js/wxml/wxss支撑小程序逻辑与页面vue/java组成后台管理及服务端sql为数据库初始化脚本另附bat一键部署脚本、properties/yml配置及详细部署文档目录结构清晰便于按层逐块学习。服务端基于SpringBoot/SSM数据库建议使用MySQL 5.7配合Navicat导入整个项目已经严格调试按文档操作即可完整跑通。已有239人学习下载适合需要完整可运行项目借鉴方案或希望快速完成课设交付的开发者。1. 微信小程序鲜花销售源码先看清包里的四块内容再动手拿到这套“微信小程序鲜花销售”的毕设源码包第一反应别是直接拖进微信开发者工具。包里面不是单个前端工程而是“小程序前端页面 后端接口源码 数据库脚本 部署教程文档”四件套。我拆过好几个类似课设九成翻车都发生在只跑了页面、数据库没导入或者接口路径对不上。这套资源适合拿来做毕业设计、课程设计也适合想完整走一遍小程序电商数据流的人。先把骨架看清楚再谈怎么改否则后面每个功能都像黑匣子。2. 数据库设计与后端接口先看懂表结构再谈跑通2.1 核心数据表用户、分类、商品、订单、明细、购物车怎么串鲜花销售小程序本质上是一个精简版电商数据库设计可以按照经典电商模型来拆。千万不要把所有数据塞进一张表里比如把订单里的商品名、价格直接存进 order 表这会给后续“订单明细查询”“修改商品价格不影响历史订单”带来很多麻烦。正确做法是把主数据拆开用外键关联我一般会先建这六张核心表表名关键字段作用userid, openid, phone, nickname用户唯一标识openid 从小程序登录拿到categoryid, name, sort鲜花分类如玫瑰、百合、康乃馨后台排序用 sortproductid, category_id, name, cover, price, original_price, stock, sales商品主体分类通过 category_id 关联 categoryorderid, order_no, user_id, total_amount, status, receiver, phone, address主订单status 区分待付款/已付款/已发货/已完成order_itemid, order_id, product_id, price, quantity订单明细一个订单对应多个商品price 记录下单时快照cartid, user_id, product_id, quantity购物车用户未下单前的临时数据这几张表的关系是user 对 order 一对多order 对 order_item 一对多product 对 order_item 也是一对多。关键点在于 order_item 里要冗余一份商品 price而不是去查 product 表否则商品以后改价历史订单金额就对不上了。category 和 product 之间是简单的主外键关联商品列表页按分类筛选时只需要 where category_id xxx。除了这六张首页轮播图建议建一张 banner 表字段就是 id、image_url、sort、status。轮播图属于高频读取、低频写入的数据单独放一张表后台改图不会污染商品表。数据库脚本一般会给每张表加 created_at、updated_at 这类时间字段方便后台按时间排序和做统计。2.2 商品查询与下单接口数据库增删改查在小程序端的长什么样后端接口不用追求高深框架这个项目的教程里通常用原生 PHP 做增删改查小程序端用 wx.request 发请求返回 JSON 即可。先看最简单的查询商品列表// api/get_products.php 商品列表查询 ?php require_once ../common/db.php; $category_id isset($_GET[category_id]) ? intval($_GET[category_id]) : 0; $page isset($_GET[page]) ? max(1, intval($_GET[page])) : 1; $pageSize 10; $where ; if ($category_id 0) { $where WHERE category_id {$category_id}; } $offset ($page - 1) * $pageSize; $sql SELECT id, name, cover, price, original_price, stock, sales FROM product {$where} ORDER BY sales DESC LIMIT {$offset}, {$pageSize}; $result $conn-query($sql); $list []; while ($row $result-fetch_assoc()) { $row[cover] https://yourdomain.com . $row[cover]; // 拼上图片域名 $list[] $row; } echo json_encode([code 0, msg ok, data $list]); $conn-close(); ?这里的参数说明category_id 用于分类筛选0 表示全部page 用于分页第 1 页就是 0 到 9 条price 和 original_price 分开存original_price 用来显示划线价。注意我在 sql 拼接 category_id 前用了 intval()这是课设代码里最容易漏掉的一点——直接用 $_GET[category_id] 拼 SQL分类参数传个字符串就可能变成 SQL 报错或注入。再看一个下单接口。下单选购物车里的商品生成订单主表和明细表核心是控制事务// api/create_order.php 创建订单写入主表和明细表 ?php require_once ../common/db.php; $user_id intval($_POST[user_id]); $pay_type $_POST[pay_type] ?? wechat; $items json_decode($_POST[items], true); // [{id:1,quantity:2}, ...] if (empty($items)) { echo json_encode([code 400, msg 购物车不能为空]); exit; } $order_no date(YmdHis) . mt_rand(1000, 9999); $total 0; $conn-begin_transaction(); // 开启事务 try { foreach ($items as $item) { $pid intval($item[id]); $qty intval($item[quantity]); $product $conn-query(SELECT price FROM product WHERE id{$pid})-fetch_assoc(); if (!$product) throw new Exception(商品不存在); $total $product[price] * $qty; } $stmt $conn-prepare(INSERT INTO order (order_no, user_id, total_amount, pay_type) VALUES (?, ?, ?, ?)); $stmt-bind_param(siis, $order_no, $user_id, $total, $pay_type); $stmt-execute(); $order_id $conn-insert_id; foreach ($items as $item) { $pid intval($item[id]); $qty intval($item[quantity]); $stmt $conn-prepare(INSERT INTO order_item (order_id, product_id, quantity) VALUES (?, ?, ?)); $stmt-bind_param(iii, $order_id, $pid, $qty); $stmt-execute(); } $conn-commit(); echo json_encode([code 0, data [order_no $order_no]]); } catch (Exception $e) { $conn-rollback(); echo json_encode([code 500, msg $e-getMessage()]); } ?这个下单接口里的关键参数items 是小程序端传过来的 JSON 数组每一项包含商品 id 和 quantityorder_no 用时间加随机数生成避免用户看到自增 id 猜测订单量。代码块里用 begin_transaction 包裹两段插入是为了防止明细插入失败时主订单已经写入造成脏数据。很多同学的课设代码没用事务测试时没问题一旦网络波动就会出现“订单总金额算出来了但明细为空”的情况所以这里值得模仿。2.3 微信小程序登录与获取手机号openid 和 phone 的处理姿势小程序登录不是自己写账号密码而是靠微信授权。前端调用 wx.login 拿到临时 code后端拿着 code 去微信服务器换 openid。先看小程序端的标准写法// utils/login.js 页面登录 wx.login({ success(res) { if (res.code) { wx.request({ url: config.baseUrl /api/login.php, method: POST, data: { code: res.code }, success(res) { // 后端返回的 token 就是 openid 对应的会话标识 wx.setStorageSync(token, res.data.token); } }); } } });后端 login.php 收到 code 后用 curl 请求微信官方接口 https://api.weixin.qq.com/sns/jscode2session带上 appid 和 secret返回 openid 和 session_key。拿到 openid 后在 user 表里查一下如果没有就插入一条新用户有就更新最后登录时间然后生成一个 token 返回给前端。这里容易踩的坑是code 只能用一次并且 5 分钟过期所以前端不要反复调用 wx.login。再说获取手机号。现在微信官方把原来的 encryptedData 解密方案改成了 code 换手机号前端按钮写法不变button open-typegetPhoneNumber bindgetphonenumberhandlePhone手机号便捷登录/buttonhandlePhone(e) { if (e.detail.errMsg ! getPhoneNumber:ok) return; // 新版返回 e.detail.code wx.request({ url: config.baseUrl /api/decode_phone.php, method: POST, data: { code: e.detail.code }, success(res) { // 后端拿到 phone 后绑定到当前 openid 对应的 user 记录 } }); }后端用这个 code 配合 access_token 调微信接口拿到真实手机号。注意新版接口要求小程序必须是认证过的企业主体个人开发者和未认证的小程序调用会返回权限错误。这一点我会在第 4 章单独展开因为很多毕设项目卡在这里不是代码写错而是账号权限不够。3. 本地部署全流程从 MySQL 安装教程到小程序页面跑通3.1 环境准备PHP、MySQL、微信开发者工具的版本选择部署这套源码不需要昂贵的服务器本地开发用集成环境最省事。数据库这边MySQL 5.7 和 8.0 都行但注意 8.0 默认密码加密规则是 caching_sha2_password有些老版本 PHP 的 mysqli 连接会报“Unknown authentication method”所以如果你照着 MySQL 安装教程装了 8.0又用 PHP 5.6建议把认证方式改成 mysql_native_password或者干脆用 PHP 7.4 搭配 MySQL 5.7。我一般推荐 PHPStudy 这类集成面板把 PHP 7.4 MySQL 5.7 Nginx/Apache 一键启动能少踩很多版本坑。微信开发者工具版本选最新的稳定版就行但项目导入时要注意如果源码工程是用旧版本基础库写的开发者工具会提示“基础库版本过低”建议不要直接点升级先在详情里看一下调试基础库版本把最低版本设低一点保证和源码一致。还有一个环境叫“调试域名”本地开发不需要真的注册域名但需要在小程序后台或开发者工具里把 request 合法域名校验关掉这一步决定了页面能不能拿到数据。3.2 导入数据库与修改连接配置让后端先活过来数据库是所有功能的地基。把源码包里的 .sql 文件导入 MySQL我习惯用命令行的方式因为能看到真实报错# 导入 flower_shop 数据库执行后会提示输入密码 mysql -uroot -p flower_shop flower_shop.sql如果 flower_shop 数据库还不存在先创建库再导入注意字符集CREATE DATABASE IF NOT EXISTS flower_shop DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE flower_shop; SOURCE flower_shop.sql;导入后不要急着开小程序先用 SQL 验证一下数据是否完整SELECT COUNT(*) AS product_count FROM product; SELECT COUNT(*) AS order_count FROM order;如果 product_count 是 0说明 SQL 文件没执行成功或者执行时选了错误的数据库。这一步是很多翻车现场的开始——页面报错说“商品为空”其实问题不在前端而是表里压根没有数据。数据库连上之后改后端连接配置。源码包里一般有一个公共连接文件比如 common/db.php// common/db.php 本地环境数据库连接 ?php $host 127.0.0.1; $user root; $pass root; $db flower_shop; $conn new mysqli($host, $user, $pass, $db); $conn-set_charset(utf8mb4); if ($conn-connect_error) { die(json_encode([code 500, msg 数据库连接失败 . $conn-connect_error])); } ?这里把 符号去掉会更好排错因为本地调试时应该让错误暴露出来。set_charset(utf8mb4) 这行务必保留否则商品描述里的 emoji 表情存进去会变乱码这也是中文乱码最常见的原因。有的人只改数据库字符集不改应用层连接照样乱码。3.3 小程序端域名与 appid 配置页面数据从哪来后端跑起来后小程序端要改两个地方一是自己的 appid二是接口域名。appid 在 project.config.json 里改或者在开发者工具详情页里换。如果你没有注册小程序账号可以先用测试号但注意测试号不支持获取手机号等能力。接口域名配置我更推荐单独写一个配置文件方便后面切换// utils/config.js module.exports { baseUrl: http://127.0.0.1:8080 // 本地开发地址真机预览要改成局域网IP };然后在需要用接口的页面引入这个模块。小程序端所有 wx.request 的 url 都以 baseUrl 拼接。这里的关键点本地调试时 127.0.0.1 只在开发者工具模拟器里有效真机预览必须改成电脑的局域网 IP比如 192.168.1.101:8080如果后端用的是 Apache/Nginx还要确认端口能被外网访问防火墙别挡。开发者工具里还要在“详情 → 本地设置”勾选“不校验合法域名、web-view业务域名、TLS 版本以及 HTTPS 证书”。不勾选的话访问 http://127.0.0.1 会被拦截报错信息是“url not in domain list”。这一步顺序很重要先勾选再重新编译改完域名后要点击“清除缓存 → 全部清除”否则小程序端缓存了旧的请求配置界面显示的还是失败。最后验证一条链路在小程序里打开商品列表页看数据是否渲染然后加购物车、提交订单到 order 表里查有没有新记录。如果这一串都能通说明部署基本完成。4. 部署与运行避坑指南五条真实排查记录4.1 数据库连不上一整屏红色报错现象打开小程序页面接口返回 code 500msg 是“数据库连接失败”MySQL 服务里也不见数据库列表。原因最常见是集成环境里的 MySQL 没启动或者密码和源码配置不一致。你照着 MySQL 安装教程装完可能用的 root 密码是 123456但 db.php 里写的是 root。也有的人是改了端口比如 MySQL 从 3306 改成了 3307连接串还写的 3306。解决先回物理机上确认 MySQL 服务是否启动再命令行里测连接mysql -uroot -p能进说明密码对。如果密码不对直接改 db.php 里的 pass 字段端口不对在连接代码里加 $conn-port 或者在 host 后加“:端口”。注意改了 DB 配置后PHP 进程如果是 opcache 模式可能要重启 PHP 服务否则旧配置一直在驻留。那次我排查了半小时最后发现是没重启服务。4.2 商品列表为空SQL 导入顺序错了现象数据库连接正常user 表现六张表都在但商品列表页一直显示“暂无数据”后台也有这个分类。原因SQL 文件里通常有多个 Insert 语句如果导入时选了错误的数据库或者中途报错中断了会导致部分表有数据、部分表没数据。另一个常见原因是商品表里 cover 字段存的图片路径是“/uploads/xxx.jpg”而前端展示时拼了完全不存在的域名图片加载失败用户看起来就像“没数据”。解决先执行 SELECT COUNT(*) FROM product确认表里有没有记录。有记录但页面空就去看 console 报错是不是图片 404没有记录就重新导入 SQL导入前把原有库删掉重来。稳妥做法是在 mysql 命令行用 SOURCE 完整执行不要只看图形化工具的一行“success”就完了。4.3 小程序请求 fail本地调试域名没放开现象开发者工具模拟器里商品接口正常但一预览到手机就白屏或者报“fail”network 面板显示 request 失败。原因真机上小程序强制校验合法域名并且 127.0.0.1 是指手机自己根本访问不到你的电脑。很多第一次接触的人以为后端跑在 127.0.0.1 就能通这是理解错了 localhost 的含义。解决本地联调用电脑局域网 IP比如 192.168.31.77:8080替代 baseUrl 里的 127.0.0.1。同时手机和电脑连同一个 Wi-Fi电脑防火墙放行 8080 端口。开发者工具里“不校验合法域名”只对模拟器生效真机只能在右上角“开发版”或“体验版”的调试模式里临时跳过否则就必须把接口部署到有 HTTPS 的服务器上。所以最省心的路是模拟器调试用 127.0.0.1真机演示前半小时统一替换成局域网 IP。4.4 微信登录 invalid codecode 用了一次就报废现象第一次登录成功退出后再登录就报“invalid code”后端日志显示 code2session 返回 errcode 40029。原因wx.login 的 code 有效期 5 分钟且只能消费一次。很多人在 onLoad 里调 wx.login 拿 code然后在按钮点击的异步回调里再传给后端这中间如果页面经历了两次请求前一个 code 就会被后端或微信端作废第二个再拿去换就报错。还有人把缓存里的 code 反复用也会报同样错。解决只在用户主动触发登录动作时调 wx.login拿到 code 后立刻发请求不要提前调用、不要缓存复用。如果后端要做并发处理记住 code2session 接口是 GET 请求失败时可以重新走一遍前端登录不要在后端手动刷新 code。我在课程设计里给 login.php 加了日志每次进来记录 code 前 10 位排查起来一眼就能看出是不是同一个 code 被用了两次。4.5 获取手机号按钮没反应主体权限与版本都影响现象点击“微信手机号快捷登录”按钮bindgetphonenumber 回调里的 errMsg 不是 getPhoneNumber:ok或者始终不触发回调。原因获取手机号能力要求小程序已经认证个人主体没有这个权限另外新版基础库从 2.21.2 开始用 e.detail.code 换手机号老教程的 encryptedData 解密逻辑在新版本里已经失效。解决先确认小程序主体是企业或个体工商户并且完成微信认证。开发者工具里可以把调试基础库切到 2.21.2 以上用新版 code 换号方式。如果只是毕设演示不需要真的拿手机号可以改成用户手动填手机号把获取手机号按钮降级为普通表单输入避免答辩现场按钮没反应。从稳定角度讲我会在 handlePhone 里做一次 errMsg 判断失败时弹出一个输入框兜底这样演示流程不会断。5. 改成自己的毕设主题替换数据与模拟支付回调5.1 把鲜花分类替换成任意商品你要做宠物、零食或者图书销售不需要改后端结构只需要替换表里的数据-- 清空分类和商品再插入自己的数据 DELETE FROM product; DELETE FROM category; INSERT INTO category (id, name, sort) VALUES (1, 宠物猫, 1), (2, 宠物狗, 2); INSERT INTO product (id, category_id, name, cover, price, stock) VALUES (1, 1, 英短幼猫, /uploads/cat.jpg, 1999, 10);改完记得同步替换 /uploads 目录下的图片cover 字段里的相对路径不要加域名让前端统一拼接。商品表里如果有 detail 富文本图片也要对应放到 uploads 下。核心原则是只换数据不换结构这样原有购物车和订单逻辑全部保留。5.2 用模拟支付回调跑通订单状态流微信支付在毕设环境里经常无法真实走通所以我一般会加一个模拟回调接口用来把订单状态从“待付款”推到“已付款”// api/mock_pay_notify.php 模拟微信支付成功回调 ?php require_once ../common/db.php; $order_no $_POST[order_no] ?? ; $stmt $conn-prepare(UPDATE order SET statuspaid WHERE order_no?); $stmt-bind_param(s, $order_no); $stmt-execute(); echo json_encode([code 0, msg 支付成功]); ?前端在“提交订单”成功后调用这个接口然后再重新拉取订单详情你会看到状态从待付款变成已付款。这样答辩演示就能完整展示“下单—支付—发货”的闭环而不是停在待付款页面。我经验里最尴尬的翻车就是演示到付款环节微信支付界面弹不出来后来干脆预置了模拟回调速度还快。从那以后每次拿到新项目我第一步就是把支付、登录这类外部依赖先换成可模拟的接口排障省一半时间。希望帮到你。本文还有配套的精品资源点击获取