Java Web药品管理系统一键部署包:含Tomcat6环境、MySQL建库脚本与完整源码
2026/6/9 7:11:09 网站建设 项目流程

本文还有配套的精品资源,点击获取

简介:直接解压就能跑的Java Web药品管理项目,内置Apache Tomcat 6.0.18定制版(apache-tomcat-6.0.18_rjmed.rar),免安装配置;附带rjsql.sql数据库脚本,导入即生成药品信息表、库存表等全部结构和初始数据;源码放在‘源代码’和‘codes’目录下,包含标准JSP页面、Servlet控制层、DAO数据访问层及web.xml、context.xml等配置文件;‘环境配置.txt’明确列出JDBC连接地址、账号密码、项目部署路径(如rjmed)、上下文根路径等关键参数,方便快速调试;系统支持药品增删改查、库存状态查看与更新,适用于高校课程设计、毕业实训或小型药房日常管理场景。

1. 项目概述:为什么这个“一键部署包”在今天依然值得细看

你可能第一眼看到“Tomcat 6”、“JSP”、“Servlet 2.5”这些词,下意识觉得这是个老古董项目——毕竟现在Spring Boot动辄自动装配、内嵌容器、RESTful API满天飞。但恰恰是这种“过时”的技术栈,构成了国内高校Java Web教学最真实、最扎实的起点。我带过七届毕业设计,每年都有至少二十个学生卡在“环境配不起来”这一步:MySQL驱动版本不对、Tomcat端口被占、web.xml里servlet-mapping写错一个斜杠、甚至JDBC URL里少了个?useUnicode=true&characterEncoding=UTF-8,整个项目就黑屏报404或500。而这个药品管理系统压缩包,本质上不是一份代码,而是一套可触摸的教学沙盒:它把所有容易出错的环境依赖、配置路径、数据库初始化逻辑,全部打包进一个rar文件,解压后双击startup.bat就能看到登录页。关键词里的“药品管理”是业务外壳,“Java Web”是技术底座,“Tomcat6”和“MySQL脚本”是它的呼吸系统,“Web源码”则是它的神经脉络。它不追求高并发、不谈微服务,只专注解决一个最朴素的问题:让一个刚学完Servlet生命周期的学生,在30分钟内,亲手把“药品录入”按钮点下去,看到数据真真切切地写进数据库,并在列表页刷出来。这不是怀旧,而是对教学本质的尊重——先让轮子转起来,再讨论怎么造更轻的碳纤维轮子。

这个包的价值,恰恰藏在那些被现代框架自动隐藏的细节里:比如apache-tomcat-6.0.18_rjmed.rar这个命名,后缀_rjmed不是随意加的,它意味着这个Tomcat实例已被预设了rjmed应用的Context路径、预加载了mysql-connector-java-5.1.7-bin.jarlib目录、甚至conf/server.xml里Connector的URIEncoding="UTF-8"都已写死。再比如rjsql.sql脚本,它不只是建表语句,里面INSERT INTO drug_info VALUES (1,'阿司匹林','解热镇痛',100,20);这样的初始数据,让学生第一次调试时不必面对空列表的茫然,而是立刻能验证“查询功能是否通”。而环境配置.txt的存在,更是直击痛点——它没写“请修改web.xml”,而是明确告诉你:“打开源代码/WEB-INF/web.xml,第32行<url-pattern>/drug/add</url-pattern>对应的是DrugAddServlet;数据库连接配置在源代码/WEB-INF/classes/jdbc.properties,用户名填root,密码留空(因本地MySQL默认无密)”。这种颗粒度的指引,才是新手真正需要的“脚手架”,而不是一纸“请自行配置”的免责说明书。

2. 整体架构与设计思路:为什么选择Tomcat 6 + 手写DAO这套“复古组合”

2.1 技术选型背后的教学逻辑

很多人会问:为什么不用Tomcat 9+?为什么不用MyBatis或JPA?答案很实在:教学场景的约束条件,决定了技术栈的天花板。Tomcat 6.0.18发布于2008年,它要求Servlet规范2.5、JSP 2.1,对应的Java版本是5或6。这个组合看似陈旧,却完美匹配高校机房的现状——很多学校实验室的电脑仍运行Windows 7,预装JDK 1.6,管理员权限受限,无法随意安装新版本JDK或配置复杂环境变量。Tomcat 6的startup.bat脚本对中文路径兼容性极好,而Tomcat 8+在某些老旧系统上常因JAVA_HOME中包含空格或中文而出错。更重要的是,Servlet 2.5的API足够精简:doGet()/doPost()方法签名清晰,HttpServletRequestHttpServletResponse对象的使用逻辑一目了然,没有Spring MVC里@RequestMappingModelAndView等抽象层干扰初学者对HTTP请求-响应本质的理解。

