【实战分享】智慧养老系统核心模块设计 —— 健康监测与自动紧急呼叫

最近刚完成了我的智慧养老系统的一个核心功能模块:个性化健康阈值配置 + 自动紧急呼叫。这是我养老系统的其中一个功能,项目刚做完,当前还未在社区应用。本篇把设计思路、关键数据表和实现要点整理成一篇实战笔记,便于在 CSDN 分享与复用。


目录

一、为什么要做这个模块

二、架构概览

三、设计要点一:个性化健康阈值

[3.1 设计原则](#3.1 设计原则)

[3.2 数据库表(核心)](#3.2 数据库表(核心))

[3.3 默认值参考(可直接采用)](#3.3 默认值参考(可直接采用))

[四、判断逻辑(后端核心实现 ------ Spring Boot)](#四、判断逻辑(后端核心实现 —— Spring Boot))

小细节:阈值变更要通知

[五、设计要点二:自动紧急呼叫(Auto Call)](#五、设计要点二:自动紧急呼叫(Auto Call))

[5.1 触发方式](#5.1 触发方式)

[5.2 流程要点](#5.2 流程要点)

[5.3 呼叫记录表(示例)](#5.3 呼叫记录表(示例))

[5.4 后端自动呼叫实现要点(核心代码节选)](#5.4 后端自动呼叫实现要点(核心代码节选))

六、前端接听

七、我在实现中学到的实战经验

八、后续优化方向

九、结语


一、为什么要做这个模块

很多独居或行动不便的老人,日常体征(心率、血压、血氧、血糖)会有个体差异。统一医学标准会导致大量误报或漏报,影响家庭和护理团队的信任。

我的目标:

  • 支持个性化阈值(老人/家属/医生可调整)

  • 异常自动分级(预警 / 紧急)

  • 紧急情况下能自动发起呼叫并通知家属/社区人员

  • 保证系统稳定:异步、并发安全、状态一致性


二、架构概览

流程简要:

复制代码
数据采集(手环/MQTT/蓝牙) → 阈值判断(个性化) → 预警/紧急判定 → 告警记录 → 自动/手动呼叫 → 实时通知(WebSocket) → 视频/电话接入

三、设计要点一:个性化健康阈值

3.1 设计原则

  • 医学参考值作为默认值

  • 支持用户/家属/医生覆盖默认值(有记录与审计)

  • 修改阈值须触发通知(避免纠纷)

3.2 数据库表(核心)

user_health_config(每人一条)

复制代码
CREATE TABLE `user_health_config` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `user_id` bigint NOT NULL COMMENT '用户ID',
  `hr_min` int DEFAULT 60 COMMENT '心率下限',
  `hr_max` int DEFAULT 100 COMMENT '心率上限',
  `bo_min` int DEFAULT 95 COMMENT '血氧下限',
  `bo_warning` int DEFAULT 98 COMMENT '血氧预警值',
  `bp_sys_min` int DEFAULT 90 COMMENT '收缩压下限',
  `bp_sys_max` int DEFAULT 140 COMMENT '收缩压上限',
  `bp_sys_emergency` int DEFAULT 180 COMMENT '收缩压紧急值',
  `bp_dia_min` int DEFAULT 60 COMMENT '舒张压下限',
  `bp_dia_max` int DEFAULT 90 COMMENT '舒张压上限',
  `bp_dia_emergency` int DEFAULT 120 COMMENT '舒张压紧急值',
  `bg_fasting_min` float DEFAULT 3.9 COMMENT '空腹血糖下限',
  `bg_fasting_max` float DEFAULT 6.1 COMMENT '空腹血糖上限',
  `step_target` int DEFAULT 6000 COMMENT '步数目标',
  `sleep_target` float DEFAULT 7.5 COMMENT '睡眠(小时)',
  `update_time` datetime DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_user_id` (`user_id`)
);

3.3 默认值参考(可直接采用)

  • 心率:60--100 次/分(静息)

  • 血氧:95%(低于 95% 预警,<90% 紧急)

  • 收缩压:90--140 mmHg(>180 紧急)

  • 舒张压:60--90 mmHg(>120 紧急)

  • 空腹血糖:3.9--6.1 mmol/L


四、判断逻辑(后端核心实现 ------ Spring Boot)

我把阈值判断封装到 HealthMonitoringService,返回等级:0-正常, 1-异常(预警), 2-紧急(需呼叫)

关键代码(节选):

复制代码
@Service
public class HealthMonitoringServiceImpl implements HealthMonitoringService {

    @Autowired
    private UserHealthConfigMapper userHealthConfigMapper;

    private int checkVitalSignStatus(Long userId, String type, Float value1, Float value2) {
        UserHealthConfig config = userHealthConfigMapper.selectByUserId(userId);
        if (config == null) {
            config = createDefaultHealthConfig(userId);
        }
        switch (type) {
            case "BP":
                return checkBloodPressureStatus(config, value1, value2);
            case "HR":
                return checkHeartRateStatus(config, value1);
            case "BO":
                return checkBloodOxygenStatus(config, value1);
            case "BG":
                return checkBloodGlucoseStatus(config, value1);
            default:
                return 0;
        }
    }

    // 血压判定示例
    private int checkBloodPressureStatus(UserHealthConfig config, Float systolic, Float diastolic) {
        if (systolic > config.getBpSysEmergency() || diastolic > config.getBpDiaEmergency()) {
            return 2;
        }
        if (systolic > config.getBpSysMax() || diastolic > config.getBpDiaMax()
                || systolic < config.getBpSysMin() || diastolic < config.getBpDiaMin()) {
            return 1;
        }
        return 0;
    }
    // 其他判定略...
}
小细节:阈值变更要通知

当阈值由家属或老人修改时,会发送消息通知对方并写入 health_config_log 做审计。


五、设计要点二:自动紧急呼叫(Auto Call)

5.1 触发方式

  • 手动:老人点击"一键求助"

  • 自动:来自健康监测模块判定为紧急(alertLevel=2)

5.2 流程要点

  1. 生成呼叫记录(emergency_call_record)并落库

  2. 拉取紧急联系人(优先家属,再社区工作人员)

  3. 顺序依次发起通知(避免多人同时骚扰老人)------每位等待一定超时时间(示例:30s)

  4. 使用并发安全结构(ConcurrentHashMap)维护正在进行的呼叫上下文

  5. 使用异步线程池执行呼叫流程,避免阻塞主线程

  6. 状态在内存与数据库同时更新,保证一致性

5.3 呼叫记录表(示例)

复制代码
CREATE TABLE `emergency_call_record` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `elder_user_id` bigint NOT NULL,
  `call_type` varchar(20),
  `alert_type` varchar(20),
  `alert_level` int,
  `alert_value` varchar(50),
  `status` varchar(20),
  `answered_by_user_id` bigint,
  `start_time` datetime,
  `end_time` datetime,
  PRIMARY KEY (`id`)
);

5.4 后端自动呼叫实现要点(核心代码节选)

复制代码
@Service
public class AutoEmergencyCallServiceImpl implements AutoEmergencyCallService {
    private final Map<Long, AutoCallContext> autoCallContexts = new ConcurrentHashMap<>();
    private final ExecutorService executorService = Executors.newCachedThreadPool();

    @Override
    public Map<String, Object> triggerAutoEmergencyCall(Long userId, String alertType, Float value1, Integer alertLevel) {
        EmergencyCallRecord record = new EmergencyCallRecord();
        record.setElderUserId(userId);
        record.setCallType("auto");
        record.setAlertType(alertType);
        record.setAlertLevel(alertLevel);
        record.setAlertValue(String.valueOf(value1));
        record.setStatus("calling");
        record.setStartTime(new Date());
        emergencyCallRecordMapper.insert(record);

        List<EmergencyContact> contacts = emergencyContactMapper.selectByUserId(userId);
        // family first -> staff next
        List<EmergencyContact> allContacts = mergeContacts(contacts);

        AutoCallContext context = new AutoCallContext();
        context.userId = userId;
        context.callRecord = record;
        context.contacts = allContacts;
        autoCallContexts.put(userId, context);

        executorService.submit(() -> performAutoCall(context));
        Map<String, Object> result = new HashMap<>();
        result.put("code", 200);
        result.put("msg", "自动紧急呼叫已触发");
        result.put("callRecordId", record.getId());
        return result;
    }
    // performAutoCall / answerAutoCall / sendCallNotification 等方法见上文逻辑
}

六、前端接听

前端通过 WebSocket 接收 EMERGENCY_CALL_NOTIFICATION 通知,弹出呼叫窗口,用户点击"接听"后调用后端 /api/auto-emergency/answer 接口并跳转到视频通话页(示例代码如下)。

复制代码
websocket.onmessage = function(event) {
    const data = JSON.parse(event.data);
    if (data.msgType === 'EMERGENCY_CALL_NOTIFICATION') {
        showCallUI(data);
    }
};

async function acceptCall(data) {
    await axios.post('/api/auto-emergency/answer', {
        callRecordId: data.callRecordId,
        answeredByUserId: currentUser.id
    });
    window.location.href = `./video-call.html?callRecordId=${data.callRecordId}&elderUserId=${data.elderUserId}`;
}

七、我在实现中学到的实战经验

  • 默认配置 + 个性化覆盖 是减少误报的关键

  • 并发控制(ConcurrentHashMap)避免重复通知与状态竞态

  • 异步执行(线程池)确保接口响应及时

  • 数据库+内存双写 保证呼叫状态的一致性与可审计性

  • 阈值修改要记录日志并通知相关人员,避免责任不明


八、后续优化方向

  • 接入跌倒检测器、智能药盒,扩展触发场景

  • 引入 AI 语音助手,支持老人语音求助

  • 对接社区医院,实现医生端直连推送

  • 增强多模态报警(短信 + 电话 + APP 推送 + 语音)


九、结语

完成这个从 0 到 1 的项目,对我而言既是一次技术练习,也是一次把业务场景落地的实践:在实现功能的过程中我遇到了并发、异步、实时通信等真实问题,也通过查阅资料与反复调试逐步解决。

相关推荐
亚马逊云开发者2 小时前
写 Prompt 让 AI 出代码?Kiro 说你该先写 Spec
java
筱顾大牛2 小时前
点评项目---分布式锁
java·redis·分布式·缓存·idea
想不明白的过度思考者2 小时前
【MyBatis 知识点解析】#{} 与 ${} 的区别及 SQL 注入实战演示
java·数据库·spring boot·sql·mybatis
丶小鱼丶2 小时前
数据结构和算法之【数组】
java·数据结构·算法
惊讶的猫2 小时前
maven介绍_1
java·maven
tongxh4232 小时前
MySQL Workbench菜单汉化为中文
android·数据库·mysql
小钻风33662 小时前
Java函数式编程-lambda表达式
java·开发语言·python
神奇小汤圆2 小时前
NIO:解开非阻塞I/O高并发编程的秘密
后端
饼干哥哥2 小时前
90%的亚马逊选品还不如算命,AI选品系统发布!!
后端·aigc