Java实战:从零构建火车票订购系统(附完整源码)

一、项目背景与需求分析
在互联网购票场景中,用户需要完成车次查询、座位选择、订单生成、支付等核心功能。本系统采用分层架构设计,包含以下核心模块:

  1. 用户管理模块:支持注册/登录/信息修改
  2. 车次管理模块:实现车次信息的增删改查
  3. 订单管理模块:处理订单生成、支付、退改签
  4. 通知服务模块:集成短信/邮件通知功能

技术选型方面,采用Spring Boot 2.7快速开发框架,结合MyBatis-Plus实现ORM映射,使用MySQL 8.0作为主数据库,Redis缓存高频访问数据。前端采用Thymeleaf模板引擎实现基础页面,预留RESTful API接口供后续扩展。

二、数据库设计详解

  1. 核心表结构设计
    ``sql
    CREATE TABLE
    train_schedule(idbigint NOT NULL AUTO_INCREMENT,train_novarchar(20) NOT NULL COMMENT '车次编号',start_stationvarchar(50) NOT NULL COMMENT '始发站',end_stationvarchar(50) NOT NULL COMMENT '终点站',depart_timedatetime NOT NULL COMMENT '发车时间',arrive_timedatetime NOT NULL COMMENT '到达时间',
    PRIMARY KEY (
    id),
    UNIQUE KEY
    idx_train_no(train_no`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

CREATE TABLE seat_inventory (
id bigint NOT NULL AUTO_INCREMENT,
schedule_id bigint NOT NULL COMMENT ‘关联车次ID’,
seat_type enum(‘FIRST_CLASS’,’SECOND_CLASS’,’HARD_SEAT’) NOT NULL COMMENT ‘座位类型’,
total_seats int NOT NULL COMMENT ‘总座位数’,
available_seats int NOT NULL COMMENT ‘可用座位数’,
PRIMARY KEY (id),
KEY idx_schedule (schedule_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

  1. 2. 索引优化策略
  2. - 在车次表的train_no字段建立唯一索引
  3. - 座位库存表按schedule_id建立普通索引
  4. - 订单表按user_idcreate_time建立复合索引
  5. 三、核心模块实现
  6. 1. 分布式锁实现余票控制
  7. ```java
  8. @Service
  9. public class SeatServiceImpl implements SeatService {
  10. @Autowired
  11. private RedisTemplate<String, Object> redisTemplate;
  12. @Override
  13. public boolean lockSeat(Long scheduleId, String seatType) {
  14. String lockKey = "seat:lock:" + scheduleId + ":" + seatType;
  15. try {
  16. return redisTemplate.opsForValue().setIfAbsent(lockKey, "1", 10, TimeUnit.SECONDS);
  17. } catch (Exception e) {
  18. log.error("获取座位锁失败", e);
  19. return false;
  20. }
  21. }
  22. @Override
  23. public void releaseSeat(Long scheduleId, String seatType) {
  24. String lockKey = "seat:lock:" + scheduleId + ":" + seatType;
  25. redisTemplate.delete(lockKey);
  26. }
  27. }
  1. 订单状态机设计
    采用枚举类定义订单状态流转:

    1. public enum OrderStatus {
    2. UNPAID(0, "待支付"),
    3. PAID(1, "已支付"),
    4. REFUNDED(2, "已退款"),
    5. CANCELLED(3, "已取消");
    6. private final int code;
    7. private final String desc;
    8. // 状态流转规则
    9. public static boolean canTransition(OrderStatus from, OrderStatus to) {
    10. switch (from) {
    11. case UNPAID:
    12. return to == PAID || to == CANCELLED;
    13. case PAID:
    14. return to == REFUNDED;
    15. default:
    16. return false;
    17. }
    18. }
    19. }
  2. 查询优化实现

  • 使用MyBatis-Plus的Wrapper条件构造器

    1. public Page<TrainSchedule> querySchedules(String startStation, String endStation,
    2. LocalDate departDate, Pageable pageable) {
    3. LambdaQueryWrapper<TrainSchedule> wrapper = new LambdaQueryWrapper<>();
    4. wrapper.eq(TrainSchedule::getStartStation, startStation)
    5. .eq(TrainSchedule::getEndStation, endStation)
    6. .ge(TrainSchedule::getDepartTime, departDate.atStartOfDay())
    7. .lt(TrainSchedule::getDepartTime, departDate.plusDays(1).atStartOfDay());
    8. return trainScheduleMapper.selectPage(
    9. new Page<>(pageable.getPageNumber(), pageable.getPageSize()),
    10. wrapper
    11. );
    12. }

四、系统部署方案

  1. 开发环境配置
  • JDK 11+
  • Maven 3.8+
  • MySQL 8.0
  • Redis 6.0+
  1. 生产环境建议
  • 采用Nginx负载均衡
  • 数据库主从复制架构
  • 引入消息队列处理异步通知
  • 使用对象存储保存票据文件
  1. 性能优化措施
  • 热点数据缓存:车次信息缓存10分钟
  • 数据库连接池配置:HikariCP默认配置优化
  • 异步处理:订单支付结果通知采用消息队列

五、完整源码获取方式
项目采用MIT开源协议,完整源码包含:

  1. 前端页面(Thymeleaf模板)
  2. 后端服务(Spring Boot项目)
  3. 数据库脚本(DDL+初始化数据)
  4. 接口文档(Swagger UI)
  5. 部署指南(Docker Compose配置)

获取方式:关注开发者社区,回复”train-ticket”获取托管仓库地址。源码包含详细注释和开发文档,适合不同层次的开发者学习参考。

六、扩展功能建议

  1. 支付系统集成:对接主流支付渠道
  2. 用户等级体系:根据购票次数划分等级
  3. 智能推荐:基于历史数据推荐车次
  4. 数据分析模块:统计客流高峰时段
  5. 移动端适配:开发微信小程序版本

本系统设计充分考虑了高并发场景下的数据一致性要求,通过分布式锁、乐观锁等机制保证余票计算的准确性。实际开发中可根据具体需求调整技术选型,例如将MySQL替换为其他关系型数据库,或引入分布式事务框架处理复杂业务场景。