
简介这是一套基于JavaWeb的医院门诊病人管理系统源码面向计算机专业毕设学生与Java项目实践者帮助解决门诊挂号、就诊、缴费、取药等业务的信息化管理需求。系统按角色划分为管理员、医生、收费员、药房四大模块管理员维护医生、药品、员工等基础信息收费员处理有/无病历本两种挂号方式及药品收费医生负责书写病历、开药与就诊记录查询药房依据缴费记录完成取药模块间协同运转适合作为课程设计或毕业设计的完整参考方案。资源包共831个文件约32.03MB以html页面、png与gif图片、jar依赖包、js脚本、jsp页面、css样式及java源码、class文件为主另含少量xml配置与数据库文件结构完整便于二次开发。目前已有68人学习下载可帮助读者快速理解JavaWeb分层开发思路、Servlet请求处理流程与多角色权限协作设计并在此基础上进行功能扩展与代码改造。1. 医院门诊病人管理系统到底在管什么从挂号到取药的闭环早上七点半门诊大厅已经排起长队。挂号窗口的护士在系统里敲下患者身份证号选择科室和医生打印出一张带条码的挂号单患者拿着单子去诊室医生在电脑上叫号、开处方处方数据实时传到收费处患者缴费后再去药房药师扫码核对后发药。这一整套动作背后就是医院门诊病人管理系统在支撑。它要解决的核心问题很具体让患者信息、挂号记录、就诊记录、处方、缴费、发药这几件事在同一套数据里流转而不是各科室各记一本账。基于 JavaWeb 的医院门诊病人管理系统源码本质是一套用 Servlet、JSP、Spring 或 SSM 这类 Java Web 技术栈搭起来的业务系统。它适合两类人一类是课程设计或毕业设计需要完整案例的学生另一类是想拿一个真实业务场景练手 JavaWeb 项目完整案例 MySQL 的开发者。源码的价值不在于代码本身多高级而在于它把门诊流程里的实体关系、状态流转和权限边界都摆出来了你能顺着它把「一个业务系统怎么从数据库设计走到页面交互」这件事走一遍。2. 拿到源码先别急着跑环境、数据库和目录结构怎么理2.1 先确认技术栈版本别让 JDK 和 Tomcat 打架拿到一份 JavaWeb 源码第一件事不是双击运行而是看它到底依赖什么。常见的老项目是 Servlet JSP JDBC新一点的是 SSMSpring SpringMVC MyBatis或者 SpringBoot。判断方法很简单看项目根目录有没有pom.xml有就是 Maven 项目看WEB-INF下有没有web.xml有就是传统 Web 项目看lib目录里有没有spring-webmvc.jar、mybatis.jar这类包。我一般会先做一张环境对照表把源码要求和本机环境对齐项目常见要求检查命令JDK1.8 或 11java -versionTomcat8.5 或 9.0看conf/server.xml端口MySQL5.7 或 8.0mysql --versionMaven3.6mvn -vIDEIDEA 或 Eclipse看.idea或.classpath这里有个血泪经验JDK 版本不匹配是最高频的翻车点。老项目用 JDK 8 编译你拿 JDK 17 去跑javax.servlet包直接找不到因为高版本 JDK 移除了部分 Java EE 模块。解决办法是在 IDEA 的 Project Structure 里把 SDK 切成 1.8同时把 Language Level 也调到 8。2.2 数据库脚本怎么导入字符集和时区两个坑先填源码里通常会带一个.sql文件位置一般在src/main/resources或项目根目录的db文件夹。导入之前先建库字符集用utf8mb4排序规则用utf8mb4_general_ci别用默认的latin1否则中文姓名和地址会变问号。-- 建库时显式指定字符集避免中文乱码 CREATE DATABASE hospital_outpatient DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_general_ci; -- 导入前先切库 USE hospital_outpatient; -- 导入脚本在命令行执行不在 SQL 窗口里跑 -- mysql -u root -p hospital_outpatient hospital_outpatient.sql导入完成后用SHOW TABLES;确认表数量。门诊系统常见的表有patient病人信息、doctor医生、department科室、registration挂号记录、prescription处方、medicine药品、payment缴费记录。如果表数量明显偏少可能是脚本只导了一半检查 SQL 文件里有没有CREATE TABLE被注释掉。MySQL 8.0 还有一个时区坑连接串里如果不加serverTimezone启动时会报The server time zone value ???ú±ê×??±?? is unrecognized。解决办法是在 JDBC URL 后面加上?serverTimezoneAsia/ShanghaiuseUnicodetruecharacterEncodingutf8。2.3 目录结构决定你改代码的速度一个典型的 JavaWeb 门诊系统目录大概长这样src/ main/ java/ com/hospital/controller/ -- 控制层处理请求 com/hospital/service/ -- 业务层挂号、开方逻辑 com/hospital/dao/ -- 数据层SQL 操作 com/hospital/entity/ -- 实体类对应数据库表 resources/ jdbc.properties -- 数据库连接配置 mybatis-config.xml -- MyBatis 配置如果有 webapp/ WEB-INF/ web.xml -- 核心配置 views/ -- JSP 页面 static/ -- CSS、JS、图片先看jdbc.properties把数据库地址、用户名、密码改成自己的。再看web.xml确认servlet-mapping和filter有没有拦截所有请求。有些项目会在web.xml里配CharacterEncodingFilter如果没配POST 请求里的中文会乱码这个后面避坑章节会细说。3. 用 IDEA 跑通第一个页面从配置到登录的完整链路3.1 IDEA 运行 JavaWeb 项目的配置步骤IDEA 运行传统 JavaWeb 项目核心是配 Tomcat。步骤不复杂但顺序错了就会卡在 404。第一步打开项目后等 Maven 依赖下载完。如果右下角一直转圈检查settings.xml里的镜像地址换成国内源。第二步配置 Tomcat。点Run→Edit Configurations→ 左上角→ 选Tomcat Server→Local。在Server标签页里Application server指向本机 Tomcat 目录。在Deployment标签页里点→Artifact→ 选xxx:war exploded。注意选war exploded而不是war前者支持热部署改 JSP 不用重启。第三步设置上下文路径。Application context填/hospital这样访问地址就是http://localhost:8080/hospital/。第四步启动。控制台出现Artifact xxx:war exploded: Deployed successfully就说明部署成功。如果报ClassNotFoundException去Project Structure→Modules→Dependencies里检查有没有漏掉的 jar 包。# 如果不想用 IDEA命令行方式也能跑Maven 项目 mvn clean package -DskipTests # 把 target 下生成的 war 包复制到 Tomcat 的 webapps 目录 cp target/hospital.war $TOMCAT_HOME/webapps/ # 启动 Tomcat $TOMCAT_HOME/bin/startup.sh命令行方式适合排查「到底是代码问题还是 IDEA 配置问题」。如果命令行能跑起来而 IDEA 不行那问题一定在 IDEA 的 Artifact 配置上。3.2 登录页打通了后面就顺了门诊系统的入口通常是登录页。管理员、医生、挂号员三种角色从同一个页面登录根据角色跳不同主页。登录逻辑一般在LoginServlet或LoginController里。// 登录核心逻辑简化版实际项目会加加密和验证码 WebServlet(/login) public class LoginServlet extends HttpServlet { protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String username req.getParameter(username); String password req.getParameter(password); // 注意实际项目密码要加密存储这里只是演示流程 User user userService.findByUsername(username); if (user ! null user.getPassword().equals(password)) { req.getSession().setAttribute(currentUser, user); // 按角色跳转 if (doctor.equals(user.getRole())) { resp.sendRedirect(doctor/main.jsp); } else { resp.sendRedirect(admin/main.jsp); } } else { req.setAttribute(msg, 用户名或密码错误); req.getRequestDispatcher(login.jsp).forward(req, resp); } } }这段代码里有两个关键点。一是req.getSession().setAttribute(currentUser, user)把登录用户存进 Session后面所有页面都靠这个判断有没有登录。二是角色跳转门诊系统至少要有管理员、医生、挂号员三种角色权限边界就在这里分。如果登录后所有角色看到一样的页面说明权限控制没做后面加功能会乱。登录成功后先别急着看业务代码。打开浏览器开发者工具看 Network 里每个请求的返回状态。如果 JSP 页面能出来但数据是空的问题在数据库查询如果页面直接 404问题在 Servlet 映射路径。3.3 挂号模块理解状态流转比看懂代码更重要挂号是门诊系统的第一个业务动作。患者来挂号系统生成一条挂号记录状态从「待就诊」开始医生叫号后变成「就诊中」开完处方变成「待缴费」缴费后变成「待发药」发药后变成「已完成」。-- 挂号记录表的核心字段 CREATE TABLE registration ( id INT PRIMARY KEY AUTO_INCREMENT, patient_id INT NOT NULL COMMENT 病人ID, doctor_id INT NOT NULL COMMENT 医生ID, department_id INT NOT NULL COMMENT 科室ID, register_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 挂号时间, status TINYINT DEFAULT 0 COMMENT 0待就诊 1就诊中 2待缴费 3待发药 4已完成, fee DECIMAL(10,2) COMMENT 挂号费, FOREIGN KEY (patient_id) REFERENCES patient(id), FOREIGN KEY (doctor_id) REFERENCES doctor(id) );状态字段status是整个系统的灵魂。所有业务操作本质上都是在改这个字段。挂号是插入一条status0的记录医生叫号是UPDATE registration SET status1 WHERE id?缴费是status2变status3。如果你发现某个功能点了没反应先查这个字段有没有被正确更新。我一般会在开发阶段加一个日志每次状态变更都打一行// 在 Service 层加状态变更日志方便排查 public void updateStatus(int registrationId, int newStatus) { int oldStatus registrationDao.getStatus(registrationId); registrationDao.updateStatus(registrationId, newStatus); System.out.println(挂号单 registrationId 状态从 oldStatus 变为 newStatus); }这行日志在联调阶段能省很多时间。门诊系统的状态流转是线性的一旦某个环节卡住后面全乱。比如缴费没更新状态药房就看不到待发药列表。4. 避坑与排查门诊系统源码跑不起来时先看这几条4.1 中文乱码POST 请求和数据库连接各查一遍现象挂号页面输入患者姓名「张三」保存后数据库里变成「å¼ ä¸‰」或者页面显示问号。原因两个地方可能出问题。一是请求编码Tomcat 8 以后默认用 UTF-8但老项目可能在web.xml里没配CharacterEncodingFilterPOST 请求体按 ISO-8859-1 解析。二是数据库连接串没指定字符集MySQL 驱动用默认编码传输。解决先在web.xml里加编码过滤器确保所有请求走 UTF-8。filter filter-nameencodingFilter/filter-name filter-classorg.springframework.web.filter.CharacterEncodingFilter/filter-class init-param param-nameencoding/param-name param-valueUTF-8/param-value /init-param init-param param-nameforceEncoding/param-name param-valuetrue/param-value /init-param /filter filter-mapping filter-nameencodingFilter/filter-name url-pattern/*/url-pattern /filter-mapping然后检查 JDBC URL确保有useUnicodetruecharacterEncodingutf8。最后检查数据库和表的字符集用SHOW CREATE TABLE patient;看CHARSET是不是utf8mb4。三处都对了乱码基本消失。4.2 404 错误路径、Artifact 和上下文三选一现象启动 Tomcat 后访问http://localhost:8080/hospital/login.jsp浏览器显示 404。原因三种可能。一是Application context配错了实际路径不是/hospital。二是 Artifact 没部署Tomcat 启动日志里没有Deployed successfully。三是 JSP 文件位置不对放在了WEB-INF下面外部不能直接访问。解决先看 Tomcat 启动日志确认 war 包部署路径。如果日志里显示Deploying web application archive [hospital.war]那上下文就是/hospital。如果 JSP 在WEB-INF/views/下不能直接访问必须通过 Servlet 转发。检查web.xml里welcome-file-list配的是什么通常应该是login.jsp或index.jsp。4.3 数据库连接失败驱动、URL、权限逐个排现象启动时报Cannot create PoolableConnectionFactory或Access denied for user。原因驱动类名写错、URL 格式不对、用户名密码不对、MySQL 没启动、防火墙拦了 3306 端口这五种情况我都遇到过。解决按顺序查。先确认 MySQL 服务在跑systemctl status mysql或net start mysql。再确认jdbc.properties里的 URL 格式MySQL 8.0 的驱动类名是com.mysql.cj.jdbc.Driver5.7 是com.mysql.jdbc.Driver写错直接ClassNotFoundException。然后确认用户名密码可以在命令行用mysql -u root -p试一下。最后确认端口如果 MySQL 改了默认端口URL 里也要改。4.4 页面能打开但数据为空SQL 和事务先看现象挂号记录列表页面能打开但表格里一条数据都没有数据库里明明有数据。原因SQL 查询条件写错了或者事务没提交或者返回结果集映射失败。解决先把 SQL 拿到数据库客户端里直接跑一遍。如果客户端有数据而页面没有问题在 Java 代码。检查 DAO 层有没有commit用 JDBC 手动管理事务时INSERT之后不commit数据不会落库。检查实体类字段名和数据库列名是否对应MyBatis 的resultMap配错了也会导致数据映射不上。最后看 Controller 有没有把数据放进request或modelJSP 里用${list}取的时候属性名要对上。4.5 修改 JSP 不生效缓存和热部署的取舍现象改了 JSP 页面刷新浏览器还是旧内容。原因Tomcat 缓存了编译后的 JSP或者 IDEA 没有自动热部署。解决在 Tomcat 配置里把On frame deactivation设为Update classes and resources。如果还不行直接删掉 Tomcat 的work目录强制重新编译 JSP。命令行方式跑的话改完 JSP 需要重启 Tomcat。这是开发阶段的常见现象不是代码问题别在这上面耗太久。5. 从能跑到能用给门诊系统加一个排队叫号看板5.1 为什么选排队叫号做进阶功能源码跑通之后很多人会想加功能。我的建议是加排队叫号看板原因有三个。第一它和核心业务强相关挂号之后自然要叫号逻辑闭环。第二它涉及实时刷新能让你接触 WebSocket 或 AJAX 轮询技术上有提升。第三它有一个直观的展示页面适合做课程设计的演示亮点。排队叫号的核心逻辑不复杂医生点击「叫下一位」系统从该医生当天status0的挂号记录里取最早的一条把状态改成status1然后把患者姓名推到候诊区大屏上。5.2 用 AJAX 轮询实现最小可用版本如果不想引入 WebSocketAJAX 轮询是最简单的方案。候诊区页面每隔 5 秒请求一次接口拿当前叫号信息。// 候诊区大屏轮询逻辑 function fetchCurrentCall() { fetch(/hospital/api/current-call?doctorId doctorId) .then(response response.json()) .then(data { if (data data.patientName) { document.getElementById(currentPatient).innerText data.patientName 请到 data.room 诊室; } }) .catch(err console.error(轮询失败, err)); } // 每 5 秒刷新一次间隔太短会给服务器压力 setInterval(fetchCurrentCall, 5000);后端接口用 Servlet 实现查当前医生最新一条status1的记录。WebServlet(/api/current-call) public class CurrentCallServlet extends HttpServlet { protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String doctorId req.getParameter(doctorId); // 查该医生当前正在就诊的患者 Registration reg registrationService .findCurrentByDoctor(Integer.parseInt(doctorId)); resp.setContentType(application/json;charsetUTF-8); if (reg ! null) { String json {\patientName\:\ reg.getPatientName() \,\room\:\ reg.getRoom() \}; resp.getWriter().write(json); } else { resp.getWriter().write({}); } } }轮询间隔设 5 秒是个折中。设 1 秒服务器压力大设 30 秒患者觉得卡。实际门诊场景里叫号频率不高5 秒足够。如果要做更实时的可以上 WebSocket但代码复杂度会翻倍课程设计阶段没必要。5.3 叫号顺序和状态回滚怎么处理叫号有一个容易忽略的问题医生点了「叫下一位」但患者没来怎么办我的做法是加一个「过号」状态。医生可以点「过号」把当前记录状态改成status5过号然后系统自动叫下一位。过号的患者如果回来了挂号员可以手动把状态改回status0重新排队。-- 过号状态处理 UPDATE registration SET status 5 WHERE id ? AND status 1; -- 患者回来重新排队排到当前队列末尾 UPDATE registration SET status 0, register_time NOW() WHERE id ? AND status 5;这里有个细节重新排队时把register_time更新为当前时间这样患者会排到队尾而不是插到原来的位置。如果不更新他会按原挂号时间排到前面对其他患者不公平。这个逻辑在代码里就是一行 SQL 的事但想不清楚就会出问题。5.4 验证方法用两个浏览器模拟医生和患者功能加完之后怎么验证开两个浏览器窗口一个登录医生账号一个打开候诊区大屏页面。医生点「叫下一位」看大屏 5 秒内有没有更新。然后测试过号医生点「过号」看大屏是不是跳到下一位。再测试重新排队用挂号员账号把过号患者状态改回待就诊看大屏会不会重新叫到他。这套验证流程走一遍基本能覆盖排队叫号的主要分支。如果大屏不刷新先看浏览器控制台有没有报错再看 Network 里接口返回的 JSON 对不对最后查数据库状态有没有更新。三步定位比盲改代码快得多。我做了这么多年业务系统最大的习惯就是每加一个功能先想清楚状态怎么变再动手写代码。门诊系统的状态流转是它的骨架骨架对了加什么功能都顺骨架乱了改一处崩三处。希望帮到你。本文还有配套的精品资源点击获取