大家好,我是Java1234_小锋老师,分享一套锋哥原创的基于Spark实时医疗健康数据监测与疾病预测系统(Java版本+可视化大屏+Kafka+SpringBoot+Vue3)
项目介绍
随着医疗信息化与物联网可穿戴设备的快速发展,医院与健康管理机构面临着体征数据规模大、产生速度快、分析时效性要求高的挑战。传统以事后统计为主的信息系统难以满足实时监测与早期预警需求。本文设计并实现了一套基于Spark的实时医疗健康数据监测与疾病预测系统,围绕“数据采集—消息传输—流式聚合—风险预测—可视化展示”的完整链路开展研究与开发。
系统后端采用Java 17与Spring Boot 3构建RESTful服务,结合Spring Security与JWT完成管理员身份认证;数据访问层使用MyBatis-Plus操作MySQL数据库db_health;实时事件通过Apache Kafka主题health_vitals进行解耦传输;计算层引入Apache Spark SQL与Spark MLlib,对按小时窗口聚合的风险指数序列进行线性回归预测,并计算RMSE、MAE、MAPE误差指标。前端采用Vue 3、Vite、Element Plus与ECharts实现管理后台与数据大屏,支持患者档案管理、体征记录查询、实时统计分析、疾病风险预测对比以及个人中心(头像上传、资料修改、密码修改)等功能。
测试结果表明,系统能够稳定完成模拟体征数据的持续接入与入库,实时统计与预测结果可在前端动态刷新,功能完整性与交互可用性满足本科毕业设计要求。本课题将大数据流处理、机器学习预测与Web工程实践相结合,对智慧医疗场景下的实时健康管理具有一定参考价值。
源码下载
链接: https://pan.baidu.com/s/1hNYZ5_11TXkswBhGGYhZHg?pwd=1234
提取码: 1234
系统展示
![]()
![]()
![]()
![]()
核心代码
package com.java1234.controller; import com.java1234.common.PageResult; import com.java1234.common.Result; import com.java1234.dto.PatientCreateRequest; import com.java1234.dto.PatientUpdateRequest; import com.java1234.service.PatientService; import com.java1234.vo.PatientVo; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.util.List; import java.util.Map; /** * 患者管理控制器 */ @RestController @RequestMapping("/api/patient") @RequiredArgsConstructor public class PatientController { private final PatientService patientService; /** * 分页查询患者列表 */ @GetMapping("/list") public Result<PageResult<PatientVo>> list( @RequestParam(defaultValue = "1") int page, @RequestParam(defaultValue = "10") int size, @RequestParam(required = false) String keyword) { return Result.success(patientService.listPatients(page, size, keyword)); } /** * 新增患者 */ @PostMapping("/create") public Result<PatientVo> create(@RequestBody PatientCreateRequest request) { return Result.success(patientService.createPatient(request)); } /** * 更新患者信息 */ @PutMapping("/update/{patientId}") public Result<PatientVo> update(@PathVariable Integer patientId, @RequestBody PatientUpdateRequest request) { return Result.success(patientService.updatePatient(patientId, request)); } /** * 删除患者 */ @DeleteMapping("/delete/{patientId}") public Result<Void> delete(@PathVariable Integer patientId) { patientService.deletePatient(patientId); return Result.success("删除成功"); } /** * 获取疾病类型列表 */ @GetMapping("/diseases") public Result<List<Map<String, Object>>> diseases() { return Result.success(patientService.listDiseases()); } }<template> <div class="page-container"> <div class="page-card"> <div class="page-title">患者管理</div> <div style="margin-bottom:16px;display:flex;gap:12px"> <el-input v-model="keyword" placeholder="搜索患者姓名" clearable style="width:240px" @clear="loadData" @keyup.enter="loadData" /> <el-button type="primary" @click="loadData">搜索</el-button> <el-button type="success" @click="openDialog()">新增患者</el-button> </div> <el-table :data="tableData" stripe border style="width:100%"> <el-table-column prop="id" label="ID" min-width="60" /> <el-table-column prop="name" label="姓名" min-width="100" /> <el-table-column prop="gender" label="性别" min-width="70" /> <el-table-column prop="age" label="年龄" min-width="70" /> <el-table-column prop="city" label="城市" min-width="100" /> <el-table-column prop="disease_name" label="疾病类型" min-width="120" /> <el-table-column prop="phone" label="联系电话" min-width="130" /> <el-table-column prop="create_time" label="创建时间" min-width="170"> <template #default="{ row }">{{ formatDateTime(row.create_time) }}</template> </el-table-column> <el-table-column label="操作" min-width="160" fixed="right"> <template #default="{ row }"> <el-button type="primary" link size="small" @click="openDialog(row)">编辑</el-button> <el-button type="danger" link size="small" @click="handleDelete(row.id)">删除</el-button> </template> </el-table-column> </el-table> <el-pagination style="margin-top:16px;justify-content:flex-end" v-model:current-page="page" v-model:page-size="size" :total="total" :page-sizes="[10, 20, 50]" layout="total, sizes, prev, pager, next" @change="loadData" /> </div> <el-dialog v-model="dialogVisible" :title="editId ? '编辑患者' : '新增患者'" width="500px"> <el-form :model="form" label-width="90px"> <el-form-item label="姓名"><el-input v-model="form.name" /></el-form-item> <el-form-item label="性别"> <el-select v-model="form.gender" style="width:100%"> <el-option label="男" value="男" /><el-option label="女" value="女" /><el-option label="未知" value="未知" /> </el-select> </el-form-item> <el-form-item label="年龄"><el-input-number v-model="form.age" :min="0" :max="120" style="width:100%" /></el-form-item> <el-form-item label="城市"><el-input v-model="form.city" /></el-form-item> <el-form-item label="疾病类型"> <el-select v-model="form.disease_id" style="width:100%"> <el-option v-for="d in diseases" :key="d.id" :label="d.name" :value="d.id" /> </el-select> </el-form-item> <el-form-item label="联系电话"><el-input v-model="form.phone" /></el-form-item> </el-form> <template #footer> <el-button @click="dialogVisible = false">取消</el-button> <el-button type="primary" @click="handleSave">保存</el-button> </template> </el-dialog> </div> </template> <script setup> /** * 患者管理页面 */ import { ref, reactive, onMounted } from 'vue' import request from '@/utils/request' import { formatDateTime } from '@/utils/format' import { ElMessage, ElMessageBox } from 'element-plus' const tableData = ref([]) const diseases = ref([]) const page = ref(1) const size = ref(10) const total = ref(0) const keyword = ref('') const dialogVisible = ref(false) const editId = ref(null) const form = reactive({ name: '', gender: '未知', age: 0, city: '', disease_id: null, phone: '' }) async function loadData() { const res = await request.get('/patient/list', { params: { page: page.value, size: size.value, keyword: keyword.value || undefined } }) tableData.value = res.data.items total.value = res.data.total } async function loadDiseases() { const res = await request.get('/patient/diseases') diseases.value = res.data } function openDialog(row) { editId.value = row?.id || null form.name = row?.name || '' form.gender = row?.gender || '未知' form.age = row?.age || 0 form.city = row?.city || '' form.disease_id = row?.disease_id || null form.phone = row?.phone || '' dialogVisible.value = true } async function handleSave() { if (editId.value) { await request.put(`/patient/update/${editId.value}`, form) } else { await request.post('/patient/create', form) } ElMessage.success('保存成功') dialogVisible.value = false loadData() } async function handleDelete(id) { await ElMessageBox.confirm('确定删除该患者?', '提示', { type: 'warning' }) await request.delete(`/patient/delete/${id}`) ElMessage.success('删除成功') loadData() } onMounted(() => { loadData(); loadDiseases() }) </script>