基于SSH框架的医疗门诊在线预约挂号系统 - 源码深度解析

JavaScriptSSH框架HTMLCSSMySQLJSP+Servlet
2026-03-264 浏览

文章摘要

本项目基于SSH(Struts2 + Spring + Hibernate)框架开发,是一款面向医疗机构和患者的门诊在线预约挂号系统。其核心业务价值在于彻底改变传统线下排队挂号的低效模式,解决了患者就医过程中“挂号难、排队久、信息不透明”的核心痛点。系统通过将预约流程线上化,不仅为患者提供了7x24...

在医疗信息化快速发展的今天,传统线下挂号模式暴露出的效率瓶颈日益凸显。患者为挂一个专家号往往需要清晨甚至凌晨到医院排队,耗费大量时间与精力,而医院方也面临着现场秩序维护难、资源分配不均衡等管理压力。针对这一行业痛点,我们设计并实现了一套基于SSH(Struts2 + Spring + Hibernate)技术栈的智能门诊预约服务平台。该平台旨在通过数字化手段重构门诊预约流程,为患者提供全天候的便捷预约服务,同时助力医疗机构提升运营效率与管理水平。

平台采用典型的多层架构设计,实现了表现层、业务逻辑层与数据持久层的清晰分离。表现层选用Struts2框架处理用户交互请求,其强大的拦截器机制为统一权限控制与数据验证提供了有力支持;业务逻辑层由Spring框架的IoC容器统一管理,通过依赖注入实现组件间的松耦合,显著增强了代码的可测试性与可维护性;数据持久层则基于Hibernate构建,将Java对象与关系型数据库表进行映射,简化了数据库操作并确保了数据一致性。整个系统前端采用JSP动态页面技术,结合HTML、CSS与JavaScript,构建了直观易用的用户界面。

数据库架构设计与核心表解析

系统底层依托MySQL数据库,共设计了7张核心数据表,支撑着平台的稳定运行。其ER关系设计严谨,清晰地反映了患者、医生、预约、科室等核心实体间的关联。以下重点分析几个关键表的结构设计亮点。

