
简介这是一份面向计算机相关专业学生及JavaWeb初学者的医药管理系统完整项目适合用作期末大作业、课程设计或项目实战练习。项目覆盖客户、代理商、药品、采购等核心业务模块包含前后端源代码和SQL数据库脚本能够在本地编译运行帮助学习者理解JavaWeb分层开发、数据库交互及基础业务逻辑。压缩包共119个文件以java源码、class编译文件、jsp页面为主辅以xml配置、jar依赖库、js前端脚本和数据库sql文件整包约3.01MB目录结构清晰便于按模块查阅。目前已有94人学习下载项目经导师指导并获评98分代码经过严格调试、运行稳定适合需要参考完整项目结构、快速完成期末作业或系统提升JavaWeb开发能力的读者。1. 为什么 Java 期末大作业选医药管理系统一份能直接跑的源代码与数据库值在哪临近期末JavaWeb 大作业最怕的不是没思路而是思路有了、代码写了一堆一运行全是红叉。我自己带过的项目里十份里有六份挂在环境配置和数据库连接上不是功能写不出来是根本没法演示。这套医药管理系统的高分源码评审 98 分正好卡在大学 JavaWeb 课程设计的典型需求上Servlet DAO 分层、MySQL 增删改查、管理员界面管理客户、药品、机构、购买记录。它不是花架子项目而是那种「导师看了点头、答辩能讲清楚、代码量适中」的范本。适合正在做期末大作业的计算机专业学生也适合刚学完 Servlet 想找完整案例练手的人——你能从里面看到 Controller 怎么调 DAO、DAO 怎么拼 SQL、页面的数据从哪来一条完整链路清清楚楚。2. JavaWeb 医药管理系统源码架构Servlet DAO 分层与四个核心业务模块2.1 从 Controller 到 DaoImpl这套源码的分层是怎么组织的拿到源码包先别急着点运行。我习惯先看一遍类名就能猜出整个项目的骨架。这套系统里出现了ClientController、AgencyController、MedicineController、BuyController四个 Controller对应客户、机构供应商、药品、购买四个业务域数据层是BaseDao加AgencyDaoImpl、ClientDaoImpl、MedicineDaoImpl、BuyDaoImpl四个实现类典型的两层结构Servlet 负责接收请求、调业务、跳页面DAO 负责拼 SQL、执行 JDBC、把结果集封装成对象。常见做法是每个 Controller 对应一张主表的增删改查而BaseDao是所有 DAO 的公共父类连接获取、关闭资源、通用查询这些重复代码都收敛在它里面。我翻过不少学生项目最大的通病是把 SQL 写在 Servlet 里页面和数据库操作揉成一团答辩被问「你怎么解耦」直接答不上来。这套源码的好处是分层清晰你甚至可以照着它的结构画出调用链浏览器发起请求 → Tomcat 路由到对应 Controller → Controller 调用某个 DaoImpl 的方法 → DaoImpl 通过 BaseDao 拿到 Connection 执行 SQL → 返回结果 → Controller 把数据塞进 request 转发到 JSP。以药品新增为例流程大概是// MedicineController 中接收表单参数 String name req.getParameter(name); String price req.getParameter(price); // 封装成 Medicine 对象 Medicine med new Medicine(); med.setName(name); med.setPrice(Double.parseDouble(price)); // 调 DAO 层 MedicineDaoImpl dao new MedicineDaoImpl(); int rows dao.insert(med); if (rows 0) { resp.sendRedirect(medicineList); // 走查询列表的 Servlet 映射 } else { req.setAttribute(msg, 添加失败); req.getRequestDispatcher(medicineAdd.jsp).forward(req, resp); }逻辑上并不复杂参数从HttpServletRequest里取出来封装成实体对象丢给 DAO 层执行再根据影响行数决定重定向还是转发。这里值得注意的一个细节是sendRedirect和forward的选择——重定向是浏览器重新发起一次请求URL 会变转发是服务端内部跳转URL 不变。这套源码里增删改成功后多用重定向目的是防止用户刷新页面时表单重复提交。有些同学喜欢全部用 forward导致刷新一次就多一条数据这属于典型的「功能能跑但不严谨」。BaseDao的职责则是把 JDBC 里最繁琐的环节挡住。我一般建议把获取连接、预编译、结果集映射都放在基类里子类只关心 SQL 和参数这样代码量能少三分之一。2.2 客户、机构、药品、购买四张业务表和增删改查怎么对上号医药管理系统听名字像医院系统实际上它的业务模型更像一个小型进销存客户是买药的机构是供货的药品是库存主体购买记录把客户和药品关联起来。从前面列出的四个 Controller 和四个 DaoImpl 能看出数据库里至少会建四张核心表对应页面上四个管理模块。我按常见实现来还原一下表结构和模块对应关系业务模块Controller 类核心字段主要操作客户管理ClientController客户编号、姓名、电话、地址增删改查、列表分页机构管理AgencyController机构编号、名称、联系人、电话增删改查、供货商维护药品管理MedicineController药品编号、名称、规格、进价、售价、库存增删改查、库存上下限购买管理BuyController购买编号、客户、药品、数量、单价、日期新增订单、按条件查记录这里有一条业务上的隐含逻辑购买记录的「单价」应该是下单时的售价快照而不是去药品表临时查当前售价。我见过有同学在购买列表页直接 join 药品表拿价格结果是药品售价改了历史订单的价格也跟着变这属于业务建模上的瑕疵。这套源码里如果购买记录是独立存了单价字段那就是对的如果以后你自己改也记得保持这个习惯。另一个值得看的是查询类操作。很多期末项目用 SELECT * 一把梭WHERE 条件全是字符串拼出来的存在 SQL 注入风险而且代码极难维护。好的做法是BaseDao里提供query(String sql, Object... params)方法用预编译占位符来传参// 药品列表 按名称模糊查询 public ListMedicine findByName(String keyword) { String sql SELECT * FROM medicine WHERE name LIKE ?; // 注意这里手动拼上 %而不是拼进 SQL return queryList(sql, Medicine.class, % keyword %); }LIKE ?和% keyword %的组合意味着参数绑定不进 SQL 字符串MySQL 驱动会做转义处理用户名里带个单引号不会把你整个查询炸掉。那queryList这个方法怎么把ResultSet转成对象列表常见做法是用反射约定列名和实体字段名一一对应遍历结果集按下标取列名反射调用 setter 赋值。理解不了反射也没关系你只需要知道这套源码里所有查询方法返回的都是 List实体对象页面直接用request.getAttribute拿就行。如果你想做二次开发我建议先从「给药品表加一个分类字段」入手。步骤是数据库加列 → 实体类加属性 → 新增页加输入框 → DAO 的 insert 方法加一个问号 → Controller 里多取一次参数。这条链路走一遍你对这个项目的掌控感会立刻不一样。3. 在 IDEA 里把项目跑起来数据库脚本、连接池配置与运行步骤3.1 导入项目前先做的事JDK、Tomcat、MySQL 版本对齐很多同学拿到源码第一步就双击 IDEA 导入然后被一堆红波浪线劝退。版本不匹配是头号杀手。这套源码用的是传统 Servlet 写法不是 Spring Boot所以跑起来有一整套环境要求JDK 8、Tomcat 8 或 9、MySQL 5.7 或 8.0。先说 JDKJava 8 编译的代码放到 JDK 17 的编译器下大概率会遇到--release版本报错Tomcat 从 9 开始把包名做了调整如果你项目里某些依赖还是 Tomcat 7 时代的写法启动时就会 ClassNotFound。我个人的组合是 JDK 8 Tomcat 8.5 MySQL 5.7这是兼容性最稳的三角组合期末演示完全够用。打开 IDEA 后选择 File → New → Project from Existing Sources选中源码目录Maven 或 Gradle 项目就选对应构建文件普通 Web 项目直接选普通文件夹。关键一步是把 Web 目录认上如果项目里没有pom.xml说明它是个纯手工 Web 项目你需要右键src文件夹 → Mark Directory as → Sources Root再右键web或webapp、WebContent文件夹 → Mark Directory as → Web Resources Root。这一步不认IDEA 就不知道 JSP 文件在哪运行配置里也没有 Artifact 可选。然后是 Tomcat 集成。在 Run → Edit Configurations 里新增 Tomcat Server → Local配置好本地安装路径Deployment 选项卡里把项目 Artifact 加上Application context 建议改成/medicine。注意这个 context 路径后面访问页面会一直带着比如首页就是http://localhost:8080/medicine/login。如果你用的是 Maven 版那更简单pom.xml会声明 servlet-api、jsp-api 的 scope 为 providedTomcat 的依赖由 maven 插件内置tomcat7-maven-plugin可以直接tomcat:run。这套源码如果提供的是传统 Web 项目结构我推荐就按上面手工配置走别在中途折腾 Maven 重构。3.2 从 BaseDao 到数据库连接池跟着配置走一遍数据库配置是另一个高频翻车点。传统 JDBC 项目一般在源码里有个 JDBC 工具类或配置文件把 URL、用户名、密码集中管理。这套系统的BaseDao里大概率会读取一个db.properties或者jdbc.properties。你需要做的事是确认三件事MySQL 服务有没有启动、数据库medicine有没有建、用户密码和配置文件里对不对得上。我建议把数据库配置独立出来做成 properties 文件原理上和代码改连接参数相同但不用重新编译jdbc.drivercom.mysql.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/medicine?useUnicodetruecharacterEncodingUTF-8useSSLfalseserverTimezoneAsia/Shanghai jdbc.usernameroot jdbc.password123456driver里写com.mysql.jdbc.Driver还是com.mysql.cj.jdbc.Driver取决于你的 MySQL 驱动 JAR 包版本。MySQL 5.7 配老驱动用前者配 8.x 驱动用后者后者是 8.0 的正式类名老名字已经提示过时但不影响跑。URL 里的useSSLfalse是给 MySQL 8 关掉默认安全连接警告的serverTimezoneAsia/Shanghai是为了解决时区报错缓存的那个The server time zone value йʱ满脸问号的问题——这两个参数建议直接抄上。如果是用了数据库连接池比如 c3p0 或 Druid那配置方式又不一样。以 Druid 为例类路径下会多一个druid.propertiesdriverClassNamecom.mysql.cj.jdbc.Driver urljdbc:mysql://localhost:3306/medicine?useUnicodetruecharacterEncodingUTF-8useSSLfalseserverTimezoneAsia/Shanghai usernameroot password123456 initialSize5 maxActive20这里initialSize是连接池启动时预创建的连接数maxActive是最大活跃连接数。期末项目访问量不大initialSize5、maxActive20完全够用设太大反而会拖慢 Tomcat 启动。如果你不确定这套源码用的是哪种方式先翻 lib 目录下有哪些 JAR 包有druid-*.jar或c3p0-*.jar就在池子配置里改账密只有mysql-connector-*.jar就在BaseDao.java的getConnection()方法里看它怎么取的连接常见做法是DriverManager.getConnection(url, user, password)。改完配置文件先用命令行测一遍数据库连通性这一步能帮你区分「代码错」还是「数据库连不上」mysql -h localhost -P 3306 -u root -p123456 -e use medicine; show tables;能列出表说明数据库层没问题。然后用 IDEA 右侧 Database 面板或 Navicat 建库建表把资源包里的.sql脚本导入。导入前一定注意字符集脚本头一般会有SET NAMES utf8mb4;没有的话你建出来的表如果是乱码大概率就是建库时字符集选成了默认的 latin1。3.3 启动与验证页面能看到什么才算跑通一套项目跑没跑通不是看 Tomcat 日志里有没有INFO: Server startup in而是页面能不能完整走一个流程。我的验收清单是登录页能不能打开 → 能不能登录进系统 → 侧边栏菜单是否齐全 → 新增一条药品记录 → 列表页能看到这条记录 → 修改 → 删除。这一条链路走完项目才算真正属于你了。启动时如果 404先看控制台有没有报错没报错的话检查访问路径是不是带上了 Application context。再去http://localhost:8080/medicine/login.jsp看到登录页说明 Web 应用部署成功。如果页面出来了但点登录没反应按 F12 看网络请求返回什么大概率是 SQL 执行出错去 Tomcat 的logs/localhost.xxx.log里找异常——Table medicine.client doesnt exist这类错误就是建表脚本没导入或者导错了库。启动阶段最常见的报错集锦我是可以提前预警的端口被占用Port 8080 required by Tomcat v8.5 Server at localhost is already in use杀进程用netstat -ano | findstr 8080找到 PID 再去任务管理器结束找不到驱动ClassNotFoundException: com.mysql.jdbc.Driver把mysql-connector-java的 JAR 包放到WEB-INF/lib下并确认已加入 ArtifactHTTP 500 且堆栈里带NullPointerException十有八九是req.getParameter取到了 null比如表单里的 name 和 Servlet 里取的参数名对不上。这套源码的数据库脚本是资源自带的导入后建议顺手打开看一眼表结构和初始数据。初始管理员账号密码一般在 SQL 里有个admin表或user表别忽略这一步很多同学栽在「登录页都打开了却不知道账号密码是什么」。4. 医药管理系统避坑指南编译运行过程中的常见问题排查4.1 乱码问题中文变问号页面上全是「锟斤拷」现象启动后页面上中文正常但从页面新增的中文数据在列表页显示为??或者数据库表里直接就是??。原因三层传递环节有一层字符集没对上。请求参数到 Servlet 的编码、Servlet 响应到浏览器的编码、数据库连接用的字符集、表字段的字符集任何一层不一致都会乱码。最常见的是三层都是 UTF-8唯独 MySQL 连接 URL 里没带characterEncodingUTF-8或者建库时用了默认的 latin1。解决三步走。第一步确认数据库、表、字段全是utf8mb4用 SQL 检查SHOW CREATE TABLE client;看到CHARSETutf8mb4才算对。第二步确认 JDBC URL 里带了characterEncodingUTF-8。第三步如果还不行在代码入口处加统一编码过滤传统 Servlet 项目里写一个EncodingFilter实现请求和响应都设 UTF-8。这条链路从头到尾捋一遍基本能治乱码。我自己的习惯是写任何传统 Web 项目都先放一个编码 Filter压根不给乱码机会。4.2 Tomcat 启动报ClassNotFoundException或NoClassDefFoundError现象Tomcat 启动阶段报错控制台提示找不到某个类比如javax.servlet.http.HttpServlet或者项目里自己写的某个DaoImpl类找不到。原因两种情况。第一种是 lib 下缺少 servlet-api、jsp-api 这类编译期依赖第二种是项目里某些类没被编译进 Artifact 的WEB-INF/classes。后者在 IDEA 里经常出现你改了代码但没重新构建Eclipse 项目导入 IDEA 后输出目录指到了别的地方。解决先 Build → Rebuild Project看编译日志里有没有java: 找不到符号之类的提示。有的话就是代码问题没有的话看 File → Project Structure → Artifacts → Output Layout展开WEB-INF/classes确认MedicineController、BaseDao这些类的编译输出是否在里面。Artifact 里缺了就把右边的target/classes拖进左边对应位置。还有一种情况是 Tomcat 部署的 Artifact 是 exploded 模式但运行配置里没选对部署内容重新点一下 Deploy 清理重来。4.3 数据库连接超时Communications link failure或Connection refused现象数据库操作时抛异常提示连接被拒或者链路失败有时是刚启动还能用过一会又断。原因MySQL 服务没启动、端口不是 3306、防火墙拦截、wait_timeout连接空闲超时后池里连接已失效。用连接池的尤其注意最后一条MySQL 默认wait_timeout8 小时但池子里的连接如果几天没活动重新取出来用就报错。解决第一步服务起没起来直接测netstat -ano | findstr 3306没监听就去 Windows 服务里启动 MySQL。第二步区分是不是连接池旧连接问题Druid 在配置里加testWhileIdletrue和validationQuerySELECT 1取连接之前先探活。第三步确认防火墙放行了 3306 端口。如果是传统 JDBC 每次现取连接考虑把配置文件里的连接改成连接池这本身也是个加分点。4.4 表单改了但页面没变化getParameter返回 null现象点击保存提示添加失败或者插入的记录部分字段为空日志里看到某个字段值就是 null。原因表单输入框的name属性和 Servlet 里req.getParameter()的参数名对不上常见于复制粘贴 JSP 代码后没改 name。另一个原因是表单没有设置methodpost一些敏感或超长参数走 GET 直接被容器丢弃一部分。解决打开 JSP 页面逐个核对输入框name和 Controller 里getParameter的字符串比如namemedName对应的就应该是getParameter(medName)。表单加methodpost然后在 Controller 里加一行参数打印日志快速排查System.out.println(name req.getParameter(name));这行日志打完表单有没有把参数传过来一目了然。很多翻车现场不是逻辑问题是手滑打了错别字。4.5 页面能打开但样式全乱CSS 和 JS 路径 404现象登录页能进但纯文本排版没有样式按 F12 看到 CSS 文件 404。原因传统 Web 项目里 JSP 引用 CSS 如果用了相对路径/css/style.css在 context path 不是/时会解析到localhost:8080/css而不是localhost:8080/medicine/css。解决JSP 里统一用${pageContext.request.contextPath}/css/style.css拼路径或写base href%basePath%标签。这套源码里如果样式路径写死了你导入后访问首页发现样式丢了改法就是统一加contextPath前缀。这一个坑在从别人机器拷项目时特别常见因为他原来的 context 是根路径你换了自己的 context 就炸了。5. 从大作业到简历项目这套源代码还能怎么改和加功能能跑通只是第一步答辩能不能拿高分取决于你在这套源码上做了多少「看得见的改进」。我的经验是与其从零写一个项目不如在高分骨架上有针对性地加功能性价比高得多。第一个推荐改的是登录模块。如果这套源码只是简单地进入系统没有用户表那么自己加一张user表密码存 MD5 或加盐哈希登录成功把用户信息放进 session再用一个 Filter 拦截未登录请求。这个改动涉及 Servlet 规范里的 Filter、Session、请求转发三个知识点是答辩时老师最爱问的「你怎么控制访问权限」。Filter 拦截的核心代码也就十几行public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) { HttpServletRequest request (HttpServletRequest) req; HttpSession session request.getSession(); if (session.getAttribute(user) null) { ((HttpServletResponse) resp).sendRedirect(request.getContextPath() /login.jsp); return; } chain.doFilter(req, resp); }这个改动把你的项目从一个「能增删改查的管理后台」升级成了「带权限控制的管理系统」含金量完全不是一个级别。第二个推荐改的是把BaseDao里的原生 JDBC 换成 Druid 连接池。不用大改业务代码只动BaseDao的getConnection()方法换成从池子里取连接。如果担心换池子影响面太大更稳的改法是「查询用原生 JDBC、写操作改成事务控制」在BuyDaoImpl的购买方法里手动开启事务先减库存再插入购买记录任何一个失败都回滚。这个逻辑一加你的答辩亮点马上就有了「我这个购买功能是带事务的防止并发下库存超卖。」第三个推荐改的是购买记录查询加一个时间段筛选起始日期和结束日期两个输入框DAO 里拼一个BETWEEN ? AND ?条件。这个改动对新手来说逻辑简单但涉及字符串拼接安全问题你自己先想想怎么用占位符写再对比源码里原有的查询写法能学到东西。拿到这套源码后我的建议是先通读一遍BaseDao和MedicineDaoImpl把 JDBC 的六个步骤加载驱动、获取连接、预编译、执行、处理结果集、关闭资源在代码里指出来然后自己对着画一遍调用流程图。等你改完上面的登录和事务这套源码就不再是老师的项目了你完全可以用自己的话说清楚每一行代码的用途。从那以后我每次拿到别人的项目源码都强制自己先走一遍「建库 → 配连接 → 跑通一个增删改查 → 改动一个功能 → 再回读代码」的流程不跑通不看别的这个习惯帮我避开了大量自我感动的无效学习。希望帮到你。本文还有配套的精品资源点击获取