1. 项目背景与核心需求
客车车票预订系统作为交通行业数字化转型的典型应用,正在从传统的线下窗口售票模式向智能化、网络化方向演进。2026届计算机相关专业毕业生选择这个课题作为毕业设计,既符合行业发展趋势,又能全面检验SSM+Vue技术栈的实战能力。
这个系统需要解决的核心痛点包括:
- 乘客购票体验差:传统购票需要到车站排队,耗时费力
- 票务管理效率低:人工统计容易出错,无法实时掌握余票情况
- 数据可视化缺失:缺乏运营数据分析支持决策
- 系统扩展性不足:节假日高峰期系统容易崩溃
2. 技术选型解析
2.1 后端技术栈:SSM框架组合
SSM(Spring+SpringMVC+MyBatis)作为经典的JavaEE开发框架组合,具有成熟的社区支持和丰富的扩展组件:
Spring 5.x:控制反转(IoC)和面向切面(AOP)的实现
- 采用注解配置替代XML配置
- 事务管理使用@Transactional注解
- 集成Hibernate Validator进行参数校验
SpringMVC:处理前端请求的分发和响应
- RESTful风格API设计
- 统一异常处理@ControllerAdvice
- 参数绑定@RequestBody/@RequestParam
MyBatis 3.5+:持久层ORM框架
- 动态SQL编写
- 二级缓存配置
- 分页插件PageHelper集成
技术选型心得:相比Spring Boot的"约定大于配置",SSM需要更多手动配置但可控性更强,适合需要深度定制的毕业设计项目。
2.2 前端技术栈:Vue生态体系
Vue 3.x作为主流前端框架,为系统提供现代化的用户界面:
核心功能:
- Composition API替代Options API
- 基于Proxy的响应式系统
- TypeScript支持
配套工具:
- Vue Router 4.x:前端路由管理
- Vuex/Pinia:状态管理
- Element Plus/Ant Design Vue:UI组件库
工程化支持:
- Vite构建工具
- Axios HTTP客户端
- ESLint+Prettier代码规范
3. 系统架构设计
3.1 整体架构图
[前端层] Vue.js ↑↓ HTTP/HTTPS [接入层] Nginx反向代理 ↑↓ [应用层] SpringMVC ↑↓ [服务层] Spring ↑↓ [持久层] MyBatis → MySQL3.2 数据库设计要点
主要数据表结构设计:
用户表(user)
CREATE TABLE `user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `username` varchar(50) NOT NULL COMMENT '登录账号', `password` varchar(100) NOT NULL COMMENT '密码', `real_name` varchar(50) DEFAULT NULL COMMENT '真实姓名', `id_card` varchar(18) DEFAULT NULL COMMENT '身份证号', `phone` varchar(11) DEFAULT NULL COMMENT '手机号', `email` varchar(100) DEFAULT NULL COMMENT '邮箱', `avatar` varchar(255) DEFAULT NULL COMMENT '头像', `status` tinyint(1) DEFAULT '1' COMMENT '状态(0-禁用,1-正常)', `create_time` datetime DEFAULT CURRENT_TIMESTAMP, `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `idx_username` (`username`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';车次表(schedule)
CREATE TABLE `schedule` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `bus_number` varchar(20) NOT NULL COMMENT '车牌号', `departure_station` varchar(50) NOT NULL COMMENT '始发站', `arrival_station` varchar(50) NOT NULL COMMENT '终点站', `departure_time` datetime NOT NULL COMMENT '发车时间', `estimated_arrival_time` datetime NOT NULL COMMENT '预计到达时间', `total_seats` int(11) NOT NULL COMMENT '总座位数', `available_seats` int(11) NOT NULL COMMENT '可用座位数', `price` decimal(10,2) NOT NULL COMMENT '票价', `status` tinyint(1) DEFAULT '1' COMMENT '状态(0-停运,1-正常)', PRIMARY KEY (`id`), KEY `idx_departure` (`departure_station`,`arrival_station`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='车次表';订单表(order)
CREATE TABLE `order` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `order_no` varchar(32) NOT NULL COMMENT '订单编号', `user_id` bigint(20) NOT NULL COMMENT '用户ID', `schedule_id` bigint(20) NOT NULL COMMENT '车次ID', `passenger_name` varchar(50) NOT NULL COMMENT '乘客姓名', `passenger_id_card` varchar(18) NOT NULL COMMENT '乘客身份证', `seat_number` varchar(10) NOT NULL COMMENT '座位号', `order_amount` decimal(10,2) NOT NULL COMMENT '订单金额', `order_status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '订单状态(0-待支付,1-已支付,2-已取消,3-已完成)', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `idx_order_no` (`order_no`), KEY `idx_user` (`user_id`), KEY `idx_schedule` (`schedule_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单表';
4. 核心功能实现
4.1 余票查询与预订
关键技术实现:
Redis缓存优化:
// ScheduleServiceImpl.java @Cacheable(value = "schedule", key = "#departure+'-'+#arrival") public List<ScheduleVO> querySchedules(String departure, String arrival, Date date) { // 查询数据库逻辑 }座位分配算法:
public synchronized String allocateSeat(Long scheduleId) { // 1. 查询车次座位分布图 String seatMap = redisTemplate.opsForValue() .get("seat_map:" + scheduleId); // 2. 查找第一个可用座位 int seatIndex = seatMap.indexOf('0'); if(seatIndex == -1) { throw new BusinessException("已无可用座位"); } // 3. 更新座位状态 char[] seats = seatMap.toCharArray(); seats[seatIndex] = '1'; redisTemplate.opsForValue() .set("seat_map:" + scheduleId, new String(seats)); // 4. 返回座位号(如'A1','B3'等) return convertToSeatNumber(seatIndex); }
4.2 订单状态机设计
使用状态模式管理订单生命周期:
// OrderState.java public interface OrderState { void pay(Order order); void cancel(Order order); void complete(Order order); } // 具体状态实现 @Component @Scope("prototype") public class PendingPaymentState implements OrderState { @Override public void pay(Order order) { // 支付逻辑 order.setState(OrderStateEnum.PAID.getStateBean()); } @Override public void cancel(Order order) { // 释放座位 seatService.releaseSeat(order.getScheduleId(), order.getSeatNumber()); order.setState(OrderStateEnum.CANCELLED.getStateBean()); } @Override public void complete(Order order) { throw new IllegalStateException("待支付订单不能直接完成"); } }5. 系统安全设计
5.1 防御常见Web攻击
SQL注入防护:
- 使用MyBatis预编译
- 禁止拼接SQL语句
- 定期SQL审计
XSS防护:
@Configuration public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.headers() .xssProtection() .and() .contentSecurityPolicy("script-src 'self'"); } }CSRF防护:
// axios拦截器设置 axios.interceptors.request.use(config => { config.headers['X-CSRF-TOKEN'] = getCookie('csrfToken') return config })
5.2 售票业务安全
超卖问题解决:
- 数据库乐观锁
- Redis分布式锁
- 异步消息队列削峰
分布式锁实现:
public boolean lock(String key, String value, long expire) { return redisTemplate.opsForValue() .setIfAbsent(key, value, expire, TimeUnit.SECONDS); } public boolean unlock(String key, String value) { String luaScript = "if redis.call('get', KEYS[1]) == ARGV[1] then " + "return redis.call('del', KEYS[1]) " + "else return 0 end"; RedisScript<Long> script = new DefaultRedisScript<>(luaScript, Long.class); Long result = redisTemplate.execute(script, Collections.singletonList(key), value); return result != null && result > 0; }
6. 论文写作要点
6.1 技术章节组织建议
系统分析:
- 需求分析(用例图、流程图)
- 可行性分析(技术/经济/操作)
系统设计:
- 架构设计图
- 数据库ER图
- 接口设计文档
系统实现:
- 核心代码片段
- 界面截图
- 测试用例
系统测试:
- 测试方案
- 压力测试报告
- 安全测试结果
6.2 创新点挖掘方向
业务创新:
- 智能推荐路线
- 动态票价策略
- 会员积分体系
技术创新:
- WebSocket实时余票更新
- 大数据分析客流量
- 微服务化改造方案
7. 开发环境搭建
7.1 后端环境
基础环境:
- JDK 17+
- Maven 3.8+
- MySQL 8.0+
- Redis 6.2+
IDE配置:
<!-- pom.xml关键依赖 --> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.3.20</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>2.0.7</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.11</version> </dependency> </dependencies>
7.2 前端环境
Node.js环境:
- Node 16.14+
- npm 8.3+
项目初始化:
# 使用Vite创建项目 npm create vite@latest bus-ticket-frontend --template vue-ts # 安装核心依赖 cd bus-ticket-frontend npm install vue-router@4 pinia axios element-plus npm install sass --save-dev开发配置:
// vite.config.js export default defineConfig({ plugins: [vue()], resolve: { alias: { '@': path.resolve(__dirname, './src') } }, server: { proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true, rewrite: path => path.replace(/^\/api/, '') } } } })
8. 常见问题解决方案
8.1 后端典型问题
MyBatis查询结果为空:
- 检查Mapper.xml中resultMap配置
- 确认字段名是否与数据库一致
- 使用@Results注解明确映射关系
事务失效场景:
- 方法必须是public
- 不能同对象内方法调用
- 异常类型需要匹配rollbackFor
8.2 前端典型问题
Vue响应式失效:
// 错误示范 state.user.age = 25 // 正确做法 state.user = {...state.user, age: 25}跨域问题处理:
// SpringMVC配置 @Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("*") .allowedMethods("GET", "POST", "PUT", "DELETE") .allowCredentials(true) .maxAge(3600); } }
9. 项目扩展方向
微信小程序接入:
- 使用uni-app跨端开发
- 对接微信支付接口
- 实现扫码检票功能
大数据分析模块:
- 使用Flink实时计算客流量
- ECharts可视化展示
- 基于历史数据预测热门线路
微服务化改造:
- Spring Cloud Alibaba技术栈
- Nacos服务注册发现
- Sentinel流量控制
实际开发中,我建议先完成核心票务功能后再考虑扩展。特别注意数据库事务的一致性和高并发场景下的系统稳定性,这些往往是毕业设计答辩时的重点考察内容。