简介:这套停车场微信小程序毕业设计源码面向计算机专业完成毕业设计或课程设计的在校学生,采用 Java + 微信小程序 + MySQL 架构,完整实现管理员、商家、用户三个角色业务闭环。管理员端覆盖个人中心、车主管理、商家管理、停车场信息管理、预约停车管理、取消预约管理、进场停车管理、商场收费管理、留言板管理及系统管理等模块;商家可在线提交停车位信息,用户则能完成预约、进场与缴费等操作,对应真实停车场运营场景。资源包共 1242 个文件,压缩后约 15.84MB。java 文件为后端逻辑,vue/js/wxml/wxss 构成小程序前端交互,sql 为数据库初始化脚本,png/svg/jpg 为界面素材与图标,另含 Maven 配置、部署脚本等工程文件,目录完整,便于直接导入 IDE 调试运行。环境基于 JDK1.8、MySQL5.7、Tomcat7 等常用配置,降低搭建门槛。已有 50 人学习下载。对需要快速获取完整可运行毕设方案、理解前后端联调与典型管理流程的学生来说,这份源码可直接复用。
1. 停车场微信小程序毕设源码包里到底装了什么
把压缩包解压之后最先看到的东西,一般不是代码,而是“java + 小程序 + mysql + LW”四个词背后的完整分工:小程序负责用户手机上的操作界面,Java 后端负责业务逻辑和接口,MySQL 存车位、订单、用户这些关系型数据,LW 是配套的毕业论文文档。很多人拿这类源码包是为了毕业设计,最怕的不是代码看不明白,而是拿到手却不知道怎么启动、答辩时说不清项目怎么跑起来的。这个课题能解决的,就是停车场景里“查车位—预约—计时计费—缴费”闭环,加上一个随时能演示的成品;适合打算用现成技术栈快速搭出可运行系统、再把核心业务改成自己想法的学生。
2. 从源码包看完整技术栈:前端页面、后端接口和数据库是这样分工的
2.1 停车场的业务主线:谁在用、用完要看到什么
先明确业务。停车场小程序不是把停车场的网页搬到手机里,而是解决三件事:车主出门前先看场地余位;到达前把车位预约好,避免到了没位;出场时费用清楚,不用排队扫码。
围绕这三件事,最基础的角色是两个:车主用户和管理员。车主端核心流程是“查看停车场→选择车位→预约→入场→计费→支付→生成订单”,管理员端核心流程是“维护车位状态→查看订单→修改计费规则”。毕设判断题能不能拿到高分,看的就是这两条线是否完整闭环,而不是页面用了几种动画效果。
拿到源码包之后,先不急着启动,跟着目录结构走一遍,心里就有底了。需要说明的是,这个项目用的是微信小程序原生开发,而不是 uniapp 跨端方案。原生方式写出来的页面和接口调用关系更直观,论文里讲“小程序生命周期”“wx.request 请求链路”都有现成素材,这也是这类毕设选题一直有人选的原因。
2.2 小程序前端源码目录:页面放哪、工具类放哪
小程序端一般是一个独立的 miniprogram/ 目录,下面按页面分组。打开之后常见的页面结构是这样:
miniprogram/ ├── pages/ │ ├── index/ // 首页停车场列表和搜索 │ ├── detail/ // 停车场详情、车位选择 │ ├── booking/ // 预约确认页 │ ├── order/ // 订单列表和支付 │ ├── user/ // 个人中心、车辆管理 │ └── admin/ // 管理员操作入口(如果有) ├── components/ // 可复用组件 ├── utils/ │ ├── request.js // wx.request 封装 │ └── config.js // 全局配置 ├── app.js ├── app.json └── app.wxss这个结构里最值得先看的是 utils/request.js,因为后面所有的接口调用都集中在它身上。app.json 决定小程序启动时第一个加载哪个页面、底部 tab 长什么样,如果你改了页面文件路径,这边漏掉注册会导致打开就是空白页。这里放目录结构只是为了让你对压缩包内容心中有数,不是要立刻改东西;真正的配置改动在第三章。
2.3 后端 Java 工程:Controller 管接口、Service 管业务、Mapper 管数据库
Java 后端的包结构也基本统一。它并不神秘,核心就是三层:
src/main/java/com/parking/ ├── controller/ // 接口入口,接收小程序来的 HTTP 请求 ├── service/ // 业务逻辑:预约、计费、订单流转 ├── mapper/ // 操作 MySQL 的持久层 ├── entity/ // 表对应的实体类 └── config/ // 拦截器、跨域、微信配置 src/main/resources/ ├── application.yml // 数据库连接、端口配置 └── mapper/ // 放 SQL 的 XML 文件三层拆开的直接好处是答辩时好讲:controller 不写业务、mapper 不写 if else,遇到“要把全部空闲车位查出来”这种需求,你能立刻说出改动落在哪一层。这也是为什么毕设源码的主流写法都选这种分层,而不是把代码全堆在一个类里。后端用 Java 而不是 Node 或 Python,最大的优势是找参考代码容易、踩坑资料多,IDE 提示也成熟,新手不容易在环境上卡死。
2.4 后端接口表:小程序发什么请求、后端回什么数据
毕业设计答辩时,老师大概率会问“小程序是怎么拿到数据的”,也就是说你得把接口讲清楚。下面这张表是停车场项目的基础 REST 接口,按用户端和管理端两条线列出:
| 接口路径 | 方法 | 作用 | 说明 |
|---|---|---|---|
| /api/parking/list | GET | 获取停车场列表 | 支持按经纬度排序、按关键词过滤 |
| /api/parking/detail | GET | 获取某个停车场详情及剩余车位 | 参数为 parkingId |
| /api/reservation/create | POST | 创建车位预约 | 预约时锁定车位,防止并发 |
| /api/reservation/cancel | POST | 取消预约 | 释放车位状态 |
| /api/order/pay | POST | 模拟支付回调 | 真实微信支付要商户号,毕设常见做法是走演示支付 |
| /api/user/vehicles | GET/POST | 车辆信息管理 | 用户换车时编辑车牌 |
参数说明:上表中的参数统一走 query string 或 JSON body,后端用 @RequestParam 或 @RequestBody 接收;返回体一般统一为 { code, message, data }。如果你拿到手的源码返回体不是这种格式,先看它的 code 定义(比如 20000 为成功),别把别的项目的习惯硬套上来。多提一句:很多源码的接口前面还会有 /api/v1 这样的前缀,属于常见做法,不是错误。改接口路径时,记得同步改前端 request.js 里的拼接逻辑,否则就会出现“后端明明通了,前端怎么都拿不到数据”。
2.5 数据库表设计:从停车场到订单的六张核心表
数据库是 MySQL,表数量在不同版本的源码里不太一样,但核心表基本离不开这几张:停车场表、车位表、用户表、预约表、订单表、计费规则表。下面的 SQL 是核心字段的精简版,导入时再导入完整 sql 文件,这里重点看表之间的关系:
CREATE TABLE parking_lot ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50) NOT NULL COMMENT '停车场名称', address VARCHAR(100), total_spaces INT DEFAULT 100, charge_rule_id INT ); CREATE TABLE parking_space ( id INT PRIMARY KEY AUTO_INCREMENT, lot_id INT NOT NULL, space_no VARCHAR(20) COMMENT '车位编号,如 A-01', status TINYINT DEFAULT 0 COMMENT '0空闲 1预约 2占用', version INT DEFAULT 0 COMMENT '乐观锁版本号' ); CREATE TABLE parking_reservation ( id INT PRIMARY KEY AUTO_INCREMENT, user_id INT NOT NULL, space_id INT NOT NULL, start_time DATETIME, end_time DATETIME, status TINYINT COMMENT '1进行中 2已完成 3已取消' ); CREATE TABLE parking_order ( id INT PRIMARY KEY AUTO_INCREMENT, reservation_id INT, user_id INT, amount DECIMAL(10,2), status TINYINT COMMENT '0待支付 1已支付 2已退款', create_time DATETIME );逻辑说明:车位表里的 status 就是预约和占用状态的标尺;订单表的 amount 来自计费引擎,不是用户自己填的;预约表和订单表分开存的原因是业务状态不同——预约可能取消,订单一旦支付就涉及金额。参数说明:version 字段是给并发控制用的,后面第四章会讲它的具体用法;DECIMAL(10,2) 存金额而不是 float,是因为金额用浮点结算会出现 0.1 + 0.2 不等于 0.3 的精度问题。不同源码包在建表语句上会有差别,有的把计费规则直接写在停车场表里,跑通优先,结构上不用强行统一。
3. 本地跑通源码的三步:数据库导入、后端启动、开发者工具预览
3.1 环境清单:JDK 1.8、MySQL 5.7 以上、微信开发者工具稳定版
先对环境摸底。这类源码包的 Java 后端几乎都跑在 JDK 1.8 上,JDK 11 以上反而可能出现 Lombok 版本不兼容的问题;MySQL 用 5.7 或 8.0 都行,但要注意驱动版本和时区配置;Maven 3.6 以上,源码包里如果没有 mvnw,就自己装一个。微信开发者工具用稳定版即可,不需要追最新。
AppID 这一步不用纠结。毕设小程序没有企业主体,在开发者工具里选“测试号”,或者用自己的小程序 AppID 都能把项目跑起来;只是微信登录、微信支付这类接口要正式 AppID 加企业资质才完整。先让项目跑起来,再来处理这些。
3.2 导入数据库:source 命令和两张核心脚本
大部分源码包会在根目录放 sql/ 文件夹,里面可能有 init.sql 和 data.sql。常见的做法是建立一个专门的库,再按顺序导入:
mysql -uroot -p # 登录后执行: CREATE DATABASE parking DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE parking; SOURCE /path/to/sql/init.sql; SOURCE /path/to/sql/data.sql;逻辑说明:SOURCE 是 mysql 客户端内的命令,/path/to 要写成绝对路径;init.sql 一般是建表语句,data.sql 是演示数据,后者非常重要,因为很多功能要有一批初始车位和订单才能演示。参数说明:字符集用 utf8mb4,因为车位备注、用户昵称可能带 emoji;如果只用默认 utf8,小程序里用户昵称里存的 emoji 会变成问号。导入完成后,用 SHOW TABLES; 数一下表数量,如果表个数和源码注释里对不上,说明导入的脚本顺序或数据库选错了。
3.3 修改后端配置并启动:application.yml 的三个必改项
后端工程导入 IDEA 后,第一件事不是点运行,而是打开 application.yml 确认下面四项:
server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/parking?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai username: root password: 123456 mybatis: mapper-locations: classpath:mapper/*.xml configuration: map-underscore-to-camel-case: true逐项说明:port 是小程序之后要请求的端口;url 里关键的三个参数是 useSSL=false(本地调试不要加密握手)、serverTimezone=Asia/Shanghai(防止结算时间差 8 小时)、characterEncoding=utf8(保证中文不乱码)。username 和 password 要和本机一致,密码不是源码默认的 123456 就改成自己的。map-underscore-to-camel-case 打开后,数据库字段 user_id 才能自动映射到实体类 userId,关闭了会出现所有关联字段都为 null 的灵异问题。
启动方式看包里有没有 mvnw:
# 如果用 IDEA 自带 maven:直接运行 Application 主类里的 main 方法即可 mvn spring-boot:run -Dspring-boot.run.profiles=dev本地第一次启动要下载大量依赖,常见做法是把 Maven 仓库切换到国内镜像(阿里云或华为云),依赖下载需要网络状态正常才能完成。启动成功后,控制台会出现 Started XXXXApplication 一类的日志,再去浏览器访问 http://localhost:8080/api/parking/list 试一下,看到 JSON 数据就代表后端通了。
3.4 开发者工具导入小程序前端:baseURL 是唯一的硬伤区
后端通之后,打开微信开发者工具,选择“导入项目”,目录选 miniprogram/,AppID 暂时选测试号。导入完成后立刻去 utils/config.js 这类文件里找 baseURL:
// config.js —— 小程序端公共配置 module.exports = { // 本地联调:填你电脑的局域网 IP,不要用 localhost baseURL: 'http://192.168.1.100:8080', requestTimeout: 10000 }注意:这里的 baseURL 不要写 localhost。小程序在真机预览时,手机访问 localhost 访问的是手机自己,永远连不到电脑;要写电脑的局域网 IP(Windows 用 ipconfig,Mac 用 ifconfig 查看)。同时手机和电脑要连同一个 WiFi。开发者工具菜单“详情 → 本地设置”里勾选“不校验合法域名”,否则工具会拦截 http 请求,报 url not in domain list,这是本地调试的正常动作,不影响源码性质。
小程序端的请求封装一般长这样:
// utils/request.js const config = require('./config.js') function request(path, method, data) { return new Promise((resolve, reject) => { wx.request({ url: config.baseURL + path, method: method, data: data, timeout: config.requestTimeout, success: res => { if (res.data && res.data.code === 200) resolve(res.data.data) else reject(new Error(res.data.message || '请求失败')) }, fail: reject }) }) } module.exports = { request }逻辑说明:这个封装把 baseURL、超时和统一返回码处理都收在同一个文件里,后面所有页面只需要调 request('/api/parking/list', 'GET', {}),不用每个页面重复设置 url 和处理错误。参数说明:code === 200 是约定后端成功标识,不同源码约定可能不同(有的是 0 或 20000),对照后端 Controller 返回体的字段改一处即可。如果你想把停车场列表缓存起来避免每次进入都请求,可以在 success 分支里写 wx.setStorageSync('parking_list', res.data.data),并记录缓存时间,下次进入先读缓存再后台刷新——这就是微信小程序设置缓存时间的常见姿势。
前端导入后,如果能打开首页、看到停车场列表数据,说明全链路已经通了。到这一步,整个项目其实就是“能跑”了,剩下的都是业务细节问题。
4. 核心模块拆解与代码复现:车位预约、计时计费与订单闭环
4.1 车位状态流转:一张状态图解决预约、入场、结算的先后
停车场的核心业务其实是一个有限状态机。车位经历空闲 → 预约 → 占用 → 空闲这四个状态,中间任何一个环节出问题,都会引发“车没停进去却扣钱了”这类矛盾。状态流转规则用文字表示就是这样:
- FREE(空闲):任何人都可预约;
- RESERVED(已预约):系统保留车位一段时间(比如 15 分钟的入场缓冲),其他人不可再约;
- OCCUPIED(已占用):用户实际入场,开始计费;
- 结算后回到 FREE,同时生成一笔订单。
关键点不是状态的定义,而是状态变更的原子性——预约和入场时,后端必须先验证当前状态,再更新状态,不能“先查一下再更新”。否则两个人同时看中最后一个车位,可能都看到 FREE,然后都成功。规避办法就是带状态条件的 UPDATE,让数据库来判断状态是否合法。
4.2 用事务和条件更新解决并发抢位
预约车位的常见实现是后端写一个 service 方法,里面先执行下面的 UPDATE,再根据受影响行数决定是否预约成功:
@Override @Transactional public ReservationResult reserve(Integer userId, Integer spaceId) { // 条件更新:只有 status = 0 的空闲车位才能被占为预约 int rows = parkingSpaceMapper.updateStatusIfFree(spaceId); if (rows == 0) { return ReservationResult.fail("车位已被预约,请选择其他车位"); } // 更新成功后,再插入预约记录 Reservation reservation = new Reservation(); reservation.setUserId(userId); reservation.setSpaceId(spaceId); reservation.setStartTime(new Date()); reservation.setEndTime(DateUtils.addMinutes(new Date(), 15)); reservation.setStatus(1); reservationMapper.insert(reservation); return ReservationResult.success(reservation); }对应的 Mapper SQL 是这样:
UPDATE parking_space SET status = 1, version = version + 1 WHERE id = #{spaceId} AND status = 0逻辑说明:updateStatusIfFree 的返回行数只有 1 和 0 两种情况;为 0 就说明这一瞬间有人已经抢先把状态改掉了,直接返回失败,不需要再做一次 SELECT 去验证。@Transactional 保证“扣状态 + 插预约”要么一起成功、要么一起回滚,不会出现车位变成已预约但预约记录没写进去的中间状态。参数说明:version 乐观锁字段的作用是给并发冲突留一个检测线索,日志里能看出是谁先抢到了锁,去掉也能工作,但排查难度会显著提高。
4.3 计费引擎:时长怎么算、跨天怎么算、封顶怎么算
计费是最容易被演示翻车的地方,因为手工算一遍就发现金额对不上。一个稳定的计费引擎,核心是先把“计费时长”算准确,再套费率。下面是一段足够应付毕设答辩的 Java 计费逻辑:
public BigDecimal calculateFee(Date entryTime, Date exitTime, ChargeRule rule) { long minutes = (exitTime.getTime() - entryTime.getTime()) / (1000 * 60); if (minutes < 0) { throw new IllegalArgumentException("出场时间不能早于入场时间"); } // 入场后 freeMinutes 分钟内免费 if (minutes <= rule.getFreeMinutes()) { return BigDecimal.ZERO; } // 不满一小时按一小时算,这是停车场常见做法 BigDecimal hours = BigDecimal.valueOf(minutes) .divide(BigDecimal.valueOf(60), 0, RoundingMode.CEILING); BigDecimal fee = hours.multiply(rule.getPerHourFee()); // 24 小时封顶,避免长时间停放费用高得离谱 if (fee.compareTo(rule.getCapPerDay()) > 0) { return rule.getCapPerDay(); } return fee; }逻辑说明:分钟差除以 1000 乘 60 得到分钟数;向上取整是为了让 61 分钟按 2 小时计费,这是行业惯例,答辩老师能接受;免费分钟、每小时费率、封顶金额全部来自 rule 对象,而不是写死的常量。参数说明:RoundingMode.CEILING 是向上取整;如果做跨天停车,这个函数只需把 24 小时内的费用相加即可,不需要额外处理“跨天”概念,因为费用只跟时长有关。
这块最容易被忽视的点是“入场时间到底用什么”。正确做法是以后端收到入场请求的时间为准,不要信任客户端传来的时间,否则用户把手机时间改一下就能“逃费”。
4.4 小程序端预约页:WXML 结构加上预约按钮的 JS
预约确认页的界面不用做得很复杂,核心就三块:车位信息、预计费用、预约按钮。WXML 片段长这样:
<view class="space-info"> <view class="parking-name">{{lotName}}</view> <view class="space-no">车位 {{selectedSpace.spaceNo}}</view> <view class="price">预计费用:¥{{estimatedFee}}</view> </view> <button class="reserve-btn" loading="{{loading}}" bindtap="handleReserve">立即预约</button>配套的 JS 逻辑:
async handleReserve() { const app = getApp(); this.setData({ loading: true }); try { const res = await request('/api/reservation/create', 'POST', { userId: app.globalData.userInfo.id, spaceId: this.data.selectedSpace.id }); wx.showToast({ title: '预约成功', icon: 'success' }); // 跳转到订单页,准备演示支付 wx.navigateTo({ url: `/pages/order/index?reservationId=${res.id}` }); } catch (e) { wx.showToast({ title: e.message || '预约失败', icon: 'none' }); } finally { this.setData({ loading: false }); } }逻辑说明:selectedSpace 在进入页面时已经通过停车场详情接口拿到,用户在页面上选中当前空闲车位,再把 userId 和 spaceId 传给后端。setData 的 loading 可以防止用户重复点击连发多个请求。参数说明:回调顺序是 onLoad 拉详情,点击后先发网络请求再跳转,这套交互顺序看似基础,但也是毕设项目里被高频追问的地方,建议答辩时强调“点击按钮到跳订单页之间发了一次真的网络请求”,而不是本地跳转。
4.5 支付环节的务实取舍:挡住毕业设计的是微信支付资质
毕设项目里最容易被卡住的功能不是预约,是微信支付。个人主体小程序拿不到微信支付商户号,企业主体的申请也需要营业执照和对公账户。源码里即使有真实的支付类代码,也多半是注释掉或预留了接口,这正是源码能跑通、但答辩演示要“演示支付”的原因。
常见做法是做一个“演示支付”按钮,前端模拟调起收银台动画,后端直接把订单状态改为已支付:
@PostMapping("/api/order/pay") public Result pay(@RequestBody PayRequest req) { // 演示支付:临时改成已支付;真实微信支付时应替换为统一下单接口 Order order = orderMapper.selectById(req.getOrderId()); order.setStatus(1); order.setPayTime(new Date()); orderMapper.updateById(order); return Result.success(order); }逻辑说明:这一段保留了支付链路的“状态闭环”,没有真实资金往来,演示效果和真实体验差别不大,关键是让答辩时“预约未支付”和“已支付”两个状态都能展示。参数说明:真实接入时只需把这个 Controller 方法的内部换成微信支付的统一下单与回调,订单 service 层的状态流转完全不用动,这也就是“预留接口”的价值。
5. 本地跑通的避坑清单:真机请求、时区、并发抢位等五个高频翻车点
5.1 真机预览连不上后端:ERR_CONNECTION_REFUSED
现象:开发者工具里接口正常,手机上一打开就报 request:fail,或者真机调试卡在加载白屏。 原因:最典型的有三个——后端进程没有监听 0.0.0.0,只监听了 127.0.0.1;手机和电脑不在同一局域网;开发者工具勾选了域名校验但后端不是 HTTPS。 解决:先用 ipconfig 或 ifconfig 拿到电脑局域网 IP,确认 application.yml 里没把地址改回 127.0.0.1;再把小程序 config.js 的 baseURL 改成这个 IP;最后手机连同一个 WiFi,在开发者工具里勾选“不校验合法域名”。做这串操作之前先测试一下手机能否在浏览器里打开 http://192.168.x.x:8080/api/parking/list,浏览器能开,小程序就能通;浏览器都打不开,问题在电脑网络或防火墙,不在小程序。
5.2 MySQL 报 Communications link failure,或账单时间差 8 小时
现象:后端一启动就报数据库连接失败,控制台提示 Communications link failure;或者没报错,但账单时间比实际时间晚了 8 小时。 原因:MySQL 8.x 的默认认证插件是 caching_sha2_password,老版 JDBC 驱动不认;MySQL 5.7 时区设置也可能是系统的 UTC,导致 Java 侧 new Date() 正常、库里的 DATETIME 却差一截。 解决:JDBC 驱动用 mysql-connector-java 8.0.30 以上的版本,URL 里固定带上 serverTimezone=Asia/Shanghai 和 useSSL=false。如果启动还报认证问题,在 MySQL 里执行 ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '你的密码'; 再刷新权限。这两个改动做完,连接和时区两个坑一起消掉。
5.3 两个用户同时预约最后剩下的车位,结果都提示成功
现象:演示时故意让两台手机同时点预约,系统给两个人都发了成功消息;数据库里预约记录两条,车位状态却只有一个。 原因:预约逻辑写成了先 SELECT 再 UPDATE,两个请求都查到 status = 0,然后各自 UPDATE 成功,根本没有做条件更新。 解决:把预约的 UPDATE 改成带状态条件的原子语句,见 4.2 小节;同时给车辆入场也做同样的处理。顺带一提,如果用的是 MyBatis 的 XML,写完 SQL 把受影响行数 return 到 service,用 int 去判断等于 1 还是等于 0,这个语义就是解决这个问题的唯一标准,别在 SQL 后面再拼一段业务判断。
5.4 小程序页面白屏但后端没报错:app.json 注册和 rpx 布局
现象:某个页面在开发者工具里能打开,真机预览却是白屏;或者底部按钮被刘海、手势区域挡住,布局错位。 原因:新增的页面没有在 app.json 的 pages 数组里登记,工具不报错也不渲染;布局用了 100vh 这类 CSS 单位,真机和工具的视口逻辑不一致。 解决:去 app.json 的 pages 数组里补上 pages/xxx/index;页面布局的主单位用 rpx,宽度基准是 750rpx,底部固定按钮要留出约 100rpx 的安全区域。改完重新编译,白屏和遮挡通常一起消失。这个点看似小,但答辩现场最容易出丑。
5.5 演示时账单金额和人工计算对不上
现象:停了一小时多一点,页面显示费用是两小时的钱;或者免费时段结束后立刻收首小时费用,现场算出来和展示的不一致。 原因:三类情况最常见——计费时长用了前端传来的入场时间(可被手机本地时间影响);计费用了浮点乘法;免费时长、首小时高价的规则没有进计费引擎。 解决:一切入场时间以后端收到请求的当前时间为准,客户端只传车位 ID 和用户 ID;金额用 BigDecimal 计算;把全部费率从常量挪到 charge_rule 表,让管理员能配置。演示前用手机计时器走一遍“免费时段边界”“超一小时整点”两个用例,能提前暴露出绝大多数费率 bug。
6. 答辩之前做一次自我验收:接口自测、参数化计费和运营端的小技巧
6.1 用一条 curl 命令做完核心链路自测
进答辩现场之前,先把后端启动,在小程序里完整走一遍“登录 → 查车位 → 预约 → 入场 → 结算 → 支付”,再补一条命令行验证接口层的正确性:
curl -X POST http://localhost:8080/api/reservation/create \ -H "Content-Type: application/json" \ -d '{"userId":1,"spaceId":3}'命令能返回预约成功 JSON,就证明数据库连接、接口路由、事务和状态流转都是通的,答辩现场即使演示网络出问题,也能用这条命令兜底。日常自测我用 Postman,但答辩只带这条 curl,因为简单、无图形依赖。
6.2 把计费规则参数化,现场演示加价最有说服力
源码如果自带演示数据,计费规则大概率是写在代码常量里的。答辩前我通常会把费率挪到 charge_rule 表,并在管理员端加两个输入框:首小时价格、每小时价格,保存后立即作用于后续订单。现场演示时,把首小时从 3 改成 5,再走一次预约流程,页面上价格跟着变——这种“代码改动可直接观察到”的验证方式,比讲十分钟类图更有说服力。
6.3 留一个“重置车位”的后台入口当演示后悔药
演示永远会被打断。最常见的意外是演示途中预约了车位但没走完结算,导致车位的状态停在“已预约”上,后面所有流程没法继续。我的习惯是给管理端加一个“重置状态”按钮,对车位表直接执行 UPDATE 把状态改回空闲。它不展示技术含量,但它是演示翻车时唯一的后悔药。答辩不是生产上线,让现场能连续走完流程才是第一优先级。
计费、预约、支付三块能串成完整闭环,再有一个管理员重置入口,这类毕设源码在答辩现场就基本能撑住。希望这些从实操里挤出来的内容能帮到你,先把环境跑通,再谈加功能,这是最稳妥的路。
本文还有配套的精品资源,点击获取