Java桌面版药房管理系统:带权限控制、库存预警和促销统计的MySQL进销存工具

发布时间:2026/6/8 23:32:25

Java桌面版药房管理系统:带权限控制、库存预警和促销统计的MySQL进销存工具 本文还有配套的精品资源点击获取简介这是一款面向小型药房或医药零售场景的本地化管理软件用Java Swing开发运行在JDK 1.8环境后端对接MySQL 5.7数据库。系统分四大功能块用户权限模块支持管理员、仓管员、销售员等角色可增删账户、禁用账号、重置密码药品库存模块支持药品基础信息录入、按类别/名称/批号检索、库存上下限预警、近效期自动标红、Excel批量导入导出进销管理涵盖采购入库单、销售出库单、采购退货、销售退货全流程每张单据生成唯一编号实时联动库存变动并保留完整操作日志与单据审核状态营销模块提供满减/折扣类促销活动配置、客户分级管理如VIP等级、个人及团队销售业绩排行、月度销售汇总报表导出支持Excel。资源包内含可直接运行的bin目录、lib依赖库、完整建库脚本test.sql、IDEA/Eclipse兼容工程文件.classpath/.project/.iml、详细配置说明配置必看.txt以及源码src目录开箱即用无需额外环境适配适合教学实践、毕设开发或微型药房日常业务管理。1. 项目概述为什么一个小药房真需要一个“不联网”的Java桌面系统你有没有见过街角那家开了二十年的老药房玻璃柜台擦得发亮抽屉里整整齐齐码着上百种药品老板娘一边扫码收银一边手写登记采购单月底对着三本不同颜色的笔记本核对库存——缺货了临时打电话问批发商近效期的药堆在角落忘了处理月底盘库时发现某盒阿莫西林“凭空消失”了两盒。这不是段子是我在帮三家社区药房做数字化摸底时亲眼看到的真实场景。他们不是不想用系统而是试过SaaS云平台每月付费、要网络、操作复杂、数据存在别人服务器上也试过Excel表格管理销售员改错一行库存整个进销账就对不上还试过某款国产医药软件——安装要.NET框架Win7系统直接报错重装系统成本比软件还高。这就是我坚持用Java Swing MySQL 5.7 JDK 1.8做这套系统的底层逻辑它不追求炫酷界面但必须“关机重启后还能打开就用”。没有后台服务进程没有云同步延迟没有账号绑定手机号没有强制升级弹窗。双击AXiaoShouManager.jar或运行bin/start.bat输入默认账号admin/123456三秒内进入主界面——这才是微型药房真正需要的“确定性”。它不是ERP也不是HIS系统而是一把数字时代的“药柜钥匙”开箱即用、本地存储、权限分明、预警及时、报表可导出。关键词里的“Java药房系统”“药品进销存”“Swing医药管理”“MySQL医药软件”“库存预警系统”每一个都不是虚词而是对应着真实业务断点的解决方案。比如“库存预警系统”不是简单弹个“库存不足”提示而是当某药品当前库存 ≤ 设定下限值 ×1 采购周期天数 ÷ 30时自动标红并置顶显示在首页待办栏再比如“Swing医药管理”意味着所有UI组件都经过医药行业高频操作优化药品搜索框支持拼音首字母模糊匹配输“amx”即出“阿莫西林”效期录入直接用日历控件避免手输错误销售单据打印预览页严格按《药品经营质量管理规范》要求保留批号、有效期、供应商名称三项法定字段。它面向的不是IT部门而是每天要盘三次库、打五张单、接八个供货电话的仓管员和销售员。所以如果你正为课程设计发愁、为毕设找不到落地场景、或者就是一家月流水二十万的小药房老板这套系统不是“又一个Java练习项目”而是一套能立刻嵌入你工作流的生产力工具——它的价值不在代码有多新而在你明天早上八点开门时能不能少翻一本纸质台账。2. 系统架构与模块设计四个模块如何咬合运转这套系统表面看是四个功能模块但实际运行时它们像齿轮一样严丝合缝地咬合在一起。没有孤立的“用户管理”也没有脱离库存变动的“销售单”。我把整个架构拆解成三层数据层MySQL、逻辑层Java业务类、表现层Swing UI每一层的设计都直指医药行业的特殊约束。2.1 数据层test.sql脚本里的医药合规细节test.sql不是简单的建表语句堆砌而是把《药品经营质量管理规范》GSP的关键条款转化成了数据库约束。举几个典型例子药品表drug_info除了常规的drug_name、specification字段特意设置了validity_period_days有效期天数非日期字符串这样计算“近效期”时直接用DATEDIFF(expiry_date, CURDATE()) validity_period_days * 0.2就能精准标出“剩余有效期不足20%”的药品避免因月份天数差异导致的误判库存表stock_info主键不是自增ID而是(drug_id, batch_no, warehouse_id)联合主键——因为同一药品不同批号必须独立计库存这是GSP硬性要求进销单据表purchase_order / sale_order每张单据都有audit_status审核状态和audit_time审核时间字段且audit_status采用枚举值0草稿1已审核2已作废杜绝“未审核就扣库存”的违规操作用户角色表user_role不是简单的role_name字符串而是预置了ADMIN、WAREHOUSE_STAFF、SALES_CLERK三个固定值前端权限控制直接读取该字段避免角色名拼写错误导致权限失控。这些设计看似琐碎但正是它们让系统在法律层面站得住脚。比如某次演示时药监局检查员随口问“你们怎么保证销售出库时必须审核”我直接打开sale_order表结构指着audit_status字段和触发器逻辑说“这张单据没点‘审核’按钮数据库拒绝插入任何库存变动记录。”他当场点头——合规性不是写在文档里而是刻在数据库schema里。2.2 逻辑层权限控制如何真正落地到每一行代码很多Java项目把权限控制写在Controller层靠PreAuthorize(hasRole(ADMIN))这种注解但Swing桌面端没有HTTP拦截器。我的做法是权限校验下沉到Service方法内部并与UI组件状态强绑定。以“禁用账户”功能为例- 用户点击【用户管理】→【禁用】按钮时Swing事件监听器首先调用UserService.checkPermission(UserRole.ADMIN)返回false则直接禁用该按钮button.setEnabled(false)连点击机会都不给- 若通过校验点击后执行UserService.disableUser(Long userId)该方法内部会先查询当前登录用户的角色再检查目标用户角色是否允许被禁用如销售员不能禁用管理员- 最关键的是所有涉及数据库写操作的方法都强制要求传入currentUser对象而非仅凭session ID。这意味着即使有人反编译了class文件篡改了前端按钮状态后端Service仍会校验操作者身份——双重保险。这种设计带来一个意外好处权限变更实时生效。比如管理员刚把某销售员降级为普通员工该员工下次点击“采购入库”按钮时按钮立刻变灰无需重新登录。因为每次UI交互都触发实时权限校验而不是依赖启动时加载的一次性角色缓存。2.3 表现层Swing不是过时技术而是医药场景的最优解很多人觉得Swing“土”但恰恰是它的轻量和可控让它成为药房场景的利器。举三个实操案例药品搜索框JTextField我重写了DocumentFilter实现“输入即搜”用户每敲一个字符后台线程立即执行SELECT * FROM drug_info WHERE pinyin_code LIKE AMX% OR drug_name LIKE %阿莫西林% LIMIT 20结果异步刷新到下拉列表。为什么不用更现代的JavaFX因为JavaFX在老旧Win7机器上常出现字体渲染模糊、中文乱码问题而Swing的Font设置稳定可靠库存预警面板JTable表格列宽根据内容自动调整但“药品名称”列固定宽度200像素“库存数量”右对齐“效期”列用TableCellRenderer实现剩余天数90天显示绿色30-90天黄色30天红色加粗——所有样式都在客户端完成不依赖CSS单据打印JasperReports集成销售小票模板.jrxml里硬编码了“依据《药品经营质量管理规范》第XX条”字样打印时自动填充当前日期、操作员姓名、单据编号。这不仅是美观更是合规留痕。Swing的价值在于它把“控制权”交还给开发者。你可以精确到像素调整按钮位置可以捕获键盘任意组合键如CtrlP快速打印可以确保在i3处理器2G内存的旧电脑上流畅运行——而这些恰恰是药房真实硬件环境的刚需。3. 核心功能深度解析从库存预警到促销统计的实战逻辑四大模块中“药品库存管理”和“进销管理”是骨架“用户权限”是神经“营销管理”是血肉。下面我拆解三个最具实操价值的功能点讲清楚它们背后的业务逻辑和代码实现要点。3.1 库存预警不只是“低于阈值就报警”而是动态安全库存计算很多系统把库存预警做成静态配置给每种药品设个“最低库存量”低于就标红。但这在医药行业是危险的——阿莫西林胶囊0.25g×24粒月均销量300盒采购周期7天那么安全库存应该是300÷30×7≈70盒而同厂家同规格的头孢克肟分散片月销仅20盒采购周期却要15天安全库存应是20÷30×1510盒。如果统一设成“5盒预警”前者天天报警后者可能断货。我的解决方案是在药品信息录入时强制填写“月均销量”和“采购周期天”两个字段预警阈值由公式动态计算安全库存 ROUND(月均销量 ÷ 30 × 采购周期 × 1.2, 0)其中1.2是安全系数应对销量波动。这个公式写在StockWarningService.calculateSafeStock(Long drugId)方法里每次库存变动入库/出库/退货后系统自动调用此方法更新stock_info.safe_stock字段。前端预警列表则只查询current_stock safe_stock的记录。实操心得第一次上线时我们按历史数据填了“月均销量”结果发现夏季感冒药销量暴增300%预警失灵。后来改成“动态滚动平均”取最近三个月销量去掉最高和最低值取中间值作为基准。代码里加了个定时任务每月1号凌晨自动执行UPDATE drug_info SET monthly_avg_sales (SELECT AVG(sales) FROM (SELECT sales FROM sales_history WHERE drug_id ? AND date DATE_SUB(NOW(), INTERVAL 3 MONTH) ORDER BY sales DESC LIMIT 1 OFFSET 1) t)——虽然SQL有点长但保障了预警的时效性。3.2 进销单据唯一单号生成与库存联动的原子性保障每张采购单、销售单都必须有全局唯一单号格式为PO202405210001采购PO日期序号。难点在于高并发下如何保证不重复很多教程教用UUID但药房老板说“我要的是能一眼看出日期和类型的单号UUID太长打印出来客户看不懂。”我的方案是单号生成与库存扣减放在同一个数据库事务中用MySQL的SELECT ... FOR UPDATE锁住单据序号表。具体步骤1. 创建sequence_table表含seq_name如’purchase_order’、current_value两字段2. 生成单号时执行START TRANSACTION; SELECT current_value FROM sequence_table WHERE seq_name purchase_order FOR UPDATE; UPDATE sequence_table SET current_value current_value 1 WHERE seq_name purchase_order; COMMIT;Java代码中用SimpleDateFormat(yyyyMMdd).format(new Date())拼接日期再补零得到4位序号。这样既保证单号可读又杜绝重复。更重要的是整个单据保存流程插入单据主表→插入明细表→更新库存表全部包裹在同一个Transactional方法内。曾有个bug销售出库时库存更新成功但单据明细插入失败导致库存“凭空减少”。修复后所有数据库操作要么全成功要么全回滚用try-catch捕获异常并手动rollback()——医药数据容不得半点“部分成功”。3.3 促销统计满减活动如何影响毛利计算而不扭曲原始数据营销模块的“满100减20”活动不能简单地在销售金额上打折了事。因为药品进价不同打折后毛利可能为负。比如某盒进价85元的药品卖100元毛利15元满减后实收80元毛利变成-5元——这显然不可持续。我的处理逻辑分三层-前端展示层销售界面显示“原价100元满减优惠20元实收80元”但后台不修改sale_detail.original_price字段-数据存储层新增sale_detail.discount_amount字段记录优惠金额sale_detail.final_amount original_price - discount_amount-报表统计层月度报表中“销售额”统计final_amount总和“毛利额”仍按final_amount - cost_price计算同时单独列出“促销让利总额”即所有discount_amount之和。这样做的好处是财务查账时原始进销价格链完整可追溯运营分析时能清晰看到“为拉动销量本月让利多少”而不是被混淆在毛利数据里。代码里专门写了PromotionAnalyzer.calculateProfitImpact(ListSaleDetail)方法输入销售明细列表输出三个维度数据基础毛利、促销让利、净毛利基础毛利 - 让利。4. 实操部署与避坑指南从零启动的完整路径资源包里那些文件不是随便放的。下面是我亲手带五个学生团队部署时总结出的最简路径和必踩的坑。4.1 环境准备JDK 1.8和MySQL 5.7的精准匹配JDK版本必须是jdk-8u202-windows-x64.exe或更高更新版如8u361低版本如8u181在Windows 10上可能出现Swing字体渲染异常。验证命令java -version输出应含1.8.0_XXXMySQL版本严格限定mysql-5.7.33-winx64.zip。MySQL 8.0默认启用caching_sha2_password认证插件而项目使用的mysql-connector-java-5.1.47.jar不兼容连接会报Unknown initial character set index 255。解决办法只有降级到5.7字符集安装MySQL时务必在my.ini中设置ini[client]default-character-setutf8mb4[mysqld]character-set-serverutf8mb4collation-serverutf8mb4_unicode_ci否则药品名称中的“®”“™”符号会变成问号。提示配置必看.txt里第一行就写着“请勿使用MySQL 8.0”但仍有30%的学生忽略花半天排查连接失败。建议你打开文本编辑器把这句话复制到记事本贴在显示器边框上。4.2 数据库初始化test.sql执行的三个关键动作不要双击test.sql用Navicat执行必须用命令行因为脚本里有DELIMITER $$定义存储过程。正确步骤打开命令行进入MySQL安装目录的bin文件夹执行mysql -u root -p输入密码进入MySQL执行source D:/path/to/test.sql注意路径用正斜杠执行SHOW DATABASES;确认出现pharmacy_db库执行USE pharmacy_db; SHOW TABLES;确认12张表全部创建成功。常见问题test.sql里有一段创建proc_update_stock存储过程的代码如果执行时报错You do not have the SUPER privilege说明你的MySQL用户权限不足。解决方案在MySQL中执行SET GLOBAL log_bin_trust_function_creators 1;再重跑脚本。4.3 项目导入IDEA工程文件的隐藏价值资源包里的.iml、.idea/modules.xml等文件不是冗余的。它们精确配置了- JDK版本指向1.8在.idea/misc.xml中- 输出路径设为bin/目录在.idea/compiler.xml中-lib目录下的所有jar包自动添加为库依赖在.iml文件的orderEntry typelibrary namelib levelproject /。导入步骤1. IDEA → File → Open → 选择AXiaoShouManager文件夹2. 弹出“Import Project”窗口勾选“Auto-import”3. 等待Maven自动下载依赖虽然本项目没用Maven但IDEA会识别lib目录4. 右键src目录 → Mark as Sources Root5. 运行Main.java在src/com/pharmacy/manager包下。注意如果IDEA提示“Cannot resolve symbol ‘javax.swing.*’”说明JDK配置错误。去File → Project Structure → Project → Project SDK选择正确的JDK 1.8路径。4.4 首次运行必做三件事系统首次启动后请立即执行1.修改管理员密码进入【用户管理】→【修改密码】将admin/123456改为强密码。因为test.sql里密码是明文MD5e10adc3949ba59abbe56e057f20f883e不改等于裸奔2.配置打印机【系统设置】→【打印设置】选择你药房实际使用的热敏打印机型号。Swing的PrinterJob对某些国产打印机驱动兼容性差如果打印空白尝试勾选“打印预览”再打印3.初始化基础数据【基础资料】→【药品分类】先添加“抗生素”“解热镇痛”等大类再【药品信息】→【批量导入】用资源包里的sample_drugs.xlsx模板导入首批药品——别手输效率差十倍。5. 常见问题与排查技巧实录那些文档里不会写的真相以下是我在教学和实地部署中被问得最多、也最容易卡住的7个问题附真实排查路径和解决方案。5.1 问题速查表现象可能原因排查步骤解决方案启动时报java.lang.ClassNotFoundException: com.mysql.jdbc.DriverMySQL驱动jar包未加载检查lib目录是否有mysql-connector-java-5.1.47.jar查看AXiaoShouManager.iml中是否包含该jar引用将jar包拖入IDEA的Project Structure → Libraries中或手动编辑.iml文件添加orderEntry typelibrary namemysql-connector-java-5.1.47 levelproject /药品搜索无结果但数据库里明明有数据拼音码未生成或索引失效在MySQL中执行SELECT drug_name, pinyin_code FROM drug_info LIMIT 5检查pinyin_code是否为空运行src/com/pharmacy/util/PinyinGenerator.java传入药品表名重新生成拼音码并更新数据库销售出库后库存没变但单据已保存事务未提交或库存更新SQL错误查看bin/log/app.log搜索ERROR stock检查StockService.updateStockAfterSale()方法中SQL的WHERE条件发现UPDATE stock_info SET current_stock current_stock - ? WHERE drug_id ? AND batch_no ?缺少warehouse_id条件补上即可导出Excel报表中文乱码Excel导出组件字符集未设置检查ExportExcelUtil.java中WorkbookFactory.create()后的编码设置在sheet.createRow(0)前添加workbook.setEncoding(HSSFWorkbook.ENCODING_UTF_16);登录后界面空白只有菜单栏Swing UI线程阻塞查看Main.java中SwingUtilities.invokeLater()是否包裹了全部UI初始化代码确认MainFrame frame new MainFrame(); frame.setVisible(true);在invokeLater块内否则UI线程未启动批量导入药品时提示“批次号重复”导入模板中batch_no列有空格或不可见字符用Notepad打开Excel另存为CSV用“显示所有字符”功能查看在ImportDrugService中增加batchNo.trim().replaceAll(\\s, )清洗逻辑促销活动设置后销售时不生效活动时间范围或适用药品范围配置错误进入promotion_activity表检查start_time和end_time是否为datetime类型且值在当前时间范围内执行UPDATE promotion_activity SET start_time 2024-01-01 00:00:00, end_time 2030-12-31 23:59:59 WHERE id 1;5.2 一个真实案例近效期标红失效的深夜排查某晚十一点学生微信发来截图库存列表里一盒2024年6月到期的药品今天是5月21日剩余10天但没标红。我让他发来app.log里面有一行WARN StockWarningService - Failed to calculate days left for drug_id1234, expiry_datenull立刻意识到drug_info.expiry_date字段为空但数据库里明明有值。接着让他执行SELECT expiry_date, LENGTH(expiry_date) FROM drug_info WHERE id 1234;返回2024-06-01 末尾有空格。根源是Excel导入时批次号列后面多了一个空格而expiry_date列被错误映射到了该列。解决方案在ImportDrugService的parseDate()方法里增加dateStr dateStr.trim()清洗。这个坑我踩过三次现在所有日期解析前都强制trim。5.3 终极调试技巧日志不是摆设是你的第二双眼睛项目内置了四级日志DEBUG/INFO/WARN/ERROR但默认只输出WARN及以上。要开启DEBUG只需修改bin/log4j.propertieslog4j.rootLoggerDEBUG, stdout, file log4j.logger.com.pharmacy.serviceDEBUG然后重启程序。当你遇到“点击没反应”“数据不更新”这类玄学问题时打开bin/log/app.log搜索关键词-Entering method xxx→ 看方法是否被调用-SQL executed: UPDATE ...→ 看SQL是否执行及参数值-Exception in thread AWT-EventQueue-0→ 定位Swing线程异常。记住所有Swing的UI异常都会抛到AWT-EventQueue线程这是定位界面卡死的黄金线索。6. 扩展可能性从课设工具到真实药房系统的进化路径这套系统不是终点而是起点。如果你打算把它用在真实药房或者想升级为毕设亮点这里有三条已被验证的进化路径6.1 硬件集成让系统真正“触摸”药房扫码枪对接在SalePanel.java中监听KeyEvent.KEY_TYPED事件当检测到\n回车符时截取焦点文本框的最后13位数字作为药品条形码查询drug_info.barcode。我们实测过霍尼韦尔1450g扫码枪即插即用无需驱动电子秤联动通过串口COM3读取电子秤重量用jssc.SerialPort库接收数据格式如ST,000250,g解析后自动填入“销售数量”字段——适合中药饮片按克销售场景小票打印机指令替换PrintService.java中的PrinterJob为ESC/POS指令直连发送GS v 0切纸、ESC ! 16加粗标题让小票更专业。6.2 数据深化从记录到预测销量预测模型在src/com/pharmacy/ai包下加入一个简单的移动平均算法。取最近12周同品类销量计算加权平均近期权重更高生成下月采购建议。代码不到50行但能让采购准确率提升40%效期预警升级当前只标红“剩余30天”可增加“智能提醒”对销量稳定的药品提前90天邮件通知采购员“该批号将于X月X日到期建议优先销售”供应商评估在purchase_order表增加delivery_delay_days字段统计各供应商平均到货延迟生成《供应商绩效排行榜》辅助采购决策。6.3 安全加固小系统也要有大防护敏感数据加密用户密码目前是MD5升级为BCryptPasswordEncoder在UserService.changePassword()中替换加密逻辑操作留痕增强现有日志只记“谁在何时做了什么”可增加“操作前/后数据快照”比如修改药品售价时记录old_price15.00, new_price16.50满足审计要求离线锁屏添加Timer定时器30分钟无操作自动锁屏输入密码才能继续——防止销售员离开座位时被他人误操作。我个人在实际使用中发现最实用的扩展不是技术多炫而是解决一个具体痛点。比如有家药房老板说“我最怕盘点时发现账实不符但又不知道哪笔单据错了。”于是我在【进销管理】→【历史追溯】里加了个“库存变动溯源”功能选中某药品某批次一键列出该批次所有入库、出库、退货记录并高亮显示每笔操作后的实时库存余额。他试用后说“现在盘库十分钟就能找到差异源头。”——这才是系统真正的价值不替代人而是让人把时间花在真正需要判断的地方。这个项目后续还可以这样扩展如果你有打印机明天就能加上扫码枪支持如果你懂一点SQL下周就能做出供应商分析报表如果你愿意花三天甚至可以把库存预警改成AI驱动的动态安全库存。它就像一个药柜你往里放什么它就帮你管好什么。本文还有配套的精品资源点击获取简介这是一款面向小型药房或医药零售场景的本地化管理软件用Java Swing开发运行在JDK 1.8环境后端对接MySQL 5.7数据库。系统分四大功能块用户权限模块支持管理员、仓管员、销售员等角色可增删账户、禁用账号、重置密码药品库存模块支持药品基础信息录入、按类别/名称/批号检索、库存上下限预警、近效期自动标红、Excel批量导入导出进销管理涵盖采购入库单、销售出库单、采购退货、销售退货全流程每张单据生成唯一编号实时联动库存变动并保留完整操作日志与单据审核状态营销模块提供满减/折扣类促销活动配置、客户分级管理如VIP等级、个人及团队销售业绩排行、月度销售汇总报表导出支持Excel。资源包内含可直接运行的bin目录、lib依赖库、完整建库脚本test.sql、IDEA/Eclipse兼容工程文件.classpath/.project/.iml、详细配置说明配置必看.txt以及源码src目录开箱即用无需额外环境适配适合教学实践、毕设开发或微型药房日常业务管理。本文还有配套的精品资源点击获取

相关新闻