ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

UML课设实战:社区健康管理系统从建模到MySQL落库

UML课设实战:社区健康管理系统从建模到MySQL落库 简介这份资源是面向软件工程、UML课程设计学习者与系统分析入门者的社区健康管理系统建模资料包围绕《UML在社区健康管理系统设计中的应用》展开帮助读者理解如何用统一建模语言完成从需求到设计的完整表达。压缩包共16个文件约418KB以6个cpp源文件与6个头文件构成可运行的代码骨架辅以2份docx设计文档、1份txt说明和1个mdl模型文件覆盖居民健康档案、预约挂号、健康咨询、疾病预防与健康数据分析等核心模块。文档部分系统梳理了用例图、类图、状态图、活动图、序列图、协作图、部署图与包图在系统中的应用思路代码则对应健康状态、健康建议、用户信息、登录与市场人员操作等类实现便于对照模型理解类间继承、关联与聚合关系。已有100人学习适合需要完整课设方案、建模范例与代码参考的读者快速上手并查漏补缺。1. 从一份课设压缩包说起社区健康管理系统到底在做什么很多同学拿到「UML课设社区健康管理系统.zip」这类标题时第一反应是去搜现成源码结果下载下来一堆 .mdj、.asta 或者 .vpp 文件打开一看全是框框线线不知道从哪下手。我当年也踩过这个坑以为 UML 课设就是画几张图交差后来才发现真正拉开差距的是你能不能把「图」和「可运行的系统」对上号。社区健康管理系统这个题目核心业务其实很具体——居民建档、慢病随访、预约挂号、健康档案查询、数据统计。它不复杂但恰好覆盖了 UML 里最常考的用例图、类图、时序图、活动图、状态图。适合谁适合正在做软件工程或面向对象课设的本科生也适合想用一个小型业务系统练手建模的初级开发者。这一篇不讲空理论只讲怎么从零把这份课设做成能讲、能跑、能答辩的东西。2. 先想清楚建模边界社区健康管理系统里哪些模块必须画哪些可以砍2.1 业务模块拆解与 UML 图的对应关系社区健康管理系统的业务边界我一般按「人、事、档、约」四个字来切。人指居民和医护人员事指随访和体检档指健康档案约指预约和提醒。对应到 UML用例图负责回答「谁用系统做什么」类图负责回答「系统里有哪些实体、它们怎么关联」时序图负责回答「一次随访或一次预约在对象之间怎么流转」活动图负责回答「业务流程的分支和并发」状态图负责回答「一个预约单或一份档案的生命周期」。很多同学一上来就画类图结果类名全是 User、Manager、Data 这种万能词答辩时老师一问「你的健康档案和随访记录是什么关系」就卡住。正确顺序是先定用例再抽实体最后补动态图。用例图里居民侧的用例至少要有「注册登录」「查看健康档案」「预约体检」「查看随访提醒」医护侧的用例至少要有「录入体检数据」「发起随访」「更新慢病标签」「导出统计报表」管理侧的用例至少要有「用户管理」「角色权限分配」「数据备份」。注意不要为了凑图量把「登录」拆成「输入用户名」「输入密码」「点击登录」三个用例那是活动图干的事。2.2 用例图与类图的最小可用集合如果时间紧我建议先保证这五张图能自洽用例图一张、类图一张、时序图两张预约和随访各一、活动图一张体检数据录入流程。状态图可以放在预约单上作为加分项。类图里必须出现的实体类包括居民 Resident、医护人员 Doctor、健康档案 HealthRecord、随访记录 FollowUp、预约 Appointment、体检项目 CheckItem、慢病标签 ChronicTag。关系上Resident 与 HealthRecord 是一对一Doctor 与 FollowUp 是一对多Appointment 关联 Resident 和 DoctorFollowUp 关联 HealthRecord 和 ChronicTag。这里有个血泪经验类图里的方法不要写 get/set要写业务方法比如addFollowUp()、updateChronicTag()、queryHistory()。老师看的是你有没有面向对象思维不是看你会不会写 JavaBean。属性上Resident 至少要有 residentId、name、idCard、phone、address、birthDateHealthRecord 要有 recordId、residentId、bloodType、allergyHistory、createTimeFollowUp 要有 followUpId、doctorId、residentId、followUpDate、content、nextDate。这些字段后面建数据库表时可以直接用别等到写代码再返工。2.3 用 PlantUML 把类图先落成可版本管理的文本工具选型上Rational Rose 和 StarUML 都能画但如果你想让图能进 Git、能 diff、能改我强烈建议用 PlantUML。下面这段是社区健康管理系统类图的核心片段直接复制到任何支持 PlantUML 的编辑器里就能渲染。startuml class Resident { -residentId: String -name: String -idCard: String -phone: String -address: String register(): void queryHealthRecord(): HealthRecord makeAppointment(): Appointment } class HealthRecord { -recordId: String -residentId: String -bloodType: String -allergyHistory: String -createTime: Date updateRecord(): void queryHistory(): ListFollowUp } class FollowUp { -followUpId: String -doctorId: String -residentId: String -followUpDate: Date -content: String -nextDate: Date addFollowUp(): void updateNextDate(): void } class Doctor { -doctorId: String -name: String -department: String initiateFollowUp(): FollowUp reviewRecord(): void } class Appointment { -appointmentId: String -residentId: String -doctorId: String -appointmentTime: Date -status: String confirm(): void cancel(): void } Resident 1 -- 1 HealthRecord : owns Resident 1 -- 0..* Appointment : makes Doctor 1 -- 0..* FollowUp : initiates HealthRecord 1 -- 0..* FollowUp : contains enduml这段代码的逻辑说明Resident和HealthRecord用1 -- 1表示一人一档Resident和Appointment用1 -- 0..*表示一个居民可以有多条预约Doctor和FollowUp用1 -- 0..*表示一个医生可以发起多次随访HealthRecord和FollowUp用1 -- 0..*表示一份档案下有多条随访。参数上status字段建议用枚举值PENDING、CONFIRMED、CANCELLED不要用中文后面写代码时方便判断。如果你用 StarUML导出时记得选.mdj和图片双份答辩现场万一打不开软件还能看图。3. 从图到库把类图翻译成 MySQL 表结构的完整脚本3.1 表结构设计与外键约束类图定完下一步就是建库。社区健康管理系统的表不用多六张核心表足够resident、doctor、health_record、follow_up、appointment、chronic_tag。下面这份 SQL 可以直接在 MySQL 8.0 里跑注意字符集用 utf8mb4不然居民姓名里的生僻字会翻车。CREATE DATABASE IF NOT EXISTS community_health DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_unicode_ci; USE community_health; CREATE TABLE resident ( resident_id VARCHAR(32) PRIMARY KEY, name VARCHAR(64) NOT NULL, id_card VARCHAR(18) NOT NULL UNIQUE, phone VARCHAR(20), address VARCHAR(255), birth_date DATE, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB; CREATE TABLE doctor ( doctor_id VARCHAR(32) PRIMARY KEY, name VARCHAR(64) NOT NULL, department VARCHAR(64), title VARCHAR(32) ) ENGINEInnoDB; CREATE TABLE health_record ( record_id VARCHAR(32) PRIMARY KEY, resident_id VARCHAR(32) NOT NULL, blood_type VARCHAR(8), allergy_history TEXT, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, CONSTRAINT fk_record_resident FOREIGN KEY (resident_id) REFERENCES resident(resident_id) ON DELETE CASCADE ) ENGINEInnoDB; CREATE TABLE follow_up ( follow_up_id VARCHAR(32) PRIMARY KEY, doctor_id VARCHAR(32) NOT NULL, resident_id VARCHAR(32) NOT NULL, follow_up_date DATE NOT NULL, content TEXT, next_date DATE, CONSTRAINT fk_follow_doctor FOREIGN KEY (doctor_id) REFERENCES doctor(doctor_id), CONSTRAINT fk_follow_resident FOREIGN KEY (resident_id) REFERENCES resident(resident_id) ) ENGINEInnoDB; CREATE TABLE appointment ( appointment_id VARCHAR(32) PRIMARY KEY, resident_id VARCHAR(32) NOT NULL, doctor_id VARCHAR(32) NOT NULL, appointment_time DATETIME NOT NULL, status ENUM(PENDING,CONFIRMED,CANCELLED) DEFAULT PENDING, CONSTRAINT fk_appt_resident FOREIGN KEY (resident_id) REFERENCES resident(resident_id), CONSTRAINT fk_appt_doctor FOREIGN KEY (doctor_id) REFERENCES doctor(doctor_id) ) ENGINEInnoDB; CREATE TABLE chronic_tag ( tag_id INT AUTO_INCREMENT PRIMARY KEY, resident_id VARCHAR(32) NOT NULL, tag_name VARCHAR(64) NOT NULL, diagnose_date DATE, CONSTRAINT fk_tag_resident FOREIGN KEY (resident_id) REFERENCES resident(resident_id) ON DELETE CASCADE ) ENGINEInnoDB;逻辑说明resident表的id_card加了唯一约束防止重复建档health_record对resident_id做了级联删除居民注销时档案自动清理appointment的status用 ENUM 限制取值范围避免脏数据chronic_tag用自增主键因为一个居民可以有多个慢病标签。参数上VARCHAR(32)的主键建议用 UUID 去掉横杠长度刚好DATETIME和DATE分开用预约精确到时间随访只到日期。3.2 插入测试数据与验证外键建完表别急着写后端先插几条数据验证约束是否生效。下面这段脚本插一个居民、一个医生、一份档案、一次随访和一条预约。INSERT INTO resident (resident_id, name, id_card, phone, address, birth_date) VALUES (R001, 张三, 110101199001011234, 13800000001, 某社区1栋101, 1990-01-01); INSERT INTO doctor (doctor_id, name, department, title) VALUES (D001, 李医生, 全科, 主治医师); INSERT INTO health_record (record_id, resident_id, blood_type, allergy_history) VALUES (H001, R001, A, 青霉素过敏); INSERT INTO follow_up (follow_up_id, doctor_id, resident_id, follow_up_date, content, next_date) VALUES (F001, D001, R001, 2025-01-10, 血压偏高建议低盐饮食, 2025-02-10); INSERT INTO appointment (appointment_id, resident_id, doctor_id, appointment_time, status) VALUES (A001, R001, D001, 2025-01-15 09:00:00, CONFIRMED);执行完可以用SELECT * FROM follow_up WHERE resident_id R001;验证关联查询。如果插入follow_up时doctor_id写成D002会直接报外键错误这就是约束的价值。注意测试数据里的身份证号是虚构的别拿真实号码跑答辩演示时也要说明数据已脱敏。3.3 用时序图核对预约流程的每一步表建好后回头用时序图核对一遍预约流程确保图、库、代码三者一致。下面这段 PlantUML 描述居民发起预约到医生确认的过程。startuml actor Resident participant 预约服务 as ApptService participant 医生服务 as DoctorService database MySQL as DB Resident - ApptService : 提交预约请求(residentId, doctorId, time) ApptService - DB : 查询医生排班 DB -- ApptService : 返回可预约时段 ApptService - DB : 插入 appointment(statusPENDING) ApptService -- Resident : 返回预约编号 DoctorService - DB : 查询待确认预约 DB -- DoctorService : 返回 PENDING 列表 DoctorService - DB : 更新 statusCONFIRMED DoctorService -- Resident : 发送确认通知 enduml逻辑说明居民提交请求后系统先查排班再落库状态初始为 PENDING医生侧轮询或主动查询待确认列表确认后更新为 CONFIRMED。参数上time要校验是否在医生排班范围内residentId和doctorId必须存在。这张图答辩时可以直接讲老师一听就知道你理解业务闭环。4. 避坑与排查课设答辩前最容易翻车的五个地方4.1 图与代码不一致老师一问就露馅现象类图里写了HealthRecord有updateRecord()方法但代码里根本没有这个方法或者方法名对不上。原因画图和写代码分两拨人做或者自己画完图就扔了后面凭感觉写。解决定稿类图后用 PlantUML 生成一次图片把图片贴在 IDE 旁边每写一个类就核对一次方法名和属性名。我一般会在代码里加注释// UML: HealthRecord.updateRecord()方便回溯。4.2 外键约束导致插入顺序错误现象插入follow_up时报Cannot add or update a child row。原因先插了随访记录但对应的resident或doctor还没插。解决按resident - doctor - health_record - follow_up - appointment的顺序插入。如果必须乱序先SET FOREIGN_KEY_CHECKS 0;插完再SET FOREIGN_KEY_CHECKS 1;但答辩演示不建议这么干容易给人留下数据一致性差的印象。4.3 状态图里的状态和数据库 ENUM 对不上现象状态图里写了WAITING、DONE但数据库 ENUM 里是PENDING、CONFIRMED、CANCELLED。原因画图时随手起了名字建库时又换了一套。解决先定 ENUM再把状态图里的状态名改成完全一致。建议在项目根目录放一个glossary.md把状态、角色、标签的命名统一列出来谁改谁更新。4.4 用例图粒度太细或太粗现象用例图里出现「输入用户名」「点击登录按钮」这种步骤级用例或者整个系统只有一个「管理社区健康」的大用例。原因对用例的定义理解偏差。解决用例必须是「对参与者有价值的结果」登录可以是一个用例但输入用户名不是。一个用例通常对应一个完整业务目标比如「预约体检」「录入随访」。如果拿不准问自己这个用例完成后参与者能不能拿到一个可感知的结果4.5 答辩时只讲图不讲业务价值现象老师问「你这个系统解决什么问题」回答「就是画了 UML 图」。原因把课设当成画图作业没从业务角度准备。解决准备一段 30 秒的话术比如「社区健康管理系统解决的是居民档案分散、随访提醒不及时的问题通过预约和随访闭环让医护人员能按计划跟进慢病居民」。图是手段业务是目的答辩时先讲业务再讲图。5. 进阶技巧用状态图驱动预约模块的代码实现如果你想让课设从「及格」冲到「优秀」我建议挑一个核心实体把状态图真正落到代码里。预约模块最适合因为它状态少、流转清晰。下面用 Python 写一个极简的状态机演示PENDING - CONFIRMED - CANCELLED的合法流转。from enum import Enum class AppointmentStatus(Enum): PENDING PENDING CONFIRMED CONFIRMED CANCELLED CANCELLED # 定义合法流转当前状态 - 允许的下一个状态 TRANSITIONS { AppointmentStatus.PENDING: {AppointmentStatus.CONFIRMED, AppointmentStatus.CANCELLED}, AppointmentStatus.CONFIRMED: {AppointmentStatus.CANCELLED}, AppointmentStatus.CANCELLED: set(), } class Appointment: def __init__(self, appointment_id): self.appointment_id appointment_id self.status AppointmentStatus.PENDING def transition_to(self, new_status): allowed TRANSITIONS.get(self.status, set()) if new_status not in allowed: raise ValueError( f非法流转: {self.status.value} - {new_status.value} ) self.status new_status return self.status # 演示 appt Appointment(A001) print(appt.transition_to(AppointmentStatus.CONFIRMED)) # CONFIRMED try: appt.transition_to(AppointmentStatus.PENDING) # 抛异常 except ValueError as e: print(e)逻辑说明TRANSITIONS字典定义了每个状态能去往哪些状态transition_to先查表再更新非法流转直接抛异常。参数上AppointmentStatus用字符串枚举和数据库 ENUM 保持一致appointment_id用字符串和表结构对齐。这段代码可以直接嵌进你的后端服务里答辩时演示一次非法流转被拦截比单纯讲状态图有说服力得多。验证方法上我习惯用三个断言覆盖初始状态必须是 PENDINGPENDING 可以到 CONFIRMED 和 CANCELLEDCANCELLED 不能再变。如果你用 Java可以用枚举加 switch 实现同样的逻辑如果用 JavaScript可以用对象映射。关键是让状态图和代码里的状态名、流转规则完全一致别一边画图一边写代码两套逻辑。最后说个我自己的教训当年做课设时我花了两周画图最后三天赶代码结果类图里的方法和代码对不上答辩被老师追问了十分钟。后来我改成先写 SQL 和状态机再回头补图图反而更准。如果你也在做这份社区健康管理系统建议先把预约和随访两条线跑通再补其他图。希望帮到你。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进