
简介共享经济模式在缓解城市停车难中具有重要作用其底层逻辑是将闲置车位的时间资源与临时需求进行匹配。本文从时间片模型和数据库设计出发分析如何利用Spring Boot构建高可用后端并通过乐观锁机制解决同一时段被重复预约的并发问题。结合微信小程序原生开发、地图选点、订单状态机等关键技术完整呈现一个可运行的停车位共享预约平台。该方案不仅适用于毕业设计场景也能为共享类小程序的产品设计提供工程参考。 去年秋天陪一个朋友在市中心找车位绕着那栋写字楼转了二十多分钟最后停到两公里外的商场。讽刺的是旁边那个住宅小区的地下车库里一整排私家车位从早上九点到下午六点都是空的。这种场景实在太常见了——城市停车难的根本问题往往不是车位总量不够而是车位和时间之间的信息没有匹配起来。也正是那次经历让我把毕业设计题目定成了“基于微信小程序的停车位共享平台设计与实现”。这个项目做完之后我有个很直接的感受它的难点根本不在小程序界面长什么样而在业务建模和并发控制上。很多同学把注意力放在页面美化上结果在“同一车位同一时间被两个人预约”这种基础问题上翻车。这篇文章会把整个项目从需求分析、技术选型、数据库设计、核心接口实现到最后的踩坑记录完整拆一遍如果你也正在做类似的小程序毕设或者想做一个真正能跑的共享类项目可以照着这条路线走。1. 为什么停车位共享值得做需求分析不是走形式1.1 停车难的本质是时间错配不是车位短缺一开始我为了写开题报告翻了不少数据发现很多城市中心城区的车位总量缺口没有想象中那么大真正的问题是潮汐现象被放大了。住宅区白天空出大量车位写字楼和医院周边白天却一位难求而晚上刚好反过来。这种错配说明车位资源天然具备“可分时复用”的属性就像酒店房间和共享单车一样核心是把“空置时段”和“临时需求”连接起来。这个洞察直接决定了项目的定位不做一个停车场导航App也不做一个车位锁硬件项目而是做一个“共享时段”的撮合平台。车位主发布自己空闲的时间段车主按小时预约平台负责匹配、订单和计费。这个定位在论文里也很好展开因为你可以明确写出“本系统解决的是车位时空资源错配问题”而不是泛泛地说“为了缓解停车难”。1.2 目标用户和核心场景要怎么切毕设项目最怕的就是想做淘宝功能铺得太大最后哪个都做不精。我当时把用户切成三类车位主、临时停车车主、平台运营方。但对于一个本科毕设来说运营后台可以只做最基础的车位审核和订单查询把主要精力放在微信小程序端的两个核心角色上。核心场景我梳理了四个车位主发布空闲车位选择小区、楼栋、车位号在地图上标记位置设置可预约的时段和价格。车主查找周边车位打开地图看到附近可预约车位点击查看空闲时段预约下单。订单履约车主到场后确认开始使用使用结束确认离场系统按实际时长计费。订单管理和结算车位主查看自己的车位和收入用户查看历史订单。这四个场景刚好对应我后面要讲的四张核心业务表也构成了论文中“系统功能模块图”的主干。能把这四个场景做成端到端闭环功能上就站得住脚了。1.3 MVP边界哪些功能我故意不做选题阶段导师问过我一个问题车位主怎么给车主开门这就引出了硬件联动的问题蓝牙开锁、地锁控制、车牌识别这些都涉及硬件做进去之后复杂度完全失控。我的处理方式是在系统里预留一个“入场凭证”的概念把开锁/放行抽象成“凭证核销”演示时用一个六位数字凭证码来模拟同时在论文的“系统展望”章节说明如果要对接智能地锁只需在凭证生成环节调用硬件开放平台的接口即可。这样既保证了业务闭环又把硬件边界画得清清楚楚。同样不做的还有真实支付。微信支付需要企业主体资质个人开发者申请不了所以我在订单里设计了“模拟支付”通道生成一笔待支付订单后点“确认支付”直接跳转成功状态。答辩时评委老师问起来就说“采用模拟支付以规避个人开发者资质限制生产环境可无缝对接微信支付统一下单接口”这比硬着头皮假装能接真实支付要体面得多。2. 技术选型为什么是小程序原生加Spring Boot2.1 前端方案uni-app和原生小程序之间的取舍现在很多教程一上来就推荐uni-app理由是跨端复用。但我在调研阶段就淘汰了这个方案。理由很简单这个项目的目标平台只有微信小程序不存在同时要出支付宝小程序或者H5的需求跨端能力是纯冗余。原生小程序框架的文档最全社区案例最多调试工具最成熟出问题能找到的解决方案也最多。这对毕设来说比什么都重要。原生小程序还有一个隐性优势它不会引入Vue或React的额外一层抽象。比如map组件的marker点击事件、cover-view的原生组件覆盖规则这些在原生环境里踩坑是直接面对官方文档的网上搜到的解决方案基本都对得上号而如果用uni-app很多组件是封装过的踩了坑你还得先判断是uni-app的bug还是小程序本身的问题。做毕设的时间本来就不多没必要在这种地方消耗。2.2 后端框架Spring Boot为什么是答辩安全牌后端我选了Spring Boot 2.7 MyBatis-Plus。说实话技术选型这块不同学校风格差异很大有些学校Java课少学生用Node.js甚至Python Flask也做得很好。但如果你是计算机科学与技术专业的我建议还是走Java这套组合原因有三点一是Spring Boot的MVC分层结构非常规范Controller、Service、Mapper一拆论文里“系统详细设计”那一章直接照着画类和时序图就行连编都不用编。二是答辩组老师大概率是Java技术栈出身你用Spring Boot他问的问题你能预判到比如依赖注入、事务管理、拦截器这些都是Java课的经典考点。三是部署方便一个jar包扔到服务器上就能跑写部署文档也简单。MyBatis-Plus的选型理由更实际单表CRUD不用写SQL代码量至少少三分之一。对于这个系统的用户表、车位表、时间片表基本都是单表操作MyBatis-Plus的LambdaQueryWrapper写条件查询非常顺手。像“查询当前时间之后status0的车位时间片”也就是一行wrapper的事不需要维护一大坨XML映射文件。2.3 地图组件选型小程序内置map组件还是天地图题目里有人会纠结用微信小程序内置map组件还是集成天地图。我的结论是用内置map组件加腾讯位置服务API原因很直接内置map组件不需要引入额外的SDK和token直接在wxml里写标签就能渲染地图它底层调用的正是腾讯地图的渲染能力数据坐标系也是GCJ-02和腾讯位置服务的逆地址解析接口天然适配。天地图在这个场景里没有优势它是标准WGS-84坐标系的而小程序map组件默认GCJ-02如果你用的是天地图的接口确实会有一个坐标系转换的问题轻则定位偏移几十米重则marker全部错位为了一个毕设项目去处理火星坐标系转换性价比太低了。不需要为了追热搜去引入一个和你技术栈不匹配的组件做出来的效果才是第一位的。2.4 开发环境需要准备的东西这个项目需要准备的开发环境有这些列出来免得你漏掉微信开发者工具稳定版即可不需要申请AppID也能在模拟器里开发但真机预览需要注册一个小程序账号拿AppID。JDK 1.8或11Maven 3.6以上IDE用IDEA社区版就够。MySQL 5.7或8.0本地或云服务器都行。Redis可选项后面会讲为什么初期可以不用它。腾讯位置服务账号用来申请逆地址解析和关键词搜索的API Key。云服务器我用的2核4G轻量应用服务器装个MySQL和Java环境跑jar包完全够用。3. 数据库建模车位不是简单的“有一辆车就能停”3.1 核心表结构四张主表怎么设计数据库是这套系统里最需要花心思的部分。很多同学习惯一张“车位表”打天下字段里塞了车位id、车位主id、起止时间和状态结果两个人同时预约同一个车位的时候状态字段根本不够表达业务语义。我的方案是把车位和时间片拆开一共四张核心表用户表、车位表、车位时间片表、订单表。用户表存微信登录相关字段openid是唯一标识nickname和avatar是基本资料还有一个user_type字段区分是车主还是车位主一个账号可以同时有两种身份。车位表存车位的静态信息包括车位主的user_id、小区名称、楼栋、车位号、纬度经度、车位照片等还有一个status字段用来审核0表示待审核1表示已上架2表示已下架。车位本身不存时间信息它是一个“地点”属性。真正关键的是车位时间片表这也是整套系统业务逻辑的核心CREATE TABLE parking_slot ( id bigint NOT NULL AUTO_INCREMENT, parking_id bigint NOT NULL COMMENT 所属车位id, start_time datetime NOT NULL COMMENT 可预约开始时间, end_time datetime NOT NULL COMMENT 可预约结束时间, price_per_hour decimal(10,2) NOT NULL COMMENT 每小时价格, status tinyint NOT NULL DEFAULT 0 COMMENT 0空闲 1已预约 2使用中 3已完成 4已锁定, lock_user_id bigint DEFAULT NULL COMMENT 当前预约用户id用于乐观锁, version int NOT NULL DEFAULT 0 COMMENT 乐观锁版本号, PRIMARY KEY (id), KEY idx_parking_id (parking_id), KEY idx_status (status) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;订单表则记录了每一次预约的完整信息包括单号、用户id、车位id、时间片id、开始和结束时间、总金额、订单状态、创建时间等。时间片这个中间层的引入解决了“状态冗余”的问题。车位主发布一个时段系统自动把这个时段拆成按小时分片比如早上8点到晚上6点就是10个时间片每个时间片是独立的可售资源。车主预约其中一个或连续多个时间片锁定的是时间片而不是车位这样数据库里的并发控制就可以精确到最小颗粒度。3.2 订单状态机的边界划分订单状态是整个项目中最容易逻辑混乱的地方。我的订单状态枚举定成这几个待支付、待使用、使用中、已完成、已取消、已超时。状态流转的规则是这样的用户提交预约但还没支付是待支付状态此时时间片处于锁定状态对其他人不可见超过15分钟未支付订单自动变成已取消时间片释放回空闲。支付成功后进入待使用表示“这个时段已经被你预定了”。到了预定开始时间用户点击“确认入场”订单进入使用中时间片状态同步改成使用中。用户点击“确认离场”后订单变成已完成时间片变成已完成不可复用。这个状态机映射到后端代码里就是Service层的一堆状态判断和更新语句。写代码之前一定先把状态流转图画出来哪怕画在草稿纸上也行不然写着写着就会出现“已取消的订单还能入场”这种低级bug。3.3 计费规则怎么设计才合理计费规则的边界条件也不少。我采用的是按实际使用时长计费但库存在预约时就锁定的是预估费用。车主预约时系统根据所选时间片数量和单价计算预估价生成待支付订单后需要立即支付这笔预估价。入场时记录实际入场时间离场时按照实际时长重新计算费用实行多退少补。为了避免用户钻空子我在规则里约定“预约时段开始后30分钟内未确认入场订单标记为超时时间片释放”。这个30分钟既给了用户缓冲时间又防止了车位被无限占用。这些业务规则看着琐碎但写论文时恰好是“系统业务流程设计”章节的素材每一个规则都能画成一张流程图。4. 小程序端核心功能从登录到预约下单的完整链路4.1 微信登录和用户身份绑定小程序端的第一步是登录。用wx.login拿到临时code传给后端后端拿着code去微信接口服务换openid和session_key。openid是用户的唯一身份标识后端生成一个自定义登录态token返回给小程序后续所有接口在请求头里带这个token。token生成我用的是JWT这个在答辩时是加分项能顺带说出“无状态认证”这个概念。不过要注意一点JWT的密钥不要硬编码在代码里放到application.yml里通过配置文件读取虽然毕设项目不涉及安全攻防但这个习惯是好的。另外换openid的时候后端要用HTTPS请求微信接口确保你的服务器能访问外网不然这块会卡很久。app.json里需要声明用户隐私相关权限尤其是获取位置的接口{ permission: { scope.userLocation: { desc: 您的位置信息将用于查找附近停车位 } }, requiredPrivateInfos: [getLocation, chooseLocation] }requiredPrivateInfos这个字段容易漏掉不声明的话真机上调用getLocation会直接报错而且错误提示不是特别明确我当初排查了好久才发现是这里少了配置。4.2 首页地图和车位marker的联动展示首页是这个项目最核心的页面也是用户感知最强的模块。我用的是微信小程序的map组件页面加载时调用wx.getLocation拿到用户当前位置然后通过经纬度范围查询附近的时间片。所有空闲时间片会转成markers数组渲染在地图上。marker的icon可以自己设计一个带价格的小图比默认的大头针好看很多。点击marker之后页面底部弹出一个卡片展示该车位的小区名、车位号、距离以及可预约的时段列表用户可以点“立即预约”直接跳转到下单页面。有个细节需要特别注意map是原生组件它的层级高于普通组件传统view弹窗会被map盖住。解决方法是弹窗部分用cover-view写或者把map和弹窗放在同一个map组件内部。我最终采用的是把底部卡片做成cover-view这样既能正常显示又能顺畅处理点击事件。cover-view内部不支持所有CSS属性但flex布局和基本文字样式都支持做这个业务卡片足够了。4.3 发布车位的表单交互和选点逻辑车位主发布车位的第一步是选地址。这个页面我用了chooseLocation这个API它允许用户在地图上手动选点回调返回选中的经纬度和详细地址。用户选完点后页面显示“小区/楼栋/车位号”的输入框再填单价和可预约时段。时段选择组件用微信小程序的picker的multiSelector模式可以支持起止时间的选择。存库的时候后端会把时间段切分成时间片一个时间段分成多个按小时的时间片。比如用户选了8点到11点就生成8-9、9-10、10-11三个时间片每个单价都是每小时价格。这里要解释一下为什么发布时按时间段切分而不是直接存一个起止时间因为如果不切分两个用户预约不同的子时段时会非常难处理。我切好了之后每个时间片独立库存用户A预约8-9点、用户B预约9-10点并发控制只在每个时间片上发生互不干扰。万一用户想预约连续4个小时系统就一次性锁定4个时间片API层面在同一个事务里完成。4.4 预约下单和入场离场的履约链路预约下单的页面要把核心信息一次性展示清楚车位名、地址、预约时段、单价、预估总价。用户点确认支付后前端调后端的创建订单接口后端先锁时间片再创建待支付订单返回订单号。这里有个支付通道的问题需要提前说清楚。真实微信支付需要企业资质我在支付页做了一个便捷的模拟方案如果是演示模式就显示“模拟支付成功”同时后端在接收到支付成功的回调后将订单状态从待支付改成待使用。在代码里支付相关的Service接口是做成了策略模式的PayService接口下RealWxPayServiceImpl和MockPayServiceImpl两个实现通过配置文件切换这样论文里能写清楚扩展点在哪。用户入场时在小程序首页点击“我的订单”找到待使用状态的订单点击“确认入场”后端校验当前时间在预约时段内后更新订单状态为使用中同时向用户展示六位入场凭证码。离场时点“确认离场”后端计算实际停车时长按“多退少补”更新订单的实际支付金额时间片状态变成已完成。这套链路走通了整个系统的核心业务闭环就算完整了。4.5 request请求封装和登录态处理小程序的网络请求有个特点不能直接像浏览器里那样有跨域限制但所有的request域名必须是备案过的HTTPS域名否则真机预览会直接报“url not in domain list”。开发阶段可以在开发者工具右上角“详情-本地设置”里勾选“不校验合法域名、web-view业务域名、TLS版本以及HTTPS证书”这样本地调试不用买服务器也行。我的request封装里统一做了baseUrl配置、token注入、401自动跳转登录、错误码统一toast这些逻辑。登录态过期后小程序会自动调wx.login刷新token这个在毕设答辩演示时虽然不是重点但代码里实现会显得你的工程完整度更高。封装之后每个接口调用就干净多了比如获取附近车位时间片const res await request({ url: /api/slot/nearby, method: POST, data: { latitude: 30.123, longitude: 120.456, radius: 3000 } });5. 后端接口和并发控制避免同一时段被重复预约5.1 统一返回结构和全局异常处理后端接口的规范程度直接决定了联调效率和答辩观感。我封装了一个Result 统一返回结构所有接口返回格式都是code、message、data三件套code为200表示成功其他为失败。前端request封装里统一判断code失败统一toast错误信息。全局异常处理用Spring Boot的RestControllerAdvice把业务异常BizException和系统异常分开处理。这样Service层抛出“该时段已被预约”时前端拿到的是200状态码但body里code是业务错误码message是中文提示。联调时少了很多“前端报500但不知道为什么”的尴尬。登录拦截器用HandlerInterceptor实现在preHandle里从请求头取token解析JWT把userId放到ThreadLocal里供后续Service使用。白名单放行登录接口和轮播图等无状态接口其他接口一律校验。5.2 防止超卖的核心乐观锁而不是同步锁这个系统最容易被问到的问题就是如果两个用户同时预约同一个空闲时间片会发生什么最简单的方案是给Service方法加synchronized或者使用分布式锁Redis锁但这两个方案在毕设里都不是最优解。synchronized只对单机进程内有效后端如果部署多实例就失效了Redis锁需要额外引入Redis服务而且锁的粒度、超时时间这些概念还得单独讲清楚。我的方案是数据库乐观锁条件更新。核心逻辑在占用时间片这一步Transactional(rollbackFor Exception.class) public Order createOrder(Long slotId, Long userId, BigDecimal amount) { // 1. 锁定时间片只有status0空闲时才能更新成功 int updated parkingSlotMapper.lockSlot(slotId, userId); // 实际执行SQL: // UPDATE parking_slot SET status 1, lock_user_id #{userId}, // version version 1 WHERE id #{slotId} AND status 0 if (updated 0) { throw new BizException(该时段刚刚被预约了请选择其他时间); } // 2. 创建订单 Order order new Order(); order.setOrderNo(generateOrderNo()); order.setUserId(userId); order.setSlotId(slotId); order.setStatus(OrderStatus.PENDING_PAY.getCode()); orderMapper.insert(order); // 3. 返回订单等待支付 return order; }这里的关键在于UPDATE语句的where条件里有status 0数据库的更新操作是行级原子性的两个并发请求同时执行这条UPDATEInnoDB引擎会串行化同一行的更新最终只有一个请求满足条件更新成功另一个影响行数为0直接抛出业务异常。这个方案不需要加锁不需要Redis性能也足够好回答“你怎么解决并发问题的”时逻辑链条非常清晰。如果你想让整个方案更完整可以再提一句“如果需要扣减多个时间片需要在事务里逐个锁定并记录锁定失败时回滚”这也体现你考虑到了事务边界的问题。5.3 超时未支付和超时未入场的处理订单超时释放逻辑我采用的是定时任务扫描方案。Spring的Scheduled注解每30秒扫描一次待支付订单如果创建时间超过15分钟还没支付把订单改成已取消同时把对应的parking_slot状态改回0lock_user_id清空。这个方案对毕设来说足够简单直接不用引入消息队列或延迟队列。如果你之后想在论文里拔高一点可以说“该系统目前采用定时轮询方案扫描超时订单满足毕业设计场景下的数据量要求在更大并发场景下可替换为延迟队列方案如RabbitMQ的TTL或Redis的ZSet延迟队列”。由于状态流转涉及订单表和时间片表两张表的更新这里必须加上Transactional保证原子性。不考虑分布式事务的问题单机部署下数据库事务足够应对。5.4 车位时间片查询的SQL和索引设计附近车位时间片查询是这样实现的前端传纬度、经度和搜索半径后端计算出一个经纬度范围先查这个范围内的车位再根据车位id集合查当前时间之后且状态为0的时间片。这里有个性能优化的点时间片的status字段要建索引parking_id字段也要建索引联合查询的时候不会全表扫描。另外注意状态用int比用varchar更省空间也更快。MyBatis-Plus的LambdaQueryWrapper写起来很舒服ListParkingSlot list parkingSlotMapper.selectList( new LambdaQueryWrapperParkingSlot() .in(ParkingSlot::getParkingId, parkingIds) .eq(ParkingSlot::getStatus, 0) .ge(ParkingSlot::getStartTime, new Date()) );5.5 权限控制和接口安全的基本功权限这块我做了一个简单的双角色判断。用户在车位主端发布车位时需要校验user_type包含车位主角色用户端下单则不需要特殊校验。拦截器里统一解析token放进ThreadLocal后Service层可以直接拿当前用户的id避免前端传userId被篡改的风险。接口安全方面虽然毕设要求不高但有两点建议要做一是所有写操作接口都校验参数比如预约时段不能是过去的时间、价格不能小于0二是对订单详情这类接口做归属校验用户只能查自己的订单不能通过遍历订单号看别人的订单数据。这两点写论文时在“系统安全性设计”里能用上答辩也常问。6. 联调阶段踩过的坑和论文写作如何对齐6.1 小程序request请求失败的排查链路联调阶段最初遇到的几个问题都跟网络有关。最常见的一个是“不在以下request合法域名列表中”这个在开发者工具里勾选不校验合法域名就行。真机预览时因为手机连的不是电脑的localhost所以后端baseUrl必须换成电脑的局域网IP比如192.168.x.x:8080同时要确保手机和电脑在同一个WiFi下。如果后端是HTTPS部署在云服务器baseUrl配成你的域名即可。另一个容易被忽略的问题是小程序请求头里的Content-Type。微信小程序默认的Content-Type是application/json后端Spring Boot的RequestBody才能正常解析。如果你在封装request时把这个值改成了application/x-www-form-urlencoded后端要用RequestParam接参数两边对不上就会白屏或者一直报参数缺失。排查这类问题有个笨办法但很有效在开发者工具的Network面板里看请求和响应详情状态码、响应体、时间线都看得到。别急着改代码先看请求到底出去了没有、响应是什么问题基本能定位一半。6.2 地图组件和第三方库的兼容性问题开发过程中有几个地图组件相关的坑值得记录第一个是marker的click事件。map组件的bindmarkertap回调里e.detail.markerId是marker的id可以对应到车位记录。但如果marker的id是字符串类型某些基础库版本会出问题最好全部用数字类型去关联。第二个是原生组件层级问题。map是原生组件普通view没法覆盖在它上面。我有一次想在首页顶部放一个搜索栏发现怎么调z-index都盖不住map后来才知道要用cover-view去写搜索栏。这是一开始做小程序最容易碰到的“原生组件天花板”。第三个是坐标偏移。这个问题刚才提过后端如果用高德或Google的API拿坐标前端的GCJ-02地图对不上就会整体漂移。我的解决方法是全部统一用腾讯位置服务后端存坐标时也只接受前端传过来了的GCJ-02坐标不做转换。再有一个隐藏问题getLocation在部分安卓手机上第一次调用会返回高度不准的坐标可以在onReady里先调一次预热或者在拿到坐标后做一次较小的范围查询这个在很多项目里都会被忽略。6.3 base64解码和文件上传的兼容性细节在开发过程中我遇到了一个印象比较深的兼容性问题小程序的atob函数在iOS上表现正常但在某些安卓机型和部分基础库版本上直接不可用。后来查了一下小程序的JsCore环境里base64解码能力不是所有平台都完整支持所以我在后端接口返回图片数据时干脆先做一次十六进制编码或用wx.arrayBufferToBase64来做转换绕开了这个差异。文件上传这块我也踩过坑。有段时间很多同学推荐直接把图片上传到云存储但当时这个项目后端是自建的Spring Boot服务文件上传我直接走的是后端的MultipartFile接口前端用wx.uploadFile上传保存路径返回给前端拼完整URL。这个方案胜在简单可控不依赖额外的云服务研究生阶段如果做毕设也是够用的。这类兼容性细节很可能不会写在正经的教科书里但确实是真实项目里最消耗时间的部分。6.4 并发测试的验证方法和答辩数据准备做并发测试时我用Jmeter简单模拟了100个并发请求同时预约同一个时间片最终只有1个成功其余99个都返回“该时段刚刚被预约了”。这个测试结果对论文的“系统测试”章节来说非常有力。把测试截图放进论文再附一段测试结论就说明你确实验证了系统的并发安全性。不过得提醒一句并发测试的时候要保证数据库里真有一个空闲时间片在且状态是0。我第一次测试时忘了清缓存数据里那个时间片已经被之前的测试改成了状态1结果100个请求全失败还以为是代码bug排查了好久才发现是脏数据。6.5 论文各章节怎么和开发过程对齐写论文的时候别等到系统做完了才动笔最好边开发边写尤其注意这几个章节的对应关系第一章绪论里的研究背景和意义用我在开头说的“信息不对称”观点来写比空谈“智慧城市”要落地得多。第二章相关技术介绍把你用到的每一样技术都写两三段包括小程序框架、Spring Boot、MySQL、JWT、腾讯位置服务接口等这个章节纯粹是体力活。第三章需求分析把用户角色、用例图、业务流程画出来内容和本文第1节里讲的核心场景直接对应。第四章系统设计把总体架构图、功能模块图、数据库ER图、核心类图放进去代码里每个实体类基本都能对应到一张表。第五章系统实现按前端页面和后端接口分小节写每小节先写原理再放关键代码片段。第六章系统测试写功能测试用例表和并发测试结果。答辩时评委老师最常问的问题也帮大家整理一下你为什么用乐观锁而不是悲观锁这个系统的盈利模式是什么如果用户到了门口发现车位被别人占了你怎么办这些问题的答案在本文里都有只要你能把第5.2节的乐观锁逻辑讲清楚把入场凭证机制说明白基本就能过。做完这个毕设项目之后我最大的感受是不要被“共享”两个字吓到也不要被“小程序”三个字带偏真正决定你这个项目价值的是业务模型的完整度和代码实现的规范度。先把时间片模型设计好把订单状态机理清楚再动手写代码你会发现整个开发过程非常顺畅。如果这个项目能让你在答辩时自信地说出“这是一个业务闭环完整、并发安全性有保障的系统”那它就不只是帮你拿到一个毕业设计分数而是让你真正走通了一个从需求抽象到工程实现的全流程。本文还有配套的精品资源点击获取