最近几年智慧医疗领域发展迅猛,医院预约挂号系统作为其中的典型应用场景,正在从传统的窗口排队向移动互联网转型。这个基于SpringBoot+小程序的掌上智慧医疗系统,正是顺应了这一趋势的毕业设计选题方案。
我在实际医疗信息化项目实施中发现,一个优秀的预约挂号系统需要解决三个核心痛点:首先是患者挂号难、排队时间长的问题;其次是医院号源管理效率低下的问题;最后是医患信息不对称的问题。这套系统通过移动互联网技术,让患者可以随时随地查看医生排班、预约挂号,同时帮助医院实现号源的数字化管理。
从技术实现角度来看,SpringBoot后端+小程序前端的架构组合具有明显优势。SpringBoot简化了Java后端开发流程,内置Tomcat服务器,可以快速构建RESTful API接口。而微信小程序则提供了跨平台的移动端解决方案,用户无需安装APP即可使用,大大降低了使用门槛。
系统采用经典的三层架构设计:
这种分层架构的优势在于:
数据库设计是系统的核心基础,主要包含以下几类关键表:
用户表(patient):存储患者基本信息
sql复制CREATE TABLE patient (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
openid VARCHAR(64) UNIQUE COMMENT '微信openid',
name VARCHAR(32) NOT NULL,
phone VARCHAR(11) NOT NULL,
id_card VARCHAR(18) COMMENT '身份证号',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP
);
医生表(doctor):存储医生信息
sql复制CREATE TABLE doctor (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(32) NOT NULL,
department_id INT NOT NULL COMMENT '科室ID',
title VARCHAR(32) COMMENT '职称',
introduction TEXT COMMENT '医生简介',
avatar VARCHAR(255) COMMENT '头像URL'
);
预约表(appointment):核心业务表
sql复制CREATE TABLE appointment (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
patient_id BIGINT NOT NULL,
doctor_id BIGINT NOT NULL,
schedule_id BIGINT NOT NULL COMMENT '排班ID',
status TINYINT DEFAULT 0 COMMENT '0-待就诊 1-已就诊 2-已取消',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
visit_date DATE NOT NULL,
time_slot VARCHAR(32) NOT NULL COMMENT '时间段'
);
提示:数据库设计时要注意建立适当的索引,比如在appointment表的patient_id、doctor_id、schedule_id等字段上建立索引,可以显著提高查询性能。
小程序端采用微信原生框架开发,主要页面包括:
关键代码示例 - 预约功能实现:
javascript复制// pages/appointment/appointment.js
Page({
data: {
timeSlots: [],
selectedSlot: null,
doctorInfo: {}
},
onLoad: function(options) {
// 获取医生信息和可预约时间段
this.getDoctorInfo(options.doctorId);
this.getAvailableSlots(options.doctorId);
},
handleSelectSlot: function(e) {
this.setData({
selectedSlot: e.currentTarget.dataset.slot
});
},
submitAppointment: function() {
if (!this.data.selectedSlot) {
wx.showToast({ title: '请选择时间段', icon: 'none' });
return;
}
wx.request({
url: 'https://yourdomain.com/api/appointment',
method: 'POST',
data: {
doctorId: this.data.doctorInfo.id,
timeSlot: this.data.selectedSlot,
openid: getApp().globalData.openid
},
success: (res) => {
if (res.data.code === 200) {
wx.showToast({ title: '预约成功' });
wx.navigateBack();
} else {
wx.showToast({ title: res.data.msg, icon: 'none' });
}
}
});
}
});
后端采用SpringBoot框架,主要技术栈:
核心控制器示例 - 预约接口:
java复制@RestController
@RequestMapping("/api/appointment")
@Api(tags = "预约管理")
public class AppointmentController {
@Autowired
private AppointmentService appointmentService;
@PostMapping
@ApiOperation("创建预约")
public Result createAppointment(@RequestBody AppointmentDTO dto) {
// 参数校验
if (StringUtils.isEmpty(dto.getOpenid()) || dto.getDoctorId() == null
|| StringUtils.isEmpty(dto.getTimeSlot())) {
return Result.fail("参数不完整");
}
try {
String orderNo = appointmentService.createAppointment(dto);
return Result.success(orderNo);
} catch (BusinessException e) {
return Result.fail(e.getMessage());
}
}
@GetMapping("/list")
@ApiOperation("查询预约列表")
public Result getAppointmentList(
@RequestParam String openid,
@RequestParam(required = false) Integer status) {
List<AppointmentVO> list = appointmentService.queryAppointments(openid, status);
return Result.success(list);
}
}
预约挂号系统最关键的难点是如何处理高并发下的号源抢占问题。当多个用户同时预约同一个医生的同一个时间段时,必须保证数据的一致性。
解决方案是采用Redis分布式锁:
java复制public String createAppointment(AppointmentDTO dto) {
String lockKey = "lock:appointment:" + dto.getDoctorId() + ":" + dto.getTimeSlot();
String requestId = UUID.randomUUID().toString();
try {
// 获取分布式锁,超时时间5秒
boolean locked = redisTemplate.opsForValue().setIfAbsent(
lockKey, requestId, 5, TimeUnit.SECONDS);
if (!locked) {
throw new BusinessException("当前时间段预约人数过多,请稍后再试");
}
// 检查号源是否可用
int available = checkAvailability(dto.getDoctorId(), dto.getTimeSlot());
if (available <= 0) {
throw new BusinessException("该时间段已约满");
}
// 创建预约记录
return doCreateAppointment(dto);
} finally {
// 释放锁
if (requestId.equals(redisTemplate.opsForValue().get(lockKey))) {
redisTemplate.delete(lockKey);
}
}
}
小程序端需要集成微信登录获取用户唯一标识openid:
实现代码:
java复制public String wechatLogin(String code) {
// 构建请求URL
String url = String.format(
"https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code",
appId, appSecret, code);
// 发送HTTP请求
ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
JSONObject json = JSON.parseObject(response.getBody());
// 处理响应
if (json.containsKey("errcode")) {
throw new BusinessException("微信登录失败: " + json.getString("errmsg"));
}
String openid = json.getString("openid");
if (StringUtils.isEmpty(openid)) {
throw new BusinessException("获取openid失败");
}
// 查询或创建用户
Patient patient = patientMapper.selectByOpenid(openid);
if (patient == null) {
patient = new Patient();
patient.setOpenid(openid);
patientMapper.insert(patient);
}
return JwtUtil.generateToken(patient.getId());
}
部署需要准备以下环境:
建议使用Flyway进行数据库版本管理,在resources/db/migration目录下创建SQL脚本:
V1__Initial_schema.sql
sql复制-- 创建用户表
CREATE TABLE patient (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
openid VARCHAR(64) UNIQUE,
name VARCHAR(32),
phone VARCHAR(11),
id_card VARCHAR(18),
create_time DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- 创建医生表
CREATE TABLE doctor (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(32) NOT NULL,
department_id INT NOT NULL,
title VARCHAR(32),
introduction TEXT,
avatar VARCHAR(255)
);
使用JMeter进行压力测试时,需要特别关注以下接口:
典型测试场景配置:
核心功能演示:
技术亮点展示:
系统扩展性讨论:
为什么选择SpringBoot+小程序的技术栈?
系统如何处理高并发预约?
系统的安全性如何保障?
这个基础版本完成后,还可以考虑以下扩展方向提升项目价值:
在实际开发中,我建议先从核心功能做起,确保预约流程的完整性和稳定性,然后再逐步添加扩展功能。对于毕业设计来说,把基础功能做扎实,并深入讲解技术实现细节,通常能获得更好的评价。