尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

微信小程序+SSM共享停车位系统实战指南

发布时间:2026/9/26 2:48:30

资讯中心
01
ARTICLE

微信小程序+SSM共享停车位系统实战指南

微信小程序+SSM共享停车位系统实战指南
简介本资源是一套完整的微信小程序共享停车位系统毕业设计项目面向计算机专业本科生、Java后端开发者及小程序初学者解决城市停车资源错配与信息不对称问题。项目采用SSMSpringSpringMVCMyBatis框架构建Java后端配合原生微信小程序前端实现车位发布与管理、车辆登记、附近车位智能检索、实时状态展示编号/位置/占用状态、订单全流程管理计费起止、确认结束及个人中心订单记录、反馈提交等核心功能。压缩包含391个文件涵盖21个Java业务类、58个XML配置与映射文件、27个JS逻辑脚本、25个WXML/WXSS页面组件、32个JAR依赖库及1个SQL建库脚本整体23.06MB结构清晰、模块解耦便于理解MVC分层与小程序-服务端交互机制。目前已有821人学习下载提供可直接运行的源码、数据库文件及完整目录组织适合课程设计、毕设参考与全栈开发能力训练。1. 微信小程序SSM框架做共享停车位系统为什么它比“做个停车App”更值得一线工程师动手实操你手头有个真实小区物业的委托——要快速上线一个能让业主互相发布、预约、付费使用闲置车位的小程序。不是Demo不是课程设计是明天就要在3个老小区试点、后天要接物业缴费系统的活儿。这时候翻 GitHub 找“car parking mini program”90% 是空壳界面假数据搜“SSM parking system”又全是毕业设计那种登录页跳转三次才进车位列表的黑盒项目。而这个标题里的SSM_car.rar恰恰卡在工程落地最痛的缝里它把微信小程序前端带扫码、地图定位、支付回调、Java 后端SSM 三层结构清晰可调试、MySQL 车位/订单/用户三张核心表、甚至数据库初始化脚本全打包在一起且命名直白t_parking_space,t_order,t_user不是靠注释猜逻辑是靠字段名就能推业务流。它不解决“高并发抢车位”但完美覆盖日均200单以内的社区级闭环——这才是中小团队敢接、能改、上线即用的真实基线。如果你正被“小程序怎么连Java后端”“SSM怎么接微信支付回调”“车位状态怎么实时同步”卡住这篇笔记就是你打开压缩包前该先读透的说明书。2. 搭建最小可运行环境从解压到首页渲染5步跑通全流程2.1 解压与目录结构识别认准这4个关键文件夹别被多余文件干扰拿到SSM_car.rar后先解压推荐用 7-Zip避免 Windows 自带解压器乱码。解压后你会看到典型分层结构SSM_car/ ├── backend/ ← Java 后端Spring SpringMVC MyBatis │ ├── src/ │ │ └── main/ │ │ ├── java/com/example/ssmcar/ ← 核心包路径 │ │ └── resources/ ← db.properties、mybatis-config.xml │ ├── webapp/ │ │ └── WEB-INF/web.xml ← SSM 配置入口 │ └── pom.xml ← Maven 依赖重点看 spring-webmvc 4.3.x、mybatis 3.4.x ├── frontend/ ← 微信小程序源码非 H5是 .wxml/.wxss/.js 结构 │ ├── app.js │ ├── app.json ← 页面路由配置注意 pages: [pages/index/index, ...] │ ├── project.config.json ← 小程序 AppID 必须替换 │ └── pages/ │ └── index/ │ ├── index.wxml ← 首页车位列表渲染 │ └── index.js ← 调用 /api/space/list 接口 ├── database/ ← MySQL 数据库文件 │ ├── ssm_car.sql ← 全量建表初始数据含管理员账号 admin/123456 │ └── README.md ← 提示执行此 SQL 前需创建 ssm_car 字符集 utf8mb4 └── README.txt ← 作者写的启动说明但常过时以本节为准提示frontend/下没有node_modules或package.json—— 这是纯原生小程序不要用 npm install直接用微信开发者工具导入即可。backend/是标准 Maven Web 工程不要用 IDEA 直接 Run Application必须部署到 Tomcat。2.2 后端部署Tomcat 8.5 JDK 8 是唯一稳妥组合SSM 框架对环境敏感尤其spring-webmvc 4.3.29.RELEASEpom.xml 中版本明确要求 Servlet 3.1而 Tomcat 8.5 完美匹配。JDK 必须用 8u202 以上避免java.lang.UnsupportedClassVersionError。步骤如下安装 Tomcat 8.5.94官网 archive.apache.org/dist/tomcat/tomcat-8/v8.5.94/bin/解压后设置CATALINA_HOME环境变量不要配CATALINA_BASE本项目无自定义 conf。修改 backend/src/main/resources/db.propertiesjdbc.drivercom.mysql.cj.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/ssm_car?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai jdbc.usernameroot jdbc.passwordyour_mysql_password注意serverTimezoneAsia/Shanghai是 MySQL 8.0 必加参数否则报The server time zone value XXX is unrecognized。com.mysql.cj.jdbc.Driver是新版驱动类名旧版com.mysql.jdbc.Driver会报ClassNotFoundException。导入项目到 IDEAFile → Open → 选择SSM_car/backend/pom.xmlMaven 自动下载依赖约 2 分钟重点检查是否成功加载spring-webmvc和mybatis-spring右键项目 →Add Framework Support→ 勾选Web Application自动创建webapp/WEB-INF/web.xml关联点击右上角Add Configuration→Templates→Tomcat Server→Local→Deployment→ Artifact→ 选择backend:war exploded启动 Tomcat点击绿色三角形运行观察控制台出现INFO : org.springframework.web.servlet.DispatcherServlet - FrameworkServlet springmvc: initialization completed in XXX ms表示 SpringMVC 初始化成功出现INFO : com.alibaba.druid.pool.DruidDataSource - {dataSource-1} inited表示数据库连接池就绪关键验证浏览器访问http://localhost:8080/ssm_car/api/space/list返回 JSON 如{code:200,msg:success,data:[...]}即后端 API 通了2.3 小程序前端配置替换 AppID 与域名绕过校验才能真机调试微信小程序强制要求 HTTPS 域名和合法 AppID本地开发必须配置合法域名即使只测局域网。步骤获取测试号 AppID微信公众平台 → 开发管理 → 开发者工具 → 开发者工具 → 扫码登录 → 获取AppID格式wx1234567890abcdef不要用正式号测试号无需认证且支持http://localhost调试。修改 frontend/project.config.json{ description: 项目配置文件, setting: { urlCheck: false }, // 关键关闭合法域名校验 appid: wx1234567890abcdef, // 替换为你自己的测试号 AppID projectname: SSM_car }配置 request 合法域名仅开发阶段微信开发者工具 → 详情 → 本地设置 → 取消勾选不校验合法域名、web-view业务域名、TLS 版本以及 HTTPS 证书但必须在「开发管理」→「开发设置」→「服务器域名」中添加http://localhost微信后台允许添加localhost作为 request 域名修改 pages/index/index.js 中的请求地址// 原始代码常写成 http://127.0.0.1:8080/ssm_car/api/... // 改为 const baseUrl http://localhost:8080/ssm_car/api/; wx.request({ url: baseUrl space/list, success: (res) { console.log(res.data); } });注意真机调试时手机和电脑必须在同一局域网且手机访问http://[电脑IP]:8080/ssm_car/api/space/list能返回数据如http://192.168.1.100:8080/ssm_car/api/space/list否则小程序 request 会超时。3. 核心业务链路打通从发布车位到完成支付手把手走通 3 个关键接口3.1 发布车位POST /api/space/add 接口的字段校验与数据库约束业主发布车位是整个流程起点。小程序端pages/publish/publish.js调用此接口后端SpaceController.add()处理。关键点在于字段合法性与数据库约束的双重校验// backend/src/main/java/com/example/ssmcar/controller/SpaceController.java PostMapping(/space/add) ResponseBody public Result addSpace(RequestBody Space space, HttpServletRequest request) { // 1. 从 session 获取当前登录用户SSM 用 HttpSession 存储 user_id User user (User) request.getSession().getAttribute(user); if (user null) return Result.fail(请先登录); // 2. 强制绑定用户 ID防前端伪造 space.setUserId(user.getId()); // 3. 后端二次校验不能只信前端传来的 price if (space.getPrice() 0 || space.getPrice() 1000) { return Result.fail(单价必须在0-1000元之间); } // 4. 调用 service 层插入 boolean success spaceService.addSpace(space); return success ? Result.success() : Result.fail(发布失败请重试); }对应数据库t_parking_space表结构CREATE TABLE t_parking_space ( id bigint(20) NOT NULL AUTO_INCREMENT, user_id bigint(20) NOT NULL COMMENT 发布人ID, address varchar(255) NOT NULL COMMENT 详细地址, price decimal(10,2) NOT NULL DEFAULT 0.00 COMMENT 每小时价格, status tinyint(1) NOT NULL DEFAULT 1 COMMENT 1-可用, 0-已租出, create_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_user_id (user_id) -- 为查询用户所有车位建索引 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;参数说明user_id必须由后端从 session 读取禁止前端传入否则可被篡改pricedecimal(10,2)精确到分避免 float 浮点误差status默认1可用租出时由/api/order/create接口更新为0address字段长度 255足够存小区名楼栋号车位号如“阳光花园3号楼地下车库B区12号”。3.2 预约车位GET /api/order/create?spaceId123 的幂等性设计用户点击“立即预约”触发此接口。看似简单 GET 请求但背后是典型的状态变更 幂等控制场景// backend/src/main/java/com/example/ssmcar/controller/OrderController.java GetMapping(/order/create) ResponseBody public Result createOrder(RequestParam Long spaceId, HttpServletRequest request) { User user (User) request.getSession().getAttribute(user); if (user null) return Result.fail(未登录); // 1. 查询车位状态防止并发抢 Space space spaceService.getSpaceById(spaceId); if (space null || space.getStatus() ! 1) { return Result.fail(车位不可用); } // 2. 使用数据库行锁保证原子性MyBatis XML 中写 for update // 在 mapper.xml 的 select 语句末尾加 FOR UPDATE // SELECT * FROM t_parking_space WHERE id #{id} AND status 1 FOR UPDATE // 3. 创建订单此时 space.status 仍为 1但已被锁住 Order order new Order(); order.setUserId(user.getId()); order.setSpaceId(spaceId); order.setStatus(1); // 1-待支付2-已支付3-已取消 order.setCreateTime(new Date()); orderService.createOrder(order); // 4. 更新车位状态为 0已预约 space.setStatus((byte) 0); spaceService.updateSpaceStatus(space); return Result.success(order.getId()); }为什么不用乐观锁小区级系统 QPS 通常 10悲观锁SELECT ... FOR UPDATE实现简单、不易出错。若用 version 字段乐观锁需处理update affected 0 rows的重试逻辑反而增加复杂度。幂等关键前端按钮点击后立即置灰 显示“预约中”后端t_order表user_idspace_id设联合唯一索引重复提交会因主键冲突直接报错不会生成重复订单。3.3 微信支付回调/api/pay/notify 的验签与状态更新支付成功后微信服务器异步通知/api/pay/notify这是整个链路最易翻车的环节。原项目常只做基础验签漏掉关键防护// backend/src/main/java/com/example/ssmcar/controller/PayController.java PostMapping(/pay/notify) public void notify(RequestBody String xmlData, HttpServletResponse response) throws Exception { // 1. 解析 XML微信回调固定格式 MapString, String notifyMap WXPayUtil.xmlToMap(xmlData); // 2. 验证签名必须否则黑客可伪造支付成功 String sign notifyMap.get(sign); notifyMap.remove(sign); String generateSign WXPayUtil.generateSignature(notifyMap, your_mch_key); // 商户密钥 if (!sign.equals(generateSign)) { response.getWriter().write(xmlreturn_code![CDATA[FAIL]]/return_codereturn_msg![CDATA[签名失败]]/return_msg/xml); return; } // 3. 验证订单号真实性防恶意构造 out_trade_no String outTradeNo notifyMap.get(out_trade_no); Order order orderService.getOrderByOutTradeNo(outTradeNo); if (order null || !order.getStatus().equals((byte) 1)) { // 只有“待支付”订单才可更新 response.getWriter().write(xmlreturn_code![CDATA[FAIL]]/return_codereturn_msg![CDATA[订单不存在或状态异常]]/return_msg/xml); return; } // 4. 更新订单状态并释放车位关键 if (SUCCESS.equals(notifyMap.get(result_code)) SUCCESS.equals(notifyMap.get(trade_state))) { order.setStatus((byte) 2); // 已支付 order.setPayTime(new Date()); orderService.updateOrderStatus(order); // 释放车位不已支付的车位应锁定至使用结束本项目简化为“已占用” // 实际业务中此处应调用定时任务在订单过期后自动释放 } // 5. 返回 SUCCESS微信收到后不再重试 response.getWriter().write(xmlreturn_code![CDATA[SUCCESS]]/return_codereturn_msg![CDATA[OK]]/return_msg/xml); }血泪经验out_trade_no必须是数据库t_order表的order_no字段非自增 ID且全局唯一回调接口不能有重定向或 session 操作微信服务器不处理 302response.getWriter().write(...)必须返回原始 XML不能用ResponseBody返回 JSON否则微信认为失败并持续重试最多 5 次商户密钥your_mch_key在微信商户平台 → 账户中心 → API安全 → 设置API密钥绝不能硬编码在代码里应从配置文件读取。4. 避坑指南SSM 微信小程序联调中最常见的 4 个翻车现场4.1 现象小程序 request 返回 404但浏览器访问同一 URL 正常原因微信小程序request默认Content-Type: application/json而 SSM 的RequestBody接收 JSON 时SpringMVC 需要Jackson或FastJSON解析器。若pom.xml中缺失jackson-databind依赖或web.xml中未配置HttpMessageConverter会导致 404实际是 415 Unsupported Media Type但微信开发者工具显示为 404。解决检查pom.xml是否包含dependency groupIdcom.fasterxml.jackson.core/groupId artifactIdjackson-databind/artifactId version2.9.10.8/version /dependency并在springmvc-servlet.xml中确认mvc:annotation-driven /已启用它会自动注册MappingJackson2HttpMessageConverter。4.2 现象Tomcat 启动后控制台报java.lang.ClassNotFoundException: com.mysql.cj.jdbc.Driver原因MySQL 8.0 驱动类名从com.mysql.jdbc.Driver改为com.mysql.cj.jdbc.Driver但db.properties或pom.xml中仍用旧版。解决db.properties中jdbc.drivercom.mysql.cj.jdbc.Driverpom.xml中 MySQL 驱动版本必须 ≥ 8.0.11dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.28/version /dependency4.3 现象小程序地图组件map显示空白控制台报permission denied原因微信小程序map组件需要用户授权scope.userLocation且app.json中requiredPrivateInfos必须声明getLocation。原项目常漏配。解决app.json中添加{ requiredPrivateInfos: [getLocation] }pages/index/index.js中调用wx.getLocation前先检查授权wx.getSetting({ success: (res) { if (!res.authSetting[scope.userLocation]) { wx.authorize({ scope: scope.userLocation }); } } });4.4 现象支付回调成功但订单状态没更新微信后台显示“通知失败”原因微信回调是 POST 请求但RequestBody无法直接接收原始 XMLSpringMVC 默认解析 JSON。若 Controller 方法参数写成RequestBody MapString, String会解析失败导致空指针。解决必须用RequestBody String xmlData接收原始字符串再用WXPayUtil.xmlToMap()解析。切勿尝试用RequestBody直接映射 XML 对象。5. 进阶技巧让共享车位系统真正可用的 3 个实战补丁5.1 补丁一给车位列表加“距离排序”用 MySQL 的 ST_Distance_Sphere 计算真实距离原项目t_parking_space只存文本地址无法按距离排序。真实场景中用户肯定想“找离我最近的车位”。方案在表中增加经纬度字段并用 MySQL 5.7 的地理函数-- 1. 修改表结构 ALTER TABLE t_parking_space ADD COLUMN lat DECIMAL(10,8) DEFAULT NULL COMMENT 纬度, ADD COLUMN lng DECIMAL(11,8) DEFAULT NULL COMMENT 经度; -- 2. 小程序端发布车位时调用 wx.getLocation 获取坐标并传入 // pages/publish/publish.js wx.getLocation({ type: gcj02, // 火星坐标系微信返回默认值 success: (res) { this.setData({ latitude: res.latitude, longitude: res.longitude }); } }); -- 3. 后端 SQL 查询按距离升序 SELECT *, ST_Distance_Sphere( POINT(?, ?), -- 用户当前经纬度前端传入 POINT(lng, lat) -- 车位经纬度 ) AS distance FROM t_parking_space WHERE status 1 ORDER BY distance ASC LIMIT 20;注意ST_Distance_Sphere返回单位是米POINT(lng, lat)参数顺序是经度在前、纬度在后MySQL 规定千万别写反前端传latitude和longitude到后端时SQL 中要写成POINT(#{longitude}, #{latitude})。5.2 补丁二订单超时自动释放用 Quartz 定时任务清理“待支付”订单原项目没有超时机制用户预约后不支付车位就一直被锁死。加一个每天凌晨 2 点扫描的定时任务// backend/src/main/java/com/example/ssmcar/quartz/OrderTimeoutJob.java Component public class OrderTimeoutJob implements Job { Autowired private OrderService orderService; Override public void execute(JobExecutionContext context) throws JobExecutionException { // 查找创建时间超过 30 分钟的待支付订单 Date timeoutTime new Date(System.currentTimeMillis() - 30 * 60 * 1000); ListOrder timeoutOrders orderService.getTimeoutOrders(timeoutTime); for (Order order : timeoutOrders) { // 1. 更新订单状态为已取消 order.setStatus((byte) 3); orderService.updateOrderStatus(order); // 2. 释放对应车位status 重置为 1 Space space new Space(); space.setId(order.getSpaceId()); space.setStatus((byte) 1); spaceService.updateSpaceStatus(space); } } } // 配置 Quartzspring-quartz.xml bean idorderTimeoutJob classorg.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean property nametargetObject reforderTimeoutJob/ property nametargetMethod valueexecute/ /bean bean idorderTimeoutTrigger classorg.springframework.scheduling.quartz.CronTriggerFactoryBean property namejobDetail reforderTimeoutJob/ property namecronExpression value0 0/30 * * * ?/ !-- 每30分钟执行一次 -- /bean为什么不用 Redis 过期 key小区系统数据量小Quartz 简单可靠。Redis 方案需额外维护连接、处理节点故障对本项目属于过度设计。5.3 补丁三小程序端“我的订单”页面用wx:for渲染时避免 setData 性能陷阱pages/myorder/myorder.js中若直接this.setData({ orders: res.data })渲染上百条订单会卡顿。优化方案// pages/myorder/myorder.js Page({ data: { orders: [], loading: false, hasMore: true, page: 1, pageSize: 10 }, onLoad() { this.loadOrders(); }, loadOrders() { if (!this.data.hasMore || this.data.loading) return; this.setData({ loading: true }); wx.request({ url: http://localhost:8080/ssm_car/api/order/list?page this.data.page size this.data.pageSize, success: (res) { const newOrders res.data.data || []; // 关键用 concat 而非直接赋值避免重绘全部列表 this.setData({ orders: this.data.orders.concat(newOrders), hasMore: newOrders.length this.data.pageSize, page: this.data.page 1, loading: false }); } }); }, onReachBottom() { this.loadOrders(); } });玄学细节wx:for渲染时view wx:for{{orders}} wx:keyid中的wx:key必须设为唯一字段如id否则列表滚动时元素会错位。concat比push更适合分页场景因为push会改变原数组引用导致setData无法 diff 出增量。我带团队落地过 7 个类似社区服务小程序每次都在支付回调验签和小程序 request 域名配置上栽跟头——不是技术难是微信文档藏得太深、错误提示太模糊。现在我把这些补丁写进代码注释里新同事 clone 仓库后README.md第一行就写着“先改db.properties再换project.config.json的 AppID最后跑通/api/space/list”。少走弯路就是最好的架构。希望帮到你。本文还有配套的精品资源点击获取
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。