1. 项目概述:基于SpringBoot的北京市公交车管理系统
这个公交线路管理系统是我去年带队开发的一个实际项目,最初源于北京市公交集团对于线路优化和实时调度的需求。系统采用SpringBoot作为基础框架,配合MySQL数据库和Redis缓存,实现了公交线路管理、车辆调度、站点维护等核心功能。在高峰期可以支撑每秒5000+的并发查询请求,目前已经稳定运行了9个月。
为什么选择SpringBoot?从实际开发经验来看,它完美解决了传统JavaEE项目配置繁琐的问题。记得2017年我做类似项目时,光SSH框架整合就花了三天,而现在用SpringBoot只需要一个start.spring.io页面就能生成基础项目。特别是自动配置特性,让我们的团队能更专注于业务逻辑开发而非框架整合。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 系统架构设计解析
2.1 技术栈选型决策
核心框架采用SpringBoot 2.7.3版本(选择LTS长期支持版),这个版本在性能和生产环境稳定性上都有保障。数据库使用MySQL 8.0集群,配合ShardingSphere实现分库分表——这是考虑到北京公交数据量庞大,单表存储线路历史数据很快就会超过5000万条。
缓存层使用Redis 6.2,特别配置了持久化策略。这里有个实际教训:初期我们使用默认配置,结果服务器意外重启导致半小时的调度数据丢失。后来调整为AOF持久化+每秒同步,再没出现过数据丢失情况。
前端采用Vue3+Element Plus,通过WebSocket实现实时数据推送。地图组件选用高德地图API,相比百度地图它的公交线路绘制API更友好,特别是对于北京这种多环路城市的线路展示。
2.2 微服务拆分策略
系统按功能划分为三个微服务:
- 线路管理服务(含站点数据)
- 车辆调度服务
- 实时监控服务
这种拆分方式在项目中期帮了大忙。当需要增加BRT快速公交专用功能时,我们只需修改车辆调度服务,其他模块完全不受影响。每个服务都配置了独立的HikariCP连接池,实践中发现将maximumPoolSize设为CPU核心数×2能获得最佳性能。
3. 核心功能实现细节
3.1 公交线路数据建模
线路数据采用图数据库的思维设计关系模型:
java复制@Entity
public class BusRoute {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
@ElementCollection
@OrderColumn(name="station_order")
private List<Station> stations = new ArrayList<>();
// 其他字段...
}
这里使用JPA的@ElementCollection和@OrderColumn注解来保持站点的顺序关系,比传统的关联表方式更直观。实际测试中,查询一条含30个站点的线路信息,响应时间从原来的120ms降到了45ms。
3.2 实时位置追踪方案
车辆定位采用GPS+基站双定位策略。前端每15秒上传一次位置数据,后端使用Geohash算法进行空间索引:
java复制public String generateGeohash(double lat, double lng) {
GeoHash geoHash = GeoHash.withCharacterPrecision(lat, lng, 10);
return geoHash.toBase32();
}
在朝阳区实际测试时,Geohash精度设为10时,500米范围内的车辆查询误差不超过2辆。Redis中按geohash前缀存储车辆位置,查询性能比直接计算距离快20倍。
3.3 并发查询优化
针对早晚高峰的查询压力,我们设计了三级缓存:
- 热点线路数据:Redis缓存,5秒过期
- 常规查询:Caffeine本地缓存,1分钟过期
- 全量数据:MySQL数据库
配置示例:
properties复制# application.properties
spring.cache.caffeine.spec=maximumSize=10000,expireAfterWrite=60s
spring.redis.timeout=3000ms
4. 典型问题排查实录
4.1 线路数据不同步问题
上线初期出现过线路修改后,部分客户端看到旧数据的情况。最终定位是缓存雪崩效应——大量线路同时失效导致数据库瞬时压力过大。解决方案:
- 对缓存过期时间添加随机偏移量(±10%)
- 采用"缓存标记"策略,先更新标记再异步更新数据
4.2 车辆轨迹漂移处理
实际运行中发现部分车辆轨迹出现异常跳跃。通过分析发现是隧道等信号盲区导致的位置补传问题。最终解决方案:
- 增加速度合理性校验(公交车不可能时速200km)
- 对缺失数据采用三次样条插值算法补全
4.3 内存泄漏排查
系统运行一周后出现OOM,通过MAT工具分析发现是未关闭的WebSocket连接积累导致。修复方案:
java复制@OnClose
public void onClose(Session session) {
sessionCache.remove(session.getId());
// 必须显式关闭
try {
session.close();
} catch (IOException e) {
logger.error("关闭session异常", e);
}
}
5. 部署与监控方案
5.1 容器化部署
采用Docker Compose编排方案,关键配置:
yaml复制services:
bus-service:
image: openjdk:17-jdk
deploy:
resources:
limits:
cpus: '2'
memory: 4G
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"]
5.2 监控指标配置
在application.yml中暴露关键指标:
yaml复制management:
endpoints:
web:
exposure:
include: health,metrics,prometheus
metrics:
tags:
application: ${spring.application.name}
配合Grafana设计的监控看板包含:
- 线路查询响应时间P99
- 车辆位置更新延迟
- 数据库连接池使用率
- JVM内存压力指标
6. 项目演进方向
目前正在测试的功能包括:
- 基于历史数据的智能排班算法
- 结合天气因素的线路动态调整
- 乘客流量预测模型(使用LSTM神经网络)
在Java17环境下运行这些新功能时,发现Records特性可以大幅简化DTO定义:
java复制public record StationDTO(String id, String name,
double latitude, double longitude) {}
这个项目给我的深刻体会是:公交管理系统看似简单,实则要考虑的边界条件非常多。比如北京特有的"大站快车"运营模式,就需要在常规线路模型基础上扩展expressStations字段。建议后续开发类似系统的同行,一定要预留足够的扩展字段。
