1. 医疗问诊小程序系统架构设计
医疗问诊小程序采用前后端分离架构,前端基于UniApp框架实现跨平台兼容性,后端采用Java Spring Boot提供稳定的API服务。这种架构选择主要基于三个考量:首先,UniApp的"一次开发,多端发布"特性可以显著降低开发成本;其次,Spring Boot的快速开发能力适合医疗系统频繁迭代的需求;最后,分离架构有利于团队分工和系统扩展。
前端技术栈中,Vue.js作为核心框架配合Vuex状态管理,能够高效处理医疗场景下的复杂交互。实测表明,使用Vue的单文件组件开发模式,比传统DOM操作开发效率提升40%以上。特别值得注意的是,我们选择了uView UI组件库而非Vant等流行方案,因为其专为UniApp优化,在微信小程序端的性能表现更优。
后端服务采用分层设计:
- 控制层:Spring MVC处理HTTP请求
- 业务层:Spring事务管理保证数据一致性
- 持久层:MyBatis-Plus简化数据库操作
- 缓存层:Redis存储高频访问数据
数据库设计遵循医疗行业规范,核心表包括:
sql复制CREATE TABLE `patient` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`openid` varchar(64) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '微信openid',
`name` varchar(32) COLLATE utf8mb4_bin NOT NULL COMMENT '患者姓名',
`id_card` varchar(18) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '身份证号',
`phone` varchar(11) COLLATE utf8mb4_bin NOT NULL COMMENT '手机号',
`gender` tinyint DEFAULT '0' COMMENT '性别(0-未知 1-男 2-女)',
`birth_date` date DEFAULT NULL COMMENT '出生日期',
`allergy_history` text COLLATE utf8mb4_bin COMMENT '过敏史',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_openid` (`openid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='患者信息表';
2. 核心功能模块实现细节
2.1 智能挂号预约系统
挂号模块采用实时队列机制处理并发预约,通过Redis的原子操作保证号源一致性。关键实现逻辑:
java复制public AppointmentResult makeAppointment(AppointmentRequest request) {
String lockKey = "lock:schedule:" + request.getScheduleId();
try {
// 分布式锁防止超卖
boolean locked = redisTemplate.opsForValue()
.setIfAbsent(lockKey, "1", 30, TimeUnit.SECONDS);
if (!locked) {
return AppointmentResult.fail("当前号源正在被其他用户锁定");
}
// 检查剩余号源
String quotaKey = "schedule:quota:" + request.getScheduleId();
Long remaining = redisTemplate.opsForValue().decrement(quotaKey);
if (remaining < 0) {
redisTemplate.opsForValue().increment(quotaKey);
return AppointmentResult.fail("号源已约满");
}
// 数据库事务处理
return transactionTemplate.execute(status -> {
try {
// 写入预约记录
appointmentMapper.insert(buildAppointment(request));
// 更新排班表剩余数量
scheduleMapper.updateRemaining(request.getScheduleId());
return AppointmentResult.success();
} catch (Exception e) {
status.setRollbackOnly();
redisTemplate.opsForValue().increment(quotaKey);
return AppointmentResult.fail("预约失败:" + e.getMessage());
}
});
} finally {
redisTemplate.delete(lockKey);
}
}
实际开发中发现三个关键点:
- 微信小程序端需要特殊处理支付超时问题,建议设置15分钟未支付自动取消
- 科室排班数据建议使用本地缓存,更新频率控制在5分钟级别
- 医生停诊情况需要同步通知已预约患者,这个功能容易被忽略
2.2 电子健康档案管理
档案模块采用分级存储策略:基础信息存MySQL,大文件(如CT影像)存对象存储。前端实现了一个创新的懒加载+预加载方案:
javascript复制// 档案列表懒加载
onReachBottom() {
if (this.loading || !this.hasMore) return
this.loading = true
this.pageNum++
this.getRecords()
},
// 图片预加载
preloadImages(records) {
records.forEach(record => {
if (record.fileType === 'IMAGE') {
const img = new Image()
img.src = record.fileUrl
}
})
}
医疗数据安全方面,我们实现了:
- 数据传输全程HTTPS加密
- 敏感字段如身份证号进行AES加密存储
- 接口访问增加患者身份校验
- 操作日志完整记录,满足医疗审计要求
3. 实时问诊通信方案
在线问诊采用混合通信模式:短消息用WebSocket保证实时性,大文件走HTTP上传。这个方案经过多次压力测试,在200并发下平均延迟<500ms。
WebSocket服务端核心配置:
java复制@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/queue", "/topic");
config.setApplicationDestinationPrefixes("/app");
config.setUserDestinationPrefix("/user");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws")
.setAllowedOrigins("*")
.withSockJS();
}
@Override
public void configureClientInboundChannel(ChannelRegistration registration) {
registration.interceptors(new AuthChannelInterceptor());
}
}
前端实现消息可靠投递机制:
javascript复制// 消息重发队列
const resendQueue = new Map()
// 发送消息
function sendMessage(destination, body) {
const messageId = generateUUID()
return new Promise((resolve, reject) => {
stompClient.publish({
destination,
body: JSON.stringify({...body, messageId}),
headers: {'receipt': messageId}
})
// 超时处理
const timer = setTimeout(() => {
resendQueue.set(messageId, {destination, body})
retrySend(messageId)
}, 5000)
// 确认回调
const sub = stompClient.subscribe(`/user/queue/receipts`, (frame) => {
const receiptId = JSON.parse(frame.body).id
if (receiptId === messageId) {
clearTimeout(timer)
resendQueue.delete(messageId)
sub.unsubscribe()
resolve()
}
})
})
}
4. 性能优化与异常处理
4.1 小程序包体积控制
UniApp打包时容易产生过大主包,我们通过以下手段优化:
- 使用分包加载非核心功能
- 静态资源走CDN分发
- 按需引入uView组件
- 压缩图片资源,建议使用TinyPNG工具
实测优化后主包从3.2MB降至1.8MB,符合微信小程序限制。
4.2 高并发场景应对
挂号模块在早高峰时段面临巨大并发压力,我们采用多级缓存策略:
- 一级缓存:本地缓存医生排班信息(5分钟过期)
- 二级缓存:Redis集群存储实时号源
- 数据库层:使用ShardingSphere进行分库分表
压力测试结果:
- 单节点QPS从120提升至350
- 平均响应时间从800ms降至200ms
- 系统资源占用降低40%
4.3 医疗数据合规要点
根据《医疗机构信息系统应用安全规范》要求,特别注意:
- 患者隐私数据脱敏显示
- 敏感操作二次认证
- 数据库审计日志保留6个月以上
- 定期漏洞扫描与渗透测试
实现数据脱敏的AOP示例:
java复制@Aspect
@Component
public class DataMaskAspect {
@Around("@annotation(maskSensitiveData)")
public Object maskData(ProceedingJoinPoint joinPoint) throws Throwable {
Object result = joinPoint.proceed();
if (result instanceof PatientDTO) {
PatientDTO dto = (PatientDTO) result;
dto.setIdCard(maskString(dto.getIdCard(), 4, 4));
dto.setPhone(maskString(dto.getPhone(), 3, 4));
}
return result;
}
private String maskString(String str, int prefix, int suffix) {
if (StringUtils.isBlank(str)) return "";
if (str.length() <= prefix + suffix) return str;
String head = str.substring(0, prefix);
String tail = str.substring(str.length() - suffix);
return head + "****" + tail;
}
}
5. 部署与监控方案
生产环境采用Docker Compose部署,典型配置:
yaml复制version: '3'
services:
app:
image: clinic-app:1.0
ports:
- "8080:8080"
environment:
- SPRING_PROFILES_ACTIVE=prod
- REDIS_HOST=redis
depends_on:
- redis
- mysql
redis:
image: redis:6-alpine
ports:
- "6379:6379"
volumes:
- redis_data:/data
mysql:
image: mysql:8.0
ports:
- "3306:3306"
environment:
- MYSQL_ROOT_PASSWORD=securepassword
- MYSQL_DATABASE=clinic
volumes:
- mysql_data:/var/lib/mysql
- ./sql/init.sql:/docker-entrypoint-initdb.d/init.sql
volumes:
redis_data:
mysql_data:
监控体系搭建:
- Prometheus采集指标数据
- Grafana展示关键仪表盘
- ELK收集分析日志
- 企业微信机器人告警
关键监控指标包括:
- 接口响应时间P99
- 数据库连接池使用率
- Redis缓存命中率
- JVM内存使用情况
- 小程序页面加载耗时
6. 项目演进方向
现有系统基础上,可以进一步扩展:
- 接入医保支付接口
- 增加AI预诊功能(需NLP技术支持)
- 开发家属代预约功能
- 对接智能硬件采集健康数据
- 实现电子处方流转至药房
技术债方面需要注意:
- 微服务化改造可能性
- 多租户支持方案
- 国际化语言包准备
- 灰度发布机制完善
在开发过程中,我们发现医疗系统有三个特别需要注意的领域知识:
- 医生排班规则复杂,不同科室差异大
- 医疗术语需要严格标准化
- 退号退款流程涉及财务对账
