ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Java+MySQL医药销售系统:权限模型与库存事务设计实战

Java+MySQL医药销售系统:权限模型与库存事务设计实战 简介这是一份基于JavaMySQL的医药销售管理系统完整源码适合JavaWeb课程设计或毕业设计参考。系统围绕员工与经理两类角色设计权限员工可管理会员、供应商、药品查询、销售退货与盘点经理可管理员工和全部基础数据但不参与销售业务并设置了供应商与顾客无访问权限的边界。包内共26个文件以19个JSP页面为核心配合XML配置、MF清单、SQL数据库脚本及JDBC驱动JAR另有README与LICENSE说明整体压缩包仅1.06MB。目前已有263人学习适合快速导入IDE后结合SQL脚本部署调试能直观理解权限控制、库存盘点等典型业务模块的编码实现。1. 医药销售管理系统先定权限边界再做 JavaMySQL 的增删改查医药销售管理系统这类 Java MySQL 课程设计表面看是员工、会员、供应商、药品的增删改查真正拉开差距的其实是权限边界和库存联动。这套项目最值得看的一点经理角色没有销售、退货权限只能做会员、供应商、员工管理和报表查看员工能卖货、能退货却进不了删除员工、删除供应商的页面职责分得开答辩时才有的聊。系统走 JSP Servlet JDBC 的传统架构配 mysql-connector-java-5.1.39-bin.jar 和随包 SQL 脚本就能跑适合正在做 Java Web 课程设计、毕业设计或者想看一套完整进销存闭环怎么处理会话、事务和外键约束的新手。2. 数据库设计与权限模型五张核心表怎么撑起销售、退货和盘点拿到压缩包先别急着把「医药销售管理系统.sql」导入就去点登录我习惯先把表关系理一遍。项目正文的页面清单已经把功能暴露得很清楚AddDrugs.jsp 对应药品与采购入库MemberManage.jsp、AddSupplier.jsp 对应会员和供应商管理Sell.jsp、Refunds.jsp 对应销售和退货WareHouse.jsp 对应盘点Records.jsp 和 Financial_Statistics.jsp 对应流水和财务统计。页面背后至少要五类核心表支撑员工表、会员表、供应商表、药品表、单据表——其中单据又拆成销售、退货、入库三张。谁能对哪张表做增删改就是权限模型要回答的问题。2.1 角色权限为什么经理反而不能卖药从页面命名能直接归纳出两套角色的边界。员工查看和添加会员、查看和添加供应商、查询药品支持按编号、名称、类别查、添加药品采购记录、销售药品、处理退货、盘点仓库、查看销售/退货/入库记录、修改个人信息。经理查看/添加/删除会员、供应商、员工盘点仓库查看销售/退货/入库记录修改个人信息但没有销售和退货入口。乍一看反直觉权限更高的经理反而不能卖货实际业务里销售和退货是收银动作必须留痕到具体员工经理管的是人员、档案和报表如果经理也能直接改销售数据财务核对时根本分不清是系统真实产生还是人为干预。门店通常的做法就是管账的和收银的分开这套系统把规则直接做进了路由Login.jsp 登录后按 role 决定进入哪套主页Sell.jsp 和 Refunds.jsp 对经理不可见。实现层面这类项目是典型的登录后把 role 放进 session每个页面再校验。我一般在类似系统里还会加一层前端按角色渲染入口只解决看不见解决不了手动输 URL 直接访问 Sell.jsp所以更稳的做法是在目标页面顶部用 Java 代码判断 session 里的 role不符合就重定向回主页。课程设计做到这一步就能跟老师聊为什么经理不能卖药而不只是我把按钮藏了。2.2 表结构拆解员工、药品、会员、供应商、单据包里没有单独的表结构文档但根据页面反推一套合格的建表脚本至少包含下面这些核心表。参考 SQL 如下实际字段名以「医药销售管理系统.sql」导出的为准CREATE TABLE employee ( emp_id INT PRIMARY KEY AUTO_INCREMENT, emp_no VARCHAR(20) UNIQUE NOT NULL, emp_name VARCHAR(50) NOT NULL, password VARCHAR(64) NOT NULL, role TINYINT NOT NULL DEFAULT 1 COMMENT 1-员工 2-经理, phone VARCHAR(20), created_at DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE member ( member_id INT PRIMARY KEY AUTO_INCREMENT, member_no VARCHAR(20) UNIQUE NOT NULL, member_name VARCHAR(50) NOT NULL, phone VARCHAR(20), points INT DEFAULT 0, created_at DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE supplier ( supplier_id INT PRIMARY KEY AUTO_INCREMENT, supplier_name VARCHAR(100) NOT NULL, contact VARCHAR(50), phone VARCHAR(20), address VARCHAR(200) ); CREATE TABLE drug ( drug_id INT PRIMARY KEY AUTO_INCREMENT, drug_no VARCHAR(30) UNIQUE NOT NULL, drug_name VARCHAR(100) NOT NULL, category VARCHAR(50), specification VARCHAR(100), unit_price DECIMAL(10,2) NOT NULL, stock INT DEFAULT 0, safety_stock INT DEFAULT 50, supplier_id INT, FOREIGN KEY (supplier_id) REFERENCES supplier(supplier_id) ); CREATE TABLE sale_record ( sale_id INT PRIMARY KEY AUTO_INCREMENT, sale_no VARCHAR(30) UNIQUE NOT NULL, drug_id INT NOT NULL, emp_id INT NOT NULL, member_id INT, quantity INT NOT NULL, amount DECIMAL(10,2) NOT NULL, sale_time DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (drug_id) REFERENCES drug(drug_id), FOREIGN KEY (emp_id) REFERENCES employee(emp_id), FOREIGN KEY (member_id) REFERENCES member(member_id) );employee 表用 emp_no 做登录账号而不是 emp_id是因为工号比自增主键更适合记忆和输入role 用 TINYINT 存 1、2比字符串admin省空间JSP 里判断 role 2 也直接。member 表带 points 积分字段对应 AddVIP.jsp 的开通入口积分能在后续做折扣、会员等级属于埋得下扩展点的设计。drug 表加了 safety_stock 安全库存字段WareHouse.jsp 盘点时靠它判断哪些药需要补货这个字段在第三章查询和第六章预警里都会用到。几个 SQL 细节值得抄作业unit_price 用 DECIMAL(10,2) 而不是 FLOAT药品价格做累计求和时浮点会出 0.10.2 不等于 0.3 的精度问题DECIMAL 是精确小数stock INT DEFAULT 0 保证了新增药品默认不超卖sale_record 同时外键关联 drug、employee、member查报表时一次 JOIN 就能把哪个员工把什么药卖给了哪个会员拉出来Financial_Statistics.jsp 的统计全部依赖这张表。sale_no 用 VARCHAR 存业务单号而不是直接用自增 id是为了以后能和纸质单据、对账单对上号。退货和入库两张表在原脚本里通常长这样refund_record 至少要带原 sale_id 外键、退款数量、退款原因和操作员工inbound_record 带 drug_id、数量、进价、采购时间和操作员工。单号生成常见做法是前缀 时间戳比如 XS20250101001因为自增 id 在并发和跨库迁移时容易撞。2.3 初始账号与默认数据导入 SQL 后先别急着登录SQL 导入完成后第一件事不是开 Tomcat而是先执行一条 SELECT看清楚 employee 表里到底存了什么。下面几条语句是我每次拿到类似系统都会跑的-- 查看所有账号和角色确认默认管理员是谁 SELECT emp_id, emp_no, emp_name, role FROM employee; -- 如果密码是明文且想改成自己的测试密码 UPDATE employee SET password 123456 WHERE emp_no admin; -- 如果密码是 MD5 密文别直接 UPDATE 明文否则永远登不进去 -- 走 MySetting.jsp 的修改密码功能最稳这里有个高频翻车点原脚本 password 字段如果是 MD5 加密存储你直接 UPDATE 成明文登录时 Java 端拿明文去比密文必然失败。先 SELECT 看数据形态再决定是查 Java 代码里的加密逻辑还是走系统自带的修改密码页面。提示改初始密码之前先备份原数据一眼至少确认原来的 password 是明文还是密文再做修改。MySQL 8.0 用户还要注意包里带的驱动是 mysql-connector-java-5.1.39-bin.jar5.1.39 对 8.0 默认的 caching_sha2_password 认证插件支持不好导入 SQL 或启动时可能报认证插件错误。我一般建议课程设计直接用 MySQL 5.7 和驱动配对省一晚上的调试时间如果非要用 8.0方案见第五章 5.5 节。3. JDBC JSP 实现链路登录路由、药品查询与库存联动这套项目没用 MyBatis、Spring 那一套就是最直接的 JSP Servlet JDBC。对课程设计来说这反而是好事能从 Login.jsp 到 Sell.jsp 把一条请求链路从头看到尾理解会话、防注入、事务这些基础概念是怎么落到代码里的。下面按登录路由 → 查询盘点 → 销售退货三条链路拆。3.1 登录会话与角色路由session 里存什么页面权限才能立住登录页 Login.jsp 收集工号和密码提交到登录 Servlet。核心逻辑是先按 emp_no 和 password 查 employee 表能查到就把员工身份写进 session然后进主页查不到就回登录页带错误提示。参考实现WebServlet(/login) public class LoginServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding(UTF-8); String empNo request.getParameter(empNo); String password request.getParameter(password); String sql SELECT emp_id, emp_name, role FROM employee WHERE emp_no ? AND password ?; try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { ps.setString(1, empNo); ps.setString(2, password); ResultSet rs ps.executeQuery(); if (rs.next()) { // 身份信息放进 session后续每个页面都靠它判断权限 HttpSession session request.getSession(); session.setAttribute(empId, rs.getInt(emp_id)); session.setAttribute(empName, rs.getString(emp_name)); session.setAttribute(role, rs.getInt(role)); // 员工和经理进同一个主页菜单根据 role 动态渲染 response.sendRedirect(HomePage.jsp); } else { request.setAttribute(errorMsg, 工号或密码错误); request.getRequestDispatcher(Login.jsp).forward(request, response); } } catch (Exception e) { e.printStackTrace(); request.setAttribute(errorMsg, 系统异常请查看日志); request.getRequestDispatcher(Login.jsp).forward(request, response); } } }从文件清单看只有 HomePage.jsp 一个主页所以更可能的做法是主页内按 role 渲染菜单——员工看到销售、退货入口经理看到员工管理、供应商删除入口。这样权限路由其实分两段主页内做菜单级控制目标页面再做动作级控制。如果后面答辩被问员工直接输 Sell.jsp 怎么办答案就在 3.3 和第六章的 Filter。这里用 PreparedStatement 而不是 Statement是因为参数都是页面传进来的字符串直接拼接 SQL 等于把登录接口变成注入点。PreparedStatement 的预编译机制把参数当成数据而不是 SQL 片段这是 Java 基础面试里常考、也是这套系统里真实存在的一层保护。3.2 药品查询与库存盘点模糊匹配和补货状态一条 SQL 搞定Sell.jsp 的查询区域通常接收一个 keyword 参数后端按药品编号、名称、类别三个维度做 LIKE 匹配SELECT drug_id, drug_no, drug_name, category, specification, unit_price, stock FROM drug WHERE drug_no LIKE ? OR drug_name LIKE ? OR category LIKE ? ORDER BY drug_id DESC;对应 Java 端就是查出来之后设置三个一样的参数值keyword 前后拼 %比如 setString(1, %阿莫%)。三个 OR 条件在数据量大时可以换 UNIQUE 索引或加药品类别下拉框缩小范围课程设计阶段不用过度设计字段上 drug_no 有 UNIQUE 索引已经够。仓库盘点 WareHouse.jsp 在查列表的同时往往要显示是否缺货我一般会直接加一个 CASE WHEN 判断SELECT drug_id, drug_no, drug_name, stock, safety_stock, CASE WHEN stock safety_stock THEN 需补货 ELSE 正常 END AS stock_status FROM drug ORDER BY stock_status DESC, drug_id;ORDER BY stock_status DESC 会把需补货排在前面盘点的人不用在整页列表里找。safety_stock 这个字段建表时有默认值 50盘点页里也能顺手把默认值改掉——这就是前面强调初始数据要改的原因之一默认安全库存不等于你药房的实际周转水平。3.3 销售与退货的库存联动一个事务里完成写单和扣减销售的核心不是 INSERT 销售单而是插入销售单 扣减库存必须同时成功或同时失败。如果先插单再扣库存扣库存失败就会留下一个凭空的销售记录如果先扣库存再插单插单失败库存就莫名其妙少了。正确写法是放在同一个数据库事务里Connection conn null; try { conn DBUtil.getConnection(); conn.setAutoCommit(false); // 关闭自动提交手动控制事务边界 // 1. 锁定药品行防止两个窗口同时卖最后一盒 String selectSql SELECT stock FROM drug WHERE drug_id ? FOR UPDATE; PreparedStatement psSelect conn.prepareStatement(selectSql); psSelect.setInt(1, drugId); ResultSet rs psSelect.executeQuery(); if (!rs.next() || rs.getInt(stock) quantity) { throw new RuntimeException(库存不足); } // 2. 生成业务单号并插入销售记录 String saleNo XS System.currentTimeMillis(); String insertSql INSERT INTO sale_record(sale_no, drug_id, emp_id, member_id, quantity, amount) VALUES (?, ?, ?, ?, ?, ?); PreparedStatement psInsert conn.prepareStatement(insertSql); psInsert.setString(1, saleNo); psInsert.setInt(2, drugId); psInsert.setInt(3, empId); psInsert.setInt(4, memberId); psInsert.setInt(5, quantity); psInsert.setBigDecimal(6, price.multiply(BigDecimal.valueOf(quantity))); psInsert.executeUpdate(); // 3. 扣库存WHERE 条件里带 stock ? 做二次兜底 String updateSql UPDATE drug SET stock stock - ? WHERE drug_id ? AND stock ?; PreparedStatement psUpdate conn.prepareStatement(updateSql); psUpdate.setInt(1, quantity); psUpdate.setInt(2, drugId); psUpdate.setInt(3, quantity); int rows psUpdate.executeUpdate(); if (rows 0) { // 走到这里说明 SELECT 之后、UPDATE 之前库存被并发改掉了 throw new RuntimeException(库存不足本次销售已回滚); } conn.commit(); // 提交事务 } catch (Exception e) { if (conn ! null) { try { conn.rollback(); } catch (Exception ex) { ex.printStackTrace(); } } throw e; } finally { if (conn ! null) { try { conn.setAutoCommit(true); } catch (Exception e) { } } DBUtil.close(conn, null, null); }逻辑说明FOR UPDATE 是行级锁把当前事务和这条药品库存绑定别人要 UPDATE 同一行必须等提交不带锁的话两个窗口同时卖最后一盒药各自 SELECT 都看到 stock1各自扣减就超卖了。步骤 3 的 UPDATE 又加了一道 WHERE stock ?即使锁失效也能用受影响行数判断是否超卖——这就是双保险。amount 金额我建议用后端 unit_price 乘 quantity 计算不要轻信前端传过来的值否则前端改个 hidden 字段就能把药价改了。退货就是反向操作INSERT 一条退款记录 UPDATE drug SET stock stock ?同样要包事务并且退货数量要小于等于原销售单的可退数量这部分在 RefundsDetail.jsp 里通常按原销售单展开明细。4. 部署复现MySQL 5.7 Tomcat 8.5 把这套系统跑起来这套系统是传统的 Java Web 项目部署路径很固定但每一步都有对应的坑。按照下面的顺序做基本半小时内能见到登录页。4.1 环境准备JDK、MySQL、Tomcat 和驱动的配对关系组件推荐版本原因JDK1.8传统 JSP/Servlet 项目最稳和 Tomcat 8.5 兼容性好MySQL5.7和 5.1.39 驱动认证方式匹配免去插件兼容问题Tomcat8.5支持 JSP 2.3Java EE 7 标准JDBC 驱动压缩包自带 mysql-connector-java-5.1.39-bin.jar版本是项目验证过的不用另下如果你的电脑装的是 JDK 17编译时大概率看到警告: 源发行版 17 需要目标发行版 17或者编译报错那是因为 Eclipse 的 Compiler compliance level 跟着 JDK 走了而项目是老的 Java 8 写法。解决方式Eclipse 里 Window → Preferences → Java → Compiler 把编译级别改成 1.8再把项目的 Java Build Path 里的 JRE 指到 JDK 8。MySQL 同理8.0 不是不能用但要用它就得同步换驱动和改 JDBC 参数新手先按 5.7 来省事。4.2 导入 SQL 与修改连接配置URL 里三个参数决定生死把压缩包解压后用命令行导入 SQL# 方式一重定向导入注意文件路径 mysql -uroot -p /path/to/医药销售管理系统.sql # 方式二进入 mysql 后用 sourceWindows 下路径用正斜杠 mysql -uroot -p mysql source D:/projects/医药销售管理系统.sql;Linux 下如果报 ERROR 2002 (HY000): Cant connect to local MySQL server through socket /var/run/mysqld/mysqld.sock说明 MySQL 服务没启动先 systemctl start mysqld 或者 service mysql start再重新执行。Windows 下如果命令行直接粘贴中文路径乱码就用 --default-character-setutf8 指定客户端编码mysql --default-character-setutf8 -uroot -p 医药销售管理系统.sql注意如果导入 SQL 时不是用命令行而是用 Navicat 这类图形工具工具默认字符集有时候会覆盖 SQL 文件里的 utf8 声明导入前先确认连接编码是 UTF-8。导入以后连接配置集中在 DBUtil 类里改成你自己的数据库账号密码private static final String URL jdbc:mysql://localhost:3306/drug_sales_management ?useUnicodetruecharacterEncodingutf8useSSLfalse; private static final String USER root; private static final String PASSWORD 123456;URL 里三个参数值得记一下useUnicodetrue 配合 characterEncodingutf8 决定中文能不能正常读写缺了它页面查出来全是问号useSSLfalse 是因为本机开发没有证书5.1.39 驱动在 MySQL 5.7 上默认会尝试 SSL 握手本地跑没必要关掉能少一堆 SSL 警告。如果你换成了 MySQL 8.0 的 8.x 驱动驱动类名要改成 com.mysql.cj.jdbc.DriverURL 里把 useSSLfalse 换成 sslModeDISABLED 更合适。4.3 从 webcontent 目录到浏览器可访问部署步骤和 404 排查Eclipse 导入步骤File → Import → General → Existing Projects into Workspace选择解压目录让 Eclipse 识别成 Dynamic Web Project。注意项目目录结构里是 webcontent 而不是通常的 WebContent如果 Eclipse 没自动识别 Web 根目录进 Project Properties → Project Facets 勾选 Dynamic Web Module再到 Deployment Assembly 里把 webcontent 映射到 /。然后把 mysql-connector-java-5.1.39-bin.jar 复制到 webcontent/WEB-INF/lib 下——这一步经常被忘忘了就是下章第一个报错。启动 Tomcat 后访问 http://localhost:8080/项目名/Login.jsp登录用的默认账号在 2.3 节查过直接输进去测。如果访问 404按这个顺序排查第一看 Tomcat 日志有没有报 Servlet 编译失败第二确认 webcontent 下 JSP 路径大小写Linux 服务器上区分大小写第三确认项目有没有成功部署到 webappsEclipse 里看 Servers 视图的状态是不是 Started最后才是怀疑代码问题。这套排查顺序对老项目特别管用别一上来就翻业务代码。5. 避坑记录驱动版本、中文乱码与重复扣库存这一章全是血泪经验。JSP JDBC 老项目的问题特征很明显报错集中在编译、编码、数据库连接三块。下面五条是我在类似项目里反复遇到的每一条按现象 → 原因 → 解决写。5.1 现象启动后报 ClassNotFoundException: com.mysql.jdbc.Driver启动 Tomcat 一访问就抛 java.lang.ClassNotFoundException: com.mysql.jdbc.Driver或者在 DBUtil 的静态块里直接打异常。原因很简单驱动 jar 没有进入 WEB-INF/lib或者 Eclipse 里 jar 只加了 Build Path 但没进部署清单。解决把 mysql-connector-java-5.1.39-bin.jar 复制到 webcontent/WEB-INF/lib 下Eclipse 里还要右键项目 → Properties → Deployment Assembly → Add → Java Build Path Entries把该 jar 勾上。判断标准很简单部署目录 WEB-INF/lib 里能看到这个 jar 才算完。5.2 现象数据库中文正常页面上全是问号加了药品阿莫西林胶囊页面上显示??????。原因是连接 URL 没带 characterEncodingutf8或者 JSP 页面缺 pageEncoding 声明又或者建库时字符集就是 latin1。解决要三层一起改MySQL 建库时用 utf8mb4CREATE DATABASE ... DEFAULT CHARACTER SET utf8mb4JDBC URL 带上 useUnicodetruecharacterEncodingutf8JSP 头部写全% page languagejava contentTypetext/html; charsetUTF-8 pageEncodingUTF-8%。注意如果库里已有乱码数据改完 URL 后要重新插入才能验证旧数据已经坏掉了。5.3 现象销售成功后刷新页面库存被重复扣减卖完一盒阿莫西林按 F5 一刷新销售单多出一条库存多扣了一盒。原因是提交表单后服务端用 forward 转发回原页面浏览器觉得刚才的 POST 还能再发一次刷新就重复提交。解决用 Post/Redirect/Get 模式销售接口处理成功后直接 response.sendRedirect 到销售列表或首页而不是 request.getRequestDispatcher().forward()。这样刷新时触发的是 GET 请求不会重复执行写库逻辑。如果场景要求更高的严谨度比如订单提交再加一次性 token课程设计做到 PRG 就够。5.4 现象删除供应商时被外键约束拦截DELETE 失败DeleteSupplier.jsp 里点删除直接抛外键约束异常说 drug 表里有记录引用这个 supplier_id。原因drug 表的外键指向 supplier 表只要还有药品挂在这个供应商名下数据库就不允许直接删父表记录——这是 InnoDB 外键的默认行为反而是在保护数据。解决删除前先做关联检查把该供应商名下的药品数查出来SELECT COUNT(*) FROM drug WHERE supplier_id 2;查出有药就先在页面上提示该供应商下有 N 种药品请先转移或下架或者让用户选择把这些药品的 supplier_id 置空再删。不要为了图方便把外键约束 DROP 掉课程设计里外键是要讲的点删了反而没得讲。5.5 现象MySQL 8.0 下驱动报 Authentication plugin 错误用 8.0 的 MySQL 跑这套系统启动时报 Communications link failure或者直接提示 Authentication plugin caching_sha2_password cannot be loaded。原因是 MySQL 8.0 默认认证插件换成了 caching_sha2_password而 mysql-connector-java-5.1.39 是 2015 年的驱动只认 mysql_native_password。解决有三条路最省事是把 MySQL 退到 5.7不想换数据库就把登录用户改回老认证插件——ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY 123456;再或者换 8.0.x 驱动并把驱动类名改成 com.mysql.cj.jdbc.Driver。三个方案我推荐第一个课程设计别在环境上花太多时间。6. 进阶用 Filter 统一权限把库存预警和日报表补上这套系统跑通之后我建议做三个很小但很显功力的加强答辩时能讲的内容立刻不一样。6.1 用 Filter 把权限规则收敛到一处前面 3.1 说过员工输 URL 直接访问 Sell.jsp 的问题只靠页面跳转是挡不住的。用 Filter 统一拦截规则集中在一处WebFilter(/*) public class AuthFilter implements Filter { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req (HttpServletRequest) request; HttpServletResponse resp (HttpServletResponse) response; String uri req.getRequestURI(); // 登录页、登录接口和静态资源直接放行 if (uri.endsWith(Login.jsp) || uri.endsWith(/login) || uri.contains(/img/)) { chain.doFilter(request, response); return; } // 未登录一律回登录页 HttpSession session req.getSession(false); if (session null || session.getAttribute(empId) null) { resp.sendRedirect(req.getContextPath() /Login.jsp); return; } // 经理不允许访问销售和退货页 Integer role (Integer) session.getAttribute(role); if (role ! null role 2 (uri.endsWith(Sell.jsp) || uri.endsWith(Refunds.jsp))) { resp.sendRedirect(req.getContextPath() /HomePage.jsp); return; } chain.doFilter(request, response); } }这个 Filter 的价值在于权限规则只写一份以后加页面只需在拦截列表里加一行面试聊到权限控制时能说出前端隐藏菜单只是体验Filter 才是边界比背八股文管用得多。再往下想上连接池就把 DBUtil 的 getConnection 换成从 Druid 或 HikariCP 数据源里拿其余调用点不用动。6.2 库存预警把 safety_stock 用起来建表时留了 safety_stock盘点页可以直接加一段高亮区SELECT drug_no, drug_name, stock, safety_stock, (safety_stock - stock) AS shortage FROM drug WHERE stock safety_stock ORDER BY shortage DESC;缺货药品按缺口排序仓库的人一眼看到最急的。再往前一步把这个查询结果做成定时任务发邮件就是一套还没上消息队列的简易补货提醒。6.3 日报表一条 GROUP BY 吃下财务统计Financial_Statistics.jsp 的单日销售统计用一条 GROUP BY 就能出SELECT DATE_FORMAT(sale_time, %Y-%m-%d) AS sale_date, COUNT(*) AS order_count, SUM(quantity) AS total_quantity, SUM(amount) AS total_amount FROM sale_record WHERE sale_time CURDATE() GROUP BY sale_date ORDER BY sale_date DESC;amount 是 DECIMAL 类型SUM 结果就是准确小数这就是建表时不用 FLOAT 的红利。以后想扩展月度、季度只改 DATE_FORMAT 的格式串和 WHERE 条件。我从那以后每次拿到别人的课程设计第一件事不再点开 README 看介绍而是先执行 SELECT 查员工表、再看 JDBC URL 三个参数、最后用 Filter 把所有受限页面扫一遍——这三步做完项目能不能跑、边界在哪基本心里有数。这套系统从项目编号 100013136 就能定位到原包按第四章的顺序导入 SQL、部署 Tomcat跑通后再把第六章的 Filter 和预警 SQL 加进去就能拿出去当课程设计交了。希望帮到你。本文还有配套的精品资源点击获取
返回列表