1. 项目背景与需求分析
2020年以来的公共卫生事件让高校管理面临前所未有的挑战。作为在高校信息化领域深耕多年的开发者,我亲历了从纸质登记到数字化管理的转型过程。传统手工登记方式存在三大痛点:数据滞后(通常延迟1-2天)、信息孤岛(各部门数据不互通)、追溯困难(接触者排查效率低下)。某985高校的实测数据显示,人工处理1000名学生的健康筛查需要8小时,而数字化系统可将时间压缩到15分钟。
这个疫情防控系统正是为解决这些痛点而生。核心需求可归纳为:
- 实时健康监测(体温、症状每日上报)
- 精准轨迹追踪(校内场所打卡记录)
- 智能预警机制(异常数据自动触发通知)
- 多维度数据分析(可视化疫情态势)
2. 技术架构设计
2.1 整体架构方案
采用前后端分离架构,这是经过多个项目验证的最佳实践。后端选择SpringBoot 2.7 + MyBatis-Plus组合,前端采用Vue 3 + Element Plus,数据库使用MySQL 8.0。特别说明选择依据:
SpringBoot优势:
- 自动配置省去70%的XML配置
- 内嵌Tomcat支持快速部署
- Actuator端点提供实时监控
- 与Spring Security天然集成
Vue 3关键考量:
- Composition API更适合复杂状态管理
- Vite构建速度比Webpack快5-8倍
- 更好的TypeScript支持
MySQL选型原因:
- 高校IT部门普遍熟悉
- 事务支持完善(ACID)
- JSON字段支持灵活扩展
2.2 高并发设计
针对开学季集中填报场景,我们做了以下优化:
// 使用Redis缓存热点数据 @Cacheable(value = "healthStatus", key = "#userId") public HealthStatus getCurrentHealthStatus(String userId) { // 数据库查询逻辑 } // 异步处理Excel导出 @Async public void exportHealthReport(Date date) { // 耗时操作放入线程池 }实测数据:单服务器(4核8G)可支撑3000+ TPS,响应时间<500ms。
3. 核心功能实现
3.1 健康上报模块
采用动态表单设计,支持各校自定义字段:
<template> <el-form :model="healthForm" :rules="rules"> <template v-for="item in customFields"> <el-form-item :label="item.label" :prop="item.field"> <component :is="getComponent(item.type)" v-model="healthForm[item.field]" /> </el-form-item> </template> </el-form> </template>避坑经验:
- 体温字段需限制输入范围(35.0-42.0)
- 症状描述要防XSS攻击(前端过滤 + 后端转义)
- 上报时间强制使用服务器时间(防止客户端篡改)
3.2 轨迹追踪实现
结合百度地图API实现:
- 移动端SDK采集经纬度
- 后端使用GeoHash算法压缩存储
- 风险判断逻辑:
public RiskLevel checkLocationRisk(Point point) { String geoHash = GeoHash.encode(point); return riskAreaCache.stream() .filter(area -> area.getGeoHash().startsWith(geoHash.substring(0, 5))) .findFirst() .map(RiskArea::getLevel) .orElse(RiskLevel.LOW); }性能优化点:
- 轨迹数据按天分表(track_20230801)
- 使用空间索引加速查询
- 热数据存入Redis GEO
4. 安全与权限设计
4.1 JWT认证方案
采用改良版JWT流程:
- 双Token机制(access_token 30分钟过期,refresh_token 7天有效)
- 指纹绑定防止盗用:
// 前端生成设备指纹 const fingerprint = md5(navigator.userAgent + screen.width); axios.defaults.headers.common['X-Device-Fingerprint'] = fingerprint;4.2 精细化权限控制
RBAC模型扩展实现:
CREATE TABLE `sys_permission` ( `permission_key` VARCHAR(50) PRIMARY KEY, `description` VARCHAR(100), `resource_type` ENUM('MENU','BUTTON','API') ); -- 示例数据 INSERT INTO `sys_permission` VALUES ('health:export', '导出健康数据', 'BUTTON'), ('track:query', '查询行程轨迹', 'API');关键配置:
@PreAuthorize("hasPermission('health:export')") @GetMapping("/export") public void exportData(HttpServletResponse response) { // 导出逻辑 }5. 数据可视化实践
5.1 ECharts深度集成
疫情看板实现技巧:
// 异步加载大数据量时的优化 function renderTrendChart() { chart.showLoading(); fetchData().then(data => { chart.setOption({ dataset: { source: data }, series: [{ type: 'line', progressive: 500, // 增量渲染 dimensions: ['date', 'cases'] }] }); chart.hideLoading(); }); }5.2 报表导出优化
使用EasyExcel解决内存溢出:
public void exportToExcel(HttpServletResponse response) { ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()) .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) .build(); // 分页查询避免OOM int pageSize = 1000; for (int page = 1; ; page++) { List<HealthRecord> records = queryPage(page, pageSize); if (records.isEmpty()) break; excelWriter.write(records, EasyExcel.writerSheet("第" + page + "页").build()); } excelWriter.finish(); }6. 部署与运维实战
6.1 容器化部署
Docker Compose编排示例:
version: '3' services: mysql: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: ${DB_PASSWORD} volumes: - ./mysql-data:/var/lib/mysql healthcheck: test: ["CMD", "mysqladmin", "ping"] backend: build: ./backend ports: - "8080:8080" depends_on: mysql: condition: service_healthy6.2 监控方案
Prometheus + Grafana配置要点:
- SpringBoot暴露metrics端点
- 关键指标报警规则:
groups: - name: health rules: - alert: HighErrorRate expr: rate(http_server_requests_errors_total[1m]) > 0.1 for: 5m7. 典型问题排查
7.1 定位信息不同步
现象:移动端上报的定位与实际情况偏差大
排查步骤:
- 检查AndroidManifest.xml是否声明位置权限
- 验证高德/百度地图SDK密钥配置
- 测试不同网络环境(WiFi/4G)下的定位精度
解决方案:
// 增加定位质量判断 if (location.getAccuracy() > 50) { logger.warn("低精度定位: {}", location); requestManualConfirm(userId); }7.2 并发提交冲突
现象:快速点击提交按钮产生重复数据
前端处理:
<el-button :loading="submitting" @click="submitForm" v-throttle="3000" > 提交 </el-button>后端防护:
@PostMapping("/report") @CacheLock(prefix = "healthReport", key = "#userId") public Result submitReport(@RequestBody ReportDTO dto) { // 业务逻辑 }8. 扩展与优化方向
微信小程序集成:
- 通过uni-app跨端方案复用80%代码
- 利用微信原生扫码能力实现场所码
大数据分析扩展:
- 使用Flink实时计算密接人员
- 基于Spark ML预测疫情发展趋势
微服务改造:
- 按功能拆分为认证服务、数据服务等
- 采用SpringCloud Alibaba体系
这个项目最让我有成就感的,是看到某高校部署后,将疫情排查时间从原来的48小时缩短到2小时。技术真正的价值,在于解决实际问题。如果读者在实施过程中遇到具体问题,欢迎交流实战经验——毕竟每个学校的实际情况都可能需要特殊适配。