毕业设计实战:基于Java+Spring Boot+MySQL的校园疫情防控系统全流程深度解析

15 阅读14分钟

毕业设计实战:基于Java+Spring Boot+MySQL的校园疫情防控系统全流程深度解析

在开发“校园疫情防控系统”毕业设计时,曾因“药品订单表与用户表关联缺失”踩过关键坑——初期仅在两表设计独立字段,未建立完整外键约束,导致管理员统计药品申领情况时无法快速关联用户信息,耗费1.5天重构表结构、优化SQL查询才解决问题📝。基于疫情期间校园管理的实际需求,本文将系统拆解从需求分析、技术选型、功能实现到测试验收的全流程要点,为同类毕设提供可落地的实施指南。

一、需求分析:疫情常态化下的校园管理痛点

1. 时代背景与核心挑战

自2019年底新冠疫情爆发以来,高校管理工作面临三大挑战:

  • 学生基数庞大:全国高校在校生超4000万,人工管理效率低下
  • 防疫流程复杂:健康打卡、核酸上报、行程追踪等多环节并行
  • 数据实时性要求高:疫情变化快速,需要实时掌握师生健康状况

2. 核心用户与功能矩阵(三级管控体系)

系统采用“管理员-教师-学生”三级管理模式,权限逐级下放,责任到人:

管理员端(校级管控)
  • 全局监控与决策
    • 疫情态势总览:实时Dashboard展示在校人数、异常上报数、隔离人数等关键指标
    • 数据统计分析:按院系/班级统计健康打卡率、核酸阴性率,生成趋势图表
    • 系统基础配置:管理用户角色、设置预警阈值、配置通知模板
  • 应急事件处理
    • 异常情况预警:体温异常、核酸阳性、密接者自动标红提醒
    • 隔离管理:分配隔离宿舍、记录隔离起止时间、追踪隔离状态
    • 药品物资管理:库存预警、申领审批、发放记录追溯
教师端(院系/班级管理)
  • 日常监督与上报
    • 学生健康监控:查看所带班级学生每日健康打卡情况,异常情况一键上报
    • 到校确认核查:核实学生返校行程,审批请假申请
    • 信息精准推送:向班级学生发送通知公告、防疫要求
  • 数据汇总上报
    • 班级防疫日报:自动生成班级健康情况日报,减少人工统计
    • 重点学生关注:标记重点关注学生(如基础疾病、心理问题)
学生端(个人防疫)
  • 每日防疫任务
    • 健康打卡:上传健康码、体温、行程码(支持图片识别自动填写)
    • 核酸结果上报:拍照上传核酸检测报告,系统OCR识别关键信息
    • 行程报备:离返校申请、外出报备、异常症状上报
  • 信息获取与服务
    • 防疫知识学习:查看最新防疫政策、健康知识
    • 药品在线申领:常见防疫药品在线申请,减少人员接触
    • 个人健康档案:查看个人历史健康数据、核酸记录

3. 需求分析避坑要点

  • 业务流程必须闭环:每个上报环节都要有“提交-审核-反馈”完整流程,避免数据黑洞
  • 数据关联性设计:健康打卡、核酸上报、行程轨迹要能关联分析,形成个人防疫画像
  • 异常处理机制:考虑网络异常、数据冲突、重复提交等边界情况
  • 隐私安全合规:健康码、身份证号等敏感信息需加密存储,符合《个人信息保护法》

二、技术选型:稳定可靠优先,兼顾扩展性

1. 核心技术栈对比分析

