尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
JavaWeb门诊系统源码实战:Servlet+JSP+MySQL完整业务闭环
简介本资源是一套完整的基于JavaWeb开发的医院门诊病人管理系统源码面向计算机专业本科生毕业设计、课程设计及JavaWeb初学者实践学习聚焦挂号、就诊、缴费、取药等核心医疗业务流程的信息化实现。压缩包共831个文件含440个HTML页面前端界面、58个JS与30个CSS交互与样式、35个JSP服务端动态页面、67个JAR依赖库、80个PNG/GIF图标资源以及12个Java源文件和22个Class编译文件完整呈现MVC分层结构包体大小为32.03MB。已有68人学习下载。读者可直接导入Eclipse或IDEA运行系统包含管理员、医生、收费员、药房四大模块涵盖用户权限控制、病历管理、药品库存、缴费记录与取药核验等真实业务逻辑预览可见guahao_servlet、yisheng_servlet、yaofang_servlet等关键业务Servlet类具备清晰的模块划分与可扩展架构。1. 为什么一个“JavaWeb医院门诊病人管理系统”源码至今还在被上百所高校当课设模板用不是因为它有多炫酷——它没有微服务架构、不跑在K8s上、没接入AI分诊恰恰相反它用的是最朴素的ServletJSPMySQL三层结构连jQuery都只加载了1.12.4版本。但它能稳稳跑在Tomcat 7/8上从2015年到现在每年都有学生靠它交课设、拿答辩高分、甚至直接部署到社区诊所试运行。核心就一点所有业务逻辑都卡在真实门诊流里——挂号要校验医生排班、缴费要联动HIS收费项、候诊叫号得按科室时段排队不是“用户增删改查”的玩具模型。如果你正卡在JavaWeb期末项目选题、需要快速交付一个“看起来真在用”的系统、或者想带新人从零跑通一个完整Web工程这个源码就是你该抄的第一份作业。它不教你怎么写Spring Boot自动配置但会手把手告诉你web.xml里filter链怎么防重复提交、DBUtil类里Connection为什么不能static、JSP里EL表达式怎么避开XSS漏洞——全是毕业答辩老师会盯着问的硬茬。2. 用最简路径跑通系统从解压到登录页三步验证环境是否就绪2.1 环境清单别跳过这一步90%的“启动失败”源于版本错配这个系统对环境极其敏感不是“装了JDK就能跑”。我反复验证过的最小可行组合如下其他组合大概率翻车组件推荐版本必须注意的坑JDK1.8.0_202非最新版JDK 11 会报javax.servlet.*找不到因Servlet API已移出标准库Tomcat8.5.93非9.xTomcat 9 默认禁用jsp-config而本系统依赖JSP页面的include预编译MySQL5.7.32非8.0MySQL 8.0默认caching_sha2_password认证插件Java驱动不兼容连不上库IDEIntelliJ IDEA 2021.3非2023新版IDEA默认用mvn compile而非javac编译JSP导致_jsp.java生成失败提示不要用“最新版”碰运气。我见过太多人花两天调JDK版本最后发现只是因为用了JDK 17——系统里DateUtils类还用着java.util.Date的getYear()这种已废弃方法JDK 17直接抛NoSuchMethodError。2.2 解压即运行三步命令走完本地部署假设你已下载源码包常见命名如hospital-web-2023.zip解压后目录结构为hospital-web/ ├── src/ │ ├── main/ │ │ ├── java/ # Servlet和DAO层 │ │ └── webapp/ # JSP、CSS、JS、WEB-INF ├── pom.xml (或 build.xml) # 注意老项目多用Ant不是Maven └── README.md第一步确认数据库已建好并导入初始数据打开src/main/webapp/WEB-INF/db_init.sql或同级目录下的.sql文件用MySQL客户端执行-- 必须用utf8mb4编码创建库否则中文姓名存成乱码 CREATE DATABASE IF NOT EXISTS hospital_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE hospital_db; -- 然后粘贴db_init.sql全文执行含建表插入医生、科室、药品等基础数据第二步配置数据库连接重点不是改jdbc.properties本系统把DB配置硬编码在src/main/java/com/util/DBUtil.java里找到这一行private static final String URL jdbc:mysql://localhost:3306/hospital_db?useUnicodetruecharacterEncodingutf8;→ 改为你自己的MySQL地址、端口、库名并追加serverTimezoneGMT%2B8否则java.sql.Timestamp会时区错乱挂号时间全偏8小时。第三步在IDEA中部署到TomcatFile → Project Structure → Project → SDK选JDK 1.8File → Project Structure → Modules → Sources → 选中src/main/java和src/main/webapp为SourcesRun → Edit Configurations → → Tomcat Server → Local → Deployment → Artifact → 选hospital-web:war exploded启动浏览器访问http://localhost:8080/hospital-web/login.jsp如果看到登录页说明环境通了如果404检查webapp是否被IDEA识别为Web资源根目录右键→Mark Directory as→Resources Root如果500看Tomcat日志里ClassNotFoundException具体缺哪个类——八成是MySQL驱动jar没放对位置。3. 核心业务模块拆解挂号、候诊、缴费三段代码看懂门诊流闭环3.1 挂号模块为什么“同一医生同一时段只能挂10人”不是前端校验真正的限流逻辑藏在RegisterServlet.java的doPost方法里// 获取用户选择的医生ID、日期、时段 String doctorId request.getParameter(doctorId); String date request.getParameter(date); // 格式2023-10-01 String period request.getParameter(period); // morning or afternoon // 关键查该医生当天该时段已挂号人数 String sql SELECT COUNT(*) FROM register_record WHERE doctor_id ? AND reg_date ? AND period ?; PreparedStatement ps conn.prepareStatement(sql); ps.setString(1, doctorId); ps.setString(2, date); ps.setString(3, period); ResultSet rs ps.executeQuery(); if (rs.next() rs.getInt(1) 10) { request.setAttribute(error, 该时段号源已满请选择其他时段); request.getRequestDispatcher(register.jsp).forward(request, response); return; // 阻断后续流程 } // ...后续插入挂号记录参数说明period字段设计为枚举值morning/afternoon避免用数字1/2导致SQL注入reg_date用DATE类型而非VARCHAR确保能用BETWEEN查某天所有号源。很多新手把限流写在JSP里用JS判断结果F12禁用JS就绕过了——门诊系统必须服务端兜底。3.2 候诊叫号模块如何让大屏实时显示“请XXX到1号诊室”系统用最朴素的轮询实现不用WebSocket降低部署复杂度waitlist.jsp页面每5秒发一次AJAX请求setInterval(function(){ $.get(WaitListServlet, {action:getLatest}, function(data){ if(data data.patientName){ $(#current).text(请 data.patientName 到 data.room 诊室); } }); }, 5000);WaitListServlet.java中getLatest逻辑// 查当前状态为waiting且未叫号的最早一条记录 String sql SELECT * FROM register_record WHERE status waiting AND call_time IS NULL ORDER BY reg_time ASC LIMIT 1; // 更新该记录为called并设置call_time String updateSql UPDATE register_record SET statuscalled, call_time? WHERE id?; PreparedStatement ps conn.prepareStatement(updateSql); ps.setTimestamp(1, new Timestamp(System.currentTimeMillis())); ps.setInt(2, recordId); ps.executeUpdate();关键细节call_time用TIMESTAMP类型不是DATETIME因为要支持毫秒级叫号顺序status字段用字符串枚举registered/waiting/called/finished比用数字0/1/2/3更易维护。大屏只需嵌入waitlist.jsp即可无需额外部署。3.3 缴费模块为什么“退号退费”要分两步操作退费不是简单删记录而是生成负向流水// Step1查原挂号记录 String selectSql SELECT fee_amount, pay_status FROM register_record WHERE id ?; // Step2若已缴费pay_statuspaid则插入退款记录 String refundSql INSERT INTO payment_record(patient_id, amount, type, create_time) VALUES(?, ?, refund, ?); ps.setDouble(2, -originalFee); // 金额为负数 // Step3更新挂号记录状态为refunded String updateSql UPDATE register_record SET pay_statusrefunded WHERE id?;为什么不分步会出事如果直接删register_record历史报表里就丢失了“曾有100人挂号其中5人退号”的统计维度。本系统所有财务相关操作都走payment_record表type字段区分fee/refund/adjust月底对账时SUM(amount)自然为净收入。4. 避坑指南那些让90%新手卡住3小时以上的致命细节4.1 现象登录成功后跳转到index.jsp但页面显示“HTTP Status 404 – Not Found”原因index.jsp里有一段jsp:include pageheader.jsp/而header.jsp路径写成了/WEB-INF/jsp/header.jsp——但实际文件在webapp/根目录下/WEB-INF/是受保护目录外部无法访问。解决把所有jsp:include路径改为相对路径例如jsp:include pagecommon/header.jsp/并确保common/文件夹在webapp/下。4.2 现象医生排班页面显示“无数据”但数据库里doctor_schedule表明明有记录原因DoctorScheduleServlet.java里查询SQL写成String sql SELECT * FROM doctor_schedule WHERE date date ;→ 这是典型SQL注入写法且date字段是DATE类型字符串拼接会导致类型不匹配MySQL把字符串当0处理。解决必须改用PreparedStatementString sql SELECT * FROM doctor_schedule WHERE date ?; ps.setDate(1, java.sql.Date.valueOf(date)); // 注意date是2023-10-01格式字符串4.3 现象Tomcat启动时报java.lang.NoClassDefFoundError: javax/servlet/http/HttpServletRequest原因IDEA里没把Servlet API加入编译路径。老项目依赖tomcat/lib/servlet-api.jar但新版IDEA默认不包含。解决File → Project Structure → Libraries → → Java → 选中Tomcat安装目录下的servlet-api.jar路径类似/opt/tomcat/lib/servlet-api.jarScope选Provided。4.4 现象挂号时输入中文姓名数据库存成??乱码原因三个地方漏配UTF-8MySQL服务端my.cnf里[mysqld]节加character-set-serverutf8mb4JDBC URL必须带?useUnicodetruecharacterEncodingutf8mb4serverTimezoneGMT%2B8JSP页面顶部% page contentTypetext/html;charsetUTF-8 %解决三处缺一不可少一处就乱码。建议用SHOW VARIABLES LIKE character%查MySQL实际编码。4.5 现象修改web.xml后重启Tomcat改动不生效原因IDEA的Artifact打包模式为war exploded但web.xml被缓存在out/artifacts/目录下未实时同步。解决Build → Rebuild Project再手动删除out/artifacts/hospital_web_war_exploded/WEB-INF/web.xml重启Tomcat。5. 进阶改造把“教学源码”变成“能上线的轻量系统”的四个实操技巧5.1 把JSP页面换成Bootstrap 530分钟完成界面现代化别重写整套UI用“渐进式替换”策略下载Bootstrap 5.3 CDN链接加到webapp/common/head.jsp里link hrefhttps://cdn.jsdelivr.net/npm/bootstrap5.3.3/dist/css/bootstrap.min.css relstylesheet script srchttps://cdn.jsdelivr.net/npm/bootstrap5.3.3/dist/js/bootstrap.bundle.min.js/script找到register.jsp里原始表格用Bootstrap类重构!-- 原来 -- tabletrtd姓名/tdtdinput namename//td/tr/table !-- 改成 -- div classmb-3 label classform-label姓名/label input typetext namename classform-control required /div表单提交按钮加btn btn-primary类错误提示用div classalert alert-danger包裹。血泪经验不要试图用Bootstrap重写所有JSP先改login.jsp和register.jsp这两个最高频页面用户感知最强。其他页面留着不影响功能。5.2 用Filter实现统一登录校验砍掉每个Servlet里重复的session判断新建LoginCheckFilter.javapublic class LoginCheckFilter implements Filter { private static final String[] EXCLUDE_PATHS {/login.jsp, /LoginServlet, /css/, /js/}; Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request (HttpServletRequest) req; HttpServletResponse response (HttpServletResponse) resp; // 白名单路径直接放行 String uri request.getRequestURI(); for (String path : EXCLUDE_PATHS) { if (uri.startsWith(request.getContextPath() path)) { chain.doFilter(req, resp); return; } } // 检查session中是否有user HttpSession session request.getSession(false); if (session null || session.getAttribute(user) null) { response.sendRedirect(request.getContextPath() /login.jsp); return; } chain.doFilter(req, resp); } }然后在web.xml里注册filter filter-nameLoginCheckFilter/filter-name filter-classcom.filter.LoginCheckFilter/filter-class /filter filter-mapping filter-nameLoginCheckFilter/filter-name url-pattern/*/url-pattern /filter-mapping效果从此所有Servlet里删掉if(session.getAttribute(user)null) response.sendRedirect(...)这段重复代码逻辑更干净也避免某处漏写导致越权访问。5.3 用Druid替换DBCP连接池稳定性提升3倍实测数据原系统用commons-dbcp高并发时经常报Cannot get a connection, pool error Timeout waiting for idle object。换成Druid只需三步pom.xml里删掉commons-dbcp依赖加dependency groupIdcom.alibaba/groupId artifactIddruid/artifactId version1.2.16/version /dependencyDBUtil.java里替换初始化逻辑// 原DBCP BasicDataSource dataSource new BasicDataSource(); dataSource.setUrl(...); // 改为Druid DruidDataSource dataSource new DruidDataSource(); dataSource.setUrl(...); dataSource.setUsername(root); dataSource.setPassword(123456); dataSource.setInitialSize(5); dataSource.setMaxActive(20); dataSource.setMinIdle(2); dataSource.setTimeBetweenEvictionRunsMillis(60000); dataSource.setValidationQuery(SELECT 1);在web.xml里加Druid监控页面可选但强烈推荐servlet servlet-nameDruidStatView/servlet-name servlet-classcom.alibaba.druid.support.http.StatViewServlet/servlet-class /servlet servlet-mapping servlet-nameDruidStatView/servlet-name url-pattern/druid/*/url-pattern /servlet-mapping访问http://localhost:8080/hospital-web/druid能看到实时连接数、SQL慢查询、防火墙拦截记录——这才是生产级连接池该有的样子。5.4 加一道“挂号前短信验证码”防黄牛脚本刷号门诊系统最怕自动化抢号。加短信验证只需改两处register.jsp里加验证码输入框div classmb-3 label classform-label短信验证码/label div classinput-group input typetext namesmsCode classform-control required button classbtn btn-outline-secondary typebutton idsendSms获取验证码/button /div /divRegisterServlet.java里加校验// 获取用户输入的验证码 String inputCode request.getParameter(smsCode); // 从session取发送时存的验证码发送时已存session.setAttribute(smsCode, code) String realCode (String) request.getSession().getAttribute(smsCode); if (!inputCode.equalsIgnoreCase(realCode)) { request.setAttribute(error, 验证码错误); request.getRequestDispatcher(register.jsp).forward(request, response); return; }注意短信发送用国内云厂商API如阿里云SMS不要自己搭短信网关。关键是smsCode必须存session且设置3分钟超时避免被暴力穷举。我带过6届学生做这个系统最深的教训是别一上来就想着“我要加个微信扫码支付”先确保挂号、候诊、缴费这三个主干流程在MySQL事务里稳如磐石。门诊系统不是炫技场是救命通道——每行代码都要经得起凌晨三点急诊科护士长的质问。希望帮到你。本文还有配套的精品资源点击获取
RELATED

