JSP进销存管理系统部署与增删改查实战:从压缩包到可运行 简介这份资源是一套基于JSP技术栈的进销存管理系统完整源码包面向学习Java Web开发的学生、课程设计者及需要参考企业级业务逻辑的开发者。系统覆盖进货、库存、销售三大核心环节用计算机全程管理替代手工操作解决商品种类繁多、业务量大、库存管理复杂带来的效率低与易出错问题适合作为毕业设计或实训项目的参考方案。压缩包共183个文件约6.68MB以77个jsp页面为主体配合12个java源文件与12个class字节码、6个jar依赖包另有26个txt说明、4个xml配置及图片、数据库文件等结构完整、层次清晰。目前已有245人学习下载。读者可从中获得可直接运行的进销存系统源码、配套数据库文件与项目文档理解商品信息、供应商、客户等实体类的设计思路掌握JSP页面与后台逻辑的协作方式并借助现成目录结构快速搭建环境、对照调试为二次开发或课程答辩提供扎实基础。1. 拿到一份 jsp 进销存管理系统压缩包先别急着双击运行很多人第一次接触 jsp 进销存管理系统是在课程设计、毕业设计或者小公司内部工具选型的场景里。压缩包名字通常长这样源码、数据库脚本、配套文档三件套齐全看起来“开箱即用”。但真正解压之后十有八九会卡在三个地方JDK 版本对不上、Tomcat 跑不起来、数据库连不上。这不是你水平问题而是这类老派 JSP 项目本身就带着强烈的时代印记——它默认你懂 Servlet 容器、懂 JDBC、懂 MySQL 字符集而不是像 Spring Boot 那样一个java -jar就完事。这篇笔记要解决的就是这件事把一份 jsp 进销存管理系统从“压缩包”变成“本地能登录、能开单、能查库存”的可运行系统并且把数据库增删改查这条主线讲透。适合两类人一是被课程设计逼到墙角、需要快速跑通的学生二是想拿它当二次开发底座、做小型仓库或门店管理工具的开发者。中间会涉及源码结构、数据库脚本导入、Tomcat 部署、常见报错排查以及后续怎么把它改造成自己能用的东西。不吹“企业级”只讲能复现的路径。2. 拆开压缩包jsp 进销存管理系统的目录结构与技术栈判断2.1 先看目录再决定用什么 JDK 和 Tomcat解压之后不要急着导入 IDE先用文件管理器把顶层目录看一遍。典型的 jsp 进销存管理系统源码目录大致长这样jsp-inventory/ ├── src/ # Java 源码按包名分层 │ └── com/xxx/inventory/ │ ├── dao/ # 数据库访问层JDBC 裸写居多 │ ├── entity/ # 实体类和数据库表一一对应 │ ├── servlet/ # 控制器处理表单和跳转 │ └── util/ # DBUtil、字符集工具等 ├── WebContent/ 或 web/ # JSP 页面和静态资源 │ ├── WEB-INF/ │ │ ├── web.xml # Servlet 映射、欢迎页 │ │ └── lib/ # 第三方 jar重点看 mysql-connector │ ├── login.jsp │ ├── product/ │ ├── stock/ │ └── order/ ├── sql/ # 数据库脚本 │ └── inventory.sql └── 文档/ # 需求说明、ER 图、使用手册看到WebContent还是web基本能判断项目年代WebContent是 Eclipse 动态 Web 项目的默认目录web更多出现在 Maven 或 IDEA 项目里。这一步的判断直接决定你后面用哪种方式部署。技术栈判断看三个文件就够了WEB-INF/lib下的mysql-connector-java-x.x.x.jar决定数据库驱动版本web.xml的version属性决定 Servlet 规范版本src里有没有WebServlet注解决定它是 Servlet 3.0 还是纯 XML 配置。常见组合是 Servlet 3.0 JDK 1.8 MySQL 5.7这个组合在 Tomcat 8.5 上最稳。提示如果lib里是mysql-connector-java-5.1.x数据库就用 MySQL 5.7如果是8.0.x驱动类名要从com.mysql.jdbc.Driver改成com.mysql.cj.jdbc.DriverURL 还要加时区和 SSL 参数。这一步搞错后面必报ClassNotFoundException。2.2 数据库脚本先读再导别直接 sourcesql/inventory.sql不要上来就source。先用文本编辑器打开重点看四件事建库语句的字符集、表引擎、外键约束、初始账号密码。-- 典型开头 CREATE DATABASE IF NOT EXISTS inventory DEFAULT CHARACTER SET utf8; USE inventory; CREATE TABLE user ( id int(11) NOT NULL AUTO_INCREMENT, username varchar(50) NOT NULL, password varchar(50) NOT NULL, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8; INSERT INTO user VALUES (1,admin,123456);如果脚本里写的是utf8而不是utf8mb4在 MySQL 8.0 上一般也能跑但涉及 emoji 或特殊符号会出问题。更常见的是脚本里没有SET NAMES utf8;导入后中文变成问号。稳妥做法是在导入前手动指定字符集mysql -uroot -p --default-character-setutf8 inventory.sql导入完成后用一条查询验证中文是否正常SELECT username FROM user;如果显示??或乱码说明客户端字符集和库字符集不一致需要检查my.ini或my.cnf里的character-set-server。这一步是后面所有增删改查的基础字符集不对后面全是玄学问题。2.3 用 IDEA 还是 Eclipse取决于你要不要改代码如果只是跑起来看效果Eclipse Tomcat 插件最省事因为老项目目录结构天然适配。如果要二次开发建议用 IDEA 新建 Java Web 项目把src和WebContent分别映射到src/main/java和src/main/webapp再补一个pom.xml把lib下的 jar 变成 Maven 依赖。这样后面加新功能、换数据库、打 war 包都顺。不改代码只跑通的话Eclipse 里File - Import - Existing Projects into Workspace选中解压目录然后配置 Tomcat 运行时把项目加到服务器启动即可。启动后访问http://localhost:8080/项目名/login.jsp。如果 404先看web.xml里的welcome-file-list再看项目上下文路径是不是被改了。3. 把 jsp 进销存管理系统跑起来Tomcat 部署与数据库连接的最小闭环3.1 配置 DBUtilJDBC 连接的四个必调参数JSP 进销存管理系统的数据库连接通常封装在util/DBUtil.java或dao/BaseDao.java里。找到这段代码public class DBUtil { private static final String DRIVER com.mysql.jdbc.Driver; private static final String URL jdbc:mysql://localhost:3306/inventory?useUnicodetruecharacterEncodingutf8; private static final String USER root; private static final String PASSWORD root; public static Connection getConnection() throws Exception { Class.forName(DRIVER); return DriverManager.getConnection(URL, USER, PASSWORD); } }四个参数逐个说清楚。DRIVER对应lib下的驱动 jarMySQL 5.x 用com.mysql.jdbc.DriverMySQL 8.x 用com.mysql.cj.jdbc.Driver。URL里的useUnicodetruecharacterEncodingutf8是中文不乱码的关键缺一不可。USER和PASSWORD换成你本地 MySQL 的实际账号。如果 MySQL 8.0URL 还要补serverTimezoneAsia/ShanghaiuseSSLfalse否则启动时报时区错误。改完不要急着启动 Tomcat先写一个main方法单独测连接public static void main(String[] args) { try (Connection conn getConnection()) { System.out.println(连接成功 conn); } catch (Exception e) { e.printStackTrace(); } }这一步能把“数据库问题”和“Web 容器问题”彻底分开。连接成功再启动 Tomcat能省掉大量排查时间。3.2 部署到 Tomcatwar 包和 exploded 模式的区别Eclipse 里把项目添加到 Tomcat 后默认是 exploded 模式也就是直接把WebContent目录发布到wtpwebapps下。这种模式改 JSP 不用重启改 Java 代码需要重启。IDEA 里则通常打 war 包再部署。不管哪种方式启动后先看控制台有没有Server startup in xxx ms。如果没有看异常栈。最常见的三类第一类ClassNotFoundException: com.mysql.jdbc.Driver说明驱动 jar 没进WEB-INF/lib或者没被加到 classpath。第二类Access denied for user rootlocalhost账号密码错或者 MySQL 没授权远程。第三类Table inventory.user doesnt exist数据库脚本没导入或者库名不对。启动成功后浏览器访问登录页。用脚本里的初始账号登录进去后先点一遍菜单商品管理、供应商管理、库存查询、销售开单。每个页面都点开看有没有 500 错误。这一步是后面做增删改查改造的基线。3.3 用一条 SQL 验证数据库增删改查链路在改代码之前先用 SQL 客户端把核心表的增删改查跑一遍确认数据库层面没问题。以商品表为例-- 增 INSERT INTO product (name, price, stock, category_id) VALUES (测试商品, 19.90, 100, 1); -- 查 SELECT id, name, price, stock FROM product WHERE name 测试商品; -- 改 UPDATE product SET stock stock - 1 WHERE id 1; -- 删 DELETE FROM product WHERE id 1;这四条语句对应 JSP 页面里的四个操作。如果 SQL 层面正常页面报错就一定是 Java 代码或 JSP 传参问题。如果 SQL 层面就报错先解决数据库别碰代码。这个顺序能避免“改了三天代码发现是数据库没导入”的血泪经验。4. 读懂 jsp 进销存管理系统的增删改查代码从 JSP 表单到 JDBC 的完整链路4.1 一个商品新增功能拆成四层来看以“新增商品”为例完整链路是product_add.jsp表单提交 →ProductServlet接收参数 →ProductDao.insert()执行 SQL → 返回列表页。每一层都有容易翻车的地方。JSP 表单form actionProductServlet?methodadd methodpost 商品名称input typetext namename /br/ 单价input typetext nameprice /br/ 库存input typetext namestock /br/ input typesubmit value保存 / /formServletprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding(UTF-8); String method req.getParameter(method); if (add.equals(method)) { String name req.getParameter(name); double price Double.parseDouble(req.getParameter(price)); int stock Integer.parseInt(req.getParameter(stock)); Product p new Product(name, price, stock); new ProductDao().insert(p); resp.sendRedirect(product_list.jsp); } }DAOpublic void insert(Product p) { String sql INSERT INTO product (name, price, stock) VALUES (?, ?, ?); try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { ps.setString(1, p.getName()); ps.setDouble(2, p.getPrice()); ps.setInt(3, p.getStock()); ps.executeUpdate(); } catch (Exception e) { e.printStackTrace(); } }三层里JSP 负责收集Servlet 负责转换和跳转DAO 负责执行。req.setCharacterEncoding(UTF-8)必须放在getParameter之前否则中文参数乱码。PreparedStatement用占位符而不是字符串拼接既防 SQL 注入也避免引号转义问题。sendRedirect用重定向而不是转发避免刷新页面重复提交。4.2 查询列表为什么要分页以及最简单的分页写法商品列表如果全量查出来数据一多页面就卡。JSP 进销存管理系统里常见的分页写法是LIMIT加页码参数SELECT * FROM product ORDER BY id DESC LIMIT ?, ?;第一个问号是偏移量(pageNo - 1) * pageSize第二个是每页条数。Servlet 里接收pageNo默认 1DAO 里计算偏移量。JSP 页面底部渲染上一页、下一页和页码。public ListProduct findByPage(int pageNo, int pageSize) { ListProduct list new ArrayList(); String sql SELECT * FROM product ORDER BY id DESC LIMIT ?, ?; try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { ps.setInt(1, (pageNo - 1) * pageSize); ps.setInt(2, pageSize); ResultSet rs ps.executeQuery(); while (rs.next()) { list.add(new Product(rs.getInt(id), rs.getString(name), rs.getDouble(price), rs.getInt(stock))); } } catch (Exception e) { e.printStackTrace(); } return list; }参数说明pageNo从 1 开始pageSize一般设 10 或 20。如果页码超过总页数查询结果为空页面要显示“暂无数据”而不是报错。总条数用SELECT COUNT(*)单独查一次用来算总页数。4.3 修改和删除主键传参的两种方式和各自坑点修改和删除都依赖主键id。传参方式有两种URL 拼接和表单隐藏域。URL 拼接简单但要注意中文和特殊字符编码隐藏域安全一些但需要多写一个表单。!-- 方式一URL 传参 -- a hrefProductServlet?methodeditid${p.id}编辑/a !-- 方式二隐藏域 -- form actionProductServlet?methoddelete methodpost input typehidden nameid value${p.id} / input typesubmit value删除 onclickreturn confirm(确认删除) / /form删除操作一定要加二次确认否则误点就没了。修改操作要先根据id查出一条记录回填到表单再提交更新。回填时注意value${p.name}里的引号嵌套如果商品名里有双引号页面会崩。稳妥做法是用c:out标签或者对特殊字符做转义。注意删除主表数据前先检查有没有外键引用。比如删除供应商之前要先确认没有商品关联这个供应商否则数据库报外键约束错误。要么先删子表要么用软删除加is_deleted字段。5. 避坑与排查jsp 进销存管理系统最常见的 5 个翻车现场5.1 中文乱码现象、原因、解决现象登录后商品名称显示问号或者新增商品后数据库里是乱码。原因三个环节都可能出问题——JSP 页面pageEncoding、Servlet 请求编码、数据库连接字符集。常见的是 JSP 里写了% page contentTypetext/html;charsetUTF-8 %但没写pageEncodingUTF-8或者 Servlet 里忘了req.setCharacterEncoding(UTF-8)。解决JSP 头部统一写% page contentTypetext/html;charsetUTF-8 pageEncodingUTF-8 %Servlet 第一行写req.setCharacterEncoding(UTF-8)JDBC URL 加useUnicodetruecharacterEncodingutf8数据库和表都用utf8。四处都对齐乱码基本消失。5.2 数据库连接池耗尽现象、原因、解决现象系统用一会儿就报Too many connections或者页面一直转圈。原因DAO 里每次操作都DriverManager.getConnection()用完没有close()。JSP 进销存管理系统源码里这种情况非常普遍因为写起来简单。解决把所有Connection、PreparedStatement、ResultSet都放进 try-with-resources确保自动关闭。如果并发量稍大引入 Druid 或 C3P0 连接池把DBUtil改成从池里取连接。改完之后用SHOW PROCESSLIST观察连接数是否稳定。5.3 Tomcat 启动报 404现象、原因、解决现象Tomcat 启动成功但访问login.jsp显示 404。原因项目上下文路径不对或者web.xml里welcome-file配置的页面不存在或者 JSP 放在WEB-INF下直接访问被禁止。解决先看 Tomcat 控制台发布的路径通常是/项目名。如果项目名带中文或空格改成英文。WEB-INF下的 JSP 不能直接访问必须通过 Servlet 转发。检查web.xml的url-pattern是否和表单action一致。5.4 修改代码不生效现象、原因、解决现象改了 Java 代码重启 Tomcat 后还是旧逻辑。原因Eclipse 的 exploded 模式有时不会重新编译或者classes目录下还是旧 class 文件。IDEA 的 war 包模式如果没重新打包也会这样。解决Eclipse 里Project - Clean然后确认build/classes下有新 class。IDEA 里Build - Rebuild Project再重新部署 war。最稳妥是每次改完 Java 代码都执行一次 clean rebuild别偷懒。5.5 初始密码不对现象、原因、解决现象用文档里写的admin/123456登录失败。原因数据库脚本里的密码是明文但登录代码里做了 MD5 加密比对或者脚本导入时INSERT失败user表是空的。解决先SELECT * FROM user;看有没有数据。如果有数据但登录失败看登录 Servlet 里密码比对逻辑是明文还是 MD5。如果是 MD5把数据库里的密码改成对应哈希值或者临时把比对逻辑改成明文登录后再改回来。6. 从能跑到好用jsp 进销存管理系统的二次开发切入点跑通之后真正有价值的是把它改成自己能用的东西。我一般会从三个地方下手按优先级排第一把DBUtil换成连接池这是稳定性的地基第二给所有列表加分页和搜索这是可用性的门槛第三把库存扣减做成事务这是数据准确性的底线。库存扣减的事务写法值得单独说。销售开单时要同时插入订单明细和更新商品库存两步必须在一个事务里Connection conn null; try { conn DBUtil.getConnection(); conn.setAutoCommit(false); // 插入订单 String orderSql INSERT INTO orders (product_id, quantity, total) VALUES (?, ?, ?); PreparedStatement ps1 conn.prepareStatement(orderSql); ps1.setInt(1, productId); ps1.setInt(2, quantity); ps1.setDouble(3, total); ps1.executeUpdate(); // 扣减库存 String stockSql UPDATE product SET stock stock - ? WHERE id ? AND stock ?; PreparedStatement ps2 conn.prepareStatement(stockSql); ps2.setInt(1, quantity); ps2.setInt(2, productId); ps2.setInt(3, quantity); int rows ps2.executeUpdate(); if (rows 0) { throw new RuntimeException(库存不足); } conn.commit(); } catch (Exception e) { if (conn ! null) conn.rollback(); e.printStackTrace(); } finally { if (conn ! null) { conn.setAutoCommit(true); conn.close(); } }关键在UPDATE ... WHERE stock ?用数据库层面的条件判断防止超卖比先查再改更可靠。rows 0说明库存不够抛异常触发回滚。这个写法在并发不高的小系统里足够用并发再高就要考虑乐观锁或队列。验证方法也简单开两个浏览器窗口同时用同一个商品下单数量都设成库存的一半多看是否只有一个成功。如果两个都成功说明事务没生效或者隔离级别不对。这个测试能帮你确认库存扣减是不是真的可靠。我自己的习惯是每改一个功能先用 SQL 客户端把对应的增删改查语句跑一遍确认数据库层面没问题再去改 Java 和 JSP。这样出问题时能快速定位是 SQL 写错了还是代码传参错了。另外改之前先备份一份原始压缩包改崩了还能回到起点。希望帮到你。本文还有配套的精品资源点击获取