1. 项目背景与需求分析
自习室作为学生和备考人群的重要学习场所,其管理效率直接影响用户体验。传统自习室普遍存在以下痛点:
- 座位管理混乱:手工登记或先到先得方式导致座位分配不透明
- 预约流程繁琐:线下排队或电话预约耗时耗力
- 资源利用率低:高峰时段座位紧张,空闲时段大量闲置
- 统计效率低下:管理员难以及时获取使用数据进行分析
我们团队在调研了30+所高校自习室后,发现75%的投诉源于预约管理问题。这个基于SpringBoot的预约系统正是为解决这些痛点而生。
2. 技术选型与架构设计
2.1 技术栈组成
后端核心:
- SpringBoot 2.7.3(稳定版)
- MyBatis-Plus 3.5.1(增强CRUD操作)
- Spring Security(权限控制)
- Redis 6.2(缓存和分布式锁)
前端技术:
- Vue 3 + Element Plus
- Axios(HTTP请求)
- ECharts(数据可视化)
数据库:
- MySQL 8.0(事务型数据)
- 表设计遵循第三范式
2.2 系统架构
采用经典三层架构:
code复制表现层(Controller) → 业务层(Service) → 持久层(Mapper)
特别增加了预约服务层处理核心业务逻辑,采用DDD领域驱动设计思想。
3. 核心功能实现
3.1 座位预约模块
关键代码实现:
java复制@Transactional
public ReservationResult makeReservation(ReservationDTO dto) {
// 分布式锁防止超卖
String lockKey = "seat:" + dto.getSeatId();
try {
boolean locked = redisTemplate.opsForValue()
.setIfAbsent(lockKey, "1", 10, TimeUnit.SECONDS);
if (!locked) {
return ReservationResult.fail("当前座位正在被预约");
}
// 检查座位状态
Seat seat = seatMapper.selectById(dto.getSeatId());
if (seat.getStatus() != SeatStatus.AVAILABLE) {
return ReservationResult.fail("座位不可用");
}
// 检查用户预约冲突
if (reservationMapper.checkConflict(dto.getUserId(), dto.getTimeRange()) > 0) {
return ReservationResult.fail("您已有其他预约");
}
// 创建预约记录
Reservation reservation = new Reservation();
BeanUtils.copyProperties(dto, reservation);
reservation.setCreateTime(LocalDateTime.now());
reservationMapper.insert(reservation);
// 更新座位状态
seat.setStatus(SeatStatus.RESERVED);
seatMapper.updateById(seat);
return ReservationResult.success(reservation.getId());
} finally {
redisTemplate.delete(lockKey);
}
}
关键技术点:
- 使用Redis分布式锁解决并发问题
- 采用乐观锁保证数据一致性
- 事务管理确保操作原子性
3.2 实时座位状态同步
前端通过WebSocket实时接收座位状态变更:
javascript复制const socket = new WebSocket(`wss://${location.host}/ws/seat`);
socket.onmessage = (event) => {
const data = JSON.parse(event.data);
store.commit('updateSeatStatus', data);
};
后端推送逻辑:
java复制@GetMapping("/status/{roomId}")
public void pushSeatStatus(@PathVariable String roomId) {
List<Seat> seats = seatService.listByRoom(roomId);
messagingTemplate.convertAndSend("/topic/seat/" + roomId, seats);
}
4. 数据库设计
4.1 主要表结构
座位表(seat):
sql复制CREATE TABLE `seat` (
`id` bigint NOT NULL AUTO_INCREMENT,
`room_id` bigint NOT NULL COMMENT '所属教室',
`seat_number` varchar(20) NOT NULL COMMENT '座位编号',
`status` tinyint NOT NULL DEFAULT '0' COMMENT '0-可用 1-已预约 2-维修中',
`x_position` int DEFAULT NULL COMMENT 'X坐标',
`y_position` int DEFAULT NULL COMMENT 'Y坐标',
PRIMARY KEY (`id`),
KEY `idx_room` (`room_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
预约记录表(reservation):
sql复制CREATE TABLE `reservation` (
`id` bigint NOT NULL AUTO_INCREMENT,
`user_id` bigint NOT NULL,
`seat_id` bigint NOT NULL,
`start_time` datetime NOT NULL,
`end_time` datetime NOT NULL,
`status` tinyint NOT NULL DEFAULT '0' COMMENT '0-预约中 1-已签到 2-已取消',
`create_time` datetime NOT NULL,
PRIMARY KEY (`id`),
KEY `idx_user` (`user_id`),
KEY `idx_seat_time` (`seat_id`,`start_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
5. 关键问题解决方案
5.1 高并发预约处理
采用多级缓存策略:
- 热点座位信息缓存在Redis
- 使用分布式锁控制并发
- 数据库层面使用乐观锁
5.2 预约冲突检测
通过组合索引优化查询:
sql复制SELECT COUNT(*) FROM reservation
WHERE seat_id = ?
AND ((start_time < ? AND end_time > ?)
OR (start_time >= ? AND start_time < ?))
5.3 定时任务处理
使用Spring Scheduled处理超时预约:
java复制@Scheduled(cron = "0 0/5 * * * ?")
public void checkExpiredReservations() {
LocalDateTime now = LocalDateTime.now();
List<Reservation> expired = reservationMapper.selectExpired(now);
expired.forEach(res -> {
res.setStatus(ReservationStatus.EXPIRED);
reservationMapper.updateById(res);
seatService.releaseSeat(res.getSeatId());
});
}
6. 系统部署方案
6.1 生产环境配置
服务器建议:
- 2核4G云服务器(最低配置)
- CentOS 7.6+
- JDK 17
- MySQL 8.0主从配置
Nginx配置示例:
nginx复制upstream backend {
server 127.0.0.1:8080;
keepalive 32;
}
server {
listen 80;
server_name yourdomain.com;
location / {
root /var/www/html;
try_files $uri $uri/ /index.html;
}
location /api/ {
proxy_pass http://backend;
proxy_set_header Host $host;
}
}
7. 开发经验总结
- 事务边界:预约业务要确保座位状态更新和预约记录插入在同一个事务中
- 缓存策略:热点数据缓存要设置合理的过期时间,避免脏读
- 接口设计:RESTful接口要遵循幂等性原则
- 日志记录:关键操作要记录详细日志便于排查问题
提示:在实际开发中发现,MySQL的间隙锁在处理时间范围冲突时非常有效,但要注意合理设置事务隔离级别。
8. 扩展优化方向
- 智能推荐:基于用户历史行为推荐合适座位
- 信用体系:建立用户信用评分机制
- 人脸识别:集成人脸识别签到功能
- 数据分析:深度分析座位使用率数据
这个项目从需求分析到最终上线历时3个月,期间最大的收获是认识到良好的系统设计应该从用户真实场景出发。比如最初设计的30分钟预约保留期在实际运营中发现太短,后调整为45分钟更符合用户从宿舍到自习室的移动时间。