1. 预约记录表(appointment

作为系统的业务核心,appointment表的设计直接关系到预约流程的准确性与完整性。其DDL定义如下:

CREATE TABLE `appointment` (
  `appointment_id` int(11) NOT NULL AUTO_INCREMENT,
  `patient_id` int(11) NOT NULL,
  `doctor_id` int(11) NOT NULL,
  `appointment_date` date NOT NULL,
  `time_slot` varchar(50) NOT NULL,
  `status` enum('pending','confirmed','cancelled','completed') NOT NULL DEFAULT 'pending',
  `symptoms` text,
  `created_time` datetime DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`appointment_id`),
  KEY `fk_appointment_patient` (`patient_id`),
  KEY `fk_appointment_doctor` (`doctor_id`),
  CONSTRAINT `fk_appointment_doctor` FOREIGN KEY (`doctor_id`) REFERENCES `doctor` (`doctor_id`),
  CONSTRAINT `fk_appointment_patient` FOREIGN KEY (`patient_id`) REFERENCES `patient` (`patient_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

设计亮点分析:

  • 状态机设计status字段采用枚举类型,明确定义了预约的四个生命周期状态:“待确认”、“已确认”、“已取消”、“已完成”。这种设计不仅约束了数据的有效性,也为后续业务流程(如状态变更、统计查询)提供了清晰的逻辑基础。
  • 时间维度分离:表结构将预约日期(appointment_date)、具体时间段(time_slot)与记录创建时间(created_time)分开存储。这种设计便于实现“按日期查询排班”与“按创建时间追溯”等不同维度的业务需求。
  • 外键约束保障数据完整性:通过外键约束,确保了每一条预约记录都关联到一个有效的患者(patient_id)和医生(doctor_id),从根本上避免了脏数据的产生。

2. 医生信息表(doctor

医生是提供医疗服务的主体,其信息表的设计注重专业性与可扩展性。

CREATE TABLE `doctor` (
  `doctor_id` int(11) NOT NULL AUTO_INCREMENT,
  `department_id` int(11) NOT NULL,
  `name` varchar(100) NOT NULL,
  `title` varchar(50) NOT NULL,
  `specialty` varchar(200) DEFAULT NULL,
  `bio` text,
  `max_patients_per_slot` int(11) DEFAULT '10',
  `is_available` tinyint(1) DEFAULT '1',
  PRIMARY KEY (`doctor_id`),
  KEY `fk_doctor_department` (`department_id`),
  CONSTRAINT `fk_doctor_department` FOREIGN KEY (`department_id`) REFERENCES `department` (`department_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

设计亮点分析:

  • 号源控制字段max_patients_per_slot字段用于控制医生在每个时间段内可接待的最大患者数,这是实现号源精细化管理的核心。管理员可根据医生实际接诊能力灵活调整此数值。
  • 上下班状态标识is_available字段作为一个布尔标志,可以快速控制医生是否参与排班。当医生休假或暂停接诊时,可将其设置为0,系统前端将不再展示该医生的可预约时段。
  • 专业信息详实:除了基本信息,title(职称)、specialty(专长)和bio(简介)字段为患者选择医生提供了充分的决策依据,提升了用户体验。

核心功能实现与代码深度解析

1. 患者端:智能医生搜索与预约流程

患者登录系统后,核心操作是查找合适的医生并完成预约。前端界面提供了按科室、医生姓名等多种筛选方式。

医生搜索界面

当患者提交搜索条件后,请求由Struts2的DoctorQueryAction处理。该Action通过Spring容器注入DoctorService业务组件,执行查询逻辑。

// DoctorQueryAction.java
public class DoctorQueryAction extends ActionSupport {
    private DoctorService doctorService; // 由Spring依赖注入
    private String departmentId;
    private String doctorName;
    private List<Doctor> doctorList; // 返回给页面的结果集

    // Struts2 Action执行方法
    public String execute() {
        try {
            DoctorQuery query = new DoctorQuery();
            if (departmentId != null && !departmentId.trim().isEmpty()) {
                query.setDepartmentId(Integer.parseInt(departmentId));
            }
            if (doctorName != null && !doctorName.trim().isEmpty()) {
                query.setName(doctorName.trim());
            }
            // 调用业务层方法
            doctorList = doctorService.findDoctorsByQuery(query);
            return SUCCESS;
        } catch (Exception e) {
            addActionError("查询医生信息时发生错误。");
            return ERROR;
        }
    }
    // Getter and Setter 省略...
}

业务层DoctorServiceImpl通过Hibernate的Criteria API构建动态查询,确保查询的灵活性与效率。

// DoctorServiceImpl.java
@Service("doctorService")
@Transactional
public class DoctorServiceImpl implements DoctorService {

    @Autowired
    private DoctorDAO doctorDAO;

    @Override
    public List<Doctor> findDoctorsByQuery(DoctorQuery query) {
        return doctorDAO.findByCriteria(query);
    }
}

// DoctorDAOImpl.java
@Repository("doctorDAO")
public class DoctorDAOImpl extends BaseHibernateDAO implements DoctorDAO {

    @SuppressWarnings("unchecked")
    public List<Doctor> findByCriteria(DoctorQuery query) {
        Criteria criteria = getSession().createCriteria(Doctor.class);
        criteria.add(Restrictions.eq("isAvailable", true)); // 只查询可预约的医生

        if (query.getDepartmentId() != null) {
            criteria.add(Restrictions.eq("department.departmentId", query.getDepartmentId()));
        }
        if (query.getName() != null && !query.getName().isEmpty()) {
            criteria.add(Restrictions.like("name", "%" + query.getName() + "%"));
        }
        // 可以添加更多查询条件,如按职称过滤等
        criteria.addOrder(Order.asc("name")); // 按姓名排序
        return criteria.list();
    }
}

找到心仪的医生后,患者可以查看其详细资料并选择可预约的时间段进行挂号。

医生详情与预约

2. 预约提交与业务校验

患者选择时间点并填写症状后,点击提交。系统通过AppointmentAction处理预约请求,其中包含了复杂的业务逻辑校验。

// AppointmentAction.java
public class AppointmentAction extends ActionSupport {
    private AppointmentService appointmentService;
    private Integer doctorId;
    private Date appointmentDate;
    private String timeSlot;
    private String symptoms;
    private String result;

    public String makeAppointment() {
        // 1. 基础数据校验
        if (doctorId == null || appointmentDate == null || timeSlot == null) {
            addActionError("预约信息不完整。");
            return INPUT;
        }

        // 获取当前登录的患者(从Session中)
        Patient currentPatient = (Patient) ActionContext.getContext().getSession().get("currentUser");

        try {
            // 2. 调用业务服务,核心校验逻辑在此
            Appointment newAppointment = appointmentService.createAppointment(
                    currentPatient.getPatientId(), doctorId, appointmentDate, timeSlot, symptoms);

            if (newAppointment != null) {
                result = "预约成功!您的预约号为:" + newAppointment.getAppointmentId();
                return SUCCESS;
            } else {
                addActionError("预约失败,该时段号源可能已满或医生不可用。");
                return ERROR;
            }
        } catch (BusinessException e) {
            addActionError(e.getMessage());
            return ERROR;
        }
    }
    // 其他方法省略...
}

业务服务层AppointmentServiceImplcreateAppointment方法是整个预约流程的核心,它在一个声明式事务中执行,确保数据一致性。

// AppointmentServiceImpl.java
@Service("appointmentService")
@Transactional
public class AppointmentServiceImpl implements AppointmentService {

    @Autowired
    private AppointmentDAO appointmentDAO;
    @Autowired
    private DoctorService doctorService;

    @Override
    public Appointment createAppointment(Integer patientId, Integer doctorId,
                                         Date date, String timeSlot, String symptoms) throws BusinessException {
        // 1. 校验医生是否存在且可用
        Doctor doctor = doctorService.getDoctorById(doctorId);
        if (doctor == null || !doctor.getIsAvailable()) {
            throw new BusinessException("指定的医生不存在或暂不可预约。");
        }

        // 2. 校验该医生在该时段是否已满员
        Long currentCount = appointmentDAO.countAppointmentsByDoctorAndTime(doctorId, date, timeSlot);
        if (currentCount >= doctor.getMaxPatientsPerSlot()) {
            throw new BusinessException("您选择的时段号源已满,请选择其他时间。");
        }

        // 3. 校验该患者在同一天同一科室是否已有预约(防止重复预约)
        boolean hasDuplicate = appointmentDAO.checkDuplicateAppointment(patientId, doctor.getDepartment().getDepartmentId(), date);
        if (hasDuplicate) {
            throw new BusinessException("您在同一天该科室已有预约,无法重复预约。");
        }

        // 4. 所有校验通过,创建预约对象并保存
        Appointment appointment = new Appointment();
        appointment.setPatient(new Patient(patientId)); // 设置患者(Hibernate会根据ID加载)
        appointment.setDoctor(doctor);
        appointment.setAppointmentDate(date);
        appointment.setTimeSlot(timeSlot);
        appointment.setSymptoms(symptoms);
        appointment.setStatus(AppointmentStatus.PENDING); // 初始状态为待确认

        appointmentDAO.save(appointment);
        return appointment;
    }
}

预约记录查看

3. 管理端:医生与科室管理

医院管理员拥有对系统基础数据进行维护的权限。医生信息管理界面允许管理员对医生档案进行增删改查操作。

医生管理界面

对应的DoctorManageAction提供了列表查询和更新的功能。

// DoctorManageAction.java
public class DoctorManageAction extends ActionSupport {
    private DoctorService doctorService;
    private List<Doctor> allDoctors;
    private Doctor doctor; // 用于接收编辑的医生对象

    // 获取医生列表
    public String list() {
        allDoctors = doctorService.getAllDoctors();
        return SUCCESS;
    }

    // 更新医生信息
    public String update() {
        if (doctor != null && doctor.getDoctorId() != null) {
            try {
                doctorService.updateDoctor(doctor);
                addActionMessage("医生信息更新成功!");
                return SUCCESS;
            } catch (Exception e) {
                addActionError("更新失败: " + e.getMessage());
            }
        }
        return INPUT;
    }
    // Getter and Setter 省略...
}

科室管理同样是医院运营的基础,其管理界面清晰展示了科室层级关系。

科室管理界面

实体模型与对象关系映射

系统通过Hibernate注解清晰地定义了实体类及其关联关系,这是ORM框架的核心。以Appointment实体为例,它映射了数据库中的appointment表,并定义了与PatientDoctor的多对一关系。

// Appointment.java
@Entity
@Table(name = "appointment")
public class Appointment implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "appointment_id")
    private Integer appointmentId;

    @ManyToOne(fetch = FetchType.LAZY) // 多对一,延迟加载
    @JoinColumn(name = "patient_id", nullable = false)
    private Patient patient;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "doctor_id", nullable = false)
    private Doctor doctor;

    @Temporal(TemporalType.DATE) // 映射日期部分
    @Column(name = "appointment_date", nullable = false)
    private Date appointmentDate;

    @Column(name = "time_slot", nullable = false, length = 50)
    private String timeSlot;

    @Enumerated(EnumType.STRING) // 枚举类型映射为字符串
    @Column(name = "status", nullable = false, length = 20)
    private AppointmentStatus status;

    @Column(name = "symptoms")
    private String symptoms;

    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "created_time", insertable = false, updatable = false) // 由数据库自动生成
    private Date createdTime;

    // 构造函数、Getter和Setter省略...
}

