尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

基于JSP的化妆品仓储库存管理系统毕设源码与实现

发布时间:2026/9/29 5:15:05

资讯中心
01
ARTICLE

基于JSP的化妆品仓储库存管理系统毕设源码与实现

基于JSP的化妆品仓储库存管理系统毕设源码与实现
简介这份资源是面向高校计算机相关专业毕业设计场景的完整项目资料围绕基于JSP的化妆品仓储库存管理系统展开采用B/S架构以Java为开发语言、MySQL为后台数据库在MyEclipse平台上完成开发适合正在准备毕设或需要同类进销存案例参考的学生与初级开发者。压缩包共164个文件约5.25MB其中60个jsp页面承担前端交互与业务展示7个java源文件与7个class文件构成后台逻辑配合15个jar依赖包、若干js与css资源以及xml、classpath等工程配置文件整体结构完整、可直接导入运行。系统区分用户与系统管理员两种角色覆盖化妆品店各项信息的登记、修改与查询等日常库存管理操作。资源内含项目完整代码及配套报告便于读者对照需求分析、功能模块划分与数据库设计思路快速理解一个中小型仓储管理系统的实现脉络也可作为二次开发与功能扩展的基础模板。目前已有123人学习关注。1. 化妆品仓储库存管理系统一份能跑通的 JSP 毕设源码到底长什么样如果你正在搜「基于jsp的化妆品仓储库存管理系统 毕业设计」大概率是三种处境之一选题刚定下来导师催着交任务书代码跑不起来MyEclipse 里一堆红叉或者答辩前想找个能讲清楚业务逻辑的完整项目。这份资源就是围绕化妆品仓储这个具体场景用 JSP JavaBean Servlet 搭的一套库存管理 Web 应用开发语言是 JavaIDE 指向 MyEclipse配套文档资料齐全。它解决的不是「从零学 JSP」的问题而是「给你一个业务闭环完整、能编译能部署、能对着讲出所以然」的毕设底稿。化妆品仓储这个场景本身有它的特殊性SKU 多、批次和保质期敏感、出入库频繁比通用的进销存多了一层效期管理。适合计算机毕业设计选题偏 Java Web 方向的同学也适合需要快速理解传统 JSP 项目结构、准备把 war 包丢进 Tomcat 跑一遍的人。2. 技术选型与项目结构为什么是 JSP 而不是 SpringBoot2.1 传统 JSP 分层在毕设场景下的合理性很多人一上来就问现在都 2025 年了为什么毕设还在用 JSP。这个问题在答辩现场被问到的概率不低得先想清楚怎么答。JSP 的本质是 Servlet 的简化写法容器负责把 .jsp 编译成 .java 再编译成 .class请求进来走的是同一套 Servlet 生命周期。对于化妆品仓储库存管理这种业务表不超过十张、并发量几乎为零的毕设项目JSP JavaBean Servlet 的 Model1/Model2 混合模式反而比 SpringBoot 更容易讲清楚「请求从哪来、到哪去、数据怎么落库」。从代码量看一个典型的 JSP 毕设项目结构是这样的CosmeticWMS/ ├── src/ │ ├── com/wms/bean/ # 实体类Product、Inventory、Inbound、Outbound │ ├── com/wms/dao/ # 数据库操作BaseDao、ProductDao、StockDao │ ├── com/wms/servlet/ # 控制器LoginServlet、StockServlet │ └── com/wms/util/ # 工具类DBUtil、PageUtil ├── WebRoot/ │ ├── WEB-INF/ │ │ ├── web.xml # Servlet 映射、过滤器配置 │ │ └── lib/ # mysql-connector-java.jar 等依赖 │ ├── css/ js/ images/ │ ├── index.jsp # 登录页 │ ├── main.jsp # 框架页 │ └── product/ stock/ # 各业务模块 JSP └── .classpath .project # MyEclipse 工程文件这个结构里WEB-INF下的内容浏览器无法直接访问必须通过 Servlet 转发这是 JSP 项目最基本的安全边界。lib目录放 JDBC 驱动MyEclipse 会自动把它加入 Build Path但如果你换到 IDEA 新建 JSP 项目这一步经常翻车——IDEA 默认不把WebRoot/WEB-INF/lib识别为依赖目录需要手动在 Project Structure 里加 Library。2.2 数据库表设计与化妆品效期字段化妆品仓储和普通仓库最大的区别在批次和效期。设计inventory表时除了常规的product_id、quantity、warehouse_id必须加batch_no、production_date、expiry_date三个字段。库存扣减不能只按商品扣要按「商品 批次」扣先进先出FIFO按expiry_date排序出库。CREATE TABLE inventory ( id int(11) NOT NULL AUTO_INCREMENT, product_id int(11) NOT NULL COMMENT 商品ID, batch_no varchar(50) NOT NULL COMMENT 生产批号, quantity int(11) NOT NULL DEFAULT 0 COMMENT 当前库存, expiry_date date NOT NULL COMMENT 到期日期, warn_days int(11) DEFAULT 30 COMMENT 预警天数, PRIMARY KEY (id), KEY idx_product (product_id), KEY idx_expiry (expiry_date) ) ENGINEInnoDB DEFAULT CHARSETutf8;warn_days这个字段是我建议加的默认 30 天查询时用DATEDIFF(expiry_date, CURDATE()) warn_days就能筛出临期品。答辩时老师问「你怎么做效期预警」这一句 SQL 就能答。索引idx_expiry别省库存表数据量虽然小但养成加索引的习惯在答辩里是加分项。2.3 MyEclipse 工程导入与 Tomcat 部署步骤拿到源码包后第一步不是急着改代码而是先把环境跑通。MyEclipse 导入现有项目走File → Import → General → Existing Projects into Workspace选中项目根目录。导入后检查三处JRE 版本是否匹配建议 1.8、Tomcat 是否已配置、web.xml的servlet-class路径是否和实际包名一致。部署时右键项目Run As → MyEclipse Server Application选 Tomcat 7 或 8。如果启动报ClassNotFoundException: com.mysql.jdbc.Driver说明驱动没进WEB-INF/lib如果报 404检查web.xml里url-pattern是不是写成了/LoginServlet而访问时漏了斜杠。数据库连接参数在DBUtil.java里默认jdbc:mysql://localhost:3306/cosmetic_wms?useUnicodetruecharacterEncodingutf8用户名密码改成你本地的。提示MySQL 8 以上版本驱动类名是com.mysql.cj.jdbc.DriverURL 要加serverTimezoneAsia/Shanghai否则连接会报时区错误。这是 JSP 老项目在新环境跑最常见的坑。3. 核心业务模块实现入库、出库与库存扣减3.1 入库单录入与批次库存更新入库的业务逻辑是先插inbound主表记录再根据批次号判断inventory表里是否已有该批次有则累加数量无则新增一条库存记录。这个过程必须放在同一个事务里否则会出现「入库单有了但库存没加」的脏数据。// InboundServlet.java 核心片段 Connection conn null; try { conn DBUtil.getConnection(); conn.setAutoCommit(false); // 开启事务 // 1. 插入入库主表 String sql1 INSERT INTO inbound(product_id, batch_no, quantity, operator, in_time) VALUES(?,?,?,?,NOW()); PreparedStatement ps1 conn.prepareStatement(sql1); ps1.setInt(1, productId); ps1.setString(2, batchNo); ps1.setInt(3, qty); ps1.setString(4, operator); ps1.executeUpdate(); // 2. 查询该批次库存是否存在 String sql2 SELECT id, quantity FROM inventory WHERE product_id? AND batch_no? FOR UPDATE; PreparedStatement ps2 conn.prepareStatement(sql2); ps2.setInt(1, productId); ps2.setString(2, batchNo); ResultSet rs ps2.executeQuery(); if (rs.next()) { // 3a. 存在则累加 int newQty rs.getInt(quantity) qty; String sql3 UPDATE inventory SET quantity? WHERE id?; PreparedStatement ps3 conn.prepareStatement(sql3); ps3.setInt(1, newQty); ps3.setInt(2, rs.getInt(id)); ps3.executeUpdate(); } else { // 3b. 不存在则新增 String sql4 INSERT INTO inventory(product_id, batch_no, quantity, expiry_date) VALUES(?,?,?,?); PreparedStatement ps4 conn.prepareStatement(sql4); ps4.setInt(1, productId); ps4.setString(2, batchNo); ps4.setInt(3, qty); ps4.setDate(4, expiryDate); ps4.executeUpdate(); } conn.commit(); // 提交事务 } catch (Exception e) { if (conn ! null) conn.rollback(); // 回滚 e.printStackTrace(); } finally { DBUtil.close(conn); }FOR UPDATE是行级锁防止两个入库操作同时查到「不存在」然后都去插入导致批次重复。毕设数据量小不加也能跑但答辩时能说出「这里用悲观锁保证批次唯一性」是实打实的加分。setAutoCommit(false)之后所有操作在同一个连接上DBUtil.close里要先setAutoCommit(true)再close否则连接回池时状态是脏的。3.2 出库 FIFO 扣减与库存不足处理出库比入库复杂因为要按效期先进先出。用户下单某个商品 100 件系统要自动从最早到期的批次开始扣扣完一个批次不够再扣下一个。这个逻辑用一条 SQL 做不了得在 Java 层循环。// OutboundServlet.java 出库核心 String sql SELECT id, batch_no, quantity FROM inventory WHERE product_id? AND quantity0 ORDER BY expiry_date ASC; PreparedStatement ps conn.prepareStatement(sql); ps.setInt(1, productId); ResultSet rs ps.executeQuery(); int need outQty; // 需要出库的总数 Listint[] deductList new ArrayList(); // 记录 [inventoryId, 扣减数] while (rs.next() need 0) { int invId rs.getInt(id); int stock rs.getInt(quantity); int deduct Math.min(stock, need); // 本批次扣多少 deductList.add(new int[]{invId, deduct}); need - deduct; } if (need 0) { // 库存不足回滚并提示 conn.rollback(); request.setAttribute(msg, 库存不足缺口 need); request.getRequestDispatcher(/outbound.jsp).forward(request, response); return; } // 执行扣减 for (int[] d : deductList) { String upd UPDATE inventory SET quantityquantity-? WHERE id?; PreparedStatement ps2 conn.prepareStatement(upd); ps2.setInt(1, d[1]); ps2.setInt(2, d[0]); ps2.executeUpdate(); } conn.commit();ORDER BY expiry_date ASC就是 FIFO 的体现。Math.min(stock, need)保证不会超扣。库存不足时先rollback再转发回页面不能先扣了再发现不够。这里有个容易忽略的点deductList是在循环里收集的真正执行扣减要等确认库存够之后避免扣了一半发现不够再回滚——虽然事务能回滚但逻辑上先校验后执行更清晰。3.3 库存预警查询与 JSP 页面渲染预警查询是化妆品仓储的刚需功能。SQL 层面用DATEDIFF算剩余天数JSP 层面用 JSTL 的c:if判断是否标红。!-- warn.jsp 预警列表片段 -- table border1 trth商品/thth批号/thth库存/thth到期日/thth剩余天数/th/tr c:forEach items${warnList} varitem tr td${item.productName}/td td${item.batchNo}/td td${item.quantity}/td td${item.expiryDate}/td td c:choose c:when test${item.remainDays 7} span stylecolor:red;font-weight:bold;${item.remainDays} 天/span /c:when c:when test${item.remainDays 30} span stylecolor:orange;${item.remainDays} 天/span /c:when c:otherwise${item.remainDays} 天/c:otherwise /c:choose /td /tr /c:forEach /tableremainDays在 DAO 层用DATEDIFF(expiry_date, CURDATE())算好塞进 beanJSP 只负责展示。7 天以内红色、30 天以内橙色这个阈值可以做成配置项但毕设里写死也够用。JSTL 标签库记得在页面顶部加% taglib prefixc urihttp://java.sun.com/jsp/jstl/core %并且WEB-INF/lib下要有jstl.jar和standard.jar缺一个就是 500 错误。4. 避坑与排查JSP 毕设跑不起来的那几件事4.1 中文乱码从表单到数据库的三层编码现象入库商品名显示成????或者æ¶²。原因JSP 页面、请求体、数据库连接、表字符集四层编码不一致。解决JSP 顶部% page contentTypetext/html;charsetUTF-8 %Servlet 里request.setCharacterEncoding(UTF-8)必须在第一次getParameter之前调用JDBC URL 加characterEncodingutf8建表用DEFAULT CHARSETutf8。四层缺一层就乱。GET 请求的乱码还要改 Tomcat 的server.xml在 Connector 上加URIEncodingUTF-8。4.2 数据库连接池耗尽Connection 没关的连锁反应现象系统跑一会儿就报Too many connections或者页面卡死。原因DAO 里Connection、PreparedStatement、ResultSet没在finally里关闭每次请求泄漏一个连接。解决统一用DBUtil.close(conn, ps, rs)封装关闭逻辑finally块里按rs → ps → conn顺序关。如果用了连接池比如 DBCPclose是归还不是真关但一样要调。4.3 web.xml 版本与 Servlet 注解冲突现象Servlet 明明写了WebServlet(/login)访问还是 404。原因web.xml的version2.5不支持注解或者metadata-completetrue让容器忽略注解。解决把web.xml升到 3.0 以上或者干脆在web.xml里显式配置servlet和servlet-mapping。MyEclipse 新建项目默认可能是 2.5导入老项目时特别容易撞这个坑。4.4 打包 war 部署到独立 Tomcat 后静态资源 404现象MyEclipse 里跑正常导出 war 丢到 Tomcatwebapps下CSS 和图片全 404。原因JSP 里引用路径写的是相对路径或者用了/CosmeticWMS/css/style.css这种带项目名的绝对路径war 包解压后上下文根变了。解决静态资源引用统一用c:url value/css/style.css/或者${pageContext.request.contextPath}/css/style.css让容器动态拼上下文路径。传统 JSP 项目打包 war 这一步路径问题是最高频的翻车点。注意如果 Tomcat 启动日志里出现SEVERE: Error deploying web application archive先看catalina.out里具体的Caused by九成是web.xml配置错误或者 jar 包冲突不要盲目删依赖。5. 从能跑到能答辩三个让项目经得起追问的技巧第一个技巧是把「库存扣减」的并发问题讲成故事。毕设答辩老师最爱问「两个人同时买最后一件怎么办」。你可以现场打开OutboundServlet指出FOR UPDATE行锁和事务边界然后补一句「如果并发再高可以把锁粒度放到 Redis 分布式锁但毕设场景 InnoDB 行锁够用」。这一句就把边界说清楚了比背概念强。第二个技巧是给效期预警加一个可配置的阈值表。原本warn_days写死在 inventory 表里你可以加一张sys_config表存warn_days_default30DAO 里先查配置再算预警。改动不大但答辩时能说「预警天数支持后台配置不用改代码」这是产品思维的体现。第三个技巧是准备一份「如果重做我会怎么改」的清单。比如把 JDBC 换成 MyBatis、把 JSP 换成 Thymeleaf、把 session 登录换成 JWT。不用真改但被问到「你觉得这个项目有什么不足」时能条理清晰地讲出技术演进路径比说「没什么不足」强太多。# 导出 war 包的命令行方式MyEclipse 里右键 Export 也行 cd /path/to/CosmeticWMS jar -cvf CosmeticWMS.war . # 部署到 Tomcat cp CosmeticWMS.war $CATALINA_HOME/webapps/ # 看启动日志确认部署成功 tail -f $CATALINA_HOME/logs/catalina.out | grep Deployment of web application archivejar -cvf打包时要在项目根目录执行确保WEB-INF在 war 包顶层。部署后访问http://localhost:8080/CosmeticWMS/上下文根就是 war 包文件名。如果改了项目名所有硬编码的路径都要跟着改这也是为什么前面强调用request.getContextPath()。从那以后我每次拿到 JSP 老项目都强制先跑一遍「导入 → 配 Tomcat → 连数据库 → 登录 → 走一遍入库出库」的冒烟流程确认基线能跑再动代码。这份化妆品仓储库存管理系统的源码和文档结构清晰、业务闭环完整拿来当毕设底稿或者 JSP 练手项目都合适。希望帮到你。本文还有配套的精品资源点击获取
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。