技术组件选型方案理由说明避坑提醒
后端框架Spring Boot 2.7.x + MyBatis Plus快速开发,内置疫情场景常用功能(如文件上传、数据导出)避免Spring Boot 3.x,兼容性问题多
数据库MySQL 8.0 + Redis 7.xMySQL事务保证数据一致性,Redis缓存高频查询(如健康码状态)必须配置utf8mb4编码存储emoji
前端框架Vue 3.x + Element Plus组件丰富,疫情数据看板可视化效果好注意Vue 3与Element Plus版本匹配
文件存储本地存储 + 七牛云OSS健康码图片先存本地,重要数据同步云存储备份设置文件大小限制(单张≤2MB)
消息推送WebSocket + 邮件/SMS重要通知实时推送,普通通知走邮件/SMSWebSocket需心跳保活机制
部署环境Docker + Nginx快速部署,方便演示,负载均衡生产环境建议用专业服务器

2. 开发环境一键配置脚本

#!/bin/bash
# 校园疫情防控系统开发环境配置脚本

echo "=== 校园疫情防控系统开发环境配置 ==="

# 1. 安装Java环境
echo "1. 安装Java 11..."
brew install openjdk@11
export JAVA_HOME=/usr/local/opt/openjdk@11

# 2. 安装MySQL 8.0
echo "2. 安装MySQL 8.0..."
brew install mysql@8.0
brew services start mysql@8.0

# 3. 创建数据库(关键配置)
echo "3. 创建数据库..."
mysql -u root -p <<EOF
CREATE DATABASE IF NOT EXISTS campus_epidemic 
DEFAULT CHARACTER SET utf8mb4 
COLLATE utf8mb4_unicode_ci;

USE campus_epidemic;