// 对应的枚举类
public enum AppointmentStatus {
    PENDING, CONFIRMED, CANCELLED, COMPLETED
}

功能展望与系统优化方向

尽管当前系统已具备完整的核心功能,但在持续演进中仍有多个可优化的方向:

  1. 集成智能推荐算法:基于患者的历史就诊记录、症状描述(利用NLP技术进行关键词提取)以及医生的专长标签,构建一个推荐引擎,在患者搜索时主动推荐最匹配的医生,提升预约精准度与用户满意度。实现上可引入Elasticsearch等搜索引擎或简单的协同过滤算法。

  2. 实现排队叫号实时同步:将线上预约系统与医院现场的物理叫号系统深度集成。开发一个WebSocket服务,实时将医生的接诊进度(如“正在接诊”、“请候诊”)推送到患者的个人页面或医院大厅的显示屏上,线上线下一体化,极大改善现场就诊体验。

  3. 构建数据可视化分析平台:利用ECharts等前端图表库,为医院管理者开发一个数据驾驶舱。动态展示每日/每周/每月的预约趋势、各科室/医生的接诊量统计、患者取消率分析等关键指标,为医院的资源调配和运营决策提供数据支持。

  4. 开发移动端App或小程序:考虑到患者使用的便捷性,未来可基于RESTful API重构部分后端接口,并开发独立的移动端应用(如微信小程序或React Native App)。这将使预约操作更加随时随地,符合现代用户的使用习惯。

  5. 增强系统安全与容灾能力:引入Spring Security框架进行更细粒度的权限控制。同时对数据库进行定期备份,并考虑部署到云平台,利用其高可用和负载均衡服务,确保系统在访问高峰期的稳定运行,防止因单点故障导致的服务中断。

该智能门诊预约服务平台通过成熟的SSH技术体系,构建了一个稳定、可扩展的医疗信息化解决方案。其清晰的分层架构、严谨的数据库设计以及围绕核心业务场景实现的完整功能链路,不仅有效解决了传统挂号模式的痛点,也为未来功能的迭代升级奠定了坚实的技术基础。随着医疗行业与互联网技术的进一步融合,此类平台将在提升医疗服务效率与质量方面发挥越来越重要的作用。

本文关键词
SSH框架医疗门诊在线预约挂号系统源码解析

上下篇

上一篇
没有更多文章
下一篇
没有更多文章