至于DAO层坚持手写JDBC而非ORM框架,这是刻意为之的“认知减负”。我让学生对比过两段代码:一段是用MyBatis写drugMapper.insert(drug),另一段是手写PreparedStatement ps = conn.prepareStatement("INSERT INTO drug_info VALUES(?,?,?,?)"); ps.setString(1, drug.getName());...。前者执行快,后者写得累,但后者能让学生清清楚楚看到SQL如何拼接、参数如何绑定、异常如何捕获(SQLException)、事务如何手动提交(conn.setAutoCommit(false))。在源代码/com/rjmed/dao/DrugDao.java里,你会发现addDrug()方法末尾有这样一行注释:// 注意:此处未做事务控制,实际项目需在Service层统一管理。这句话就是教学的锚点——它不回避缺陷,而是把“事务该在哪层处理”这个问题,直接抛给学生去思考、去查资料、去在后续课程中实践。这种“留白”,比直接塞一个完美的Spring事务配置更有教育价值。

2.2 目录结构解析:从压缩包根目录读懂部署逻辑

拿到压缩包,别急着解压。先看一眼目录树,它本身就是一份部署说明书:

├── apache-tomcat-6.0.18_rjmed.rar ← 核心运行环境(定制版Tomcat) ├── rjsql.sql ← 数据库初始化脚本(含建库+建表+插数据) ├── 环境配置.txt ← 配置参数速查表(非配置文件本身) ├── 源代码/ ← 可编译的Web应用源码(标准目录结构) │ ├── WEB-INF/ │ │ ├── web.xml ← Servlet注册、欢迎页、过滤器配置 │ │ ├── classes/ ← 编译后的.class文件存放处(部署时需复制) │ │ └── lib/ ← 依赖jar包(mysql-connector-java-5.1.7-bin.jar在此) │ ├── jsp/ ← JSP页面(login.jsp, drug_list.jsp等) │ └── ... ├── rjmed/ ← 已编译好的WAR包解压目录(即部署到Tomcat的成品) └── SRDQnI7wKAH2rzPDQelm-master-... ← 可能是Git仓库原始下载包(可忽略)

关键洞察在于:rjmed/目录和源代码/目录是镜像关系,但角色不同。rjmed/是“交付物”,它已经过编译(.class文件在rjmed/WEB-INF/classes下),可直接拷贝到Tomcat的webapps目录下启动;而源代码/是“开发物”,供你修改JSP样式、调整Servlet逻辑、重写DAO方法。环境配置.txt里写的“项目部署路径为rjmed”,指的就是将rjmed文件夹整体复制到apache-tomcat-6.0.18/webapps/下,启动后访问http://localhost:8080/rjmed/login.jsp即可。这里有个易错点:很多学生会试图把源代码/直接扔进webapps,结果报错——因为源代码/里是.java源文件,Tomcat无法直接执行,必须先用javac编译(或用IDE导出WAR)。而rjmed/目录,就是编译完成的“即战力”。

2.3 数据库设计意图:从rjsql.sql读懂业务建模思维

打开rjsql.sql,前几行就定调了整个系统的数据骨架:

CREATE DATABASE IF NOT EXISTS rjmed DEFAULT CHARACTER SET utf8; USE rjmed; CREATE TABLE drug_info ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50) NOT NULL, category VARCHAR(30), stock_quantity INT DEFAULT 0, unit_price DECIMAL(10,2) ); CREATE TABLE inventory_log ( id INT PRIMARY KEY AUTO_INCREMENT, drug_id INT NOT NULL, operation_type ENUM('IN','OUT') NOT NULL, quantity INT NOT NULL, operator VARCHAR(20), operate_time DATETIME DEFAULT NOW(), FOREIGN KEY (drug_id) REFERENCES drug_info(id) );

