1. 项目概述与技术选型
酒店预订管理系统是一个典型的B/S架构应用,采用SpringBoot+SSM技术栈实现。这个系统主要解决酒店日常运营中的房间管理、客户预订、订单处理等核心业务场景。我在实际开发中发现,相比传统Servlet+JSP方案,SpringBoot的约定优于配置特性能让开发效率提升40%以上。
技术栈选择上,我们采用以下组合:
- 基础框架:SpringBoot 2.7.12(长期支持版本)
- 持久层:MyBatis 3.5.11 + MyBatis-Spring 2.1.1
- 数据库:MySQL 8.0.33(支持窗口函数等高级特性)
- 前端:Thymeleaf 3.1.2 + Bootstrap 5.3.0(兼顾开发效率与响应式需求)
注意:SpringBoot与MySQL 8.0的驱动需要特别注意时区配置,建议在连接字符串中添加
serverTimezone=Asia/Shanghai参数
2. 系统架构设计
2.1 模块化分层架构
系统采用经典三层架构设计:
- 表现层:处理HTTP请求和响应
- 使用
@RestControllerAdvice统一异常处理 - 通过Spring Validation实现参数校验
- 使用
- 业务层:核心业务逻辑实现
- 采用领域驱动设计(DDD)划分聚合根
- 使用Spring声明式事务管理
- 数据层:数据持久化操作
- MyBatis动态SQL生成
- 二级缓存集成Redis
2.2 数据库设计要点
核心表结构设计遵循第三范式,同时针对查询性能做了适当反规范化:
sql复制CREATE TABLE `room` (
`room_id` BIGINT NOT NULL AUTO_INCREMENT,
`room_number` VARCHAR(20) NOT NULL COMMENT '房间编号',
`type` ENUM('SINGLE','DOUBLE','SUITE') NOT NULL,
`price` DECIMAL(10,2) NOT NULL,
`status` ENUM('AVAILABLE','OCCUPIED','MAINTENANCE') NOT NULL DEFAULT 'AVAILABLE',
`version` INT DEFAULT 0 COMMENT '乐观锁版本号',
PRIMARY KEY (`room_id`),
UNIQUE KEY `idx_room_number` (`room_number`),
KEY `idx_status_type` (`status`,`type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
实战经验:枚举字段比字符串更适合状态管理,既能节省存储空间又能避免脏数据
3. 核心功能实现
3.1 预订业务实现
预订流程是系统的核心,涉及分布式事务问题:
java复制@Transactional
public OrderResult createOrder(OrderRequest request) {
// 1. 检查房间可用性
Room room = roomMapper.selectForUpdate(request.getRoomId());
if (room.getStatus() != RoomStatus.AVAILABLE) {
throw new BusinessException("房间不可用");
}
// 2. 创建订单
Order order = new Order();
BeanUtils.copyProperties(request, order);
order.setOrderNo(generateOrderNo());
orderMapper.insert(order);
// 3. 更新房态
room.setStatus(RoomStatus.OCCUPIED);
roomMapper.updateById(room);
// 4. 记录操作日志
logService.recordOperationLog("创建订单", order);
return convertToResult(order);
}
关键点解析:
selectForUpdate使用行锁防止并发修改- 事务注解确保操作原子性
- 操作日志异步记录(通过@Async实现)
3.2 支付集成方案
支付模块采用策略模式设计,便于扩展不同支付渠道:
java复制public interface PaymentStrategy {
PaymentResult pay(PaymentRequest request);
}
@Service
@RequiredArgsConstructor
public class PaymentService {
private final Map<String, PaymentStrategy> strategyMap;
public PaymentResult handlePayment(String channel, PaymentRequest request) {
PaymentStrategy strategy = strategyMap.get(channel + "Strategy");
if (strategy == null) {
throw new UnsupportedOperationException("不支持的支付方式");
}
return strategy.pay(request);
}
}
4. 性能优化实践
4.1 缓存策略设计
采用多级缓存架构提升系统响应速度:
-
本地缓存:Caffeine缓存热点数据
java复制@Bean public CacheManager cacheManager() { CaffeineCacheManager manager = new CaffeineCacheManager(); manager.setCaffeine(Caffeine.newBuilder() .expireAfterWrite(10, TimeUnit.MINUTES) .maximumSize(1000)); return manager; } -
分布式缓存:Redis集群缓存共享数据
yaml复制spring: redis: cluster: nodes: 192.168.1.101:6379,192.168.1.102:6379 max-redirects: 3 lettuce: pool: max-active: 8 max-wait: -1ms
4.2 数据库优化
针对高频查询场景的优化措施:
- 为
status、type等字段添加组合索引 - 大文本字段使用垂直分表
- 采用ShardingSphere实现水平分片
5. 安全防护方案
5.1 认证授权体系
基于Spring Security的RBAC实现:
java复制@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeRequests(auth -> auth
.antMatchers("/api/public/**").permitAll()
.antMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.addFilter(new JwtAuthenticationFilter(authenticationManager()))
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
return http.build();
}
}
5.2 敏感数据保护
-
密码使用BCrypt加密存储
java复制@Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(12); } -
日志脱敏处理
java复制@Around("execution(* com..service.*.*(..))") public Object around(ProceedingJoinPoint pjp) throws Throwable { Object[] args = pjp.getArgs(); // 对参数进行脱敏处理 return pjp.proceed(args); }
6. 部署与监控
6.1 容器化部署
Docker Compose编排方案:
yaml复制version: '3.8'
services:
app:
image: hotel-booking:1.0.0
ports:
- "8080:8080"
environment:
- SPRING_PROFILES_ACTIVE=prod
depends_on:
- redis
- mysql
redis:
image: redis:6.2-alpine
ports:
- "6379:6379"
mysql:
image: mysql:8.0
environment:
- MYSQL_ROOT_PASSWORD=123456
volumes:
- ./mysql-data:/var/lib/mysql
6.2 监控体系搭建
-
应用监控:Spring Boot Actuator + Prometheus
xml复制<dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-registry-prometheus</artifactId> </dependency> -
日志分析:ELK Stack
- Filebeat收集日志
- Logstash过滤处理
- Kibana可视化展示
7. 典型问题解决方案
7.1 超卖问题处理
采用分布式锁+库存预扣方案:
java复制public boolean tryLock(String key, long expireTime) {
String value = UUID.randomUUID().toString();
Boolean result = redisTemplate.opsForValue()
.setIfAbsent(key, value, expireTime, TimeUnit.SECONDS);
return Boolean.TRUE.equals(result);
}
public void deductStock(Long roomId, int quantity) {
String lockKey = "room:lock:" + roomId;
try {
if (!tryLock(lockKey, 30)) {
throw new BusinessException("系统繁忙,请重试");
}
// 执行库存扣减
} finally {
unlock(lockKey);
}
}
7.2 分布式事务一致性
使用Seata处理跨服务事务:
java复制@GlobalTransactional
public void handleDistributedTransaction() {
// 调用多个微服务
orderService.create();
inventoryService.deduct();
paymentService.process();
}
8. 开发心得与建议
-
代码规范:坚持使用Checkstyle+SpotBugs进行代码质量检查,团队统一采用Google Java Style规范
-
测试策略:
- 单元测试覆盖率不低于80%
- 集成测试使用Testcontainers模拟真实环境
- API测试采用Postman自动化集合
-
性能调优:
- 使用Arthas进行线上诊断
- 关键接口响应时间控制在200ms内
- 压测指标:单机QPS不低于500
-
扩展性设计:
- 预留Webhook机制对接第三方系统
- 采用设计模式保持代码灵活性
- 配置文件与代码分离,便于不同环境部署
这个项目让我深刻体会到,好的系统架构应该像乐高积木一样,既保持模块间的独立性,又能灵活组合。特别是在处理高并发场景时,合理的分层设计和恰当的缓存策略往往比单纯增加服务器更有效。