城市公交管理系统是现代智慧交通建设的重要组成部分。作为一名长期从事交通信息化建设的开发者,我最近完成了一个基于SpringBoot+Vue的公交管理系统,核心功能聚焦在公交路线维护和站点管理模块。这个系统从实际需求出发,解决了公交运营中路线调整频繁、站点信息更新不及时等痛点问题。
系统采用前后端分离架构,后端使用SpringBoot+MyBatisPlus构建RESTful API,前端采用Vue.js实现响应式界面。特别在路线可视化展示和智能优化方面做了深入开发,通过对接地图API和历史客流数据,为调度人员提供了直观的决策支持工具。
Spring Boot作为后端框架的选择主要基于以下几个考量:
数据库选用MySQL 8.0,主要考虑到:
java复制// 典型的路由实体类设计
@Entity
@Table(name = "bus_route")
public class BusRoute {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String routeNumber;
@Column(nullable = false)
private String routeName;
@OneToMany(mappedBy = "route", cascade = CascadeType.ALL)
private List<RouteStation> stations = new ArrayList<>();
// 其他字段和方法...
}
Vue 3的组合式API让前端开发更加高效:
javascript复制// 路线地图展示组件
import { useRouteStore } from '@/stores/route'
const store = useRouteStore()
const initMap = () => {
const map = new AMap.Map('map-container', {
zoom: 12,
center: [116.397428, 39.90923]
})
store.routeList.forEach(route => {
const path = route.stations.map(s => [s.lng, s.lat])
new AMap.Polyline({
path: path,
strokeColor: getRandomColor(),
strokeWeight: 4,
map: map
})
})
}
路线管理模块包含以下关键功能点:
数据库设计采用三张核心表:
sql复制CREATE TABLE `bus_route` (
`id` bigint NOT NULL AUTO_INCREMENT,
`route_number` varchar(20) NOT NULL COMMENT '路线编号',
`route_name` varchar(100) NOT NULL COMMENT '路线名称',
`first_station` varchar(50) NOT NULL COMMENT '始发站',
`last_station` varchar(50) NOT NULL COMMENT '终点站',
`mileage` decimal(10,2) DEFAULT NULL COMMENT '里程(公里)',
`status` tinyint DEFAULT '1' COMMENT '状态(0停运1运营)',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_route_number` (`route_number`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
站点管理的关键技术点:
java复制// MyBatis-Plus的关联查询示例
public interface BusStationMapper extends BaseMapper<BusStation> {
@Select("SELECT s.* FROM bus_station s " +
"JOIN route_station rs ON s.id = rs.station_id " +
"WHERE rs.route_id = #{routeId} " +
"ORDER BY rs.seq_num")
List<BusStation> selectByRouteId(@Param("routeId") Long routeId);
}
基于历史客流数据的路线优化策略:
java复制// 简单的发车间隔计算示例
public class DispatchCalculator {
public static int calculateInterval(List<PassengerFlow> flows) {
// 计算平均客流量
double avg = flows.stream()
.mapToInt(PassengerFlow::getCount)
.average()
.orElse(0);
// 基础间隔10分钟,根据客流动态调整
int base = 10;
if (avg > 100) return base - 2;
if (avg > 50) return base - 1;
if (avg < 20) return base + 2;
return base;
}
}
使用WebSocket实现的实时监控功能:
javascript复制// WebSocket连接处理
const socket = new WebSocket('wss://your-domain.com/ws/monitor')
socket.onmessage = (event) => {
const data = JSON.parse(event.data)
if (data.type === 'VEHICLE_POSITION') {
updateVehicleMarker(data.payload)
} else if (data.type === 'PASSENGER_FLOW') {
updateFlowChart(data.payload)
}
}
采用RBAC模型实现细粒度权限控制:
java复制// Spring Security配置核心代码
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/api/auth/**").permitAll()
.antMatchers("/api/admin/**").hasRole("ADMIN")
.antMatchers("/api/route/**").hasAnyRole("ADMIN", "DISPATCHER")
.anyRequest().authenticated()
.and()
.addFilter(new JwtAuthenticationFilter(authenticationManager()))
.addFilter(new JwtAuthorizationFilter(authenticationManager()));
return http.build();
}
}
java复制// 数据加密示例
public class DataEncryptor {
private static final String ALGORITHM = "AES/CBC/PKCS5Padding";
private static final IvParameterSpec iv = new IvParameterSpec(
"1234567890123456".getBytes());
public static String encrypt(String input, String key) {
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE,
new SecretKeySpec(key.getBytes(), "AES"),
iv);
byte[] encrypted = cipher.doFinal(input.getBytes());
return Base64.getEncoder().encodeToString(encrypted);
}
}
使用Docker Compose编排服务:
yaml复制# docker-compose.yml示例
version: '3'
services:
backend:
build: ./backend
ports:
- "8080:8080"
depends_on:
- mysql
- redis
frontend:
build: ./frontend
ports:
- "80:80"
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: rootpass
MYSQL_DATABASE: bus_db
redis:
image: redis:alpine
java复制// Spring Cache配置示例
@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory factory) {
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(30))
.disableCachingNullValues();
return RedisCacheManager.builder(factory)
.cacheDefaults(config)
.build();
}
}
在实际开发过程中,有几个关键点值得特别注意:
路线-站点关联处理:最初设计时没有考虑站点顺序问题,后来增加了seq_num字段记录站点在路线中的顺序。建议类似关联关系一定要考虑排序需求。
地图集成:不同地图API的坐标系可能不同,我们遇到了百度地图和GPS坐标转换的问题。最终采用开源库coordtransform解决。
批量导入性能:初期站点批量导入采用单条插入,性能极差。优化后改用MyBatis的批量插入语法,性能提升近百倍。
java复制// 批量插入优化示例
public void batchInsertStations(List<BusStation> stations) {
SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH);
try {
BusStationMapper mapper = session.getMapper(BusStationMapper.class);
for (BusStation station : stations) {
mapper.insert(station);
}
session.commit();
} finally {
session.close();
}
}
这个项目让我深刻体会到,一个好的公交管理系统不仅要考虑技术实现,更要理解公交运营的实际业务场景。比如路线调整时需要考虑首末班车时间、司机排班等因素,这些业务知识对系统设计至关重要。