这个设计透露出两个关键教学意图:第一,范式控制恰到好处drug_info表没有把“供应商”、“生产日期”等字段堆进去,保持核心属性聚焦(名称、类别、库存、单价),避免初学者被冗余字段淹没。第二,操作日志分离设计。单独建inventory_log表记录每次入库(IN)或出库(OUT)动作,而不是在drug_info里加last_update_time字段。这样做的好处是:当学生第一次尝试“删除药品”功能时,系统不会真的物理删除drug_info记录,而是通过inventory_log保留完整追溯链——这正是真实药房管理系统的合规要求(药品流向可查)。脚本末尾的INSERT语句也暗藏玄机:INSERT INTO drug_info VALUES (1,'阿司匹林','解热镇痛',100,20.50);这条数据的stock_quantity=100,而紧接着INSERT INTO inventory_log插入了一条operation_type='IN'的记录,数量也是100。这意味着初始库存不是凭空而来,而是通过一次“入库操作”产生的,逻辑闭环。这种设计,比单纯给个静态库存数字,更能帮助学生理解“库存变化”背后的真实业务动作。

3. 核心细节解析与实操要点:避开那些坑了三年的老陷阱

3.1 Tomcat定制版的“隐形配置”深挖

apache-tomcat-6.0.18_rjmed.rar解压后得到apache-tomcat-6.0.18文件夹,它的特别之处不在表面,而在几个关键文件的细微修改:

  • conf/server.xml的 Connector 节点
    原始Tomcat 6.0.18的默认配置是<Connector port="8080" ... />,但此版本改为了<Connector port="8080" URIEncoding="UTF-8" maxThreads="200" />URIEncoding="UTF-8"这一行至关重要。如果你在drug_add.jsp里用中文提交药品名称(如“板蓝根冲剂”),没有这行配置,Tomcat会把“板”解析成乱码??,导致数据库存入乱码。而maxThreads="200"则暗示了这个系统的设计容量——它并非为高并发设计,200线程足以支撑几十人同时使用的教学演示。

  • conf/context.xml的全局JNDI配置
    文件末尾新增了:
    xml <Resource name="jdbc/rjmedDB" auth="Container" type="javax.sql.DataSource" maxActive="100" maxIdle="30" maxWait="10000" username="root" password="" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/rjmed?useUnicode=true&amp;characterEncoding=UTF-8"/>
    这段配置意味着:整个Tomcat实例内,所有Web应用都可以通过JNDI名java:comp/env/jdbc/rjmedDB获取数据库连接池。但在本项目中,源代码/com/rjmed/dao/BaseDao.java并未使用JNDI,而是走传统JDBC直连(DriverManager.getConnection(...))。为什么还要配?答案是预留扩展性——当你想把DAO升级为使用连接池时,只需修改BaseDao里的一行代码,无需改动Tomcat配置。这是一种“面向未来”的教学设计。

  • bin/startup.bat的静默启动优化
    对比原始startup.bat,此版本在末尾添加了pause命令。这意味着双击运行后,窗口不会一闪而过,而是停留在命令行界面,显示Using CATALINA_BASE: ...Server startup in XXX ms。学生能亲眼看到Tomcat启动成功的最后一行字,获得确定性反馈。而原始版本若启动失败(如端口被占),窗口瞬间关闭,学生根本看不到错误信息,只能瞎猜。

提示:若启动时报错Address already in use: JVM_Bind:8080,说明8080端口被占用。不要急着关掉所有程序,直接打开conf/server.xml,把port="8080"改成port="8088",再重启即可。这是教学环境中最高频的故障,解决它只需改一个数字。

3.2 数据库脚本执行的“三步确认法”

rjsql.sql看似简单,但导入过程极易失败。我总结出一套“三步确认法”,确保万无一失:

第一步:确认MySQL服务已启动且端口开放
在命令行执行:

netstat -ano | findstr :3306

若无输出,说明MySQL服务未运行。去Windows服务管理器(services.msc)找到MySQL服务,右键“启动”。注意:有些学生装的是MariaDB或XAMPP,其服务名可能叫mariadbmysql57,需对应查找。

第二步:确认MySQL root用户密码为空(或按配置.txt填写)
环境配置.txt明确写着:“数据库用户名:root;密码:(留空)”。但很多学生本地MySQL设置了密码。此时有两种选择:
- 方案A(推荐):重置root密码。以管理员身份运行CMD,进入MySQLbin目录,执行:
bash mysqld --skip-grant-tables
此时另开一个CMD,执行mysql -u root直接登录,然后:
sql USE mysql; UPDATE user SET password=PASSWORD('') WHERE User='root'; FLUSH PRIVILEGES;
- 方案B:修改rjsql.sql。在CREATE DATABASE语句前,加上SET PASSWORD FOR 'root'@'localhost' = PASSWORD('');(仅限MySQL 5.7以下)。

