1. 项目概述
停车难问题已经成为现代城市发展的痛点之一。这个基于SpringBoot+小程序的停车位租赁平台,正是针对这一社会痛点的技术解决方案。作为一个完整的毕业设计项目,它不仅包含了前后端全栈技术实现,还提供了配套文档和代码讲解,甚至支持定制化开发服务。
从技术架构来看,项目采用了经典的Java后端+微信小程序前端的组合方式。后端使用SpringBoot框架搭建RESTful API服务,前端则通过微信小程序提供用户交互界面。这种技术选型既保证了系统的稳定性和扩展性,又能充分利用微信生态的用户基础和传播优势。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心需求解析
2.1 用户角色划分
系统主要涉及三类用户角色:
- 车主用户:核心需求是快速找到可用停车位、完成在线支付、获取导航指引
- 车位业主:需要便捷的车位管理功能、收益统计和提现服务
- 平台管理员:负责系统运维、数据统计、纠纷处理等后台管理工作
2.2 核心业务流程
完整的停车位租赁流程包含以下关键环节:
- 车位发布与审核
- 车位搜索与筛选
- 在线预约与支付
- 使用验证与计时
- 费用结算与评价
3. 技术架构设计
3.1 后端技术栈
采用SpringBoot作为核心框架,主要基于以下考虑:
- 自动配置特性大幅减少XML配置
- 内嵌Tomcat容器简化部署流程
- 丰富的Starter依赖快速集成常用组件
- 完善的生态和社区支持
关键组件选型:
- 持久层:MyBatis-Plus + MySQL
- 缓存:Redis(用于会话管理和热点数据缓存)
- 消息队列:RabbitMQ(处理异步通知)
- 文件存储:阿里云OSS
- 支付对接:微信支付SDK
3.2 前端技术方案
微信小程序作为前端载体具有明显优势:
- 无需安装,即用即走
- 天然的用户信任感
- 完善的支付生态
- 丰富的API支持(定位、扫码等)
UI框架选择:
- 基础组件:微信原生组件库
- 扩展组件:Vant Weapp(提供更丰富的UI控件)
- 地图服务:腾讯位置服务JavaScript SDK
4. 数据库设计要点
4.1 核心表结构
sql复制-- 用户表
CREATE TABLE `user` (
`id` bigint NOT NULL AUTO_INCREMENT,
`openid` varchar(64) DEFAULT NULL COMMENT '微信openid',
`username` varchar(32) DEFAULT NULL,
`phone` varchar(11) DEFAULT NULL,
`avatar` varchar(255) DEFAULT NULL,
`balance` decimal(10,2) DEFAULT '0.00',
`user_type` tinyint DEFAULT '0' COMMENT '0-普通用户 1-车位主',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `idx_openid` (`openid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 停车位表
CREATE TABLE `parking_space` (
`id` bigint NOT NULL AUTO_INCREMENT,
`user_id` bigint DEFAULT NULL COMMENT '所属用户ID',
`title` varchar(64) DEFAULT NULL,
`address` varchar(255) DEFAULT NULL,
`longitude` decimal(10,7) DEFAULT NULL,
`latitude` decimal(10,7) DEFAULT NULL,
`price_per_hour` decimal(6,2) DEFAULT NULL,
`status` tinyint DEFAULT '0' COMMENT '0-可用 1-已出租 2-维护中',
`images` text COMMENT '图片URL,逗号分隔',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_location` (`longitude`,`latitude`),
KEY `idx_user` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 订单表
CREATE TABLE `order` (
`id` bigint NOT NULL AUTO_INCREMENT,
`order_no` varchar(32) DEFAULT NULL,
`user_id` bigint DEFAULT NULL,
`space_id` bigint DEFAULT NULL,
`start_time` datetime DEFAULT NULL,
`end_time` datetime DEFAULT NULL,
`total_amount` decimal(10,2) DEFAULT NULL,
`status` tinyint DEFAULT '0' COMMENT '0-待支付 1-已支付 2-使用中 3-已完成 4-已取消',
`pay_time` datetime DEFAULT NULL,
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `idx_order_no` (`order_no`),
KEY `idx_user` (`user_id`),
KEY `idx_space` (`space_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
4.2 关键设计考虑
- 地理位置索引:为停车位表建立复合索引(longitude, latitude),支持高效的地理位置查询
- 订单号生成:采用"时间戳+随机数"的方式生成唯一订单号,避免使用自增ID暴露业务量
- 余额处理:使用DECIMAL类型存储金额,避免浮点数精度问题
- 图片存储:多个图片URL用逗号分隔存储,实际项目中可考虑使用JSON格式
5. 核心功能实现
5.1 车位搜索与推荐
java复制@RestController
@RequestMapping("/api/space")
public class ParkingSpaceController {
@Autowired
private ParkingSpaceService spaceService;
@GetMapping("/nearby")
public Result<List<ParkingSpaceVO>> getNearbySpaces(
@RequestParam BigDecimal longitude,
@RequestParam BigDecimal latitude,
@RequestParam(defaultValue = "5000") Integer radius) {
// 参数校验
if(longitude == null || latitude == null) {
throw new BizException(ErrorCode.PARAM_ERROR);
}
// 计算经纬度范围(简化版,实际应使用GIS函数)
List<ParkingSpaceVO> spaces = spaceService.findNearby(longitude, latitude, radius);
// 按距离排序
spaces.sort(Comparator.comparingDouble(ParkingSpaceVO::getDistance));
return Result.success(spaces);
}
}
5.2 微信支付集成
支付流程关键步骤:
- 小程序端调用后端创建预支付订单
- 后端调用微信支付统一下单API
- 后端返回支付参数给小程序
- 小程序调起微信支付界面
- 微信支付结果异步通知
java复制@Service
public class WxPayServiceImpl implements PayService {
@Value("${wxpay.appid}")
private String appid;
@Value("${wxpay.mchid}")
private String mchid;
@Value("${wxpay.key}")
private String key;
@Override
public Map<String, String> createPrepayOrder(Order order, String openid) {
// 构造请求参数
Map<String, String> params = new HashMap<>();
params.put("appid", appid);
params.put("mch_id", mchid);
params.put("nonce_str", WxPayUtil.generateNonceStr());
params.put("body", "停车位预约-" + order.getOrderNo());
params.put("out_trade_no", order.getOrderNo());
params.put("total_fee", order.getTotalAmount().multiply(new BigDecimal("100")).intValue() + "");
params.put("spbill_create_ip", "127.0.0.1");
params.put("notify_url", "https://yourdomain.com/api/pay/notify");
params.put("trade_type", "JSAPI");
params.put("openid", openid);
// 生成签名
String sign = WxPayUtil.generateSignature(params, key);
params.put("sign", sign);
// 调用统一下单API
String xmlResult = WxPayUtil.httpRequest(
"https://api.mch.weixin.qq.com/pay/unifiedorder",
"POST",
WxPayUtil.mapToXml(params));
// 解析返回结果
Map<String, String> result = WxPayUtil.xmlToMap(xmlResult);
if("FAIL".equals(result.get("return_code"))) {
throw new BizException("微信支付下单失败:" + result.get("return_msg"));
}
// 构造小程序支付参数
Map<String, String> prepayParams = new HashMap<>();
prepayParams.put("appId", appid);
prepayParams.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));
prepayParams.put("nonceStr", WxPayUtil.generateNonceStr());
prepayParams.put("package", "prepay_id=" + result.get("prepay_id"));
prepayParams.put("signType", "MD5");
String paySign = WxPayUtil.generateSignature(prepayParams, key);
prepayParams.put("paySign", paySign);
return prepayParams;
}
}
5.3 计时计费实现
java复制@Service
public class OrderServiceImpl implements OrderService {
@Autowired
private OrderMapper orderMapper;
@Scheduled(fixedRate = 60000) // 每分钟执行一次
public void autoUpdateOrderStatus() {
// 查询使用中的订单
List<Order> usingOrders = orderMapper.selectByStatus(OrderStatus.USING.getCode());
for(Order order : usingOrders) {
// 计算当前费用
long minutes = Duration.between(order.getStartTime(), LocalDateTime.now()).toMinutes();
BigDecimal currentFee = order.getPricePerHour()
.divide(BigDecimal.valueOf(60), 2, RoundingMode.HALF_UP)
.multiply(BigDecimal.valueOf(minutes));
// 更新订单信息
order.setTotalAmount(currentFee);
orderMapper.updateById(order);
// 推送消息给用户(可通过WebSocket或模板消息)
pushOrderUpdate(order.getUserId(), order.getId());
}
}
}
6. 小程序端关键实现
6.1 地图选点与展示
javascript复制// pages/map/map.js
Page({
data: {
markers: [],
latitude: 39.90469,
longitude: 116.40717,
},
onLoad() {
this.getLocation();
this.loadNearbySpaces();
},
getLocation() {
wx.getLocation({
type: 'gcj02',
success: res => {
this.setData({
latitude: res.latitude,
longitude: res.longitude
});
}
});
},
loadNearbySpaces() {
wx.request({
url: 'https://yourdomain.com/api/space/nearby',
data: {
longitude: this.data.longitude,
latitude: this.data.latitude,
radius: 2000
},
success: res => {
const markers = res.data.map(item => ({
id: item.id,
latitude: item.latitude,
longitude: item.longitude,
iconPath: '/images/marker.png',
width: 30,
height: 30,
callout: {
content: `¥${item.pricePerHour}/小时`,
color: '#ff5a5f',
fontSize: 12,
borderRadius: 10,
padding: 5,
display: 'ALWAYS'
}
}));
this.setData({ markers });
}
});
},
handleMarkerTap(e) {
const spaceId = e.markerId;
wx.navigateTo({
url: `/pages/space/detail?id=${spaceId}`
});
}
});
6.2 支付流程实现
javascript复制// pages/order/confirm.js
Page({
data: {
order: null,
loading: false
},
onLoad(options) {
this.loadOrderDetail(options.id);
},
handlePay() {
this.setData({ loading: true });
wx.login({
success: loginRes => {
wx.request({
url: 'https://yourdomain.com/api/pay/prepay',
method: 'POST',
data: {
orderId: this.data.order.id,
code: loginRes.code
},
success: res => {
const payParams = res.data;
wx.requestPayment({
...payParams,
success: () => {
wx.redirectTo({
url: `/pages/order/result?id=${this.data.order.id}`
});
},
complete: () => {
this.setData({ loading: false });
}
});
}
});
}
});
}
});
7. 部署与运维
7.1 后端部署方案
推荐使用Docker容器化部署,主要优势:
- 环境一致性保障
- 快速部署和扩展
- 资源利用率高
示例Dockerfile:
dockerfile复制FROM openjdk:8-jdk-alpine
VOLUME /tmp
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
7.2 小程序发布流程
-
开发环境配置
- 配置合法域名(需HTTPS)
- 配置业务域名(如需web-view)
- 配置服务器域名(request合法域名等)
-
版本管理策略
- 开发版:用于日常开发测试
- 体验版:供产品经理和测试人员使用
- 审核版:提交微信审核的版本
- 线上版:正式发布的版本
-
发布注意事项
- 提前准备应用描述和截图
- 检查所有功能在微信审核模式下的表现
- 准备好相关资质文件(如涉及支付类目)
8. 项目扩展方向
8.1 功能扩展建议
-
智能推荐系统:
- 基于用户历史行为推荐车位
- 动态定价策略(高峰时段自动调价)
-
物联网集成:
- 智能地锁控制
- 车牌识别系统对接
-
增值服务:
- 洗车服务预约
- 电动汽车充电服务
8.2 性能优化方案
-
缓存策略优化:
- 热点车位信息缓存
- 使用Redis集群提高缓存容量
-
数据库优化:
- 读写分离架构
- 历史订单归档策略
-
搜索体验优化:
- 基于Elasticsearch实现全文搜索
- 地理围栏技术优化附近搜索
9. 常见问题排查
9.1 微信支付集成问题
问题现象:调用支付接口返回"签名错误"
- 检查商户密钥(key)配置是否正确
- 确认签名算法一致(MD5/HMAC-SHA256)
- 检查参数顺序和空值处理是否符合微信要求
- 使用微信提供的签名校验工具验证
问题现象:支付成功但未收到回调通知
- 检查notify_url是否外网可访问
- 确认服务器防火墙未拦截微信服务器IP
- 检查回调处理逻辑是否有未捕获的异常
- 在微信支付后台手动补发通知测试
9.2 定位偏差问题
问题现象:小程序获取的坐标与实际位置偏差大
- 确认使用的是gcj02坐标系(国内标准)
- 检查是否开启了高精度定位模式
- 在安卓设备上检查GPS和网络定位是否都开启
- 考虑使用微信的逆地址解析服务提高精度
10. 毕设答辩准备建议
-
技术亮点提炼:
- 强调SpringBoot的自动配置和Starter机制应用
- 展示微信生态整合的完整度(支付、定位、消息等)
- 突出解决的实际问题(如计时计费的精确性处理)
-
演示准备技巧:
- 准备两套演示数据(正常流程和异常场景)
- 录制备用视频防止现场网络问题
- 重点展示管理员后台的数据统计功能
-
常见答辩问题准备:
- 为什么选择SpringBoot而不是其他框架?
- 系统如何处理高并发场景下的车位竞争?
- 用户隐私数据如何保护?
- 项目的商业可行性分析?
在实际开发过程中,有几个关键点特别值得注意:首先是微信生态的各种限制和规范,比如支付接口必须使用备案域名;其次是地理位置相关功能在不同机型上的表现可能不一致,需要充分测试;最后是订单状态机的设计要考虑到各种边缘情况,比如用户支付中途退出小程序等场景。
