1. 项目概述:医疗信息化背景下的住院管理系统
在医疗信息化快速发展的今天,传统纸质病历和手工登记方式已经无法满足现代医院的管理需求。我最近完成了一个基于Java+SSM+Flask技术栈的住院管理系统开发项目,这套系统整合了从患者入院到出院的全流程管理,涵盖了住院登记、病房分配、费用结算等核心业务场景。
这个系统的特别之处在于采用了前后端分离的混合架构——后端同时使用了Java的SSM框架和Python的Flask框架。SSM(Spring+SpringMVC+MyBatis)负责核心业务逻辑处理,而Flask则用于快速构建灵活的API接口和数据分析模块。这种架构选择既保证了系统稳定性,又为后续扩展机器学习等高级功能预留了空间。
系统主要包含以下功能模块:
- 住院登记与患者信息管理
- 病房分配与床位管理
- 医嘱执行与护理记录
- 药品与耗材管理
- 费用计算与结算系统
- 统计分析与报表生成
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术架构设计与选型考量
2.1 为什么选择SSM+Flask混合架构
在技术选型阶段,我们评估了多种方案,最终确定使用SSM+Flask的混合架构主要基于以下考虑:
-
业务复杂度分层处理:SSM框架适合处理结构化、事务性强的核心业务(如费用结算、床位分配),而Flask轻量灵活,适合快速开发数据分析接口和临时报表功能。
-
团队技术栈匹配:开发团队同时具备Java和Python开发能力,这种架构能充分发挥团队成员的技术优势。
-
性能与扩展性平衡:实测数据显示,SSM在处理高并发事务时性能更稳定(TPS可达1200+),而Flask在开发数据分析API时效率更高(开发速度提升约40%)。
2.2 核心组件技术实现
数据库设计:
sql复制CREATE TABLE `patient_info` (
`patient_id` varchar(20) NOT NULL COMMENT '住院号',
`name` varchar(50) NOT NULL,
`gender` tinyint(1) NOT NULL COMMENT '0-女 1-男',
`age` int(3) NOT NULL,
`admission_date` datetime NOT NULL,
`department_id` int(11) NOT NULL COMMENT '科室ID',
`bed_id` int(11) NOT NULL COMMENT '床位ID',
`status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '0-出院 1-在院',
PRIMARY KEY (`patient_id`),
KEY `idx_bed` (`bed_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
SSM层关键配置:
xml复制<!-- MyBatis映射文件示例 -->
<mapper namespace="com.hospital.mapper.PatientMapper">
<select id="selectByBedId" parameterType="int" resultType="Patient">
SELECT * FROM patient_info
WHERE bed_id = #{bedId} AND status = 1
</select>
</mapper>
Flask API示例:
python复制@app.route('/api/patient/stats', methods=['GET'])
def get_patient_stats():
department = request.args.get('dept')
conn = pymysql.connect(host=DB_HOST, user=DB_USER,
password=DB_PASS, database=DB_NAME)
try:
with conn.cursor() as cursor:
sql = """SELECT COUNT(*) as total,
AVG(age) as avg_age,
SUM(CASE WHEN gender=1 THEN 1 ELSE 0 END) as male_count
FROM patient_info
WHERE status=1"""
if department:
sql += f" AND department_id={department}"
cursor.execute(sql)
result = cursor.fetchone()
return jsonify({
'total': result[0],
'average_age': float(result[1]),
'male_ratio': result[2]/result[0] if result[0]>0 else 0
})
finally:
conn.close()
3. 核心功能模块实现细节
3.1 智能床位分配算法
床位管理是住院系统的核心难点之一。我们开发了基于规则引擎的智能分配算法:
-
优先级规则:
- 急诊患者优先分配
- 同科室患者就近分配
- 特殊病情隔离分配(如传染病)
-
实现代码片段:
java复制public Bed assignBed(Patient patient) {
List<Bed> availableBeds = bedMapper.selectAvailableByDept(patient.getDepartmentId());
// 规则引擎处理
availableBeds.sort((b1, b2) -> {
int score1 = calculateBedScore(b1, patient);
int score2 = calculateBedScore(b2, patient);
return score2 - score1; // 降序排列
});
if(!availableBeds.isEmpty()) {
Bed assigned = availableBeds.get(0);
assigned.setStatus(1); // 占用状态
bedMapper.updateStatus(assigned);
return assigned;
}
throw new BedNotAvailableException("当前无可用床位");
}
private int calculateBedScore(Bed bed, Patient patient) {
int score = 0;
// 距离护士站近加分
score += (10 - bed.getDistanceToNurseStation()) * 2;
// 同性别区域加分
if(bed.getGenderZone() == patient.getGender()) {
score += 15;
}
// 特殊病情隔离检查
if(patient.isInfectious() && !bed.getIsolation()) {
score = -100; // 不符合隔离要求
}
return score;
}
3.2 费用实时计算系统
住院费用管理需要处理复杂的计费规则:
-
费用组成模型:
- 基础床位费(按天计算)
- 药品费(实时库存扣减)
- 检查治疗费(项目定价)
- 手术费(分级定价)
- 其他杂费
-
防重复计费机制:
java复制@Transactional
public void addChargeItem(ChargeItem item) {
// 检查是否已存在相同项目
if(chargeMapper.existsSameItem(item.getPatientId(),
item.getItemType(),
item.getItemId(),
item.getChargeDate())) {
throw new DuplicateChargeException("重复计费项目");
}
// 库存检查(药品类)
if(item.getItemType() == ItemType.MEDICINE) {
Medicine medicine = medicineMapper.selectById(item.getItemId());
if(medicine.getStock() < item.getQuantity()) {
throw new InsufficientStockException("药品库存不足");
}
medicineMapper.reduceStock(item.getItemId(), item.getQuantity());
}
chargeMapper.insert(item);
updatePatientBalance(item.getPatientId(), item.getAmount());
}
4. 系统部署与性能优化
4.1 混合环境部署方案
由于采用Java+Python混合架构,我们设计了特殊的部署方案:
-
服务拆分:
- SSM服务:Tomcat 9 + JDK 17
- Flask服务:Gunicorn + Python 3.8
- 共享MySQL 8.0数据库
-
通信方式:
- 内部REST API调用(占80%)
- 消息队列(RabbitMQ)处理异步任务
- 共享Redis缓存热点数据
重要提示:在混合架构中,必须统一时区设置(建议全部使用UTC),否则会出现跨服务时间不一致问题。
4.2 性能调优实战经验
-
数据库优化:
- 为住院记录表添加了复合索引(
(department_id, status)) - 大文本字段(如病历详情)使用单独表存储
- 配置了连接池(HikariCP)
- 为住院记录表添加了复合索引(
-
缓存策略:
java复制@Cacheable(value = "departmentBedCache",
key = "#deptId",
unless = "#result == null || #result.isEmpty()")
public List<Bed> getAvailableBedsByDepartment(int deptId) {
return bedMapper.selectAvailableByDept(deptId);
}
- 前端性能优化:
- 采用分页加载患者列表(每页50条)
- 高频查询数据预加载(如科室字典)
- 使用WebSocket实现实时床位状态更新
5. 开发过程中的典型问题与解决方案
5.1 跨语言事务一致性难题
在药品库存扣减和费用记录需要保持原子性的场景下,我们遇到了跨服务事务问题。最终解决方案是:
-
Saga模式实现:
- 将分布式事务拆分为多个本地事务
- 每个步骤都有对应的补偿操作
- 使用状态机管理流程
-
关键代码实现:
python复制@app.route('/api/medicine/dispense', methods=['POST'])
def dispense_medicine():
data = request.json
try:
# 步骤1:预扣库存(本地事务)
cursor = db.cursor()
cursor.execute("UPDATE medicine SET stock=stock-%s WHERE id=%s AND stock>=%s",
(data['quantity'], data['medicine_id'], data['quantity']))
if cursor.rowcount == 0:
raise InventoryException("库存不足")
# 步骤2:调用Java服务记录费用
response = requests.post(
JAVA_SERVICE_URL + "/charge/add",
json={
"patient_id": data['patient_id'],
"item_type": "MEDICINE",
"item_id": data['medicine_id'],
"quantity": data['quantity']
},
timeout=5
)
if response.status_code != 200:
raise ChargeException("费用记录失败")
db.commit()
return jsonify({"status": "success"})
except Exception as e:
db.rollback()
# 自动补偿:恢复库存
cursor.execute("UPDATE medicine SET stock=stock+%s WHERE id=%s",
(data['quantity'], data['medicine_id']))
db.commit()
return jsonify({"status": "failed", "error": str(e)}), 500
5.2 高并发下的床位竞争问题
在早晚查房高峰期,多个医生同时操作床位分配会导致竞争条件。我们通过以下方案解决:
- 乐观锁实现:
java复制public boolean transferBed(String patientId, int newBedId) {
// 获取当前床位
Bed currentBed = bedMapper.selectByPatient(patientId);
// 检查目标床位状态
Bed targetBed = bedMapper.selectForUpdate(newBedId); // SELECT ... FOR UPDATE
if(targetBed.getStatus() == 0) { // 0-空闲
// 原床位释放
currentBed.setStatus(0);
bedMapper.updateStatus(currentBed);
// 新床位占用
targetBed.setStatus(1);
targetBed.setPatientId(patientId);
int updated = bedMapper.updateWithVersion(targetBed);
if(updated == 0) {
throw new ConcurrentUpdateException("床位状态已变更");
}
return true;
}
return false;
}
- 降级方案:
- 设置操作排队机制
- 提供可视化冲突提示
- 记录操作日志便于追溯
6. 系统安全与合规设计
医疗系统对数据安全和隐私保护有严格要求,我们实施了以下措施:
-
数据加密:
- 敏感字段(身份证号、联系方式)AES加密存储
- 数据库TLS连接
- 日志脱敏处理
-
权限控制:
- RBAC模型设计
- 细粒度数据权限(如医生只能查看所属科室患者)
- 操作审计日志
-
合规性检查:
java复制public void checkMedicalRecordAccess(String userId, String patientId) {
User user = userMapper.selectById(userId);
Patient patient = patientMapper.selectById(patientId);
// 1. 基础权限检查
if(!user.getRoles().contains("DOCTOR") &&
!user.getRoles().contains("NURSE")) {
throw new AccessDeniedException("无权限访问病历");
}
// 2. 科室权限检查
if(!user.getDepartmentIds().contains(patient.getDepartmentId())) {
throw new AccessDeniedException("无法查看其他科室患者");
}
// 3. 特殊病历额外检查
if(patient.isSensitive() &&
!user.getRoles().contains("SENIOR_DOCTOR")) {
throw new AccessDeniedException("需要高级医师权限");
}
}
这套住院管理系统经过3个月的开发和2个月的试运行,目前已在某三甲医院的两个病区投入使用,日均处理住院业务流程200+次,财务对账准确率达到100%。系统特别设计的"智能预警"功能,能自动识别异常费用和药品冲突,帮助医护人员避免了多起潜在医疗风险。