# 创建学生表(学号为主键)
CREATE TABLE student (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    student_id VARCHAR(20) UNIQUE NOT NULL COMMENT '学号',
    name VARCHAR(50) NOT NULL,
    college VARCHAR(100) COMMENT '学院',
    major VARCHAR(100) COMMENT '专业',
    class_name VARCHAR(50) COMMENT '班级',
    phone VARCHAR(11) UNIQUE,
    id_card VARCHAR(18) COMMENT '身份证号加密存储',
    status TINYINT DEFAULT 1 COMMENT '1正常 2隔离 3离校',
    create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
    INDEX idx_college_class (college, class_name)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
EOF

# 4. 安装Redis
echo "4. 安装Redis..."
brew install redis
brew services start redis

echo "=== 环境配置完成 ==="
echo "数据库: campus_epidemic (utf8mb4)"
echo "Redis端口: 6379"
echo "Java版本: 11"

三、数据库设计:疫情数据的关联与溯源

1. 核心表结构设计(12张表精炼版)

-- 1. 学生健康打卡表(高频操作)
CREATE TABLE health_report (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    student_id VARCHAR(20) NOT NULL,
    report_date DATE NOT NULL COMMENT '打卡日期',
    temperature DECIMAL(3,1) COMMENT '体温',
    health_code_color VARCHAR(10) COMMENT '健康码颜色',
    health_code_img VARCHAR(255) COMMENT '健康码截图',
    location VARCHAR(200) COMMENT '当前位置',
    symptom TEXT COMMENT '异常症状描述',
    is_abnormal TINYINT DEFAULT 0 COMMENT '是否异常',
    reporter_id BIGINT COMMENT '上报人(学生/教师)',
    create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
    UNIQUE KEY uk_student_date (student_id, report_date),
    INDEX idx_date_status (report_date, is_abnormal),
    FOREIGN KEY (student_id) REFERENCES student(student_id)
) COMMENT='每日健康打卡';

-- 2. 核酸记录表(时效性强)
CREATE TABLE nucleic_acid_test (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    student_id VARCHAR(20) NOT NULL,
    test_date DATETIME NOT NULL COMMENT '检测时间',
    result TINYINT COMMENT '1阴性 2阳性 3待复核',
    result_img VARCHAR(255) COMMENT '检测报告',
    test_institution VARCHAR(100) COMMENT '检测机构',
    test_type VARCHAR(50) COMMENT '检测类型(单检/混检)',
    validity_period DATETIME COMMENT '有效期至',
    create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
    INDEX idx_student_result (student_id, result),
    INDEX idx_validity (validity_period)
) COMMENT='核酸检测记录';

-- 3. 行程轨迹表(关联分析)
CREATE TABLE travel_track (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    student_id VARCHAR(20) NOT NULL,
    track_date DATE NOT NULL,
    time_period VARCHAR(50) COMMENT '时间段',
    location VARCHAR(200) NOT NULL COMMENT '具体位置',
    location_type VARCHAR(20) COMMENT '类型(教室/食堂/宿舍)',
    is_risk_area TINYINT DEFAULT 0 COMMENT '是否风险区域',
    create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
    INDEX idx_student_date (student_id, track_date)
) COMMENT='行程轨迹';

-- 4. 药品申领表(事务处理)
CREATE TABLE medicine_application (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    application_no VARCHAR(32) UNIQUE NOT NULL COMMENT '申领单号',
    student_id VARCHAR(20) NOT NULL,
    medicine_id BIGINT NOT NULL,
    quantity INT NOT NULL DEFAULT 1,
    reason TEXT COMMENT '申领原因',
    status TINYINT DEFAULT 1 COMMENT '1待审核 2已通过 3已拒绝 4已领取',
    auditor_id BIGINT COMMENT '审核人',
    audit_time DATETIME COMMENT '审核时间',
    pick_up_time DATETIME COMMENT '领取时间',
    create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (student_id) REFERENCES student(student_id),
    FOREIGN KEY (medicine_id) REFERENCES medicine(id),
    INDEX idx_status_time (status, create_time)
) COMMENT='药品申领';

-- 5. 隔离管理表(状态跟踪)
CREATE TABLE quarantine_record (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    student_id VARCHAR(20) NOT NULL,
    start_time DATETIME NOT NULL COMMENT '隔离开始时间',
    end_time DATETIME COMMENT '预计结束时间',
    quarantine_type VARCHAR(20) COMMENT '隔离类型(居家/集中)',
    location VARCHAR(200) COMMENT '隔离地点',
    reason TEXT COMMENT '隔离原因',
    status TINYINT DEFAULT 1 COMMENT '1隔离中 2已解除',
    daily_temperature JSON COMMENT '每日体温记录',
    release_approver BIGINT COMMENT '解除审批人',
    release_time DATETIME COMMENT '实际解除时间',
    create_time DATETIME DEFAULT CURRENT_TIMESTAMP
) COMMENT='隔离管理';

2. 关键业务查询SQL

-- 1. 查询今日未打卡学生(教师端使用)
SELECT s.student_id, s.name, s.class_name, s.phone
FROM student s
LEFT JOIN health_report hr ON s.student_id = hr.student_id 
    AND hr.report_date = CURDATE()
WHERE hr.id IS NULL 
    AND s.status = 1  -- 在校状态
    AND s.college = '计算机学院'  -- 按院系筛选
ORDER BY s.class_name;

-- 2. 统计各班级健康异常率(管理员看板)
SELECT 
    s.college,
    s.class_name,
    COUNT(DISTINCT s.student_id) as total_students,
    SUM(CASE WHEN hr.is_abnormal = 1 THEN 1 ELSE 0 END) as abnormal_count,
    CONCAT(
        ROUND(
            SUM(CASE WHEN hr.is_abnormal = 1 THEN 1 ELSE 0 END) * 100.0 / 
            COUNT(DISTINCT s.student_id), 
        2), '%'
    ) as abnormal_rate
FROM student s
LEFT JOIN health_report hr ON s.student_id = hr.student_id 
    AND hr.report_date = CURDATE()
WHERE s.status = 1
GROUP BY s.college, s.class_name
ORDER BY abnormal_rate DESC;

-- 3. 查找密接者(根据行程重叠)
SELECT DISTINCT s2.student_id, s2.name, s2.phone
FROM travel_track t1
JOIN travel_track t2 ON t1.location = t2.location 
    AND t1.track_date = t2.track_date
    AND t1.time_period = t2.time_period
    AND t1.student_id != t2.student_id
JOIN student s1 ON t1.student_id = s1.student_id
JOIN student s2 ON t2.student_id = s2.student_id
WHERE s1.student_id = '2021001'  -- 确诊学生
    AND t1.track_date >= DATE_SUB(CURDATE(), INTERVAL 3 DAY);

3. 事务处理关键代码(药品申领)

@Service
@Transactional(rollbackFor = Exception.class)
public class MedicineApplicationService {
    
    @Autowired
    private MedicineStockService stockService;
    
    @Autowired
    private NotificationService notificationService;
    
    /**
     * 处理药品申领(完整事务)
     */
    public ApplicationResult applyMedicine(MedicineApplicationDTO dto) {
        // 1. 验证学生状态
        Student student = studentRepository.findByStudentId(dto.getStudentId());
        if (student.getStatus() == StudentStatus.QUARANTINE) {
            throw new BusinessException("隔离期间无法申领药品");
        }
        
        // 2. 检查库存(加锁防止超卖)
        Medicine medicine = medicineRepository.findByIdWithLock(dto.getMedicineId());
        if (medicine.getStock() < dto.getQuantity()) {
            throw new BusinessException(medicine.getName() + "库存不足");
        }
        
        // 3. 扣减库存
        medicine.setStock(medicine.getStock() - dto.getQuantity());
        medicineRepository.save(medicine);
        
        // 4. 创建申领记录
        MedicineApplication application = new MedicineApplication();
        application.setApplicationNo(IdGenerator.generate("MA"));
        application.setStudentId(dto.getStudentId());
        application.setMedicineId(dto.getMedicineId());
        application.setQuantity(dto.getQuantity());
        application.setStatus(ApplicationStatus.PENDING);
        applicationRepository.save(application);
        
        // 5. 发送通知给审核人(异步,不影响主事务)
        notificationService.sendAuditNotification(
            application.getId(), 
            student.getName(), 
            medicine.getName()
        );
        
        // 6. 记录库存变更流水
        stockService.recordStockChange(
            medicine.getId(), 
            -dto.getQuantity(), 
            "学生申领:" + student.getStudentId()
        );
        
        return ApplicationResult.success(application.getApplicationNo());
    }
    
    /**
     * 审核药品申领
     */
    @Transactional
    public void auditApplication(Long applicationId, boolean approved, String auditOpinion) {
        MedicineApplication application = applicationRepository.findById(applicationId)
            .orElseThrow(() -> new NotFoundException("申请记录不存在"));
        
        if (application.getStatus() != ApplicationStatus.PENDING) {
            throw new BusinessException("申请已处理,无法重复审核");
        }
        
        if (approved) {
            application.setStatus(ApplicationStatus.APPROVED);
            // 发送领取通知给学生
            notificationService.sendPickupNotification(
                application.getStudentId(),
                application.getApplicationNo()
            );
        } else {
            application.setStatus(ApplicationStatus.REJECTED);
            // 退回库存
            Medicine medicine = medicineRepository.findById(application.getMedicineId());
            medicine.setStock(medicine.getStock() + application.getQuantity());
            medicineRepository.save(medicine);
        }
        
        application.setAuditOpinion(auditOpinion);
        application.setAuditTime(LocalDateTime.now());
        applicationRepository.save(application);
    }
}

四、功能实现:疫情防控全流程覆盖

1. 学生端:一站式防疫服务

<template>
  <div class="epidemic-container">
    <!-- 今日防疫任务卡片 -->
    <el-row :gutter="20">
      <el-col :span="8">
        <task-card 
          title="健康打卡" 
          status="pending"
          icon="health"
          @click="goHealthReport">
          <template #default>
            <div v-if="todayReport">
              已打卡:体温{{ todayReport.temperature }}°C
              <el-tag :type="getHealthCodeColor(todayReport.healthCodeColor)">
                {{ todayReport.healthCodeColor }}
              </el-tag>
            </div>
            <div v-else class="text-danger">
              今日未打卡,点击立即打卡
            </div>
          </template>
        </task-card>
      </el-col>
      
      <el-col :span="8">
        <task-card 
          title="核酸上报" 
          :status="nucleicAcidStatus"
          icon="test-tube"
          @click="goNucleicAcid">
          <template #default>
            <div v-if="latestNucleicAcid">
              最近检测:{{ formatDate(latestNucleicAcid.testDate) }}
              <el-tag :type="latestNucleicAcid.result === 1 ? 'success' : 'danger'">
                {{ getResultText(latestNucleicAcid.result) }}
              </el-tag>
            </div>
          </template>
        </task-card>
      </el-col>
      
      <el-col :span="8">
        <task-card 
          title="行程报备" 
          status="normal"
          icon="location"
          @click="goTravelReport">
          <template #default>
            <div>今日已到访:{{ todayLocations.length }}个地点</div>
          </template>
        </task-card>
      </el-col>
    </el-row>
    
    <!-- 健康状态时间轴 -->
    <el-timeline>
      <el-timeline-item
        v-for="(item, index) in healthTimeline"
        :key="index"
        :timestamp="item.date"
        placement="top">
        <el-card>
          <h4>{{ item.title }}</h4>
          <p>{{ item.description }}</p>
          <div v-if="item.images" class="image-preview">
            <el-image
              v-for="(img, idx) in item.images"
              :key="idx"
              :src="img"
              :preview-src-list="item.images"
              style="width: 80px; margin-right: 10px;">
            </el-image>
          </div>
        </el-card>
      </el-timeline-item>
    </el-timeline>
  </div>
</template>

<script>
export default {
  data() {
    return {
      todayReport: null,
      latestNucleicAcid: null,
      todayLocations: [],
      healthTimeline: []
    }
  },
  computed: {
    nucleicAcidStatus() {
      if (!this.latestNucleicAcid) return 'pending'
      const daysDiff = this.dateDiff(this.latestNucleicAcid.testDate)
      if (daysDiff > 7) return 'warning'
      return 'normal'
    }
  },
  methods: {
    // 健康码颜色转换
    getHealthCodeColor(color) {
      const map = { '绿码': 'success', '黄码': 'warning', '红码': 'danger' }
      return map[color] || 'info'
    },
    
    // 上传健康码(支持图片识别)
    async uploadHealthCode(file) {
      const formData = new FormData()
      formData.append('file', file)
      formData.append('studentId', this.studentId)
      
      try {
        // 1. 上传图片
        const uploadRes = await this.$api.uploadFile(formData)
        
        // 2. 调用OCR识别(模拟)
        const ocrResult = await this.$api.recognizeHealthCode(uploadRes.url)
        
        // 3. 自动填充表单
        this.form.temperature = ocrResult.temperature || ''
        this.form.healthCodeColor = ocrResult.color || '绿码'
        
        this.$message.success('健康码识别成功')
      } catch (error) {
        this.$message.error('识别失败,请手动填写')
      }
    }
  }
}
</script>

2. 教师端:班级防疫监控台

@RestController
@RequestMapping("/teacher")
@Api(tags = "教师防疫管理")
public class TeacherEpidemicController {
    
    @Autowired
    private HealthReportService healthReportService;
    
    @Autowired
    private StudentService studentService;
    
    /**
     * 班级健康日报
     */
    @GetMapping("/class-health-daily")
    @ApiOperation("获取班级健康日报")
    public ClassHealthDailyVO getClassHealthDaily(
            @RequestParam String teacherId,
            @RequestParam(required = false) String date) {
        
        LocalDate reportDate = date != null ? 
            LocalDate.parse(date) : LocalDate.now();
        
        // 1. 获取教师所带班级
        List<String> classNames = teacherService.getTeachingClasses(teacherId);
        
        // 2. 按班级统计
        List<ClassHealthStat> stats = new ArrayList<>();
        for (String className : classNames) {
            ClassHealthStat stat = new ClassHealthStat();
            stat.setClassName(className);
            
            // 总人数
            int total = studentService.countByClassName(className);
            stat.setTotalStudents(total);
            
            // 已打卡人数
            int reported = healthReportService.countReported(className, reportDate);
            stat.setReportedCount(reported);
            
            // 异常人数
            int abnormal = healthReportService.countAbnormal(className, reportDate);
            stat.setAbnormalCount(abnormal);
            
            // 未打卡名单
            List<StudentSimpleVO> notReported = 
                healthReportService.getNotReportedStudents(className, reportDate);
            stat.setNotReportedStudents(notReported);
            
            stats.add(stat);
        }
        
        // 3. 生成汇总数据
        ClassHealthDailyVO vo = new ClassHealthDailyVO();
        vo.setReportDate(reportDate);
        vo.setClassStats(stats);
        vo.setTotalReportRate(this.calculateTotalRate(stats));
        
        return vo;
    }
    
    /**
     * 一键催打卡(批量通知)
     */
    @PostMapping("/urge-report")
    @ApiOperation("一键催打卡")
    public Result urgeHealthReport(@RequestBody UrgeRequest request) {
        List<String> studentIds = request.getStudentIds();
        String message = request.getMessage() != null ? 
            request.getMessage() : "请及时完成今日健康打卡";
        
        // 异步发送通知
        notificationService.batchSend(
            studentIds, 
            NotificationType.HEALTH_REPORT_REMINDER,
            message
        );
        
        // 记录催办日志
        logService.logTeacherAction(
            request.getTeacherId(),
            "URGE_HEALTH_REPORT",
            "催办" + studentIds.size() + "名学生打卡"
        );
        
        return Result.success("催办通知已发送");
    }
    
    /**
     * 异常情况上报
     */
    @PostMapping("/report-abnormal")
    @Transactional
    @ApiOperation("上报异常情况")
    public Result reportAbnormal(@RequestBody AbnormalReportDTO dto) {
        // 1. 验证学生信息
        Student student = studentService.getById(dto.getStudentId());
        if (student == null) {
            throw new BusinessException("学生不存在");
        }
        
        // 2. 创建异常记录
        AbnormalRecord record = new AbnormalRecord();
        record.setStudentId(dto.getStudentId());
        record.setReportType(dto.getAbnormalType());
        record.setDescription(dto.getDescription());
        record.setReportedBy(dto.getTeacherId());
        record.setEmergencyLevel(dto.getEmergencyLevel());
        record.setStatus(AbnormalStatus.PENDING);
        
        abnormalRecordRepository.save(record);
        
        // 3. 根据紧急程度触发不同处理流程
        if (dto.getEmergencyLevel() >= EmergencyLevel.HIGH) {
            // 高风险:立即通知管理员
            notificationService.notifyAdmins(
                "高风险异常上报:" + student.getName(),
                "请立即处理"
            );
            
            // 自动标记学生为关注状态
            student.setFocusStatus(StudentFocusStatus.HIGH_RISK);
            studentService.update(student);
        }
        
        // 4. 发送确认通知给学生
        notificationService.sendToStudent(
            dto.getStudentId(),
            NotificationType.ABNORMAL_CONFIRMATION,
            "您的异常情况已上报,请保持通讯畅通"
        );
        
        return Result.success("异常情况已上报", record.getId());
    }
}

在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述

五、测试验收:模拟真实疫情场景

1. 核心场景测试用例

测试场景模拟数据预期结果关键验证点
晨午检高峰1000名学生同时打卡,持续5分钟系统响应时间<3秒,无数据丢失数据库连接池配置,Redis缓存命中率
核酸阳性应急模拟1名学生核酸阳性报告上传自动触发密接者排查,隔离流程启动业务流程完整性,通知及时性
药品库存临界某药品库存剩5份,10人同时申领前5人成功,后5人失败,库存为0数据库锁机制,事务一致性
网络断线重连打卡过程中断网,30秒后重连本地缓存数据,恢复后自动同步前端数据持久化,重试机制

2. 压力测试配置

# application.yml 关键配置
spring:
  datasource:
    hikari:
      maximum-pool-size: 50  # 根据预估并发调整
      minimum-idle: 10
      connection-timeout: 30000
      idle-timeout: 600000
      max-lifetime: 1800000
      
  redis:
    lettuce:
      pool:
        max-active: 100
        max-idle: 20
        min-idle: 5
        
  servlet:
    multipart:
      max-file-size: 5MB
      max-request-size: 20MB
      
  jackson:
    time-zone: GMT+8
    date-format: yyyy-MM-dd HH:mm:ss

server:
  tomcat:
    max-threads: 200
    min-spare-threads: 50
    max-connections: 10000
    connection-timeout: 30000
    
# 业务配置
epidemic:
  # 打卡时间窗口
  report:
    morning-start: 06:00
    morning-end: 09:00
    afternoon-start: 12:00
    afternoon-end: 15:00
    
  # 预警阈值
  warning:
    abnormal-rate: 0.05  # 异常率超过5%预警
    quarantine-rate: 0.02  # 隔离率超过2%预警
    report-rate: 0.90  # 打卡率低于90%预警
    
  # 核酸有效期
  nucleic-acid:
    validity-days: 7  # 核酸7天有效
    reminder-days: 2  # 提前2天提醒
    
  # 通知配置
  notification:
    enabled: true
    channels: [WEBSOCKET, SMS, EMAIL]
    batch-size: 100  # 批量发送大小

3. 安全测试要点

  • 数据加密:身份证号、手机号等敏感信息AES加密存储
  • 权限验证:每个API接口必须验证用户角色和权限
  • 防SQL注入:使用MyBatis参数绑定,避免拼接SQL
  • XSS防护:前端输入过滤,后端输出转义
  • CSRF防护:重要操作添加Token验证
  • 操作日志:关键操作记录完整日志,支持审计追溯

六、答辩准备:突出疫情防控特色

1. 演示流程设计(10分钟完整演示)

第一阶段:学生端防疫日常(3分钟)
  1. 学生登录 → 查看今日防疫任务
  2. 健康打卡(演示健康码图片识别)
  3. 核酸上报(展示OCR识别功能)
  4. 药品申领(完整流程)

第二阶段:教师端班级管理(3分钟)
  1. 教师登录 → 查看班级健康日报
  2. 异常学生一键上报
  3. 批量催打卡功能
  4. 数据导出与统计

第三阶段:管理员端指挥中心(4分钟)
  1. 疫情态势总览大屏
  2. 异常预警实时处理
  3. 隔离管理全流程
  4. 数据报表与决策支持

2. 技术亮点阐述

  • 智能识别技术:健康码、核酸报告OCR识别,减少手动输入
  • 实时预警系统:多级预警机制,及时响应异常情况
  • 数据关联分析:健康、行程、核酸数据关联,精准防控
  • 移动端适配:响应式设计,支持手机端便捷操作
  • 离线能力:网络异常时本地缓存,恢复后自动同步

3. 常见问题预判

  • Q:如何保证数据真实性? A:多维度验证(学号认证、定位验证、图片识别)+ 人工审核机制

  • Q:系统如何应对突发大规模异常? A:分级预警 + 应急预案 + 人工介入通道

  • Q:隐私保护如何实现? A:数据脱敏展示、加密存储、最小权限原则、操作日志审计

  • Q:系统可扩展性如何? A:微服务架构预留,支持插件化扩展新功能模块

结语

校园疫情防控系统作为后疫情时代的典型应用,既有现实意义又具备技术深度。开发过程中要把握几个关键:业务流程要闭环、数据关联要清晰、异常处理要完善、用户体验要友好。不必追求功能的复杂性,但必须保证核心防疫流程的完整性和可靠性。