1. 项目背景与需求分析
在突发公共卫生事件频发的当下,社区作为基层治理单元面临着前所未有的管理压力。去年参与某街道智慧社区建设时,我亲眼目睹了社区工作者用Excel表格手工统计上千户居民健康信息的场景——数据滞后、重复录入、统计误差等问题层出不穷。这正是我们团队决定开发这套疫情管理系统的初衷。
传统社区疫情管理存在三个典型痛点:一是信息采集依赖人工上门或居民自主填报,实时性差;二是纸质档案难以进行多维数据分析;三是通知传达效率低下。我们调研了7个中小型社区后发现,85%的社区仍在使用微信群接龙+纸质登记的方式管理疫情信息,平均每天要花费3-5小时进行数据整理。
这套系统要实现的核心目标是:建立疫情数据"采集-分析-决策-反馈"的闭环管理机制。具体需求包括:
- 居民端:5分钟内完成健康打卡,实时查看社区风险等级
- 管理员端:动态掌握社区健康态势,精准定位高风险区域
- 决策端:自动生成物资调配建议,可视化展示疫情发展趋势
2. 技术架构设计
2.1 整体架构方案
采用前后端分离架构是经过多次技术论证后的选择。在初期技术选型时,我们对比了三种方案:
- 传统JSP模式:开发效率低,难以应对复杂前端交互
- PHP+Laravel:生态局限,后期扩展成本高
- SpringBoot+Vue:组件化开发优势明显,社区支持完善
最终系统采用经典的三层架构:
code复制前端层:Vue2 + ElementUI + Axios
网关层:Nginx反向代理 + JWT鉴权
服务层:SpringBoot2.7 + MyBatis-Plus + Redis
数据层:MySQL8.0 + 阿里云OSS
特别要说明的是选择MyBatis而非JPA的考量:社区疫情数据具有明显的业务复杂性,需要编写高度优化的SQL语句。在某次压力测试中,针对5000条关联查询,MyBatis的定制SQL比JPA的HQL性能高出40%。
2.2 关键技术实现
2.2.1 实时数据推送方案
疫情数据时效性要求极高,我们放弃了传统的轮询方式,采用WebSocket+消息队列的混合方案:
java复制// WebSocket配置核心代码
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws-ep")
.setAllowedOrigins("*")
.withSockJS();
}
}
实际测试表明,在200并发连接下,该方案的消息延迟<200ms,比轮询方式节省了75%的带宽消耗。
2.2.2 权限控制设计
基于RBAC模型进行了深度定制,独创"三级权限隔离"机制:
- 社区级:不同社区数据完全隔离
- 角色级:6种预设角色(超级管理员、社区管理员、网格员等)
- 操作级:细粒度到按钮级别的权限控制
权限校验采用AOP+注解的方式实现:
java复制@PreAuthorize("@pms.hasPermission('material:allocate')")
@PostMapping("/allocate")
public Result allocateMaterials(@RequestBody AllocateDTO dto) {
// 物资分配逻辑
}
3. 核心功能实现
3.1 疫情数据上报模块
3.1.1 智能表单设计
考虑到中老年用户的操作习惯,我们做了三项优化:
- 体温输入采用滑块控件,避免键盘输入错误
- 症状选择使用可视化图标而非文字描述
- 提交前自动进行数据校验(如体温>38℃触发高亮提示)
前端关键代码:
vue复制<template>
<el-form :model="reportForm" :rules="rules">
<el-form-item prop="temperature">
<el-slider v-model="reportForm.temperature"
:min="35" :max="42" :step="0.1"
show-input>
</el-slider>
</el-form-item>
</el-form>
</template>
3.1.2 数据聚合分析
采用时间轮算法实现高效统计:
java复制// 按小时聚合体温异常数据
public List<AbnormalStat> getHourlyAbnormalStats(LocalDateTime start, LocalDateTime end) {
return baseMapper.selectMaps(
new QueryWrapper<Report>()
.select("HOUR(report_time) as hour", "COUNT(*) as count")
.between("report_time", start, end)
.gt("temperature", 37.3)
.groupBy("HOUR(report_time)")
).stream().map(map ->
new AbnormalStat(
Integer.parseInt(map.get("hour").toString()),
Long.parseLong(map.get("count").toString())
)
).collect(Collectors.toList());
}
3.2 物资管理模块
3.2.1 智能预警机制
设置三级库存预警:
- 黄色预警:库存量 < 周均消耗量×2
- 橙色预警:库存量 < 周均消耗量
- 红色预警:库存量 < 3日消耗量
实现代码:
java复制public WarningLevel checkInventoryWarning(Long materialId) {
Material material = getById(materialId);
double weeklyAvg = statService.getWeeklyConsumption(materialId);
if (material.getStockQuantity() < weeklyAvg * 0.3) {
return WarningLevel.RED;
} else if (material.getStockQuantity() < weeklyAvg) {
return WarningLevel.ORANGE;
} else if (material.getStockQuantity() < weeklyAvg * 2) {
return WarningLevel.YELLOW;
}
return WarningLevel.NONE;
}
3.2.2 物资分配算法
采用基于优先级的动态分配策略:
- 网格员申请优先级 > 普通居民申请
- 高风险区域分配权重 ×1.5
- 特殊人群(老人、孕妇)自动提升优先级
4. 性能优化实践
4.1 数据库优化
针对疫情上报表设计了复合索引:
sql复制CREATE INDEX idx_resident_time ON report(resident_id, report_time);
CREATE INDEX idx_status_time ON report(health_status, report_time);
通过EXPLAIN分析,查询性能提升约60%。同时配置了MySQL连接池参数:
yaml复制spring:
datasource:
hikari:
maximum-pool-size: 20
minimum-idle: 5
connection-timeout: 30000
idle-timeout: 600000
4.2 缓存策略
采用多级缓存架构:
- 一级缓存:MyBatis本地缓存
- 二级缓存:Redis集群
- 热点缓存:Caffeine本地缓存
缓存更新策略特别需要注意的点:物资库存数据采用"先更新数据库再删除缓存"的策略,避免出现脏读。我们曾因顺序错误导致过库存显示异常的问题。
5. 部署与运维
5.1 容器化部署
使用Docker Compose编排服务:
yaml复制version: '3'
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
volumes:
- ./mysql/data:/var/lib/mysql
backend:
build: ./backend
ports:
- "8080:8080"
depends_on:
- mysql
5.2 监控方案
集成Prometheus+Grafana监控体系,关键指标包括:
- 接口响应时间P99 < 500ms
- JVM内存使用率 < 70%
- 数据库连接池活跃连接数
6. 踩坑与经验
- 时间格式问题:前端传递的日期格式要与后端@DateTimeFormat注解匹配,我们曾因时区问题导致数据查询异常
- 批量导入性能:最初使用MyBatis逐条插入,后来改为批量插入,性能提升20倍
- 微信浏览器兼容:iOS微信浏览器对WebSocket支持有特殊要求,需要配置SockJS备用方案
一个特别值得分享的优化案例:在居民健康打卡的并发场景下,最初采用同步锁控制,QPS只能达到200左右。后来改用Redis分布式锁+本地缓存,QPS提升到1200+。
项目上线后,试点社区的平均疫情信息处理时间从4小时缩短到15分钟,物资调配效率提升300%。这套系统目前已在17个社区稳定运行超过8个月,期间平稳度过了两次疫情波动期。