
1. 项目背景与技术选型图书馆座位资源紧张一直是高校普遍存在的问题。每到考试周学生们凌晨排队抢座位的场景屡见不鲜。传统的人工管理方式效率低下容易引发纠纷。我去年参与开发的这个SpringBootVue图书馆座位预约系统就是为了解决这个痛点。技术栈选择上后端采用SpringBoot 2.7 MyBatis Plus组合。SpringBoot的自动配置特性让项目搭建变得非常简单MyBatis Plus则提供了强大的单表CRUD操作能力。数据库选用MySQL 8.0主要看中其事务处理能力和稳定性。前端使用Vue 3 Element Plus响应式开发体验非常好。开发工具方面推荐使用IntelliJ IDEA进行后端开发VS Code进行前端编码。数据库管理工具Navicat或DBeaver都不错。记得在pom.xml中加入Lombok依赖可以省去大量getter/setter代码dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency2. 需求分析与功能设计通过与学校图书馆老师的多次沟通我们梳理出核心需求场景学生可以查看座位状态并预约预约后需在15分钟内签到临时离开需设置保留时间管理员需要监控座位使用情况系统主要功能模块设计如下2.1 用户端功能座位查询与预约可按区域、类型筛选座位预约管理查看当前/历史预约记录签到功能扫描座位二维码完成签到信用积分违规行为会扣除信用分2.2 管理端功能座位管理添加/禁用座位预约审核处理异常预约数据统计生成使用率报表系统设置配置预约规则等数据库ER图中核心实体包括用户表(user)座位表(seat)预约记录表(reservation)信用记录表(credit)3. 后端核心实现3.1 座位预约接口开发预约业务需要考虑并发控制我们采用乐观锁实现Transactional public Result makeReservation(ReservationDTO dto) { // 检查座位状态 Seat seat seatMapper.selectById(dto.getSeatId()); if (seat.getStatus() ! SeatStatus.AVAILABLE) { return Result.error(该座位不可用); } // 乐观锁更新 int updated seatMapper.updateStatus(seat.getId(), SeatStatus.AVAILABLE, SeatStatus.RESERVED); if (updated 0) { return Result.error(座位状态已变更); } // 创建预约记录 Reservation reservation new Reservation(); reservation.setUserId(getCurrentUserId()); reservation.setSeatId(dto.getSeatId()); reservation.setStartTime(dto.getStartTime()); reservationMapper.insert(reservation); return Result.success(); }3.2 签到功能实现签到采用JWT生成临时令牌前端扫码后提交验证public String generateCheckinToken(Long reservationId) { MapString, Object claims new HashMap(); claims.put(reservationId, reservationId); return Jwts.builder() .setClaims(claims) .setExpiration(new Date(System.currentTimeMillis() 15*60*1000)) .signWith(SignatureAlgorithm.HS512, secret) .compact(); } public Result handleCheckin(String token) { try { Claims claims Jwts.parser() .setSigningKey(secret) .parseClaimsJws(token) .getBody(); Long reservationId claims.get(reservationId, Long.class); // 更新预约状态 return Result.success(); } catch (Exception e) { return Result.error(签到令牌无效); } }4. 前端关键功能实现4.1 座位地图展示使用SVG实现可交互的座位地图template div classseat-map svg :viewBox0 0 ${width} ${height} g v-forseat in seats :keyseat.id rect :xseat.x :yseat.y width30 height30 :class[seat, seat.status] clickhandleSeatClick(seat) / text :xseat.x 15 :yseat.y 20 {{ seat.number }} /text /g /svg /div /template script export default { data() { return { seats: [], // 从API获取座位数据 width: 800, height: 600 } }, methods: { handleSeatClick(seat) { if (seat.status available) { this.$emit(select, seat); } } } } /script4.2 预约时间选择使用Element Plus的DateTimePicker组件el-date-picker v-modelreservationTime typedatetime :disabled-datedisabledDate :shortcutsshortcuts placeholder选择预约时间 /5. 数据库设计与优化5.1 核心表结构CREATE TABLE seat ( id bigint NOT NULL AUTO_INCREMENT, number varchar(20) NOT NULL COMMENT 座位编号, zone varchar(50) NOT NULL COMMENT 区域, status tinyint NOT NULL DEFAULT 0 COMMENT 0-可用 1-已预约 2-维修中, x int DEFAULT NULL COMMENT 坐标X, y int DEFAULT NULL COMMENT 坐标Y, PRIMARY KEY (id), KEY idx_zone_status (zone,status) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; 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-已完成 3-已取消, checkin_time datetime DEFAULT NULL, PRIMARY KEY (id), KEY idx_user (user_id), KEY idx_seat_time (seat_id,start_time) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;5.2 查询优化实践对于高频的座位查询接口我们添加了Redis缓存public ListSeatVO getAvailableSeats(String zone) { String cacheKey seats:available: zone; String cached redisTemplate.opsForValue().get(cacheKey); if (cached ! null) { return JSON.parseArray(cached, SeatVO.class); } ListSeat seats seatMapper.selectAvailableByZone(zone); ListSeatVO result seats.stream() .map(this::convertToVO) .collect(Collectors.toList()); redisTemplate.opsForValue().set( cacheKey, JSON.toJSONString(result), 5, TimeUnit.MINUTES); return result; }6. 系统部署与测试6.1 后端部署配置application-prod.yml关键配置server: port: 8080 servlet: context-path: /api spring: datasource: url: jdbc:mysql://localhost:3306/library_seat?useSSLfalse username: root password: yourpassword hikari: maximum-pool-size: 20 redis: host: localhost port: 63796.2 压力测试结果使用JMeter进行并发测试500并发用户持续5分钟平均响应时间238ms错误率0.12%吞吐量1250请求/秒测试中发现的问题及解决方案预约接口在高并发下出现超卖解决方案改用Redis分布式锁座位查询响应变慢解决方案添加二级缓存7. 项目总结与扩展这个项目让我深刻理解了如何将理论知识应用到实际开发中。有几个特别值得注意的点事务处理要细致最初版本没有处理好预约和座位状态更新的事务导致数据不一致前端性能优化座位地图首次渲染较慢通过虚拟滚动解决了问题安全防护增加了防XSS和CSRF的中间件未来可以扩展的方向增加人脸识别签到开发微信小程序端实现智能推荐座位功能开发过程中最大的收获是学会了如何平衡功能实现和代码质量。建议学弟学妹们在开发时先写好技术方案设计文档合理规划开发里程碑尽早进行性能测试重视代码review环节