ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

基于微信小程序与Java后端的智能停车场管理系统开发实战

基于微信小程序与Java后端的智能停车场管理系统开发实战 简介基于微信小程序与Java后端的智能停车场管理系统毕业设计资源包面向计算机相关专业毕业生和课程设计学生采用微信开发者工具、Java SSM、MySQL及B/S架构完整实现用户端车位预定与管理员端业务管理。压缩包共1182个文件其中含80个Java文件、117个Vue文件、70个WXML页面、72个WXSS样式、81个JSON配置及大量PNG/SVG图标素材并附带SQL数据库脚本整体大小仅10.99MB目录结构清晰便于按模块学习。已有226人学习下载适合需要快速搭建同类型项目的读者。资源内含完整项目源码、数据库初始化脚本和说明文档前端小程序支持首页、地图定位、个人中心及车位预定后台管理覆盖首页、个人中心、用户管理、车位信息管理、车位预定管理和系统管理另提供安装、运行、构建批处理脚本可减少环境配置成本帮助读者在毕业设计或课程设计中直接借鉴前后台分离实现与权限管理思路。1. 微信小程序Java后端的停车场管理系统拆开看就是这三块一套挂着智能停车场名字的毕业设计学生做出来的大半卡在同一处小程序界面能跑后端接口也能通一合起来就崩。基于微信小程序java后端的智能停车场管理系统核心就三件事小程序端查车位、预约、缴费Java 后端管订单、管余位、管计费MySQL 把业务状态落库。它适合当毕业设计因为业务完整度刚好——有微信登录、列表分页、并发扣减、计费规则一两个月能做完又足够在答辩讲出深度。接下来按拆结构、写小程序、写后端、联调排坑、部署答辩的顺序把从拿到源码包到本地跑通、能讲清设计的过程完整过一遍重点放在代码能落地、参数能对上、坑能避开。2. 系统拆分与数据库设计先定清边界再动手写代码拿到毕业设计包打开后一般会看到后端工程目录、小程序目录、sql 数据库脚本和说明文档四样东西。动手之前先要把边界定清小程序只做展示和交互Java 后端只做业务和数据MySQL 只做持久化。这套结构本质上就是一个前后端分离项目实战的缩影答辩时老师最常问的第一个问题就是你这个系统怎么分层的这一章把分层和数据模型讲清楚后面的代码才有地方放。2.1 用户端小程序四个页面把查位、预约、缴费串起来小程序端最典型的结构是四个业务页面再加一个我的走 tabBar首页停车场列表显示名称、地址、总车位数和剩余车位支持分页加载和下拉刷新。详情页某个停车场的车位占用情况、计费规则、位置地图底部固定立即预约按钮。预约页选入场时间、出场时间填车牌号提交后生成预约订单。订单页订单列表加状态标签待支付、已支付、已完成、已取消点进详情能支付或取消。页面之间是单向跳转关系首页点停车场进详情详情页点立即预约进预约页预约成功跳订单详情。tabBar 通常放首页和我的订单页从我的里进也可以直接把订单页挂进 tabBar看老师要求没有标准答案。为什么要这样拆核心是让每条业务链路只跨三个页面查列表、看详情、下单。很多人上来就塞十几个页面结果每个页面都写不满一百行答辩时反而讲不出一个完整功能。页面少一点把每个页面的交互写扎实比页面多但全是空壳强得多。实战里给页面起名字也讲究小程序的路由是 pages/index/index 这种形式页面文件名和目录名保持一致后面真机调试、配 tabBar 都不容易乱。2.2 Java 后端分层Controller、Service、Mapper 各管什么后端最常见的是 Spring Boot 三层结构目录大致是这样src/main/java/com/parking/ ├── controller/ # 接收前端请求参数校验返回 Result ├── service/ # 业务逻辑下单、计费、余位扣减、取消 ├── mapper/ # MyBatis 接口对应 Mapper XML 或注解 SQL ├── entity/ # 与数据库表对应的实体类 ├── config/ # 跨域配置、拦截器、全局异常处理 └── common/ # Result 统一返回、Jwt、常量Controller 层要做的事很轻拿到小程序传来的 JSON做一次非空和格式校验然后调 Service。很多新手把 SQL 写在 Controller 里接口一多就变成一坨改一个字段要翻半天。Service 层是业务核心——预约的时候要先查停车场状态、再扣余位、再生成订单这三步必须在一个事务里完成这就是 Service 存在的原因。Mapper 层就纯粹一些只做数据库增删改查每条业务会导致多张表写入但每张表的增删改查独立放在自己的 Mapper 里互不干扰。答辩被问到为什么这么分层标准答法是把职责说清楚Controller 不管业务、Mapper 不管逻辑、Service 只调接口不写 SQL。再补一句这样改计费规则只动 Service 层换数据库只动 Mapper 层老师基本就不再追问了。这也解释了为什么毕设包里的代码普遍是这个结构——它不是最花哨的方案但是最经得起问的方案。2.3 数据库设计六张表撑起整个停车场业务数据库脚本是整个毕设的地基表结构设计不对后端的 SQL 全得返工。常见的做法是六张表用户表、停车场表、车位表、预约表、支付记录表、管理员表。表名关键字段说明userid, openid, nickname, phone, plate_number, create_timeopenid 唯一车牌可多绑parking_lotid, name, address, total_space, available_space, price_per_hour, status余位字段直接冗余在停车场表parking_spaceid, lot_id, space_no, statusstatus 0空闲 1占用 2预约可选设计reservationid, user_id, lot_id, plate_number, start_time, end_time, amount, status状态 0待支付 1已支付 2入场 3完成 4取消payment_recordid, reservation_id, pay_type, pay_time, amount, transaction_id与预约一对多managerid, username, password后台管理账号表两张核心表之间的关联是reservation.user_id 指向 user.idreservation.lot_id 指向 parking_lot.idpayment_record.reservation_id 指向 reservation.id。不少毕设把支付字段直接堆进预约表也能跑但答辩时老师一问已支付的流水怎么对账就露馅拆出独立表反而是加分项。每个表的 id 字段统一用自增主键不搞业务主键写 Mapper 的时候省心。一个容易忽略的细节是 available_space 要不要单独存。我建议存而不是每次 count 车位表。列表页每刷一次就要显示几十个停车场的余位实时 count 几百上千行接口会明显变慢。余位字段靠后端 UPDATE 语句维护保证它不错乱是第四章的核心内容。后面如果要给表加字段比如车位加一个是否充电桩标记直接 ALTER TABLE 修改结构就行同时把 SQL 脚本里保留一句带注释的 ALTER 语句说明文档里写清改动原因——这才是源码包里说明文档该有的样子而不是把建表语句贴一遍就完事。3. 小程序端落地登录鉴权、列表加载更多与预约下单这一章是前端动手环节三个代码块分别对应三条必经链路怎么拿到用户身份、怎么把列表做成能一直往下翻、怎么把一次预约提交得又对又稳。3.1 登录鉴权wx.login 拿 codeJava 后端换 openid微信小程序没有传统意义上的账号密码身份靠 openid 识别。流程是小程序 wx.login 拿到一个临时 code把它 POST 给后端后端拿着 code 去微信的 jscode2session 接口换 openid再查库、决定是登录还是注册最后返回 token 给小程序存起来。// utils/request.js const BASE_URL http://192.168.1.100:8080; // 开发期用局域网 IP真机也能访问 function login() { return new Promise((resolve, reject) { wx.login({ success: async (res) { if (!res.code) { reject(new Error(wx.login 拿不到 code)); return; } const { data } await wx.request({ url: ${BASE_URL}/api/user/login, method: POST, data: { code: res.code } }); if (data.code 200) { wx.setStorageSync(token, data.data.token); wx.setStorageSync(openid, data.data.openid); resolve(data.data); } else { reject(new Error(data.msg)); } }, fail: reject }); }); }// UserController.java PostMapping(/login) public Result login(RequestBody LoginRequest req) { String openid userService.getOpenidByCode(req.getCode()); User user userService.findOrCreate(openid); String token JwtUtil.createToken(user.getId()); return Result.ok(new LoginResponse(user.getId(), openid, token)); }逻辑说明小程序的 wx.login 每次返回的 code 有效期只有五分钟且只能用一次所以后端必须即时调 jscode2session不能缓存。jscode2session 的完整地址是https://api.weixin.qq.com/sns/jscode2session?appidAPPIDsecretSECRETjs_codeCODEgrant_typeauthorization_codeappid 和 secret 在小程序后台的开发管理 → 开发设置里拿。需要强调的一点secret 永远不要写进小程序代码里它只能放后端配置中否则被任何人拿到都能以你的小程序名义调接口这是被薅过之后的血的教训。参数说明BASE_URL 里我用的是局域网 IP 而不是 localhost。原因很简单——本地调试时开发者工具能访问 localhost但真机预览时手机访问的是电脑上的后端localhost 指向手机自己必失败。另外这里直接await wx.request依赖微信开发者工具的增强编译开关如果工具没打开 Promise 风格就需要自己用 Promise 包一层这是代码里最隐蔽的兼容性问题。3.2 车位列表加载更多page、pageSize 与触底防重首页列表不分页的话数据库几百条记录一次全返回接口慢、页面卡。常见的分页做法是前端维护 page 和 pageSize后端返回当前页数据加上是否有下一页前端滚动到底部时用 onReachBottom 触发下一页加载。// pages/index/index.js Page({ data: { lotList: [], page: 1, pageSize: 10, hasMore: true, isLoading: false }, onLoad() { this.loadLots(true); }, onReachBottom() { if (this.data.hasMore !this.data.isLoading) { this.loadLots(false); } }, async loadLots(reset) { if (this.data.isLoading) return; // 防重正在请求就不处理新触发 this.setData({ isLoading: true }); const page reset ? 1 : this.data.page; try { const res await wx.request({ url: ${getApp().globalData.BASE_URL}/api/lot/list, data: { page, pageSize: this.data.pageSize } }); const { list, hasMore } res.data.data; this.setData({ lotList: reset ? list : this.data.lotList.concat(list), page: reset ? 2 : page 1, hasMore }); } catch (e) { wx.showToast({ title: 列表加载失败, icon: none }); } finally { this.setData({ isLoading: false }); } } });逻辑说明loadLots 接收 reset 参数下拉刷新时传 true 走第一页触底加载时传 false 走追加。page 在请求成功后才自增不是请求前自增——这样失败后重新触发时还能拿同一页不会跳过数据。hasMore 由后端根据list.length pageSize判断前端拿到 false 就不再发请求。这套逻辑里最容易翻车的是 onReachBottom 连续触发。手指快速滑动时onReachBottom 可能在 isLoading 置位前被调用两次所以函数开头那句if (this.data.isLoading) return;是必须的不是可选项。后端接口也建议做一道防御如果传进来的 page 小于当前已返回的最大页直接返回空数组避免重复数据。前后端各拦一道这才是前后端分离项目该有的默契。提示如果详情页要做沉浸式头部把导航栏隐藏掉app.json 里配 navigationStyle: custom就得自己处理顶部导航栏高度。常见做法是用wx.getMenuButtonBoundingClientRect()拿胶囊按钮的位置再用系统信息里的 statusBarHeight 算出可用头部高度。不同机型上这个值不一样写死 64px 的结果就是部分手机上头部被压扁这是微信小程序页面开发里特别容易被忽略的适配问题。3.3 预约下单金额计算、状态流转与按钮防重复提交预约是最能体现系统完整度的功能。用户在预约页填好车牌和进出场时间前端把数据 POST 给后端后端在一个事务里完成扣余位 → 算金额 → 插订单返回预约单号和应付金额。// pages/reserve/reserve.js Page({ data: { submitting: false }, async submitReserve() { if (this.data.submitting) return; // 前端防重复提交 this.setData({ submitting: true }); try { const res await wx.request({ url: ${getApp().globalData.BASE_URL}/api/reserve/create, method: POST, data: { lotId: this.data.lotId, plateNumber: this.data.plateNumber, startTime: this.data.startTime, endTime: this.data.endTime } }); if (res.data.code 200) { const { id, amount } res.data.data; // 跳订单详情amount 为 0 直接显示预约成功 wx.redirectTo({ url: /pages/order/detail?id${id}amount${amount} }); } else { wx.showToast({ title: res.data.msg, icon: none }); } } catch (e) { wx.showToast({ title: 提交失败请重试, icon: none }); } finally { this.setData({ submitting: false }); // 失败后要恢复按钮否则按钮永远禁用 } } });// ReserveService.java Transactional(rollbackFor Exception.class) public Reservation createReserve(ReserveRequest req) { // 1. 扣余位。返回 0 说明车位已满事务回滚 int rows parkingLotMapper.deductSpace(req.getLotId()); if (rows 0) { throw new BizException(车位已满); } // 2. 同一个用户只能有一条进行中的预约防重复下单 int active reservationMapper.countActiveByUserId(req.getUserId()); if (active 0) { throw new BizException(您有未完成的预约); } // 3. 金额计算 BigDecimal amount calcAmount(req); // 4. 插表 Reservation r new Reservation(); r.setUserId(req.getUserId()); r.setLotId(req.getLotId()); r.setPlateNumber(req.getPlateNumber()); r.setStartTime(req.getStartTime()); r.setEndTime(req.getEndTime()); r.setAmount(amount); r.setStatus(0); // 待支付 reservationMapper.insert(r); return r; }逻辑说明前端用 submitting 标志位把提交按钮锁住防止用户连点两次后端再查一次进行中预约数防止多设备并发下绕过前端限制。前后端对于这类重复提交的校验方法是各管一段——前端管体验把按钮置灰后端管数据用查询约束兜底两边缺一不可。参数说明calcAmount 的规则一般放在 Service 里比如30 分钟内免费超过后按分钟数除以 60 乘单价四舍五入到分。这里注意用 BigDecimal 的 RoundingMode.HALF_UP别用 float 或 double 算金额答辩时用两个 0.1 相加不等于 0.2的例子解释为什么选 BigDecimal老师会认可这个细节。startTime 和 endTime 建议用标准字符串传参后端用LocalDateTime.parse解析别用时间戳在数据库里也存 DATETIME这样 desc 查询和展示都直观。4. Java 后端落地Spring Boot 分层、余位并发控制与跨域小程序端写得再好后端接口一崩全白搭。这一章把后端的三件事讲透工程怎么配、并发下余位怎么保证不错、前后端联调时跨域问题怎么一刀解决。4.1 Spring Boot 工程依赖与配置文件pom.xml 和 application.yml 这么设先看依赖。Spring Boot 的 starter-web 是必须的MyBatis 连 MySQL再加一个 JWT 做登录态。以下是我在这个方向常用的依赖组合版本以你自己 Spring Boot parent 管理为准dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.mybatis.spring.boot/groupId artifactIdmybatis-spring-boot-starter/artifactId version2.3.0/version /dependency dependency groupIdcom.mysql/groupId artifactIdmysql-connector-j/artifactId scoperuntime/scope /dependency dependency groupIdcom.auth0/groupId artifactIdjava-jwt/artifactId version4.4.0/version /dependency /dependencies参数说明mybatis-spring-boot-starter 2.3.0 配 Spring Boot 2.7 是常见组合如果换到 Spring Boot 3.x要对应使用 mybatis-spring-boot-starter 3.x否则启动直接报错。mysql-connector-j 在 Spring Boot 2.7.5 之后由 parent 统一管理版本不需要手填。很多毕设包会用 MyBatis-Plus 替代纯 MyBatis那种情况下单表的增删改查不用写 XML省时间但也少了手写 SQL 的答辩谈资各有利弊——我的建议是如果包原生是纯 MyBatis就顺着它不要中途换。然后是配置文件最值得注意的就是连接串上的两个参数server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/parking?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver逻辑说明characterEncodingutf8 保证中文不乱码serverTimezoneAsia/Shanghai 保证时间字段不带 8 小时时区偏差这两个参数漏一个后面排错至少半天。driver-class-name 对应新版驱动老项目里的 com.mysql.jdbc.Driver 在新驱动下已经废弃启动会打 warning虽然能跑但不建议留着。另外把spring.jackson.date-format配成 yyyy-MM-dd HH:mm:ss接口返回的时间格式才统一。4.2 余位扣减的并发控制一条条件 UPDATE 解决超卖余位字段存的是数字数字在并发下最容易出问题。最常见的错误写法是先 select 余位数、Java 里减一、再 update 回去两个请求同时读到 1都减一都写回数据库余位变成 0但实际卖出了两单。正确的常见做法是把判断和更新放进同一条 SQL靠影响行数判断是否成功!-- ParkingLotMapper.xml -- update iddeductSpace UPDATE parking_lot SET available_space available_space - 1 WHERE id #{lotId} AND available_space 0 /updateTransactional(rollbackFor Exception.class) public void deductOrThrow(Long lotId) { int rows parkingLotMapper.deductSpace(lotId); if (rows 0) { throw new BizException(车位已满); } }逻辑说明UPDATE ... WHERE available_space 0在数据库层面做原子判断。就算十个请求同时进来MySQL 的行锁会让它们排队执行第一个成功把余位扣到 0后面九个的 WHERE 条件不满足影响行数都是 0全部走车位已满分支。这就是把并发控制下推到数据库的做法也是答辩时最能讲出技术深度的点。取消预约时要反向加回来同样用条件 UPDATESET available_space available_space 1 WHERE id #{lotId}。这套方案能应对毕设场景但要清晰地说出它的边界它保证的是不超卖不保证预约者能优先占到具体车位。如果要精确到每个车位被谁占就得把停车位表做成可预约状态用同样的条件 UPDATE 去锁定具体车位行比如UPDATE parking_space SET status 2 WHERE id #{spaceId} AND status 0。有余力的话把这个也做了答辩时从停车场级余位控制讲到车位级状态控制层次感直接拉满。4.3 跨域配置与统一返回前后端分离项目的第一步联调小程序 wx.request 不受浏览器同源策略约束所以小程序连后端通常没有跨域问题。但很多毕设还带一个 Web 端管理后台用 axios 调同一套接口这时跨域就会拦住你。配置写好后两边都能调是稳赚不赔的一步。// CorsConfig.java Configuration public class CorsConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/**) .allowedOriginPatterns(*) .allowedMethods(GET, POST, PUT, DELETE, OPTIONS) .allowedHeaders(*) .maxAge(3600); } }参数说明allowedOriginPatterns(*) 放行所有来源毕设阶段够用如果后面要部署到服务器建议收紧成具体域名比如https://admin.example.com。allowedMethods 里一定要带 OPTIONS因为浏览器复杂请求会先发一个 OPTIONS 预检后端不响应预检浏览器就把真实请求拦了。maxAge 3600 是让预检结果缓存一小时减少重复预检的开销。跨域只是联调第一关第二关是统一返回格式。所有接口都返回同样的结构小程序端解析逻辑就不用每个页面写一遍Data public class ResultT { private int code; // 200 成功500 业务失败 private String msg; private T data; public static T ResultT ok(T data) { ResultT r new Result(); r.code 200; r.msg success; r.data data; return r; } public static T ResultT error(String msg) { ResultT r new Result(); r.code 500; r.msg msg; return r; } }配套的全局异常处理用 RestControllerAdvice把 BizException 和系统异常统一转成 Result.error接口层就不用到处写 try-catch。小程序端在 request 统一封装里判断res.data.code 200非 200 直接 toast msg。做到这一步前后端联调的效率会明显提升也是后端跨域、统一格式这类基建的价值体现。5. 避坑清单停车场毕设从跑通到演示的 5 个高频翻车点这一章是前面所有代码的对照检查表每一条都是实际调试中出现过的现象照章排查能少走很多弯路。5.1 真机预览连不上后端接口现象微信开发者工具里功能全部正常一扫码在真机上打开列表加载不出来Network 面板显示 request fail控制台报 net::ERR_CONNECTION_REFUSED。 原因代码里 baseURL 写的是 http://localhost:8080。开发者工具里 localhost 指向电脑真机上指向手机自己必然连不上。另一个叠加原因是微信真机默认校验 request 合法域名http 且没在小程序后台登记的域名会直接拦截控制台报url not in domain list。 解决后端启动加配置server.address0.0.0.0这样局域网内设备才能访问小程序里把 baseURL 换成电脑的局域网 IPWindows 用 ipconfig 查mac 用 ifconfig 查。开发期在微信开发者工具右上角详情 → 本地设置勾选不校验合法域名真机预览就能通。上线的正规做法是在小程序后台配置 request 合法域名需要服务器域名备案毕业设计做到不校验合法域名 局域网 IP这步就足够答辩了。5.2 中文乱码与时间差 8 小时连接串和字符集一起改现象页面上输入的中文名称存进数据库变成问号或者订单时间比实际时间多 8 小时数据库里看时间是凌晨页面上显示是中午。 原因数据库连接串少了 characterEncodingutf8 和 serverTimezone 参数另一种情况是建表时表字符集是 latin1中文根本存不进去。时间差 8 小时是因为 MySQL 的 timezone 和 Java 的时区没对齐默认走了 UTC。 解决连接串补成jdbc:mysql://localhost:3306/parking?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai。已经建好的表直接改结构用 ALTER 语句把字符集切到 utf8mb4utf8mb4 才能存 emoji 这类四字节字符ALTER DATABASE parking CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; ALTER TABLE user CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;执行前一定先把数据备份一份ALTER 语句会对整表重建数据量大时有锁表风险这是做这个方向以来最深的血泪经验。改完字符集要重启后端连接池里旧的连接还带着老字符集不重启等于白改。5.3 余位变负数并发场景下的超卖问题现象车库明明只剩 1 个车位两个用户同时预约两个都收到成功提示数据库里余位变成 -1。 原因后端代码写成先查余位、判断大于 0、再更新并发下两个请求都通过了判断都执行了更新。这是典型的先查后改非原子操作单线程测试没问题并发一上来就露馅。 解决用 4.2 的条件 UPDATE 替换把判断和更新合并到一条 SQL靠影响行数决定成败。验证方式很简单写一个小脚本用两个线程同时调预约接口或者用 Postman 的 Runner 跑 50 次并发看数据库余位是否始终大于等于 0。这个坑是答辩老师最爱的切入点你的系统怎么保证余位不超卖能讲清楚 WHERE 条件加事务回滚的机制比背十页论文都有说服力。5.4 列表加载触发两次重复请求现象列表快速滑到底部同一条数据出现两次或者第 2 页的数据和第 1 页重叠。 原因onReachBottom 在 isLoading 标志位还没置位时连续触发两次。另一个常见原因是 page 在请求前就自增了失败重试时跳过了某一页。 解决按 3.2 的写法loadLots 开头先判断 isLoading请求成功后才自增 pagefinally 里复位标志位。后端接口再兜一层如果请求的 page 小于等于已返回的最大页直接返回空列表。前后端各做一道线上就不会出现重复数据。排查方法也简单——打开开发者工具的 Network 面板看是不是同时发出两个同样的 list 请求看到两个就说明前端防重没过关。5.5 微信支付调不起来用模拟支付兜底现象调用 wx.requestPayment 一直报 invalid param 或支付签名验证失败或者提示当前商户号无权限。 原因个人主体的小程序无法开通微信支付即使有商户号也需要在小程序后台完成支付关联、下载商户证书、配置 API 密钥签名算法里参数顺序不能错。毕设阶段这些依赖往往不齐全。 解决最常见的做法是模拟支付。用户点确认支付后前端调后端/api/pay/mock接口后端把预约状态从待支付改成已支付插入一条支付记录返回成功。前端拿到成功的返回后展示支付成功页面。答辩时可以这样解释当前环境未接入真实微信支付接口签名已按官方规范预留验收时替换为商户号即可。如果老师要求演示真实支付链路就要提前确认自己是否具备企业主体小程序和商户号这条路至少预留两周联调时间别拖到最后一天。6. 本地部署与答辩演示把这套系统变成能讲清楚的作品6.1 按这个顺序把项目跑起来部署顺序是导库、配后端、起后端、导小程序、联调。先执行 sql 脚本建库建表确认表名和 Mapper 里的注释对得上再打开后端 application.yml 改数据库账号密码确认连接串带 characterEncoding 和 serverTimezone然后mvn spring-boot:run启动看到 Tomcat started on port 8080 就成功了。微信开发者工具导入小程序目录用测试号把 BASE_URL 改成电脑局域网 IP本地设置勾选不校验合法域名编译走一遍完整流程。验证后端最简单的方式是直接 curl 一下curl http://localhost:8080/api/lot/list?page1pageSize10返回 JSON 且 code 是 200接口层就没什么问题了。回显乱码先查终端编码Windows 控制台代码页不对会出现假乱码那不是接口的锅。6.2 答辩演示按脚本走数据库对照是最佳说服力演示翻车基本都是临场操作导致的。答辩前把演示流程固定成脚本启动后端、首页刷新、进详情、预约下单、取消订单、查数据库余位。每一步配一句讲解词全程控制在五分钟内不演示不稳定的功能。最有说服力的演示是预约成功后现场查一次数据库SELECT id, total_space, available_space FROM parking_lot WHERE id 1;下单前余位 5下单后变 4比讲一百句架构都直观。老师追问并发时翻出 4.2 的条件 UPDATE 和 Transactional讲清 WHERE 条件加影响行数判断的原理这就是全场的技术亮点。最后一个习惯答辩前一周只改配置和 bug不动核心逻辑。我见过太多人最后一天改计费规则把整个订单流程改崩的例子。数据库脚本和关键 Java 文件提前备份改出问题还有后悔药。这套项目做完前后端分离、数据库设计、并发控制三件事都能讲透比写十套增删改查都值。希望帮到你。本文还有配套的精品资源点击获取
返回列表