Joejoe_Hotel:Spring Boot + MyBatis-Plus 酒店管理系统
完整的酒店后台管理系统,集成 MyBatis-Plus、Spring Security、JWT、Druid、Swagger 等技术栈。
Joejoe_Hotel:Spring Boot + MyBatis-Plus 酒店管理系统
系统功能
包含酒店管理的基本模块:房间管理、预订管理、入住登记、订单结算。虽然功能看起来常规,但酒店业务有几个很有意思的技术难点。
核心难点:时间冲突检测
酒店预订系统最核心的算法是检测两个预订时间段是否重叠:
public boolean hasConflict(Long roomId, Date newStart, Date newEnd) {
// 冲突条件:新预订开始 < 已有预订结束 AND 新预订结束 > 已有预订开始
LambdaQueryWrapper<Booking> wrapper = Wrappers.<Booking>lambdaQuery()
.eq(Booking::getRoomId, roomId)
.in(Booking::getStatus, "confirmed", "checked_in")
.lt(Booking::getCheckIn, newEnd) // 已有开始 < 新结束
.gt(Booking::getCheckOut, newStart); // 已有结束 > 新开始
return bookingMapper.selectCount(wrapper) > 0;
}
这个冲突检测逻辑不局限于酒店——会议室预约、租车、机房机位、教室等所有需要"时间段独占"的场景都适用。
需要注意的边界情况:
- 入住当天 14:00 到退房当天 12:00 算一天(时间精度问题)
- 同一个房间的连续预订中间需要预留打扫时间(+2 小时)
- 跨月、跨年的预订日期计算
房间状态流转
房间有 4 种状态,状态转换有严格限制:
空闲 ──预订──→ 已预订 ──入住──→ 入住中 ──退房──→ 空闲
↑ ↑ ↓
└──打扫完成──← 打扫中 ←───── 退房 ─────────┘
状态机实现:
public enum RoomStatus {
AVAILABLE, // 空闲
RESERVED, // 已预订(未入住)
OCCUPIED, // 入住中
CLEANING; // 打扫中
public boolean canTransitionTo(RoomStatus target) {
return switch (this) {
case AVAILABLE -> target == RESERVED;
case RESERVED -> target == OCCUPIED || target == AVAILABLE;
case OCCUPIED -> target == CLEANING;
case CLEANING -> target == AVAILABLE;
};
}
}
状态机可以防止非法操作:比如入住中的房间不能跳过打扫直接变为空闲。
价格体系
酒店价格根据不同日期变化:
- 平日:标准价
- 周末:标准价 × 1.2
- 节假日:标准价 × 1.5-2.0(如春节、国庆)
- 连住优惠:连住 3 天以上打 9 折
public BigDecimal calculatePrice(Room room, LocalDate start, LocalDate end) {
BigDecimal total = BigDecimal.ZERO;
LocalDate date = start;
while (date.isBefore(end)) {
BigDecimal price = isHoliday(date) ? room.getHolidayPrice()
: isWeekend(date) ? room.getWeekendPrice()
: room.getWeekdayPrice();
total = total.add(price);
date = date.plusDays(1);
}
// 连住优惠
long nights = ChronoUnit.DAYS.between(start, end);
if (nights >= 3) total = total.multiply(new BigDecimal("0.9"));
return total;
}
总结
酒店管理系统的难点不在 CRUD,而在时间冲突检测、状态机管理、动态定价这三个业务逻辑。这些模式在会议室、机票、租车等预订类系统中都是通用的,理解了一个就等于理解了全部。