简介鲜花销售微信小程序毕业设计完整项目包面向需要完成小程序类毕设或课程设计的高校学生。资源包含用户端微信小程序与Java后端管理平台实现首页、个人中心、用户/商家管理、鲜花信息与分类管理、管理员及系统管理等核心模块后端基于SSM框架Spring、SpringMVC、MyBatis搭配MySQL 5.7数据库。压缩包共1341个文件涵盖vue小程序页面、java后端代码、js交互逻辑、json配置、wxss/wxml样式结构以及sql数据库脚本等类型整体大小约20.28MB目录结构完整便于直接导入开发工具eclipse/idea、HBuilder X运行调试。项目附带详细说明文档和答辩演示PPT覆盖需求分析、数据库设计、功能实现与操作指南可帮助快速理解前后端联调流程。目前已有85人学习参考适合正在筹备毕业设计答辩或希望系统掌握小程序全栈开发流程的读者。1. 鲜花销售微信小程序毕设先看清这套完整前后端到底给你准备了什么打开压缩包你会发现它不是一个只能演示静态页面的 HTML 套壳而是把微信小程序前端、后端服务、MySQL 数据库全部放进同一份工程。以鲜花销售微信小程序源码为例这类项目在毕业设计里出现频率很高因为业务链路足够完整用户登录、商品分类、购物车、下单、订单列表每一个环节都要前后端配合才能跑通。zip 里还带了 SQL 文件、说明文档和 LW 论文文档意味着你拿到的是一套答辩级交付物不是零散的页面片段。下面我会按拆结构、跑起来、调参数、排坑的顺序把这份源码怎么用、哪些参数必须改、坑在哪一次说清。适合正在做小程序类毕设的同学也适合想快速看懂一套商城小程序工程怎么组织的开发者。2. 拆解源码结构前端页面、后端接口与 MySQL 表是怎么咬合的拿到 zip 先别急着导入微信开发者工具先花十分钟把目录摸清楚后面会少走很多弯路。一套典型的小程序毕设工程通常包含三个部分miniprogram 或 pages 目录放小程序前端server 或 src 目录放后端 Java 工程sql 或 db 目录放数据库脚本。如果这三块缺了任何一块都不能叫完整前后端。2.1 前端目录pages、components、utils 各自在干嘛前端大多是原生微信小程序而不是 uniapp 或 Taro 工程识别方法很简单看目录里有没有 app.js、app.json、app.wxss 三个入口文件。原生工程的好处是结构直观答辩时随便点开一个页面都能顺着生命周期讲下去。常见目录结构如下miniprogram/ ├── app.js ├── app.json ├── app.wxss ├── pages/ │ ├── index/ # 首页轮播图鲜花列表 │ ├── category/ # 分类左侧分类右侧商品 │ ├── cart/ # 购物车数量加减、选中结算 │ ├── order/ # 订单订单列表与状态tab │ └── user/ # 个人中心登录入口、地址管理 ├── components/ │ ├── flower-card/ # 商品卡片组件 │ └── number-input/ # 数量步进器组件 └── utils/ ├── config.js # 全局接口地址、AppID等配置 └── request.js # wx.request 封装pages 下每个目录就是一个页面标准配置是四个文件.js 写逻辑、.wxml 写结构、.wxss 写样式、.json 写页面配置。components 是复用模块商品卡片在首页和分类页都会被引用所以单独抽出来。utils/config.js 是你第一个要打开的文件里面一般放着 BASE_URL后端接口地址、AppID、Secret 等全局常量。这里最容易犯的错是只看页面不追数据流。你要在脑子里形成一条链路首页 index.js 在 onLoad 里调用某个请求方法该方法从 utils/request.js 里调 wx.request请求打到后端 /api/flower/list后端查 MySQL 返回 JSON前端 setData 渲染到 wxml。这套链路能完整讲清楚答辩的基础分就到手了。2.2 后端工程controller、service、mapper 的分层与接口风格后端绝大多数情况下是 Spring Boot MyBatis 的组合因为这一套在高校课程里覆盖面最广老师也容易验证。工程目录按 controller、service、mapper 三层拆开controller 负责接收前端请求service 写业务逻辑mapper 访问 MySQL。一个典型鲜花项目的接口清单大概长这样接口路径方法作用前端页面/api/user/loginPOST微信登录返回 tokenuser / index 登录弹窗/api/flower/listGET分页查询鲜花列表index/api/flower/detailGET查询鲜花详情index 详情/api/cart/listGET查询当前用户购物车cart/api/cart/addPOST加入购物车index 商品卡片/api/order/createPOST创建订单cart 结算/api/order/listGET查询用户订单orderController 的写法一般很薄只做参数接收和结果包装。下面这段是一个典型的分页查询鲜花列表的控制器代码RestController RequestMapping(/api/flower) public class FlowerController { Autowired private FlowerService flowerService; GetMapping(/list) public Result list(RequestParam(defaultValue 1) Integer page, RequestParam(defaultValue 10) Integer pageSize) { PageBeanFlower data flowerService.pageFlower(page, pageSize); return Result.success(data); } }这段代码的逻辑是前端传 page 和 pageSize后端返回统一结构 Result里面的 data 是包括总条数和当前页数据的对象。RequestParam 带默认值就算前端漏传参数也不会直接报错。Result 是自定义的返回体一般包含 code、msg、data 三个字段code 为 0 表示成功。答辩时如果老师问为什么前端能拿到总页数答案就在 PageBean 这个对象里。后端还有一个容易被忽略的点图片处理。鲜花商品必须展示图片常见的做法是后端做一个文件上传接口 /api/file/upload把图片存在本地的 upload 目录数据库只存相对路径如 /upload/flowers/rose.jpg。这意味着前端展示时必须拼接 BASE_URL后面避坑章节会专门讲。2.3 MySQL 表设计用户、商品、订单、购物车的字段与关系数据库脚本一般在 sql 目录下文件名类似 flower.sql 或 db_flower.sql。导入后通常有 6 到 8 张表核心表有用户表、商品表、分类表、购物车表、订单表、订单明细表另外还有轮播图表和地址表。以商品表为例建表语句大致如下CREATE TABLE t_flower ( id int(11) NOT NULL AUTO_INCREMENT, category_id int(11) DEFAULT NULL COMMENT 分类id, name varchar(100) NOT NULL COMMENT 鲜花名称, cover varchar(255) DEFAULT NULL COMMENT 封面图片, price decimal(10,2) DEFAULT NULL COMMENT 销售价格, stock int(11) DEFAULT 0 COMMENT 库存, sales int(11) DEFAULT 0 COMMENT 销量, status tinyint(1) DEFAULT 1 COMMENT 1上架 0下架, create_time datetime DEFAULT NULL, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;这张表是商城类项目最典型的设计category_id 关联分类表price 用 decimal 而不是 float避免金额计算出现精度误差status 用于上下架sales 用于按销量排序。表与表之间的关系也很清晰购物车表通过 user_id 关联用户、flower_id 关联商品订单主表记录总金额和状态订单明细表再记录每个商品的单价和数量。为什么要拆订单主表和明细表因为一个订单可能包含多束花主表存订单整体信息、明细表存每件商品这样既能在订单列表页只查主表又能在详情页展示明细。多数毕设项目不会建物理外键而是在应用层维护关系这样增删数据更灵活答辩时也能解释清楚。用户表最关键的字段是 openid它是微信用户在小程序体系内的唯一标识。登录时后端拿前端传来的 code 去微信接口换 openid再拿 openid 查用户表查不到就自动注册一条新用户。注意 openid 不能暴露给前端否则会有安全隐患后端一般只把用户 id 和 token 返回给小程序端。3. 本地跑起来从 MySQL 导入到微信开发者工具出首页的完整步骤这个项目不复杂但环境配置步骤多顺序错了就会看到前端请求一堆报错。我建议按数据库 → 后端 → 前端的顺序来因为小程序首页一加载就会发请求后端都没起来的话前端只会得到一堆网络错误容易误判为代码问题。3.1 环境准备与导入顺序需要准备的东西不多都是高校实验室常见的版本。为了避免版本不兼容下表是我跑这类工程时的推荐组合软件推荐版本说明JDK1.8 或 11Spring Boot 2.x 用 JDK 8 最稳Maven3.6用于下载依赖和打包MySQL5.7 或 8.05.7 不挑驱动8.0 需要改时区参数IDEA2020 以上社区版够用微信开发者工具稳定版导入小程序工程用顺序上的坑如果你电脑上 MySQL 之前装过且没设对密码后端连接失败是很常见的事。先跑一下mysql -u root -p确认能进再启动后端。另外确认 3306 端口没有被占用Windows 上可以用 netstat -ano | findstr :3306 查mac 上用 lsof -i:3306。3.2 把 SQL 导入 MySQL 并改对连接参数找到 sql 目录下的脚本文件后打开命令行进入 MySQL用 source 命令导入。这里要注意脚本里如果带 CREATE DATABASE 语句你不用先建库如果没有需要手动建一个同名的库再导入。mysql -u root -p Enter password: 你的数据库密码 source /Users/你的路径/flower.sql; show databases; use flower_shop; show tables;执行 show tables 后如果能看到 t_user、t_flower 这些表说明导入成功。接下来打开后端工程的 src/main/resources/application.yml把数据库连接改成你本机的配置spring: datasource: url: jdbc:mysql://localhost:3306/flower_shop?useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltruecharacterEncodingutf8 username: root password: 你的密码 jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT8这里几个参数值得记一下serverTimezoneAsia/Shanghai 是 MySQL 8 的必填项不加会报 Server returns invalid timezoneallowPublicKeyRetrievaltrue 解决 MySQL 8 的 RSA 公钥获取报错characterEncodingutf8 防止存入的中文乱码。jackson 的时间配置决定返回给前端的日期格式如果你发现订单时间显示一串时间戳就是少了这两行。改完这些参数数据库这步就算完成了。3.3 后端启动IDEA 里 Maven 构建与端口确认后端工程用 IDEA 打开后等右下角 Maven 把依赖下载完找到启动类直接运行。启动类的名字通常是 Application 结尾比如 FlowerApplication.java上面有 SpringBootApplication 注解。运行后看控制台输出出现 Tomcat started on port(s): 8080 就表示后端起来了。不习惯用 IDEA 的话命令行也能跑前提是本机装了 Maven 并且配了环境变量cd server mvn spring-boot:run启动成功后先用浏览器或 curl 验证一个不需要登录的接口确认后端真的能查数据库curl http://localhost:8080/api/flower/list如果返回 JSON 里有 List 数据说明后端已经正常。如果返回 404看看接口路径是否真的叫这个如果报数据库连接错误回头检查 3.2 节的 yaml 配置。后端端口不是 8080 也很正常看控制台提示改成实际端口就行改端口在 application.yml 里加一行 server.port。3.4 小程序端导入与 AppID 配置打开微信开发者工具选择导入项目目录选到 miniprogram 或直接选工程根目录。这里有个细节如果工具提示不是小程序项目看一下目录里有没有 app.json没有就选到包含 app.json 的那一层。AppID 可以选择测试号不需要注册正式小程序点击导入即可看到首页。导入后先别急着点编译打开 utils/config.js 确认接口地址// utils/config.js const BASE_URL http://localhost:8080 module.exports { BASE_URL }如果后端端口改过这里要同步改。然后点击编译如果首页出现了鲜花列表说明全链路已经通了如果图片裂了或者首页空数据大概率是接口地址、数据库数据或图片路径拼接的问题。另外开发阶段必须在微信开发者工具的详情 → 本地设置里勾选不校验合法域名、web-view业务域名否则 wx.request 请求 http://localhost 会被拦截报出 not in domain list。4. 必调参数与联调联试把登录、购物车、下单串成一条线项目跑到首页能出数据只是第一步毕设答辩最常问的是登录和下单这两个链路也是前后端参数最容易对不上的地方。这一章把三个核心链路依次过一遍。4.1 登录链路wx.login 到 code2Session 到 token登录是小程序项目里最绕的环节因为它涉及三次网络请求小程序 → 微信接口 → 后端。前端先调 wx.login 拿到临时 code再把 code 发给后端后端拿着 code 去微信的 jscode2session 接口换 openid 和 session_key后端用 openid 查用户表生成 token 返回给前端。前端把 token 存进 storage后续所有请求都带上它。前端的登录唤起代码一般长这样// pages/user/user.js 登录按钮事件 handleLogin() { wx.login({ success: (res) { wx.request({ url: BASE_URL /api/user/login, method: POST, data: { code: res.code }, success: (res2) { if (res2.data.code 0) { wx.setStorageSync(token, res2.data.data.token) wx.setStorageSync(userInfo, res2.data.data.userInfo) wx.showToast({ title: 登录成功 }) } else { wx.showToast({ title: res2.data.msg, icon: none }) } } }) } }) }这段代码的逻辑是wx.login 的 res.code 有效期只有五分钟且只能用一次所以要立刻发给后端。后端返回的 token 是自定义的常见做法是 UUID 或 JWT存到 storage 里。注意 login 后不能直接在 success 里拿 openid微信官方早就改了openid 只能由后端从 code 换。答辩时如果被问到安全设计可以说openid 不经过前端由后端保存并用 token 标识用户。后端的核心代码主要是拼请求和查表简化后如下public LoginInfo wxLogin(String code) { String url https://api.weixin.qq.com/sns/jscode2session ?appid appid secret secret js_code code grant_typeauthorization_code; String body HttpUtil.get(url); // 返回JSON String openid JSONUtil.parseObj(body).getStr(openid); User user userMapper.findByOpenid(openid); if (user null) { user new User(openid); userMapper.insert(user); } return new LoginInfo(user, UUID.randomUUID().toString()); }这里用到的 HttpUtil 和 JSONUtil 来自 hutool 工具包如果你的项目没引入就改成 HttpClient fastjson 的组合效果一样。appid 和 secret 要改成你自己小程序账号下的值测试号也能拿到。如果调用微信接口返回 errcode最常见的是 40013appid 错误和 40125secret 错误去小程序后台核对一下。还有一点code 使用后立即失效后端要避免重复请求微信接口否则第二次会报 code been used。4.2 请求封装baseUrl、token 注入、状态码处理商城类小程序几乎每个页面都要发请求如果每个页面都写一遍 wx.request代码会非常冗余。所以源码里基本都会有一个封装好的 request.js把 BASE_URL 拼接、token 注入、状态码统一处理都做掉。常见的封装长这样// utils/request.js const request (url, method GET, data {}) { return new Promise((resolve, reject) { wx.request({ url: BASE_URL url, method, data, header: { Content-Type: application/json, token: wx.getStorageSync(token) }, success: (res) { if (res.data.code 0) { resolve(res.data.data) } else if (res.data.code 401) { wx.removeStorageSync(token) reject(res.data.msg) } else { reject(res.data.msg) } }, fail: (err) reject(err) }) }) } module.exports request这个封装用 Promise 把 wx.request 包了一层页面里就可以用 async/await 写业务不用陷入回调地狱。header 里放 token 是前端传身份标识最常用的方式后端拦截器从 header 里取出校验。注意这里的字段名token必须和后端代码一致如果后端用的是Authorization或x-token前端不改字段就会一直 401。另外 res.data.code 的判断要和后端 Result 一致有的项目用 200 而不是 0需要对上。使用封装后页面里的调用就简洁多了const list await request(/api/flower/list?page1pageSize10) this.setData({ flowerList: list.pageData })这种写法答辩演示很方便也方便你定位问题如果某个页面数据为空先看 Network 面板里这个请求有没有发出去、返回什么再决定是前端问题还是后端问题。4.3 购物车与下单库存校验和订单号生成购物车接口相对简单就是把商品 id、数量、用户 id 插到购物车表。真正有业务含量的是下单它至少要做四件事校验商品是否上架、校验库存够不够、生成订单号、扣减库存并创建订单主表和明细表。下单接口的事务处理是答辩的高频问题老师看到你用了 Transactional基本会认为你理解了事务概念。订单号生成代码一般是这样的// 后端生成订单号 String orderNo FL System.currentTimeMillis() String.format(%04d, new Random().nextInt(10000));这段代码用时间戳加四位随机数拼出订单号FL 前缀代表 Flower。时间戳保证不同毫秒级的订单号不重复随机数防止同一毫秒并发时撞号。正式项目里会用雪花算法或者数据库序列但毕设规模用这种拼接完全够答辩时能讲清楚为什么不直接按自增 id 暴露给用户就行。下单接口的典型逻辑如下Transactional public String createOrder(OrderCreateParam param) { Flower flower flowerMapper.selectById(param.getFlowerId()); if (flower null || flower.getStatus() ! 1) { throw new BizException(商品已下架); } if (flower.getStock() param.getQuantity()) { throw new BizException(库存不足); } // 扣减库存 flowerMapper.reduceStock(param.getFlowerId(), param.getQuantity()); // 生成订单主表 Order order new Order(); order.setOrderNo(generateOrderNo()); order.setUserId(param.getUserId()); order.setTotalPrice(flower.getPrice().multiply(BigDecimal.valueOf(param.getQuantity()))); order.setStatus(0); orderMapper.insert(order); // 生成订单明细 OrderItem item new OrderItem(); item.setOrderId(order.getId()); item.setFlowerId(flower.getId()); orderItemMapper.insert(item); return order.getOrderNo(); }这里的逻辑用到了几个关键细节库存扣减用 update 语句在数据库层面执行不是先把库存查出来在 Java 里减完再写回去避免超卖金额计算用 BigDecimal 而不是 double加 Transactional 让订单主表、明细表和库存扣减在同一次事务里任何一个失败都整体回滚。前端拿到 orderNo 后跳转订单详情或提示支付成功这就是一套完整的闭环。订单状态一般用 0、1、2、3 表示待付款、待发货、已发货、已完成订单列表页按状态 tab 筛选时就是查这个字段。5. 避坑记录鲜花销售小程序跑通前最常踩的五个坑这一章是我把这些项目从零跑到通的过程里遇到最多的问题汇总。基本都是环境、路径、参数不一致导致的以及几条看似不起眼却浪费一晚上的经验。5.1 图片 404 或一片灰首页商品图全裂了现象小程序首页能显示商品名和价格但所有图片都是灰块打开调试器看到 image 请求状态是 404 或 failed。原因不是图片文件丢了而是数据库里存的是相对路径 /upload/flowers/rose.jpg前端直接拿这个路径给 image 组件加载变成了请求本地小程序的 /upload 目录自然找不到。解决方式是在前端拼接后端地址前缀通常在 utils 里导出一个静态资源地址变量// utils/config.js const BASE_URL http://localhost:8080 const IMG_URL BASE_URL /upload module.exports { BASE_URL, IMG_URL }页面里这样用image src{{IMG_URL}}{{item.cover}} modeaspectFill/image注意 modeaspectFill 也是商品图常用的属性能让图片在固定尺寸的框里不变形地裁切展示。如果后端返回的字段已经是全路径也就是以 http 开头前端就不要再拼前缀否则会出现双协议头。判断标准很简单打印一下数据里的 cover 字段以 / 开头就拼接以 http 开头直接用。5.2 登录永远失败token 字段名对不上导致连环 401现象前端调用 /api/user/login 明明返回了 token但紧接着的 /api/cart/list 等请求全部 401或者登录接口直接报参数错误。原因一般是两个项目之间约定不一致后端拦截器从 header 里取的是 Authorization而前端 request.js 里写的是 token。解决是全局搜索统一字段前后端各改一处// 前端 request.js 的 header 中修改 Authorization: wx.getStorageSync(token)// 后端拦截器读取时 String token request.getHeader(Authorization); if (token null || token.isEmpty()) { return 未登录; }还有一个隐蔽情况拦截器写了但只对部分路径生效比如 /api/user/login 被排除了但 /api/flower/list 没有排除且必须登录你会发现首页的数据一会儿有一会儿没有。建议排查时先看拦截器的 exclude 名单把公开接口列进去其余接口统一鉴权。5.3 MySQL 8 一启动就报时区错Server returns invalid timezone现象后端启动时控制台报 com.mysql.cj.exceptions.InvalidConnectionAttributeException: The server time zone value Öйú±ê׼ʱ¼ä一大串乱码。原因 MySQL 8 默认时区不是 UTC8 而 JDBC 驱动会在连接时检查配置里没给 serverTimezone。解决就是数据源 url 加参数前面 3.2 写过这里再强调一下完整写法jdbc:mysql://localhost:3306/flower_shop?useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingutf8allowPublicKeyRetrievaltrue另外如果项目用的 MySQL 驱动版本是 5.x 而连的是 MySQL 8会额外报 Public Key Retrieval is not allowed解决方案就是加上 allowPublicKeyRetrievaltrue。这两个参数对刚装 MySQL 8 的同学来说是必加的不改基本起不来。5.4 手机预览白屏真机连不上电脑上的后端现象开发工具里一切正常但用手机扫码预览时首页空白、接口超时。原因手机上访问的是 localhost:8080而 localhost 指向的是手机自己不是电脑。解决是改用电脑的局域网 IP并让手机和电脑处于同一 Wi-Fi。先查本机 IPmac 用 ifconfigWindows 用 ipconfig找到 192.168 开头的地址把 utils/config.js 里的 BASE_URL 改掉const BASE_URL http://192.168.1.103:8080同时要注意 Windows 防火墙可能会拦截 8080 端口的入站请求需要在防火墙设置里放行或临时关闭。还有一个容易漏的点开发工具详情里不校验合法域名的开关手机预览时如果没打开调试照样会拦截 http 请求。在手机上小程序右上角胶囊菜单里打开开发调试再重新扫码很多请求类问题会消失。5.5 新增商品后列表不刷新order by 不够明确现象后台或 SQL 里新插入一条鲜花前端列表还是老数据刷新也没变化。原因可能有两个一是列表查询 SQL 没有加明确排序MySQL 对相同数据的返回顺序不稳定新数据可能排到了中间位置前端分页缓存不更新导致看不到。解决是给列表查询加上明确排序SELECT * FROM t_flower WHERE status 1 ORDER BY sales DESC, id DESC LIMIT #{pageSize} OFFSET #{offset}二是前端 onLoad 和 onShow 的逻辑问题从详情页返回首页onLoad 不会重新触发如果数据只在 onLoad 里加载就会显示旧数据。建议把加载函数放到 onShow 里执行每次页面获得焦点都刷新一遍列表这样演示时体验也好。改成 onShow 后注意别在每次弹窗关闭时也触发避免请求过多。这五条是最影响能不能跑起来的坑另外像端口被占用、Maven 依赖下载慢这类环境问题解法比较直接端口占用用 netstat/lsof 查占用进程然后换端口依赖慢就配 Maven 镜像源。把上面的字段、时区、域名三个大方向查一遍一个花店小程序基本就稳了。6. 把项目改成答辩能讲的样子三个验证技巧与一个交付习惯项目能跑起来之后最值得花的不是加功能而是把演示流程做顺。第一个技巧是善用微信开发者工具的 Network 面板。答辩演示时老师看到的不应该只是一个能点的页面而应该是一整套可以讲述的请求链条。打开首页Network 面板会把每次 wx.request 请求按时间顺序列出来login 先返回 tokenflower/list 接着返回商品数据。按着这个请求顺序讲就能把前端如何登录、后端如何鉴权、数据如何流动全部串起来比背稿更有说服力。第二个技巧是准备一组 Postman 接口测试。把登录、商品列表、购物车、创建订单这几个接口的请求和响应保存下来万一现场微信开发者工具突然抽风直接打开 Postman 重放接口也能完整展示后端逻辑。Postman 里重点关注返回结构 code、msg、data 的一致性这也是老师经常检查的地方。第三个技巧是把订单状态流转整理成一张小表放在说明文档的首页答辩时可以按表格讲业务闭环状态值状态名触发时机后续动作0待付款下单成功用户支付模拟1待发货支付成功管理员发货2已发货发货操作用户确认收货3已完成确认收货订单结束一个交付习惯交源码前重新导出一次干净的数据库脚本并且把自己测试产生的脏数据删干净。我以前就吃过亏压缩包里的 SQL 带着一堆测试花束123的数据老师导入后页面看起来乱七八糟印象分直接降。正确的导出方式是先清理再导出mysqldump -u root -p flower_shop flower_clean.sql导出后打开文件检查有没有本机绝对路径、有没有测试账号的敏感数据再写一个 README 说明默认登录方式、后端端口、数据库账号密码。这一套做完哪怕答辩前一周才跑通也会显得项目非常完整。希望帮到你。本文还有配套的精品资源点击获取