1. 项目概述
这个酒店预订系统采用前后端分离架构,前端使用Vue.js框架,后端基于Spring Boot实现。系统主要解决传统酒店预订过程中存在的效率低下、信息不透明、管理混乱等问题。我在实际开发中发现,这种架构特别适合中小型酒店的数字化升级需求,既能保证系统响应速度,又能降低后期维护成本。
系统包含用户端和管理端两个模块。用户端提供酒店查询、房型展示、在线预订、订单管理等功能;管理端则负责房源管理、订单处理、数据统计等后台操作。从技术实现角度来看,这种分离设计让前后端开发团队能够并行工作,大幅提升开发效率。
2. 核心功能解析
2.1 用户端功能实现
用户注册登录模块采用JWT认证机制,这是我经过多次项目验证的稳定方案。前端Vue组件中,登录状态通过Vuex进行全局管理,关键代码如下:
// store/modules/user.js const actions = { login({ commit }, userInfo) { return new Promise((resolve, reject) => { login(userInfo).then(response => { const { data } = response commit('SET_TOKEN', data.token) setToken(data.token) resolve() }).catch(error => { reject(error) }) }) } }房型展示页面采用了懒加载技术,这是我特别推荐的做法。当用户滚动到页面底部时,才会触发后续房型的加载请求,显著提升了首屏加载速度。实测下来,这种方案比传统分页方式的用户体验更好。
2.2 管理端功能设计
后台管理系统采用RBAC权限控制模型,这是我经过多个项目验证的最佳实践。权限表设计如下:
| 表名 | 字段 | 说明 |
|---|---|---|
| sys_user | id,username,password | 管理员账户表 |
| sys_role | id,name,description | 角色表 |
| sys_menu | id,name,url,perms | 菜单权限表 |
| sys_user_role | user_id,role_id | 用户角色关联表 |
| sys_role_menu | role_id,menu_id | 角色菜单关联表 |
订单统计模块使用了ECharts实现数据可视化,这是我发现的最适合中小型项目的方案。它既不需要复杂的配置,又能满足基本的统计需求。
3. 技术架构详解
3.1 前端技术栈选型
Vue 2.x版本的选择是经过慎重考虑的。虽然Vue 3已经发布,但考虑到生态成熟度和团队熟悉程度,2.x版本仍然是目前企业项目的最稳妥选择。特别是配合Element UI组件库,可以快速搭建出专业的管理界面。
我在项目中特别注意了以下几点:
- 使用axios拦截器统一处理请求和响应
- 采用vue-router实现路由守卫
- 通过环境变量管理不同环境的API地址
- 使用ESLint统一代码风格
3.2 后端技术实现
Spring Boot的版本选择2.3.7.RELEASE,这是长期支持版本,稳定性有保障。数据库选用MySQL 5.7,主要考虑到以下几点:
- 事务支持完善
- 社区资源丰富
- 与Spring生态集成度高
MyBatis-Plus的使用大幅简化了CRUD操作,这是我强烈推荐的ORM框架。它的Wrapper条件构造器让复杂查询变得非常简单:
// 示例:查询今天之后的预订订单 LambdaQueryWrapper<Order> wrapper = new LambdaQueryWrapper<>(); wrapper.ge(Order::getCheckInDate, LocalDate.now()) .orderByAsc(Order::getCreateTime); List<Order> orders = orderMapper.selectList(wrapper);4. 数据库设计要点
4.1 核心表结构
酒店系统的数据库设计有几个关键点需要特别注意:
- 房型表与房间表的分离设计
- 订单状态的完整生命周期记录
- 价格日历的特殊处理
房型表(hotel_room_type)设计示例:
CREATE TABLE `hotel_room_type` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `hotel_id` bigint(20) NOT NULL COMMENT '所属酒店ID', `name` varchar(50) NOT NULL COMMENT '房型名称', `bed_type` varchar(20) DEFAULT NULL COMMENT '床型', `max_occupancy` int(11) DEFAULT '2' COMMENT '最大入住人数', `area` decimal(10,2) DEFAULT NULL COMMENT '面积(平方米)', `window_type` tinyint(4) DEFAULT '1' COMMENT '窗户类型:1-有窗 2-无窗', `status` tinyint(4) DEFAULT '1' COMMENT '状态:0-下架 1-上架', PRIMARY KEY (`id`), KEY `idx_hotel_id` (`hotel_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='房型表';4.2 订单表设计技巧
订单表的设计有几个经验要点:
- 保留价格快照,防止后续价格变更影响历史订单
- 记录完整的操作日志
- 考虑取消政策的时间节点
订单表的核心字段设计:
| 字段名 | 类型 | 说明 |
|---|---|---|
| order_no | varchar(32) | 订单编号(业务主键) |
| user_id | bigint(20) | 用户ID |
| room_type_id | bigint(20) | 房型ID |
| check_in_date | date | 入住日期 |
| check_out_date | date | 离店日期 |
| total_amount | decimal(10,2) | 订单总金额 |
| status | tinyint(4) | 订单状态 |
| create_time | datetime | 创建时间 |
| update_time | datetime | 更新时间 |
5. 开发中的关键问题与解决方案
5.1 并发预订问题处理
酒店预订最关键的并发问题,我通过以下方案解决:
- 使用数据库乐观锁控制库存
- 关键操作添加分布式锁
- 引入排队机制缓解瞬时压力
具体实现代码示例:
public boolean bookRoom(Long roomTypeId, LocalDate checkInDate, int nights) { // 1. 检查房态 RoomStock stock = roomStockMapper.selectForUpdate(roomTypeId, checkInDate); if (stock == null || stock.getRemain() <= 0) { throw new BusinessException("该房型已售罄"); } // 2. 扣减库存 int updateRows = roomStockMapper.reduceStock( roomTypeId, checkInDate, stock.getVersion()); if (updateRows == 0) { throw new ConcurrentBookingException("预订冲突,请重试"); } // 3. 创建订单 // ... }5.2 日期价格动态计算
酒店价格随日期波动的实现方案:
- 基础价格 + 价格日历的组合设计
- 节假日价格的特殊处理
- 连住优惠的逻辑实现
价格计算的核心逻辑:
public BigDecimal calculatePrice(Long roomTypeId, LocalDate checkInDate, int nights) { BigDecimal total = BigDecimal.ZERO; // 获取基础价格 RoomType roomType = roomTypeMapper.selectById(roomTypeId); BigDecimal basePrice = roomType.getBasePrice(); // 按天计算价格 for (int i = 0; i < nights; i++) { LocalDate currentDate = checkInDate.plusDays(i); // 检查是否有特殊日期价格 SpecialPrice specialPrice = specialPriceMapper.selectByDate( roomTypeId, currentDate); BigDecimal dayPrice = specialPrice != null ? specialPrice.getPrice() : basePrice; total = total.add(dayPrice); } // 应用连住优惠 if (nights >= 3) { total = total.multiply(BigDecimal.valueOf(0.9)); } return total.setScale(2, RoundingMode.HALF_UP); }6. 部署与性能优化
6.1 系统部署方案
推荐以下部署架构:
- 前端静态资源部署在Nginx
- 后端Spring Boot应用使用Docker容器化
- MySQL建议主从配置
- Redis缓存会话和热点数据
这是我验证过的高性价比方案,特别适合中小型酒店。Nginx配置关键部分:
server { listen 80; server_name hotel.example.com; location / { root /usr/share/nginx/html; index index.html; try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://backend:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }6.2 性能优化实践
经过实际压测,以下几个优化措施效果显著:
- 添加Redis缓存房型基本信息
- 使用CDN加速静态资源
- 数据库查询优化
- 启用Gzip压缩
缓存实现示例:
@Cacheable(value = "roomType", key = "#id") public RoomType getRoomTypeById(Long id) { return roomTypeMapper.selectById(id); } @CacheEvict(value = "roomType", key = "#roomType.id") public void updateRoomType(RoomType roomType) { roomTypeMapper.updateById(roomType); }7. 安全防护措施
7.1 常见安全风险防范
在开发过程中,我特别注意了以下几点安全防护:
- SQL注入防护:使用预编译语句
- XSS攻击防护:前端过滤 + 后端转义
- CSRF防护:Spring Security默认启用
- 敏感数据加密:密码加盐哈希存储
密码加密实现:
public class PasswordEncoder implements org.springframework.security.crypto.password.PasswordEncoder { private final BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(); @Override public String encode(CharSequence rawPassword) { return encoder.encode(rawPassword); } @Override public boolean matches(CharSequence rawPassword, String encodedPassword) { return encoder.matches(rawPassword, encodedPassword); } }7.2 接口安全设计
API接口安全方案:
- 使用HTTPS传输
- 接口签名验证
- 敏感操作二次认证
- 完善的权限控制
接口限流实现(使用Guava RateLimiter):
@Aspect @Component public class RateLimitAspect { private final Map<String, RateLimiter> limiters = new ConcurrentHashMap<>(); @Around("@annotation(rateLimit)") public Object around(ProceedingJoinPoint pjp, RateLimit rateLimit) throws Throwable { String key = rateLimit.value(); RateLimiter limiter = limiters.computeIfAbsent( key, k -> RateLimiter.create(rateLimit.permit())); if (limiter.tryAcquire()) { return pjp.proceed(); } else { throw new BusinessException("操作过于频繁,请稍后再试"); } } }8. 项目扩展方向
基于这个基础框架,还可以进一步扩展以下功能:
- 会员积分系统
- 智能推荐算法
- 微信小程序端
- 对接第三方支付
- 酒店PMS系统集成
会员积分系统的设计思路:
- 积分获取规则配置
- 积分消耗场景设计
- 积分过期策略
- 积分流水记录
积分核心表结构建议:
CREATE TABLE `member_points` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `user_id` bigint(20) NOT NULL, `balance` int(11) NOT NULL DEFAULT '0', `version` int(11) NOT NULL DEFAULT '0', PRIMARY KEY (`id`), UNIQUE KEY `uk_user_id` (`user_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE `points_log` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `user_id` bigint(20) NOT NULL, `points` int(11) NOT NULL, `type` tinyint(4) NOT NULL COMMENT '1-获取 2-消耗', `biz_type` varchar(20) NOT NULL COMMENT '业务类型', `biz_id` varchar(32) DEFAULT NULL COMMENT '业务ID', `remark` varchar(255) DEFAULT NULL, `create_time` datetime NOT NULL, PRIMARY KEY (`id`), KEY `idx_user_id` (`user_id`), KEY `idx_create_time` (`create_time`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;在实际开发中,我发现酒店预订系统有几个特别需要注意的点:日期处理一定要考虑时区问题,价格计算要保留足够的小数位精度,订单状态流转要设计完整的生命周期。这些细节处理不好,后期会产生很多边界问题。