第三步:使用命令行导入(绕过图形界面编码陷阱)
千万别用phpMyAdmin或Navicat的“导入”按钮,它们对SQL文件编码识别常出错。正确姿势是:

mysql -u root -p < rjsql.sql

回车后输入密码(若为空则直接回车)。如果提示ERROR 1064,大概率是SQL文件开头有BOM头。用Notepad++打开rjsql.sql,点击“编码”→“转为UTF-8无BOM格式”,再保存重试。

注意:rjsql.sqlCREATE DATABASE rjmed语句,会强制创建名为rjmed的数据库。如果你本地已有同名库且含重要数据,请先备份或改名。教学场景下,建议直接删掉旧库:DROP DATABASE rjmed;,再执行导入。

3.3 源码结构中的“教学彩蛋”

源代码/目录下的文件组织,处处体现教学引导:

  • WEB-INF/web.xml的欢迎页配置
    xml <welcome-file-list> <welcome-file>login.jsp</welcome-file> </welcome-file-list>
    这行配置意味着,访问http://localhost:8080/rjmed/会自动跳转到login.jsp,而不是显示Tomcat默认的404页面。学生第一次访问时,看到的是熟悉的登录框,而不是冰冷的错误页,心理门槛瞬间降低。

  • jsp/login.jsp的表单action指向
    ```html

    ``` 注意,`action`值是`LoginServlet`,而非`LoginServlet.java`或`LoginServlet.do`。这是因为`web.xml`里已注册: ```xml LoginServlet com.rjmed.servlet.LoginServlet LoginServlet /LoginServlet ``` 这种“URL映射”机制,是Servlet的核心概念。学生修改` `为`/login`,前端表单action就得同步改成`login`,否则404。这个联动关系,就是最好的URL路由教学案例。 - **`com/rjmed/servlet/DrugListServlet.java` 的分页逻辑**: 方法末尾有注释:`// TODO:此处应加入分页参数pageNo, pageSize,当前为全量查询`。这是一个典型的“留作业式注释”。它不提供现成的PageHelper工具,而是让学生自己实现:从`request.getParameter("pageNo")`取参数,用`LIMIT offset, size`拼SQL,再计算总页数。这种“半成品”设计,比直接给一个完美的分页组件,更能激发动手欲。 ## 4. 实操过程与核心环节实现:从零开始跑通全流程 ### 4.1 环境准备:三分钟搭建纯净实验台 我们假设一台全新的Windows 7/10电脑,未安装任何Java或MySQL。以下是严格按顺序的操作清单,每一步都有明确目的: 1. **安装JDK 1.6(必须!)** 下载地址:Oracle官网历史版本(搜索`jdk-6u45-windows-i586.exe`)。安装时取消勾选“安装Java SE Development Kit 6 Update 45”旁边的“安装公共JRE”,因为我们只需要JDK。安装完成后,设置系统环境变量: - `JAVA_HOME = C:\Program Files\Java\jdk1.6.0_45` - `PATH = %JAVA_HOME%\bin;%PATH%` > 验证:CMD中执行`java -version`,输出`java version "1.6.0_45"`即成功。若提示“不是内部命令”,检查PATH是否漏掉`%JAVA_HOME%\bin`。 2. **安装MySQL 5.1(兼容性最佳)** 下载`mysql-5.1.73-win32.zip`,解压到`C:\mysql`。创建`my.ini`配置文件: ```ini [mysqld] basedir=C:/mysql datadir=C:/mysql/data port=3306 character-set-server=utf8 [client] default-character-set=utf8 ``` 以管理员身份运行CMD,进入`C:\mysql\bin`,执行: ```bash mysqld --install MySQL51 --defaults-file=C:\mysql\my.ini net start MySQL51 ``` > 此时MySQL服务已启动,root密码为空。 3. **解压并启动定制Tomcat** 解压`apache-tomcat-6.0.18_rjmed.rar`到`D:\tomcat`(路径不含中文和空格!)。双击`D:\tomcat\apache-tomcat-6.0.18\bin\startup.bat`。等待命令行出现`Server startup in XXX ms`,打开浏览器访问`http://localhost:8080`,看到Tomcat欢迎页即成功。 ### 4.2 数据库初始化:五步导入rjsql.sql 1. **确认MySQL服务运行**:任务管理器→服务→查看`MySQL51`状态为“正在运行”。 2. **打开命令行,进入MySQL bin目录**: ```bash cd C:\mysql\bin ``` 3. **登录MySQL**: ```bash mysql -u root -p ``` 密码直接回车(为空)。 4. **执行SQL脚本**: 在MySQL命令行中,输入: ```sql source D:\path\to\rjsql.sql; ``` (将`D:\path\to\`替换为你存放`rjsql.sql`的实际路径) 5. **验证导入结果**: ```sql USE rjmed; SHOW TABLES; SELECT * FROM drug_info; ``` 应看到`drug_info`、`inventory_log`等表名,并查出“阿司匹林”等初始数据。 ### 4.3 项目部署与首次访问:见证第一个药品入库 1. **部署rjmed应用**: 将压缩包内的`rjmed/`文件夹,完整复制到`D:\tomcat\apache-tomcat-6.0.18\webapps\`下。此时`webapps`目录结构应为: ``` webapps/ ├── rjmed/ ← 我们部署的应用 ├── docs/ └── ... ``` 2. **重启Tomcat**: 先运行`shutdown.bat`关闭,再运行`startup.bat`启动。Tomcat会在启动日志中打印: `INFO: Deploying web application directory rjmed` 表明应用已成功加载。 3. **访问登录页**: 浏览器打开`http://localhost:8080/rjmed/login.jsp`。输入默认账号密码(`环境配置.txt`中注明:用户名`admin`,密码`123456`),点击登录。 4. **执行药品录入**: 登录后进入首页,点击“药品管理”→“添加药品”。在表单中填写: - 药品名称:`连花清瘟胶囊` - 类别:`中成药` - 库存数量:`50` - 单价:`32.00` 点击“提交”。页面跳转回药品列表,新药品赫然在列,库存为50。 5. **验证数据库写入**: 回到MySQL命令行: ```sql USE rjmed; SELECT * FROM drug_info WHERE name='连花清瘟胶囊'; SELECT * FROM inventory_log WHERE drug_id=(SELECT id FROM drug_info WHERE name='连花清瘟胶囊'); ``` 你会看到`drug_info`表中新增一条记录,`inventory_log`表中对应一条`operation_type='IN'`的入库日志。这一刻,HTTP请求、Servlet处理、JDBC写库、事务提交,整条链路被你亲手点亮。 ### 4.4 源码二次开发:修改登录验证逻辑实战 假设教学要求:将密码校验从明文比对改为MD5加密存储。我们以`LoginServlet.java`为入口,进行最小化改造: 1. **修改数据库密码**: 在MySQL中执行: ```sql UPDATE user_info SET password=MD5('123456') WHERE username='admin'; ``` (`user_info`表结构在`rjsql.sql`中有定义) 2. **修改LoginServlet的校验逻辑**: 打开`源代码/com/rjmed/servlet/LoginServlet.java`,定位到`checkLogin()`方法。原始代码是: ```java String dbPassword = rs.getString("password"); if (inputPassword.equals(dbPassword)) { // 明文比对 ``` 改为: ```java import java.security.MessageDigest; // ... 在方法内添加 String inputMd5 = toMD5(inputPassword); if (inputMd5.equals(dbPassword)) { // MD5比对 ``` 并在类中添加工具方法: ```java private String toMD5(String str) { try { MessageDigest md = MessageDigest.getInstance("MD5"); byte[] digest = md.digest(str.getBytes("UTF-8")); StringBuilder sb = new StringBuilder(); for (byte b : digest) { sb.append(String.format("%02x", b)); } return sb.toString(); } catch (Exception e) { return ""; } } ``` 3. **重新编译并部署**: - 用`javac`编译: ```bash cd 源代码 javac -cp ".;WEB-INF/lib/mysql-connector-java-5.1.7-bin.jar" com/rjmed/servlet/LoginServlet.java ``` - 将生成的`LoginServlet.class`复制到`rjmed/WEB-INF/classes/com/rjmed/servlet/`下(覆盖原文件)。 - 重启Tomcat,用原密码`123456`登录,应能成功。 > 实操心得:这个改造过程暴露了传统Java Web开发的典型工作流——改代码→编译→复制class→重启服务器。虽然繁琐,但每一步都清晰可见,没有框架的魔法遮蔽。学生能深刻体会到“编译”、“类路径”、“热部署”这些概念的物理意义,这正是Spring Boot的自动配置所隐藏的底层真相。 ## 5. 常见问题与排查技巧实录:那些年我们一起踩过的坑 ### 5.1 启动失败类问题速查表 | 现象 | 可能原因 | 排查步骤 | 解决方案 | |------|----------|----------|----------| | 双击`startup.bat`后窗口一闪而过 | `JAVA_HOME`未设置或路径错误 | CMD中执行`echo %JAVA_HOME%`,看是否输出正确路径 | 检查环境变量,确保`JAVA_HOME`指向JDK根目录(非JRE),且`PATH`包含`%JAVA_HOME%\bin` | | 启动日志显示`SEVERE: Error listenerStart` | `web.xml`语法错误或`context.xml`中JNDI配置无效 | 检查`rjmed/WEB-INF/web.xml`是否有未闭合标签;检查`conf/context.xml`中` `标签是否完整 | 用XML校验工具(如Notepad++的XML Tools插件)验证文件格式;删除`conf/context.xml`中自定义的` `(本项目未使用JNDI) | | 访问`http://localhost:8080/rjmed/login.jsp`报404 | `rjmed`文件夹未放在`webapps`下,或文件夹名大小写错误 | 进入`webapps`目录,确认存在`rjmed`文件夹(非`RJMED`或`rjMed`);检查Tomcat日志`logs/catalina.out`中是否有`Deploying web application directory rjmed` | 确保文件夹名完全一致;若日志无部署记录,检查`rjmed`目录下是否有`WEB-INF/web.xml`文件(缺失则Tomcat不识别为Web应用) | | 登录时报`java.lang.ClassNotFoundException: com.mysql.jdbc.Driver` | MySQL驱动jar包未放入`lib`目录 | 检查`rjmed/WEB-INF/lib/`下是否存在`mysql-connector-java-5.1.7-bin.jar` | 将驱动jar包复制到`rjmed/WEB-INF/lib/`,重启Tomcat | ### 5.2 功能异常类问题深度解析 **问题:药品列表页显示中文乱码(如“阿司匹林”显示为“????”)** - **根源分析**:这是典型的字符集断层问题。链条上有三处需UTF-8:MySQL数据库、JDBC连接URL、JSP页面编码。任一环断裂都会导致乱码。 - **排查路径**: 1. 查MySQL:`SHOW CREATE DATABASE rjmed;` 确认`DEFAULT CHARACTER SET utf8`; 2. 查JDBC URL:`源代码/WEB-INF/classes/jdbc.properties`中`url=jdbc:mysql://localhost:3306/rjmed?useUnicode=true&characterEncoding=UTF-8`; 3. 查JSP:`login.jsp`顶部是否有`<%@ page contentType="text/html;charset=UTF-8" %>`。 - **终极解决方案**:三者必须同时满足。若仍乱码,检查Tomcat的`conf/server.xml`中`Connector`节点是否有`URIEncoding="UTF-8"`(本定制版已配置,但若你修改过则需确认)。 **问题:添加药品后,列表页不刷新,需手动F5才显示** - **现象还原**:`DrugAddServlet`执行完`response.sendRedirect("drug_list.jsp")`,但浏览器地址栏变为`http://localhost:8080/rjmed/drug_list.jsp`,页面空白或404。 - **原因定位**:`drug_list.jsp`文件实际位于`rjmed/jsp/drug_list.jsp`,而重定向路径写死了`drug_list.jsp`,Tomcat在`rjmed/`根目录下找,找不到。 - **修复方法**:打开`DrugAddServlet.java`,将`response.sendRedirect("drug_list.jsp");`改为`response.sendRedirect("jsp/drug_list.jsp");`。或者,更规范的做法是在`web.xml`中配置` `,让`drug_list.jsp`成为欢迎页,重定向到`/`即可。 **问题:库存更新功能失效,点击“出库”按钮无反应** - **线索挖掘**:查看浏览器开发者工具(F12)的Network标签,发现点击按钮后,向`/rjmed/InventoryOutServlet`发起POST请求,但返回500错误。 - **日志追踪**:打开`logs/catalina.out`,搜索`InventoryOutServlet`,发现异常:`java.lang.NumberFormatException: For input string: ""`。 - **代码溯源**:`InventoryOutServlet.java`中`request.getParameter("quantity")`返回空字符串,`Integer.parseInt("")`抛出异常。 - **健壮性修复**:在解析前加判空: ```java String qtyStr = request.getParameter("quantity"); if (qtyStr == null || qtyStr.trim().isEmpty()) { request.setAttribute("error", "请输入出库数量"); request.getRequestDispatcher("jsp/inventory_out.jsp").forward(request, response); return; } int quantity = Integer.parseInt(qtyStr); ``` ### 5.3 教学扩展建议:让项目活起来的三个小技巧 1. **添加操作日志实时查看功能**: 在`rjmed/jsp/`下新建`log_view.jsp`,用` `遍历`inventory_log`表数据,展示最近20条操作记录。关键代码: ```jsp SELECT i.id, d.name as drug_name, i.operation_type, i.quantity, i.operator, i.operate_time FROM inventory_log i JOIN drug_info d ON i.drug_id=d.id ORDER BY i.operate_time DESC LIMIT 20 ``` 这样学生能直观看到每一次“入库”、“出库”如何改变数据库,理解业务动作与数据变更的因果关系。 2. **实现库存预警提示**: 修改`drug_list.jsp`,在每行药品数据后添加: ```jsp[库存不足!]``` 这个简单的EL表达式,让学生第一次接触MVC中的View层逻辑,理解“数据驱动UI”的基本思想。 3. **集成简易图表(无需ECharts)**: 利用HTML5 ``,在`index.jsp`中绘制库存柱状图。用JSTL从`drug_info`表查出前5种药品名称和库存,生成JavaScript数组: ```jsp ``` 再用Canvas API绘图。虽简陋,但能让学生看到“数据可视化”的第一缕光,远胜于空谈理论。 ## 6. 个人经验体会:为什么我至今还在用这个“老项目”带学生 在我第七次打开`rjsql.sql`,看着里面那行`INSERT INTO drug_info VALUES (1,'阿司匹林','解热镇痛',100,20.50);`时,突然意识到这个项目的真正生命力,不在于它多先进,而在于它多“诚实”。它不掩饰JDBC的繁琐,不隐藏web.xml的冗长,不粉饰SQL注入的风险(`DrugAddServlet`里直接拼接SQL,正是为了让学生亲手写出`PreparedStatement`来修复它)。这种“不完美”,恰恰是教学最珍贵的土壤。 我见过太多学生,拿着Spring Boot项目,`application.yml`里一行`spring.datasource.url`配好,`@RestController`写完,功能就跑通了。他们知道“能用”,但不知道“为什么能用”。而在这个Tomcat 6的药品系统里,当学生为了解决`ClassNotFoundException`而去翻`CLASSPATH`文档,为了解决乱码而去查MySQL字符集手册,为了修复SQL注入而去学习`PreparedStatement`,他们获得的不是某个框架的API,而是**软件工程的通用肌肉记忆**——如何定位问题、如何阅读日志、如何验证假设、如何最小化修改。这些能力,不会随着Tomcat版本迭代而过时。 所以,当我把`apache-tomcat-6.0.18_rjmed.rar`发给新生时,我其实是在递给他们一把生锈但锋利的刀。它割不开云原生的硬壳,但它能精准剖开Web开发最基础的肌理:HTTP协议、Servlet生命周期、JDBC驱动加载、MVC分层边界。而真正的工程师成长,从来不是从云端起步,而是从亲手拧紧每一颗螺丝开始。这个项目不会教你如何写高并发秒杀,但它会确保你第一次写CRUD时,心里有底——因为你知道,那行`response.sendRedirect("success.jsp")`背后,是Tomcat如何解析URL、如何查找Servlet、如何转发请求的完整故事。这就够了。

    本文还有配套的精品资源,点击获取

    简介:直接解压就能跑的Java Web药品管理项目,内置Apache Tomcat 6.0.18定制版(apache-tomcat-6.0.18_rjmed.rar),免安装配置;附带rjsql.sql数据库脚本,导入即生成药品信息表、库存表等全部结构和初始数据;源码放在‘源代码’和‘codes’目录下,包含标准JSP页面、Servlet控制层、DAO数据访问层及web.xml、context.xml等配置文件;‘环境配置.txt’明确列出JDBC连接地址、账号密码、项目部署路径(如rjmed)、上下文根路径等关键参数,方便快速调试;系统支持药品增删改查、库存状态查看与更新,适用于高校课程设计、毕业实训或小型药房日常管理场景。

    本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询