简介:农产品商城微信小程序项目源码包,完整包含前端小程序、Java后端与MySQL数据库,适合作为毕业设计或课程设计参考,也适合希望快速掌握小程序全栈开发流程的初学者。项目演示了从商品展示、用户下单到订单管理的常见电商业务闭环。压缩包共1241个文件,约19.59MB,主要包括png界面图、vue页面与js逻辑、java后端接口、wxml/wxss页面结构、json配置以及sql数据库脚本,目录划分清晰,便于按功能模块查阅。目前已有90人参与学习。资源附带项目说明文档,可帮助理解整体架构设计、前后端交互方式及数据库表结构,并结合实际源码掌握微信开发者工具使用、Java+Maven环境搭建与Tomcat部署流程。无论是用于毕设答辩还是上手小程序开发,这套完整源码都能提供从环境配置到功能落地的直接参考。
1. 农产品商城小程序源码包:先认清这个毕业设计里 Java、小程序、MySQL 各自扮演什么角色
当你在毕业设计选题表里看到“农产品商城小程序源码(java+小程序+mysql)”这个名字时,容易误以为它是一个“装好就能跑”的完整作品。实际拿到手里你会发现,它更像是一个结构完整的工程骨架:微信小程序端负责商品展示、加购、下单和支付入口,Java 后端(常见是 SSM 或 Spring Boot)提供登录鉴权、商品管理、订单处理的 REST 接口,MySQL 则把用户、商品、订单、购物车这些数据持久化下来。这套组合适合做电商类毕设的学生,也适合想快速搭一个农产品销售 Demo 的开发者。但“有源码”和“能跑通”之间隔着环境配置、依赖版本、微信生态限制三道坎,接下来的内容会帮你把这三道坎逐个踩平。
2. 把源码在本地跑起来:JDK、MySQL、小程序开发者工具的三件套准备
2.1 后端 Java 环境:JDK 版本与 Maven 依赖的匹配问题
先说结论:不管这套源码是 SSM 还是 Spring Boot,我建议你先把 JDK 固定在 1.8(8u202 或更高),因为绝大多数毕设源码都诞生在 JDK 8 时代。用 JDK 11 或 17 打开老工程,经常会在编译阶段报无法访问org.springframework.*或程序包com.sun.xxx不存在之类的错误,而这本质上是高版本 JDK 对反射和内部 API 的约束,不是你的代码写错了。
第一步,确认本机命令行能访问 Java 工具链:
java -version javac -version mvn -version如果mvn提示找不到命令,说明 Maven 没装或没配环境变量。Maven 是 Java 项目拉取依赖的工具,源码包里的pom.xml就是它的配置。打开pom.xml,重点看两处:<parent>里的spring-boot-starter-parent版本号(如果是 Spring Boot 项目),以及<properties>里的<java.version>。
很多毕设源码的 README 和 pom.xml 已经是两套说法,作者用的是自己电脑上的旧版本,但你用新版本去编译就会失败。常见做法是,在 IDEA 里通过 File → Project Structure → SDKs 添加一个 JDK 8 的 SDK,并把 Project SDK、Module SDK、Language Level 三处全部指到 8。配置完后执行编译命令:
mvn clean install -DskipTestsclean清掉上次编译的 target 目录,install把打好的 jar/war 放进本地 Maven 仓库,-DskipTests跳过单元测试,避免老工程里那些依赖外部环境的测试用例把编译卡死。这条命令执行成功之后,项目依赖才算真正齐了。如果源码是 SSM 结构(带spring-mvc.xml、mybatis-config.xml),同样先把 Maven 依赖下载完,再确认 IDEA 的 External Libraries 里有 spring-webmvc 和 mybatis 的 jar。SSM 工程常要打包成 war 丢进 Tomcat,但本地联调时我一般是直接用 IDEA 配置一个 Tomcat 的 Run Configuration 来启动,效果一样,省去反复拷 war。
2.2 MySQL 建库与数据导入:用命令行还是 Navicat
拿到源码包后,先找sql/或db/目录,里面通常有一个.sql文件,名字可能叫farm.sql或shop.sql。打开文件先看前 20 行,确认它有没有包含CREATE DATABASE。有的脚本自带建库语句,有的只有建表语句,这两种情况的导入方式不一样。
如果脚本自带建库,可以直接用命令行导入,Windows 下在 CMD 或 PowerShell 里执行:
mysql -u root -p < farm.sql输入密码后脚本按顺序执行,建库、建表、插入初始数据一步完成。如果提示mysql: command not found,说明安装 MySQL 时没有把 bin 目录加进系统 PATH。这个“mysql 安装配置教程”里常被忽略的一步,会让不少新手在导入脚本时遇到第一张红牌。临时解法是进到 MySQL 安装目录的 bin 目录后,再执行这条命令,但更稳妥的是把该目录永久添加进 Path 环境变量。
如果脚本只有建表语句,那就先手动建一个库,再导入:
mysql -u root -p -e "CREATE DATABASE IF NOT EXISTS farmdb DEFAULT CHARSET utf8mb4;" mysql -u root -p farmdb < farm.sql注意farmdb要和后端application.yml里配置的数据库名一致,否则后面启动后端会直接报连不上数据库。导入完成后,用一条命令确认表是否齐全:
mysql -u root -p -e "USE farmdb; SHOW TABLES;"表名、字段名是否和后端 Mapper 里的 SQL 对得上,这里一眼就能看出来。接下来改数据源配置。打开application.yml(Spring Boot)或jdbc.properties(SSM),把数据库名、用户名、密码改成你的:
spring: datasource: url: jdbc:mysql://localhost:3306/farmdb?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: yourpasswordcharacterEncoding=utf8保证商品详情里的中文不乱码;serverTimezone=Asia/Shanghai是 MySQL 8.0 以上必须带的时区参数,不加的话 JDBC 驱动会抛The server time zone value is unrecognized。如果你的源码用的是 MySQL 5.7,serverTimezone=Asia/Shanghai仍然建议保留,但 JDBC 驱动版本用 5.1.x 没问题;如果是 MySQL 8.0,驱动必须升到 8.0.x,这点会在第 5 章坑二里展开。
2.3 小程序前端的导入与 AppID 配置
小程序端一般叫miniapp/、wechat/或mp/。打开微信开发者工具,点“导入项目”,目录选这个文件夹。先看一眼根目录:如果是原生小程序,会有app.json;如果根目录是pages.json和manifest.json,那说明这套前端是用 uniapp 开发后导出的,导入方式不同,需要先在 HBuilderX 里打开项目重新发行到微信开发者工具。这一点决定了你接下来修改代码的位置,值得在最开始确认。
AppID 处可以选“测试号”,本地联调没问题,但要做真机预览,还是建议注册一个小程序账号填正式 AppID,否则登录和部分 API 会受限。导入后看右上角“详情 → 本地设置”,把“不校验合法域名”勾上。这一步是本地开发必须的:微信官方要求线上wx.request的域名必须走 HTTPS 且在后台配置过合法域名,但本地联调时后端往往是http://localhost:8080,不勾选这个选项,所有请求都会被拦。等你要发布体验版时,再把勾去掉,并把后端改成 HTTPS。
在app.js或config.js里找到类似baseUrl: 'http://localhost:8080'的配置,改成你本机后端地址。如果后端在虚拟机或另一台电脑,就填局域网 IP 如http://192.168.1.100:8080,同时确保当前电脑能 ping 通。改完在开发者工具里重新编译,如果能看到第一个页面正常弹出,三件套准备就完成了。这一步做完不要急着往下走,先把首页截个图,后面排查问题时有对比依据。
3. 读懂核心链路:从微信登录到下单,代码里的订单与购物车逻辑
3.1 微信登录与手机号获取:code2Session 和手机号组件的调用
农产品商城这种电商小程序,登录流程几乎是固定的:前端调用wx.login()拿到临时 code,把 code 发给 Java 后端,后端拿着 code 调微信code2Session接口换取 openid,再用 openid 作为用户唯一标识去查库或建用户。后端 Controller 的简化写法:
@RestController @RequestMapping("/api/user") public class UserController { @Autowired private WechatService wechatService; @Autowired private UserService userService; @PostMapping("/login") public Result login(@RequestBody LoginDTO dto) { // 1. 用小程序传来的 code 去微信服务器换 openid String openid = wechatService.code2Session(dto.getCode()); // 2. 查库里是否已有这个 openid,没有就新建用户 User user = userService.findOrCreateByOpenid(openid); // 3. 生成业务 token 返回给前端,后续请求都带这个 token String token = JwtUtil.generate(user.getId(), user.getNickname()); return Result.ok().put("token", token).put("user", user); } }这段代码的关键不是“调微信接口”本身,而是 openid 不能直接暴露给前端当令牌用。普通用户只要拿到 openid,就能伪装成这个用户。常见做法是像这里一样,服务端用 openid 换出自己的 token,前端每次请求在 header 里带Authorization,后端通过拦截器校验 token。如果源码里没有 JWT 工具,而是直接把 openid 存到 session 里,也说得通,只是每次请求都要从 redis 或内存里取 session。毕设演示规模下两者都能跑通,但 JWT 在代码里更自包含,也更好讲。
很多毕设源码里还有一个“微信小程序登录获取手机号”的需求。注意实现方式已经从早期的按钮授权改成了“手机号快速验证组件”。前端写法大致是:
<button open-type="getPhoneNumber" bindgetphonenumber="onGetPhoneNumber">获取手机号</button>onGetPhoneNumber(e) { // 手机号快速验证组件返回的是动态 code,而不是手机号本身 if (e.detail.code) { wx.request({ url: baseUrl + '/api/user/phone', method: 'POST', data: { code: e.detail.code }, success: (res) => { this.setData({ phone: res.data.phone }); } }); } }手机号换取接口的调用权限,个人主体小程序没有,需要企业主体。如果你用的是个人测试号,这步会失败。答辩时我建议把“登录成功但没有手机号”做成正常流程:在“我的”页面允许用户手动填写手机号。演示时现场申请企业小程序不现实,这个保留方案能让你避开权限死穴。
3.2 商品列表与购物车:本地缓存还是服务端存储
商品列表是商城最基础的一页。多数源码的首页结构是:wx.request拉取/api/goods/list,后端从 MySQL 分页查询,前端在onReachBottom里追加下一页。这就是“页面列表加载更多”的实现点,也是答辩现场常被追问的“你做过性能优化吗”。写一个典型的分页商品接口:
@GetMapping("/list") public Result list(@RequestParam(defaultValue = "1") Integer page, @RequestParam(defaultValue = "10") Integer size, @RequestParam(required = false) String category) { PageHelper.startPage(page, size); List<Goods> goods = goodsMapper.selectByCategory(category); // PageHelper 会在 select 之后把总数塞进 PageInfo,分页 SQL 自动拼接 PageInfo<Goods> info = new PageInfo<>(goods); return Result.ok().put("rows", info.getList()).put("total", info.getTotal()); }参数说明:page是页码,从 1 开始;size是每页条数,滚动加载一般固定 10 或 20;category可空。用 PageHelper 的好处是不用手写LIMIT offset, size,它通过 MyBatis 拦截器在 SQL 后面自动拼接。如果源码里是手写分页,你要确认排序字段有没有索引,否则数据量稍大翻页会变慢甚至重复。
购物车是另一个容易踩坑的点。很多毕设把购物车纯放前端 storage,理由是“购物车不进数据库,减轻后端压力”。我不建议沿用这个设定,因为农产品商城有个特殊动作:下单前要改数量、选规格、算运费,数据一旦只存前端,换设备就丢,答辩也难解释。更好的做法是服务端也建一张 cart 表,前端购物车只做展示和交互,增删改都调接口。我一般会这样设计购物车接口:加购、改数量、删除、清空四个接口,每个接口都带上 userId,从 token 里解析而不是让前端传 userId,因为前端传的用户标识可以伪造。这个细节也是答辩加分项。
3.3 订单流程:库存扣减与状态机设计
订单是商城源码里逻辑最密的模块。正常流程是:用户从购物车勾选商品 → 后端生成订单(待支付)→ 微信支付回调成功 → 已支付 → 管理员发货 → 已发货 → 用户收货 → 已完成。中间还有取消订单、退款等分支。代码里一定会看到order_status字段,常见取值 0/1/2/3/4 分别代表待付款、待发货、待收货、已完成、已取消。如果源码里这些状态是散落在 if-else 里的裸数字,建议顺手抽成常量类:
public class OrderStatus { public static final Integer WAIT_PAY = 0; public static final Integer WAIT_SHIP = 1; public static final Integer WAIT_RECEIVE = 2; public static final Integer FINISHED = 3; public static final Integer CANCELLED = 4; }这样在判断逻辑里可读性更好,答辩时也能讲“我用常量管理状态枚举”。这一步改动成本极小,但对代码质量的展示收益很明显。
库存扣减是最需要小心的地方。合格源码会在生成订单时执行一条带条件的更新:
UPDATE goods SET stock = stock - #{num} WHERE id = #{id} AND stock >= #{num}用受影响的行数判断扣减是否成功:如果返回 0,说明库存不足,整个订单要回滚或提示。如果源码是“先 SELECT 查库存,再 UPDATE”,那就是典型的并发超卖写法,虽然毕设规模下很难复现问题,但老师追问时容易露怯。我建议把它改成这种带条件的更新语句。订单表设计上还要冗余一份“商品快照”,比如商品名、单价、数量直接存进订单明细表,而不是下单后只关联商品主键去查。因为商品表价格会变动,订单的历史价格不能被改掉。这个点你可以在回答“为什么订单明细要存冗余字段”时自然引出。
4. Java 后端与 MySQL 的交互设计:SSM 还是 Spring Boot,表结构怎么建
4.1 技术选型:为什么毕业设计里 SSM 和 Spring Boot 都很常见
打开源码的 pom.xml 或 lib 目录,先确认它是哪一代技术栈。如果是 SSM(Spring + SpringMVC + MyBatis),你要习惯 XML 配置时代:spring-mvc.xml里配<mvc:annotation-driven/>,web.xml里配 DispatcherServlet。如果是 Spring Boot,配置文件是application.yml,启动直接跑主类 main 方法,内嵌 Tomcat 已经替你解决了部署 web 容器的麻烦。
| 对比项 | SSM | Spring Boot |
|---|---|---|
| 配置方式 | XML 为主 | application.yml / properties |
| 部署产物 | war 包进外部 Tomcat | 内嵌 Tomcat,直接跑 jar |
| 启动方式 | IDEA 配 Tomcat Run Configuration | 直接运行主类 |
| 常见于毕业设计的年份 | 2019 以前较多 | 2020 以后较多 |
这两者在“农产品商城”这个题目里没有绝对优劣。SSM 的好处是老师容易看出你理解 MVC 分层,Controller-Service-Mapper 的调用链很清晰;Spring Boot 的好处是起步快,启动、打 jar、改配置都比 SSM 省事。拿到手的是 SSM 就继续用 SSM,别中途改成 Spring Boot,因为改造工程量远大于你想象;拿到手的是 Spring Boot 就安心用 Boot,也别为了“显得更底层”退回 SSM。毕业设计的评分点是“你能完整讲清楚一个请求如何从前端流到数据库”,而不是谁用了更新的框架。
流程先记住:小程序wx.request→ 后端 Controller → Service → Mapper → MySQL → 返回 JSON → 小程序setData渲染页面。答辩时能按代码位置指出这条链路,老师就相信这套源码是你跑通的。常见的一个误区是只背概念不指代码,比如讲“用了 RESTful 风格”却找不到一个对应的@PostMapping,这种回答最容易被追问到细节。
4.2 核心表结构设计:用户、商品、订单、购物车
表结构是整套源码里最像“农产品商城”的地方,也是答辩证时最容易被追问的地方。核心表至少三张:用户表、商品表、订单表。农产品和通用电商的差别主要体现在商品表字段,比如产地、规格(斤/箱)、预售状态。我用一个简化版商品表做例子:
CREATE TABLE `goods` ( `id` INT NOT NULL AUTO_INCREMENT, `name` VARCHAR(100) NOT NULL COMMENT '商品名称', `category_id` INT DEFAULT NULL COMMENT '分类ID', `price` DECIMAL(10,2) NOT NULL DEFAULT '0.00' COMMENT '单价', `origin` VARCHAR(100) DEFAULT NULL COMMENT '产地,如赣南脐橙', `stock` INT NOT NULL DEFAULT 0 COMMENT '库存数量', `image` VARCHAR(255) DEFAULT NULL COMMENT '商品主图URL', `detail` TEXT COMMENT '富文本详情', `status` TINYINT NOT NULL DEFAULT 1 COMMENT '1上架 0下架', `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `idx_category` (`category_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;解释几个参数选择:DECIMAL(10,2)而不是DOUBLE,因为价格需要精确数值,浮点类型累计计算会出现 0.1+0.2 不等于 0.3 的尴尬;utf8mb4而不是utf8,是为了能存用户昵称里的 emoji,utf8三字节在遇到 emoji 时直接落库失败;KEY idx_category给分类字段建索引,因为商城首页最常做的就是“按分类筛选商品”。加索引不是万能,但这个场景确实是高频查询,能明显减少扫描行数。
订单表有两个关键点。一是要冗余商品快照,下单那一刻把商品名、单价、数量存进订单明细,不后查商品表,因为商品价格改了之后订单历史价格不能被改动。二是要有order_no唯一字符串,给前端展示和管理员对账用,不要用自增主键当订单号,因为会暴露业务量并产生歧义。用户表也不只是 id、openid、昵称。农产品商城里建议加一个receive_address字段或独立的地址表,因为下单需要填收货地址,没有地址的用户在支付阶段会卡住。很多源码把地址存在前端 storage,会导致换手机就丢地址,这不是好设计。
4.3 MyBatis 的 XML 映射:联表查询与动态 SQL
MyBatis 模式下,Mapper 接口和 XML 对应关系是毕设源码里最常见的代码。很多新手看到<resultMap>就头疼,我先讲一个最实用的问题:商品列表要显示分类名,但goods表只有category_id,怎么联表查出来。一个常见的联表查询 SQL:
<select id="selectGoodsWithCategory" resultType="map"> SELECT g.id, g.name, g.price, g.origin, g.stock, g.image, c.name AS category_name FROM goods g LEFT JOIN category c ON g.category_id = c.id WHERE g.status = 1 <if test="categoryId != null"> AND g.category_id = #{categoryId} </if> ORDER BY g.create_time DESC LIMIT #{offset}, #{size} </select>逻辑说明:LEFT JOIN保证即使某商品没分类也能查出来,分类名是 NULL 而不是把商品丢掉;<if test="categoryId != null">是 MyBatis 动态 SQL,让你用同一个 SQL 同时处理“全部商品”和“分类筛选”两个场景;LIMIT #{offset}, #{size}是手动分页,如果你用 PageHelper,这一句不用写,但手动版更直观,答辩时更好解释。
改这个 SQL 时注意一个参数细节:#{}是预编译占位符,防止 SQL 注入;${}是字符串拼接,只能用于表名、排序字段这类无法占位的地方。商城源码里如果出现直接把用户输入拼进 SQL 的地方,一定要改成#{}。如果源码里用的是注解 SQL(@Select),个人意见是能不改就不改。注解方式在简单查询时很清爽,但一旦需求变成动态多条件查询,注解写起来远不如 XML 可读。你在答辩时可以主动说一句“我把多条件查询放在 XML 里,是为了方便维护”,这是真实的工程偏好,能加分。
5. 避坑与排查:拿到这套源码后最容易翻车的 5 个地方
拿到源码包之后,最糟的状态不是启动失败,而是被一连串报错耗掉一整天耐心。我把接触这类毕设源码时最常碰到的 5 个坑按频率排了一下,前两个基本每个项目都会遇到,后三个取决于源码作者的习惯和你的演示场景。按现象、原因、解决的顺序写,方便你对照着排查。
5.1 坑一:小程序请求后端失败,控制台报 ERR_NAME_NOT_RESOLVED
现象:点击登录或加载商品列表时,微信开发者工具控制台报ERR_NAME_NOT_RESOLVED,一看就是找不到域名或主机。
原因:小程序端config.js里配的还是源码作者电脑上的地址,比如http://192.168.1.5:8080,换到你电脑上自然解析不了。
解决:把baseUrl改成http://127.0.0.1:8080(后端在本机时)或本机局域网 IP。改完在“详情 → 本地设置”里勾选“不校验合法域名”,让 request 能发出去。如果后端在另外一台电脑,记得给后端所在机器的防火墙放行 8080 端口,如果是 Windows 系统还要确认当前网络配置为“专用网络”,否则防火墙默认会拦掉入站请求。改完之后在 Network 面板重新观察请求,能看到状态码从-100变成正常值就说明通了。
5.2 坑二:MySQL 8.0 的认证插件导致后端启动报 Access denied
现象:后端日志出现Access denied for user 'root'@'localhost',但你确定密码没有输错。
原因:MySQL 8.0 默认用caching_sha2_password认证插件,而老毕设源码里的 JDBC 驱动(5.1.x)只认mysql_native_password插件,两边对不上就报认证失败。
解决:优先把 pom.xml 里的mysql-connector-java版本升到 8.0.x:
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.33</version> </dependency>改完后重新执行mvn clean install。如果你不想动依赖版本,也可以在 MySQL 里把 root 改成旧插件:
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '你的密码'; FLUSH PRIVILEGES;我建议优先换驱动,因为改 root 认证方式会降低数据库安全性,而且新项目早晚要换新驱动,不如一步到位。换完驱动后如果还报错,检查一下application.yml里url是否带了serverTimezone=Asia/Shanghai,这个参数和 MySQL 8.0 驱动是配套关系,缺了会有新的时间报错。
5.3 坑三:真机上页面顶部和胶囊按钮重叠,自定义导航栏高度不对
现象:开发者工具里一切正常,真机预览时,自定义导航栏的标题和微信的胶囊按钮叠在一起,或者顶部多出一截黑条。
原因:源码用了navigationStyle: custom自定义导航栏,页面默认从屏幕顶部渲染,不同机型的状态栏高度和胶囊按钮位置不一样。这里就涉及“微信小程序顶部导航栏高度”的适配:如果不动态计算,只按 iPhone 的固定值写,安卓机型大概率会翻车。
解决:在app.js的onLaunch里读取胶囊位置:
const info = wx.getWindowInfo(); const capsule = wx.getMenuButtonBoundingClientRect(); this.globalData.statusBarHeight = info.statusBarHeight; // 导航栏高度 = 胶囊顶部到状态栏的距离 * 2 + 胶囊本身高度 this.globalData.navBarHeight = (capsule.top - info.statusBarHeight) * 2 + capsule.height;然后在自定义导航栏组件里用这个高度做padding-top和标题行高。注意wx.getWindowInfo()是新版 API,老代码里如果用的是wx.getSystemInfoSync(),会有少量弃用提示,功能本身还能用,但新项目建议顺手换成新版。改完后在开发者工具里切换几种机型模拟器验证,再拿一台安卓真机确认,这个坑基本就稳了。
5.4 坑四:商品图片加载不出来,页面一片灰块
现象:首页商品卡片能显示文字,图片全是灰块,Network 面板里图片请求返回 404。
原因:绝大多数毕设源码里,商品图片 URL 是相对路径,比如/upload/goods/xxx.jpg,而后端没有把 upload 目录映射成静态资源,或者根本没有 upload 目录。
解决:在 Spring Boot 的application.yml里加一行静态资源映射:
spring: web: resources: static-locations: file:${user.dir}/upload/,classpath:/static/注意 YAML 里逗号后的空格不能省。配好后重启后端,把图片文件放到项目根目录的 upload 文件夹里。如果源码里图片是外链(http://xxx.com/img/1.jpg),大概率作者随手写了占位链接,你要么统一换成本地图片,要么用一张公网可访问的占位图顶着,千万别在答辩现场等一个不存在的图加载。判断是哪种情况有个技巧:在浏览器里直接访问图片 URL,能打开就是外链,打不开就是路径映射问题。
5.5 坑五:支付调不起来,点击支付直接报 fail
现象:模拟器里点“微信支付”按钮,回调返回fail,或者页面提示“当前微信版本不支持”。
原因:微信支付必须用真实的小程序 AppID、商户号,并且要在小程序后台开通微信支付。毕设源码里往往只留了支付接口的壳,没有真实商户配置。个人主体的小程序也无法申请微信支付。
解决:毕设演示阶段不建议硬接真实支付。常见做法是把支付按钮改成“模拟支付”,前端确认订单后直接向后端发“已支付”回调:
confirmOrder() { wx.showModal({ title: '模拟支付', content: '毕业设计环境下使用模拟支付,是否确认支付?', success: (res) => { if (res.confirm) { wx.request({ url: baseUrl + '/api/order/pay', method: 'POST', data: { orderId: this.data.orderId }, success: () => { wx.redirectTo({ url: '/pages/order/detail?id=' + this.data.orderId }); } }); } } }); }这个方案的重点是“流程完整”:确认订单 → 模拟支付 → 改状态 → 显示订单详情。答辩时你可以主动说明“如果要上线,把模拟支付替换成真实微信支付即可”,这是诚实且专业的说法。处理这个问题时也顺带检查一下后端/api/order/pay接口,确认它有没有把订单状态从WAIT_PAY改成WAIT_SHIP,没有的话模拟完支付订单仍停留在待付款,演示会穿帮。
6. 把毕业设计变成能演示的作品:数据填充、模拟支付与答辩前验证
6.1 用 SQL 脚本造一批像样的农产品数据
农产品商城最怕演示时商品列表空荡荡。我一般会写一个demo_data.sql,插入 10 到 20 个商品,覆盖水果、蔬菜、粮油几个分类,价格带小数,库存设几档。图片可以先不填或用同一个占位图,不要让图片问题打断演示节奏。数据里最好有几条有明显特色的商品名,比如“赣南脐橙 5 斤装”“五常大米 10 斤装”,这样演示时老师一眼就能看出这是一个农产品主题的商城,而不是随便找个电商模板改的。
6.2 演示前把整条订单链路跑通一遍
如果源码里没有模拟支付入口,就按 5.5 的代码在订单确认页加一个按钮。演示时完整走一遍“添加购物车 → 生成订单 → 模拟支付 → 管理员发货 → 确认收货”,每一步都能讲出对应表里的状态值变化。这比反复截图更有说服力,因为你操作时老师能看到页面和数据在变。发货动作如果在后端没有管理端接口,可以直接改数据库订单状态,但更推荐在后端加一个简单的发货接口,哪怕是UPDATE order SET status=1 WHERE id=?这种几十行的接口,也能让整套逻辑闭环。
6.3 答辩前必做的三项验证
一、图片验证:列表页、详情页、购物车里的图在真机上都能加载。二、登录验证:换一部手机扫码登录,确认用户表里新增了 openid,购物车数据不丢。三、接口验证:用 Postman 请求/api/goods/list,确认返回 JSON 字段和小程序前端取值的字段完全一致,大小写不一致是毕设里最常见的低级 bug。这三个验证做完,再往后翻一遍源码里几个关键页面的onLoad,确保没有遗留的 console 调试代码或写死的临时数据。
我自己当年跑这类源码时,最大的教训就是想当然地认为“源码包都给了,肯定能跑”,结果把时间花在到处找环境上。后来我养成一个习惯:拿到源码先读一遍 README 和数据库脚本,再决定先装哪个环境,省掉很多无用功。这篇写到的坑大多是我和身边同学真实踩过的,如果你按着章节顺序做一遍,应该能顺利跑起来并讲清楚。希望帮到你。
本文还有配套的精品资源,点击获取