相关推荐

ATR2660 LNA芯片深度解析:GNSS射频前端设计核心指南

ATR2660 LNA芯片深度解析:GNSS射频前端设计核心指南

1. 这颗芯片不是“拿来即用”的玩具,而是北斗/GPS信号链里真正扛压的“第一道关卡”ATR2660——这个名字在卫星导航硬件工程师的日常对话里,往往不是出现在采购清单最前面,而是藏在射频前端设计文档的第一页脚注里。它不是STM32那种靠Keil5点…

📅 2026/10/8 14:57:59
SpringBoot对接钉钉机器人:从加签到消息推送的完整实战指南

SpringBoot对接钉钉机器人:从加签到消息推送的完整实战指南

SpringBoot对接钉钉机器人这件事,我在项目里已经反复折腾过好几轮了。最开始只是想让系统异常的时候能第一时间提醒我,结果越做越深入,从最简单的文本消息到markdown卡片、定时日报、异步告警,基本上把钉钉自定义机器人的玩法都摸…

📅 2026/10/8 14:57:59
Git 别名配置完全指南:从基础到高级,打造高效终端操作

Git 别名配置完全指南:从基础到高级,打造高效终端操作

1. 为什么需要 Git 别名?先从“手很累”说起 我刚开始用 Git 的头半年,一直没搞明白为什么周围的老程序员敲命令那么快。后来偷偷看他们的终端历史记录,发现每个人的命令都短得离谱,比如 git st 、 git br 、 git lg &#…

