1. 项目概述
作为一名有10年Java全栈开发经验的工程师,我经常被问到如何选择一个既实用又有技术深度的毕业设计项目。基于SpringBoot的航空公司售票系统就是一个非常不错的选择,它不仅涵盖了企业级应用开发的完整技术栈,还能很好地展示你的综合能力。
这个系统采用前后端分离架构,后端使用SpringBoot+MyBatisPlus,前端使用Vue.js,数据库采用MySQL,是一个典型的现代化Web应用。系统实现了用户管理、航班查询、机票预订、订单管理等核心功能模块,完全模拟了真实航空公司的业务场景。
2. 技术选型解析
2.1 后端技术栈
Spring Boot作为我们的核心框架,它最大的优势在于"约定优于配置"的理念。在实际开发中,我发现以下几点特别值得注意:
-
自动配置:Spring Boot会根据项目依赖自动配置各种Bean。比如我们引入了spring-boot-starter-web,它就会自动配置Tomcat和Spring MVC。
-
Starter依赖:通过spring-boot-starter-*系列依赖,可以快速集成各种功能。例如:
xml复制<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> -
Actuator监控:生产环境中特别有用,可以监控应用健康状态:
properties复制management.endpoints.web.exposure.include=*
2.2 数据库设计
MySQL作为关系型数据库,在设计中我遵循了以下原则:
-
三范式设计:确保数据冗余最小化。例如用户表和订单表分开设计,通过外键关联。
-
索引优化:对高频查询字段如航班号、出发时间建立索引:
sql复制CREATE INDEX idx_flight_number ON flight(flight_number); -
事务处理:对于购票这种关键操作,使用@Transactional确保数据一致性:
java复制@Transactional public void bookTicket(Order order) { // 扣减库存 flightMapper.updateSeat(order.getFlightId(), -1); // 创建订单 orderMapper.insert(order); }
3. 核心功能实现
3.1 用户认证模块
采用JWT实现无状态认证,这是我总结的最佳实践:
-
登录流程:
java复制public String login(String username, String password) { User user = userService.findByUsername(username); if(!passwordEncoder.matches(password, user.getPassword())) { throw new RuntimeException("密码错误"); } return Jwts.builder() .setSubject(username) .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME)) .signWith(SignatureAlgorithm.HS512, SECRET) .compact(); } -
权限控制:使用Spring Security实现基于角色的访问控制:
java复制@PreAuthorize("hasRole('ADMIN')") @GetMapping("/users") public List<User> getAllUsers() { return userService.findAll(); }
3.2 航班查询功能
这是系统的核心功能之一,我采用了以下优化策略:
-
缓存设计:使用Redis缓存热门航线数据:
java复制@Cacheable(value = "flights", key = "#departureCity+'-'+#arrivalCity") public List<Flight> searchFlights(String departureCity, String arrivalCity, Date date) { // 数据库查询 } -
分页查询:MyBatisPlus提供的分页功能非常便捷:
java复制Page<Flight> page = new Page<>(pageNum, pageSize); return flightMapper.selectPage(page, new QueryWrapper<Flight>() .eq("departure_city", departureCity) .eq("arrival_city", arrivalCity) .ge("departure_time", date) );
4. 订单系统设计
4.1 订单状态机
订单状态流转是售票系统的核心逻辑,我设计了一个状态机来处理各种状态转换:
java复制public enum OrderStatus {
PENDING_PAYMENT {
@Override
public boolean canChangeTo(OrderStatus newStatus) {
return newStatus == PAID || newStatus == CANCELLED;
}
},
PAID {
@Override
public boolean canChangeTo(OrderStatus newStatus) {
return newStatus == COMPLETED || newStatus == REFUNDING;
}
},
// 其他状态...
}
4.2 库存控制
为了防止超卖,我实现了两种方案:
-
乐观锁:
java复制@Update("UPDATE flight SET seats = seats - 1 WHERE id = #{id} AND seats > 0") int deductSeat(@Param("id") Long id); -
分布式锁(适用于集群环境):
java复制public boolean bookWithLock(Long flightId) { String lockKey = "flight_lock:" + flightId; try { Boolean locked = redisTemplate.opsForValue().setIfAbsent(lockKey, "1", 10, TimeUnit.SECONDS); if(locked != null && locked) { // 执行购票逻辑 } } finally { redisTemplate.delete(lockKey); } }
5. 系统部署方案
5.1 容器化部署
使用Docker可以大大简化部署流程,这是我的Dockerfile示例:
dockerfile复制FROM openjdk:8-jdk-alpine
VOLUME /tmp
COPY target/airline-system-0.0.1-SNAPSHOT.jar app.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
5.2 CI/CD流程
配合Jenkins实现自动化部署:
- 构建阶段:执行单元测试和打包
- 部署阶段:通过SSH将jar包上传到服务器
- 启动阶段:执行docker-compose up -d
6. 常见问题与解决方案
6.1 性能优化
在实际开发中,我遇到了几个性能瓶颈:
- N+1查询问题:使用MyBatisPlus的@TableField(select = false)延迟加载关联字段
- 大表查询慢:添加适当索引并考虑分表策略
- 高并发下单:使用Redis分布式锁+库存预扣减
6.2 安全防护
- SQL注入:坚持使用MyBatis的参数化查询
- XSS攻击:前端使用vue-sanitize过滤输入
- CSRF防护:Spring Security默认提供的CSRF防护
7. 项目扩展方向
这个基础系统还可以进一步扩展:
- 大数据分析:集成Hadoop分析航线热度
- 推荐系统:基于用户历史订单推荐相关航线
- 移动端适配:开发React Native跨平台应用
- 微服务改造:将系统拆分为用户服务、航班服务、订单服务等
8. 开发心得
经过这个项目的开发,我总结了以下几点经验:
- 文档先行:在编码前先写好API文档,使用Swagger UI展示
- 测试驱动:对核心功能如购票流程编写完整的单元测试
- 代码规范:使用Checkstyle和SpotBugs保证代码质量
- 性能考量:在早期就考虑缓存策略和数据库优化
对于初学者,我建议先从基础功能开始,逐步添加复杂特性。例如先实现单机版的购票流程,再考虑分布式锁和消息队列等高阶功能。