简介:医药管理系统后台源码是一套基于Java/JSP和MySQL的医药后台管理项目,主要面向医药管理方向的课程设计、毕业设计及需要快速搭建药品管理后台的Java学习者。系统业务覆盖全面,实现添加药品、查看药品、高级查询、库存查看、类别添加与统计、购买药品、销售管理、进货需求管理以及系统管理,能够完整支撑医药进销存的基本流程。压缩包共162个文件,包含31个JSP页面、30个Java源码、30个class编译文件、26个jar运行依赖库以及SQL数据库脚本等,整体大小9.34MB。目前已有2058人学习下载。源码目录层级清晰,注释规范,可直接导入开发工具运行;开发环境为JDK 1.8与MySQL,含SQL脚本便于快速初始化数据,适合在此基础上进行功能扩展与二次开发,也可作为学习Java Web分层架构、DAO模式及MVC实现的实用参考。
1. 医药管理系统源码.zip:先搞清楚它是什么,再决定下不下
医药管理系统源码.zip是目前Java课程设计、毕业设计里流传最广的一类资源包:把JSP页面、Servlet控制层、MySQL建库脚本、数据库配置和说明文档打成一个压缩包,解压导入后就能得到一个能登录、能录药品、能入库出库、能看库存预警的完整业务系统骨架。它的受众很明确:期末赶课程设计的学生、刚学完Java Web想抄一份完整项目看包结构的新手,以及想拿现成后台接进自己前端页面的人。但这类zip最大的坑不在代码,而在版本:压缩包里配套的JDBC驱动、Tomcat和MySQL,跟你本机的未必对得上。下面按我拿到这类包最习惯的一条落地路径讲:怎么拆、怎么跑、怎么改、坑在哪。
2. 拆开zip看门道:这类医药管理系统的模块划分与技术栈
新手拿到zip一般直接双击解压,然后打开里面的"安装说明.txt"。我的习惯是先列目录,不解压先看文件树,花不了两分钟就能把项目归到对应流派,省掉后面一整个晚上的瞎试。
# 不解压直接看 zip 内部结构,Windows 用 7-Zip 打开,Linux 命令行用 unzip -l unzip -l medical-system.zip | head -40unzip -l只列出压缩包内容不实际解压,配合head看到前40行目录结构。如果换在Windows上,7-Zip右键"打开内部"看效果一样,还能预览文件大小和压缩前后对比,用于判断这个包是完整的工程还是一个残缺的半成品。这一步之后再决定要不要往下走,比先解压再后悔要省事得多。
2.1 两种主流技术栈:JSP+Servlet+MySQL 和 Spring Boot+MyBatis
市面上能下到的医药管理系统源码,九成以上是老派Java Web课程设计:JSP做页面、Servlet做控制层、JDBC直连MySQL,少部分比较新的用Spring Boot+MyBatis。两者差别不只是写法,还决定你本机要装什么环境。
| 对比项 | JSP+Servlet+MySQL | Spring Boot+MyBatis |
|---|---|---|
| Java版本 | JDK 8 最省事 | JDK 8及以上,部分包要求JDK 11 |
| 部署方式 | 打war包丢进Tomcat的webapps目录 | 内置Tomcat,mvn启动或java -jar直接跑 |
| 数据库 | MySQL 5.7 / 8.0 都能跑 | MySQL 8.0 居多 |
| 依赖管理 | 手动把jar放进WEB-INF/lib | Maven自动下载依赖 |
| 适合场景 | 链路直观,适合课程设计 | 贴近企业主流,适合往上线方向扩展 |
判断方法很简单:zip根目录有pom.xml的是Maven工程,大概率Spring Boot;只有src、WebContent、.classpath、.project的是老式Eclipse动态Web工程。两类我都部署过,说句实在话,纯粹交课程设计的话老式结构反而好改,所有jar明摆在WEB-INF/lib下面,少一层框架黑匣子,答辩时被问到"请求怎么从页面走到数据库"也更容易讲清楚。正因为这层原因,这一结构版本的包在网上常被划进"java课程设计案例源码"这个分类里,搜索时按这个组合词找,能过滤掉不少前端模板冒充的伪源码。
2.2 zip包里最该有的文件清单:少了哪样会跑不起来
我一般把这类包里的关键文件按用途分成四类:数据库脚本、Java源码、页面与配置、部署说明。拿下面这张表对照你手上的包,缺了哪一块心里先有数。
| 文件/目录 | 作用 | 缺失后果 |
|---|---|---|
| db/medical.sql 或根目录下的.sql文件 | 建库建表语句,可能含测试数据 | 没它数据库只能手搓表,基本劝退 |
| src/ | Java源码,含DAO、Servlet、工具类 | 缺src还能跑那才奇怪 |
| WebContent/ 或 webapp/ | JSP页面、CSS/JS、WEB-INF/web.xml | 页面缺失,访问报404 |
| WEB-INF/lib/ | 依赖jar,重点是MySQL驱动 | 缺驱动启动直接ClassNotFoundException |
| readme.txt / 使用说明 | 作者写的部署步骤、初始账号 | 找不到初始账号只能逐个表翻 |
| .classpath / .project | Eclipse工程标识文件 | IDEA导入时非必须,但能辅助识别结构 |
注意,有些包里根本没有web.xml,这是Servlet 3.0+改用@WebServlet注解的结果,属正常现象。判断逻辑是有web.xml先看web.xml,没有就全局搜@WebServlet注解。
2.3 三个入口先定位:登录页、数据库工具类、配置文件
找到读代码的入口比从头到尾读源码高效得多。我拿到手会先看三个地方。第一,login.jsp或index.jsp,确定系统登录账号密码表是user还是admin;第二,src下util/DBUtil.java,看数据库连接是写在properties文件里还是硬编码在Java里;第三,web.xml或Servlet注解,确认首页地址和初始化Servlet。这三个点看完,整个系统怎么组织的就明白了七八分。
配置文件常见叫db.properties、jdbc.properties,也可能直接写死在DBUtil.java里。写死的情况下改连接密码要改的是那个Java文件,不是某个properties,很多人栽在这里。顺带说一句,网上有些资源站点管整站打包叫"源码建站"或"网站源码",那一般指带前后台的整站工程;而医药管理系统源码.zip特指带业务逻辑的Java后台工程,两者不是一回事,下载前看清楚标题再动手。另外养成一个习惯,读这几个入口文件时顺手记笔记,哪里改了配置、哪里改了SQL,记下来比在磁盘上堆十个版本的zip管用。
3. 本地跑通最小流程:解压、建库、改配置、部署一条龙
3.1 用7-Zip或unzip解压:linux解压缩命令zip的关键参数
这一步看着简单,翻车率却最高,基本卡在中文文件名和权限上。
# Linux 上解压到指定目录,-d 指定输出路径 unzip medical-system.zip -d /opt/medical # 如果 zip 里的文件名是 GBK 编码(老压缩软件常见),加 -O 指定编码 unzip -O GBK medical-system.zip -d /opt/medicalunzip的-d参数后面跟的是解压目标目录,不带的话默认解压到当前目录,容易把文件和现有项目混在一起。Linux下遇到文件名乱码,-O GBK能解决大多数问题;macOS或较老版本的unzip没有-O选项,就得换7-Zip的命令行版本7zz来解。
Windows下我直接用7-Zip右键解压,不推荐用系统自带的压缩文件夹功能。这里有个知识点,网上搜"zip伪加密"会看到不少此类压缩包的案例:有些分享者为了不让资源被直接转载,会给zip打上加密标记,但内容其实没有真加密。用7-Zip打开这类文件时,如果能看到内部文件名、解压却提示输入密码,可以试试直接"提取"并留空密码,或把zip重新保存一遍去掉伪加密标记。另外,win10右键菜单里的"压缩为zip文件夹"是系统自带功能,不认识的文件容易被它默认关联,解压前最好右键→打开方式→选7-Zip,避免Windows资源管理器因为长路径报错。部署完想删除整个项目目录时,Windows有时提示文件被占用,那是Tomcat还在运行,先停服务再删。
3.2 建库并导入SQL脚本:MySQL命令行的两种姿势
数据库脚本是整套系统的地基,先把库建出来,再把表导进去。
# 进入 MySQL 交互式命令行 mysql -u root -p # 在 MySQL 提示符下执行: CREATE DATABASE medical DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE medical; SOURCE /opt/medical/db/medical.sql;SOURCE是MySQL客户端的内部命令,后面跟绝对路径,执行过程中如果某条语句报错不会中断整个脚本,而是继续往下跑,所以需要人工盯着输出里的ERROR行。另一种更常见的方式是重定向:
mysql -u root -p medical < /opt/medical/db/medical.sql这条命令要先把medical库建好,否则会提示Unknown database。两种方式都行,我习惯先跑一次SOURCE看全量报错,确认无误后再DROP DATABASE重新导入一遍,保证库里是干净的。
建库字符集直接决定后面中文乱不乱。utf8mb4是utf8的超集,能存四字节emoji和生僻字,MySQL 8.0默认就是utf8mb4;MySQL 5.7如果脚本写的是DEFAULT CHARSET=utf8,存中文也没问题,但建议统一改成utf8mb4。如果脚本自带CREATE DATABASE语句,注意它要创建的库名和你本机已有库名是否冲突,冲突就改脚本或先删旧库。
3.3 改数据库连接配置:db.properties和JDBC URL参数
绝大多数系统把数据库连接放在src目录下的.properties文件里,文件名常见db.properties、jdbc.properties、database.properties,内容长这样:
jdbc.driver=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/medical?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai jdbc.username=root jdbc.password=123456四个参数每一行都可能有坑。jdbc.driver:MySQL 5.x驱动类名是com.mysql.jdbc.Driver,MySQL 8.x必须写成com.mysql.cj.jdbc.Driver,写错启动报ClassNotFoundException。jdbc.url:localhost:3306/后面跟的是数据库名,要和上一步建的库名保持一致;后面那串参数里characterEncoding=utf8管中文不乱码,serverTimezone=Asia/Shanghai是MySQL 8需要的时区参数,5.7不写也能跑。jdbc.username和jdbc.password改成你本机MySQL的实际账号密码,有些资源包作者留下的密码就是root,而你本机root设了别的密码,这一行不改必报Access denied。
如果项目里翻遍了properties也没找到连接配置,那它多半写死在src/util/DBUtil.java的常量里,全局搜"jdbc:mysql"就能定位。
提示:配置文件改完注意检查BOM头。Windows记事本保存的UTF-8文件可能带BOM,导致properties解析第一行key异常,项目起不来还没有报错信息。遇到这种玄学问题,用VSCode或Notepad++另存为"UTF-8无BOM"再试。
3.4 部署进Tomcat:IDEA与Eclipse的两种导入方式
老式Eclipse工程的导入姿势和IDEA不一样。包里有.classpath和.project时,用IDEA导入选Import Project,在对话框里选Eclipse模型,一路Next,IDEA会保留Web模块结构;直接File→Open打开目录虽然也能识别,但经常丢掉Web facet,导致跑起来没有HTTP服务。
Eclipse里导入简单很多:Import → Existing Projects into Workspace,选项目根目录,勾选Copy projects into workspace,导入后右键项目→Properties→Targeted Runtimes,勾选已配置的Tomcat版本,然后把项目Add到Server里启动。
启动成功后访问地址一般是http://localhost:8080/项目名/,注意项目名是Tomcat管理器里显示的应用名,不是zip文件名。404了先去看Tomcat日志或控制台输出,大多数时候是jar缺失,或者web.xml里的Servlet映射路径和实际访问路径对不上。
4. 核心业务模块拆解:登录、入库、过期预警的代码与SQL
系统跑起来只是第一步,真正值钱的业务逻辑集中在三个地方:登录与权限、药品入库与库存更新、过期预警。下面按我读源码和改代码的顺序讲,每个地方给出最小可运行实现,你对照自己手里的包找对应代码就行。
4.1 从login.jsp到Session:一个完整登录Servlet的写法
登录模块套路千篇一律:login.jsp表单提交→LoginServlet接收参数→UserDao查询数据库→成功写入Session并跳转到主页,失败回login.jsp带错误提示。核心代码如下:
@WebServlet("/login") public class LoginServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String username = req.getParameter("username"); String password = req.getParameter("password"); User user = userDao.findByUsernameAndPassword(username, password); if (user != null) { req.getSession().setAttribute("loginUser", user); resp.sendRedirect("index.jsp"); } else { req.setAttribute("msg", "用户名或密码错误,请重新输入"); req.getRequestDispatcher("login.jsp").forward(req, resp); } } }这段逻辑里有两个细节值得注意。第一,成功用sendRedirect、失败用forward是有讲究的:重定向会改变浏览器地址栏,防止刷新页面重复提交表单;转发则保留request里的msg变量,所以错误提示必须用forward带过去。第二,密码比对这里大多数课程设计都是明文,本地演示没问题,真往线上放必须改,第6章给加盐MD5方案。
登录之后,其他JSP页面判断登录态靠session.getAttribute("loginUser"),常见写法是每个需要权限的页面顶部加一段脚本判断,为空就跳回登录页。有的包做得规范些,抽了个过滤器统一做权限判断,那种结构值得学,改动一个地方就能覆盖全站。
4.2 入库出库与库存原子更新:事务一步都不能省
药品入库不是一个insert就完事,它涉及两张表:入库明细表记录"哪批药、多少数量、什么单价进的",药品表里的库存字段要同步增加。要保证两步同时成功必须开事务,下面是精简后的DAO代码:
public boolean stockIn(int drugId, int quantity, BigDecimal price) { Connection conn = null; PreparedStatement ps = null; try { conn = DBUtil.getConnection(); conn.setAutoCommit(false); // 关掉自动提交,事务开始 ps = conn.prepareStatement( "INSERT INTO stock_in_detail(drug_id, quantity, price, in_time) " + "VALUES(?, ?, ?, NOW())"); ps.setInt(1, drugId); ps.setInt(2, quantity); ps.setBigDecimal(3, price); ps.executeUpdate(); ps = conn.prepareStatement( "UPDATE drug SET stock = stock + ?, last_in_time = NOW() " + "WHERE drug_id = ?"); ps.setInt(1, quantity); ps.setInt(2, drugId); ps.executeUpdate(); conn.commit(); // 都成功才提交 return true; } catch (SQLException e) { if (conn != null) { try { conn.rollback(); } catch (SQLException ex) { ex.printStackTrace(); } } return false; } finally { DBUtil.close(conn, ps, null); } }conn.setAutoCommit(false)之后所有SQL直到commit才真正生效,catch到异常要rollback回滚,否则会出现库存加了但明细没记录、账对不上的情况。UPDATE drug SET stock = stock + ?直接在SQL里做增量表达式,而不是先select出来在Java里加完再update,后一种写法在两个人同时入库时会互相覆盖更新,SQL原子表达式没有这个问题。
出库逻辑完全对称,只是把+改成-,并在执行更新前先查当前库存够不够,不够直接抛业务提示"库存不足"。有的包把出库数量校验放在JSP里的JS判断,那是不靠谱的,绕过页面直接请求Servlet照样能减出负数,校验必须放在Servlet或Service层。
4.3 过期预警与近效期查询:一条SQL搞定,不用Java遍历
医药系统最实用的功能是过期预警:把三个月内到期的药列出来提醒管理员处理。实现它根本不用在Java里循环比对日期,SQL一条就够:
SELECT drug_id, drug_name, batch_no, expire_date, stock FROM drug WHERE expire_date BETWEEN CURDATE() AND DATE_ADD(CURDATE(), INTERVAL 90 DAY) AND stock > 0 ORDER BY expire_date;三个参数值得解释。CURDATE()只取当前日期不取时分秒,避免当天过期的药被漏掉(用NOW()比较的话,会把今天还没到23:59的药错误排除);INTERVAL 90 DAY是预警窗口,想改60天或180天直接改这个数字;AND stock > 0把库存为零的过期药过滤掉,因为已不影响销售。如果还想同时看到已经过期的,把BETWEEN改成expire_date < DATE_ADD(CURDATE(), INTERVAL 90 DAY)即可。
有的包会把预警天数做成页面下拉框,道理一样,最终落到SQL就是改INTERVAL的数值。这条SQL不需要额外Service逻辑,DAO里查出来、页面表格展示,完整闭环。
4.4 为什么我建议先跑通"入库→库存→出库"这条链路
登录能进页面不代表系统没问题。我拿到这类源码后会先把入库、查库存、出库、再查库存从头点一遍,因为这条链路覆盖了表单接收、事务、SQL更新、页面刷新四个最容易出错的基础点;而且这三个表之间的数据一致性,是期末答辩时老师最喜欢追问的地方。手里系统的数据流和代码能对得上,后面再改什么都心里有底。
5. 部署避坑:版本不匹配、中文乱码、端口冲突与zip伪加密
下面五条是我在大量这类资源包上实际踩过的坑,每条按"现象→原因→解决"写,遇到类似问题直接对号入座。
5.1 现象:Tomcat启动后访问页面报 ClassNotFoundException: com.mysql.jdbc.Driver
原因:两个可能叠加。要么MySQL驱动jar没进WEB-INF/lib,要么你用MySQL 8但包里驱动是5.x的旧类名。
解决:先在WEB-INF/lib下确认有mysql-connector开头的jar;再看驱动类名与URL的版本对应关系:
# 驱动 5.1.x 配 MySQL 5.7,老代码最常见的组合 jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/medical?useUnicode=true&characterEncoding=utf8 # 驱动 8.0.x 配 MySQL 8.0 jdbc.driver=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/medical?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai注意5.1那边useSSL和serverTimezone写不写都行,但8.0那边缺一个就报Communications link failure或时区异常。如果用IDEA,jar放进WEB-INF/lib后还要右键Add as Library,否则编译期能找到、运行期照样ClassNotFound。
5.2 现象:页面和数据库里的中文全是问号或乱码
原因:建库字符集、连接URL的characterEncoding、JSP页面编码三者不一致。最常见组合是库建成了utf8、连接URL没带编码参数、JSP却是GBK,三头对不上。
解决:把三个地方统一到UTF-8。建库用utf8mb4;连接URL带characterEncoding=utf8;JSP页面头部检查有没有<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>。另外Tomcat的server.xml里Connector加URIEncoding="UTF-8"处理GET请求中文参数,老版本Tomcat默认是ISO-8859-1,不改的话URL带中文必乱。
5.3 现象:Tomcat启动报Address already in use,或改完代码页面还是老样子
原因:8080端口被占,另一个进程或上一个Tomcat实例没关干净。改代码不生效则是IDEA的Artifacts没有重新构建,老式结构里JSP改动有时不用rebuild,但Java类改动必须重新编译。
解决:端口冲突改tomcat/conf/server.xml里的Connector端口,一个Tomcat有HTTP、AJP和socket监听三处端口,一般只改HTTP那个8080为8081即可;重启前先确认没有残留的java进程,Windows下用netstat -ano | findstr 8080查占用进程PID,再在任务管理器里结束它。IDEA里改完代码点Build→Rebuild Project,再重启Tomcat,这个顺序别颠倒。
5.4 现象:解压出来项目文件夹名乱码,Linux下文件全乱
原因:zip文件内用GBK编码存文件名,压缩者大概率用的老版Windows中文压缩软件;网上说的"zip伪加密"包,文件列表能看到但部分工具解压会要密码或失败。
解决:Linux下用unzip -O GBK,或7zz x 文件名.zip,对编码兼容性更好;Windows下用7-Zip右键"提取到当前文件夹",7-Zip对伪加密的容忍度比系统自带解压高。如果只是文件名乱码、文件内容正常,用7-Zip重打包一次即可;如果内容也乱,说明这个包可能是二次转发受损的资源,建议重新找来源,没必要在修复上耗时间。
5.5 现象:导入SQL脚本报 Unknown database 或 Table already exists
原因:脚本里有USE database_name;但库还没建;重复导入时旧表还在,CREATE TABLE撞表名直接报错。
解决:先看脚本前五行,有没有CREATE DATABASE或USE语句。有USE没建库就手动建库再导;重复导入前先DROP DATABASE,保证表结构干净。还有的脚本带外键约束,导入顺序错了会报Cannot add foreign key constraint,这种按文件里的注释调整表顺序,或者临时关掉外键检查:SET FOREIGN_KEY_CHECKS=0;导完再开回来。
6. 二次开发进阶:把课程设计改成能拿得出手的医药管理系统
系统跑通、坑也排掉之后,下一步就是改。改哪里性价比最高?我的回答是登录密码和权限控制,这两处是答辩老师必看,也是决定系统能不能往线上放的关键分界。
6.1 登录密码升级:MD5加盐,十几行代码挡掉明文风险
找到UserDao里的密码判断那一段,把明文比对改成加密比对,工具方法如下:
import java.security.MessageDigest; public class MD5Util { public static String md5(String input) { try { MessageDigest md = MessageDigest.getInstance("MD5"); byte[] bytes = md.digest(input.getBytes("UTF-8")); StringBuilder sb = new StringBuilder(); for (byte b : bytes) { sb.append(String.format("%02x", b)); } return sb.toString(); } catch (Exception e) { throw new RuntimeException("MD5 计算失败", e); } } public static String md5WithSalt(String password, String salt) { return md5(salt + password); } }注册时存md5WithSalt(password, username),登录时用同一个salt做同样算法再比对。salt取username能保证两个相同密码的人哈希值不同,而且不需要额外存储。这套方案拦截的是"数据库被拖了直接拿到明文密码"的场景,防不住针对性暴力破解,但对一个医药管理系统的课程设计来说,方向已经对了,真要上生产再换BCrypt也不迟。
6.2 验收五连问:拿到任何源码包我都先过这五关
最后分享一个习惯。我现在拿到任何源码包,第一反应不是急着点运行,而是先过五关:第一,数据库脚本能不能一次导入成功,导入后有没有测试数据;第二,初始账号能不能在文档里找到,找到后能否登录进主页;第三,入库一个药品,库存数量是不是恰好增加;第四,出库数量大于库存时,系统是弹提示还是直接报错;第五,手动改库里日期后,过期预警列出的药品是否随之变化。这五关走完,这个包对我来说才算从黑匣子变成白盒。
这个检查顺序让我少踩了很多坑,也让我在答辩和同事面前少丢了几次人。医药管理系统源码.zip这类包,下十次不如完整跑通一次划算;把它改成自己的东西,比下载再多新版本都实在。希望帮到你。
本文还有配套的精品资源,点击获取