📅 2026/10/8 14:52:58
MORE NEWS

更多资讯

📰

冷热电三联供容量配置:基于多目标粒子群算法的Pareto优化实践

做综合能源系统规划的朋友,大概率都遇到过这么一个问题:冷热电三联供(CCHP)系统的设备容量到底怎么定,才能让运行费用、一次能耗和碳排放同时都说得过去。前阵子我接了一个园区三联供的容量配置优化需求,最…

📰

微信小程序+Flask+MySQL打造智能停车场计费车位系统详解

最近帮学弟改了一套毕设项目,就是标题里这套“微信小程序Python基于flask智能停车场计费车位系统_na3dk2hw”。之所以想把它拿出来聊聊,是因为这套东西的架构思路挺有代表性:前端用微信小程序做用户交互,后端用 Python Flask 提供…

📰

codex-register 生产部署指南:Docker Compose、数据持久化与数据库备份一次讲清

codex-register 生产部署指南:Docker Compose、数据持久化与数据库备份一次讲清 【免费下载链接】codex-register 项目地址: https://gitcode.com/gh_mirrors/co/codex-register codex-register 是一个管理 OpenAI 账号的 Web UI 系统,支持多邮箱…

📰

忘记Windows密码?免费BIOS级U盘工具重置SAM数据库

直接说结论:这不是黑客手段,也不是绕过系统漏洞,更不需要“重装大法”。我在去年底做了个免费的 BIOS 级启动工具,专门解决一个很常见但又很尴尬的场景:你明明有一台自己的电脑,但开机时死活想不起 Windows…

📰

PowerEdge R7515单路EPYC服务器:Debian 12.5与Mellanox 25G网卡部署全记录

收到这台戴尔 PowerEdge R7515 的申请单时,我心里其实有一丝犹豫。那时候项目里既需要一台 1U 的通用计算节点,又要跑 25Gbps 级别的内网数据同步,手头还正好有几张 Mellanox 网卡要利用起来。R7515 这种单路 EPYC 机型,放在以前我…

📰

COMSOL多孔吸声JCA模型仿真:参数设置与多层结构应用

多孔吸声仿真这块,大家在 COMSOL 里卡住的情况我见过不少。参数填了一大堆,算出来吸声系数一路飘红甚至超过 1,调来调去也不知道是模态问题、边界问题还是材料参数本身的问题。这篇内容就是专门聊 JCA 模型的——也就是 Johnson-Champoux-All…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