1. 项目背景与核心价值
疫情常态化背景下,图书馆作为公共场所面临着人员流动管控、座位预约管理、图书消毒追踪等新需求。传统图书馆管理系统往往缺乏应对突发公共卫生事件的灵活扩展能力,这正是我们开发这套系统的初衷。
这套基于SpringBoot+Vue+MySQL的技术方案具有三个显著优势:
- 模块化设计使得疫情相关功能(如入馆预约、密接查询)可快速迭代
- 前后端分离架构便于多终端适配(小程序/PC/自助终端)
- 完整的源码交付包含从权限控制到数据可视化的全套解决方案
提示:系统默认集成健康码核验接口预留位,实际部署时需要对接当地政务平台API
2. 技术架构解析
2.1 后端SpringBoot设计要点
采用多模块Maven项目结构:
library-parent ├── library-common // 通用工具包 ├── library-system // 核心业务模块 ├── library-quarantine // 疫情专项模块 └── library-admin // 管理后台接口疫情相关功能实现示例(座位预约控制):
@RestController @RequestMapping("/seat") public class SeatController { @Autowired private DisinfectionService disinfectionService; @PostMapping("/reserve") public Result reserveSeat(@Valid SeatReserveDTO dto) { // 检查该座位上次使用后的消毒记录 if(!disinfectionService.checkSeatStatus(dto.getSeatId())){ throw new BusinessException("该座位尚未完成消毒"); } // 预约时间间隔控制(默认2小时) if(reserveMapper.checkDuration(dto.getUserId()) > 7200){ throw new BusinessException("单日预约时长已达上限"); } return reserveService.createReservation(dto); } }2.2 前端Vue实现方案
使用Vue3+Element Plus构建管理后台,主要疫情功能组件包括:
- 可视化座位预约组件(基于SVG的场馆平面图)
- 读者健康申报表单(动态问卷配置)
- 密接查询时间轴组件
关键疫情数据看板实现:
<template> <div class="dashboard"> <el-row :gutter="20"> <el-col :span="8"> <contagion-risk-chart :data="contagionData"/> </el-col> <el-col :span="16"> <disinfection-schedule :rooms="rooms"/> </el-col> </el-row> </div> </template> <script setup> import { ref, onMounted } from 'vue' import { getEpidemicStats } from '@/api/epidemic' const contagionData = ref([]) const rooms = ref([]) onMounted(async () => { const res = await getEpidemicStats() contagionData.value = res.riskData rooms.value = res.disinfectionRooms }) </script>3. 数据库关键设计
3.1 MySQL表结构优化
针对疫情场景特别设计的表:
CREATE TABLE `lib_seat_reservation` ( `id` bigint NOT NULL AUTO_INCREMENT, `seat_id` varchar(20) NOT NULL COMMENT '座位编号', `user_id` bigint NOT NULL COMMENT '读者ID', `start_time` datetime NOT NULL COMMENT '开始时间', `end_time` datetime NOT NULL COMMENT '结束时间', `health_status` tinyint DEFAULT '0' COMMENT '0-正常 1-黄码 2-红码', `disinfection_flag` tinyint DEFAULT '0' COMMENT '是否已消毒', PRIMARY KEY (`id`), KEY `idx_seat_time` (`seat_id`,`start_time`), KEY `idx_user_time` (`user_id`,`start_time`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE `lib_disinfection_record` ( `id` bigint NOT NULL AUTO_INCREMENT, `object_type` tinyint NOT NULL COMMENT '1-座位 2-图书 3-区域', `object_id` varchar(50) NOT NULL COMMENT '消毒对象ID', `disinfect_time` datetime NOT NULL COMMENT '消毒时间', `operator` varchar(50) NOT NULL COMMENT '操作人员', `method` varchar(20) DEFAULT 'UV' COMMENT '消毒方式', PRIMARY KEY (`id`), KEY `idx_object` (`object_type`,`object_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;3.2 疫情数据查询优化
高频查询的索引策略:
- 读者行程追溯查询
-- 查询某读者14天内去过的区域 SELECT area_id, COUNT(*) AS visit_count FROM lib_access_log WHERE user_id = ? AND access_time BETWEEN DATE_SUB(NOW(), INTERVAL 14 DAY) AND NOW() GROUP BY area_id;- 密接人员筛查
-- 查找同一时段出现在相同区域的人员 SELECT DISTINCT l1.user_id FROM lib_access_log l1 JOIN lib_access_log l2 ON l1.area_id = l2.area_id WHERE l2.user_id = ? -- 确诊用户ID AND ABS(TIMESTAMPDIFF(MINUTE, l1.access_time, l2.access_time)) < 30 AND l1.access_time BETWEEN DATE_SUB(NOW(), INTERVAL 14 DAY) AND NOW();4. 系统部署实战
4.1 环境准备清单
| 组件 | 版本要求 | 备注 |
|---|---|---|
| JDK | 1.8+ | 推荐Amazon Corretto 11 |
| MySQL | 5.7+ | 需要开启MVCC事务支持 |
| Node.js | 14.x+ | 前端构建依赖 |
| Redis | 6.0+ | 会话管理和缓存 |
| Nginx | 1.18+ | 前端部署和API反向代理 |
4.2 疫情专项配置项
application-epidemic.yml关键配置:
epidemic: seat: max-hours-daily: 2 # 单日最大预约时长(小时) disinfection-gap: 30 # 两次使用最小间隔(分钟) access-control: health-check: true # 是否启用健康码核查 temp-check: true # 是否启用体温检测 contact-tracing-days: 14 # 行程追溯天数 notification: close-contact-template: "【图书馆】您于${date}在${area}的访问记录与确诊者有时空交集"5. 典型问题解决方案
5.1 高并发预约处理
采用Redis分布式锁防止超订:
public boolean tryLock(String key, long expireSeconds) { String value = UUID.randomUUID().toString(); Boolean result = redisTemplate.opsForValue() .setIfAbsent(key, value, expireSeconds, TimeUnit.SECONDS); return Boolean.TRUE.equals(result); } @Transactional public ReservationResult reserveSeat(ReservationDTO dto) { String lockKey = "seat:lock:" + dto.getSeatId(); try { if (!redisLock.tryLock(lockKey, 30)) { throw new BusinessException("当前座位正在被其他用户操作"); } // 核心预约逻辑... } finally { redisLock.unlock(lockKey); } }5.2 轨迹数据压缩存储
采用位图法存储读者到访记录:
public void saveDailyAccess(Long userId, LocalDate date, Integer areaId) { String key = String.format("access:%s:%s", userId, date.format(DateTimeFormatter.BASIC_ISO_DATE)); redisTemplate.opsForValue().setBit(key, areaId, true); // 设置30天过期 redisTemplate.expire(key, 30, TimeUnit.DAYS); } public List<Integer> getAccessedAreas(Long userId, LocalDate date) { String key = String.format("access:%s:%s", userId, date.format(DateTimeFormatter.BASIC_ISO_DATE)); BitSet bitSet = BitSet.valueOf(redisTemplate.opsForValue().get(key)); // 转换位图为区域ID列表... }6. 扩展开发建议
- 智能预约推荐:基于历史数据预测各时段人流量,推荐低风险时段
# 示例:使用Prophet进行人流量预测 from prophet import Prophet def predict_visitors(df_history): m = Prophet(seasonality_mode='multiplicative') m.fit(df_history) future = m.make_future_dataframe(periods=24, freq='H') forecast = m.predict(future) return forecast[['ds', 'yhat']]图书消毒追踪系统:在RFID标签中记录最后消毒时间
应急响应模块:出现确诊案例时自动生成受影响区域报告
注意事项:对接健康码API时需特别注意:
- 敏感数据需加密存储
- 核验结果缓存不超过2小时
- 保留完整的访问日志但需定期归档