
简介这份资源面向超市经营者、门店管理人员及信息系统初学者提供一套覆盖商品进货、销售管理、库存统计与订单管理全流程的进销存管理方案并附系统用例图帮助理解员工、顾客、供应商等参与者与各功能模块之间的交互关系适合课程设计、毕业设计参考或小型超市信息化落地。压缩包共103个文件约2.03MB以aspx页面、cs后台代码、jpg与gif界面截图为主辅以css样式、bmp与png图片及mdl数据库模型、mdf与ldf数据库文件构成较完整的Web系统源码与设计素材。已有4380人学习下载。读者可从中获得进货录入与采购订单生成、销售出库与发票处理、库存阈值预警与周转分析、订单状态追踪等模块的实现思路并借助用例图快速梳理系统功能边界与业务流程为开发或优化同类系统提供直接参照。1. 从一张用例图说起超市进销存到底管什么去年帮一个做社区超市的朋友看系统他甩过来一个压缩包说里面有一套进销存管理系统的源码还附了用例图。我打开一看用例图先摆在那儿采购员、收银员、库管、店长四个角色围着商品、库存、销售、供应商几个实体转。很多人拿到这类项目第一反应是直接翻代码我一般反过来先盯着用例图把角色和动作对齐因为进销存这类系统的复杂度不在算法而在业务闭环——进货进来、库存变动、卖出去、账目对得上任何一环断了系统就是摆设。这套超市进销存管理系统面向的就是中小型超市、便利店这类场景核心解决三件事商品档案统一管理、采购入库与销售出库的库存联动、以及按角色划分的操作权限。它适合两类人一类是刚学完 Java Web 或 Python Web 想做完整项目练手的学生另一类是真想给自家小店搭一套能用系统的开发者。用例图在这里不是装饰它是后面所有模块划分的依据谁操作、操作什么、数据往哪流图上一目了然。下面我就按「这系统怎么跑起来、核心模块怎么实现、哪里容易翻车、怎么改成自己的」这条线把这份资源拆开讲。2. 技术栈与目录结构先看清骨架再动手2.1 技术选型与运行环境这类进销存项目主流有两套技术路线一套是 Java 系Spring Boot MyBatis MySQL 前端模板或 Vue一套是 Python 系Flask/Django SQLite/MySQL。从「附用例图、面向教学与二次开发」这个定位看最常见的是 Spring Boot 单体架构前端用 Thymeleaf 或 Layui 这类轻量模板数据库 MySQL 5.7/8.0。我按这套来讲因为它对新手最友好一个 jar 包加一个 SQL 脚本就能跑。运行环境我一般这样配组件版本建议说明JDK8 或 11Spring Boot 2.x 主流搭配Maven3.6依赖管理打包用MySQL5.7 / 8.0字符集统一 utf8mb4IDEIntelliJ IDEA社区版够用前端浏览器即可模板渲染无需 Node提示如果项目里带pom.xml先看java.version和spring-boot-starter-parent的版本JDK 版本对不上是最常见的启动失败原因别急着改代码。2.2 目录结构逐层拆解一个标准的 Spring Boot 进销存项目src/main下大致是这样组织的src/main/java/com/example/supermarket/ ├── controller/ # 接口层商品、库存、采购、销售、用户 ├── service/ # 业务层库存扣减、订单结算等核心逻辑 ├── mapper/ # 持久层MyBatis 接口 ├── entity/ # 实体类与数据库表一一对应 ├── config/ # 配置拦截器、数据源、权限 └── SupermarketApplication.java src/main/resources/ ├── mapper/ # MyBatis XML写 SQL ├── templates/ # 页面模板 ├── static/ # css/js/图片 └── application.yml # 数据库连接、端口controller层只做参数接收和返回封装真正的库存加减、金额计算全在service。我见过不少新手把库存扣减逻辑写在 Controller 里结果并发一上来就超卖这是后面避坑章要重点说的。entity和数据库表严格对应表结构一般在项目根目录的sql/或db/文件夹里导入前先看一眼建表语句里的字段类型尤其是金额字段用decimal(10,2)而不是float这是进销存系统的底线。2.3 数据库初始化与首次启动跑起来的第一步永远是建库导数据。常见做法是项目里带一个supermarket.sql里面既有建表也有初始数据比如默认管理员账号、几条商品分类。# 1. 登录 MySQL 并创建数据库 mysql -u root -p -e CREATE DATABASE supermarket DEFAULT CHARACTER SET utf8mb4; # 2. 导入建表与初始数据脚本 mysql -u root -p supermarket sql/supermarket.sql # 3. 修改 application.yml 里的数据库账号密码 # 4. Maven 打包并启动 mvn clean package -DskipTests java -jar target/supermarket-0.0.1-SNAPSHOT.jar启动后访问http://localhost:8080用脚本里的默认账号登录。如果页面能出来但登录报错八成是初始数据里的密码字段加密方式和代码里的校验逻辑不一致比如库里存的是明文、代码里却用 BCrypt 比对。这种问题不用改代码把库里密码改成代码期望的加密结果即可或者临时把校验逻辑改成明文比对先跑通再回头统一加密方式。3. 核心模块拆解从商品档案到库存联动3.1 商品与分类管理一切数据的起点商品档案是整个系统的地基采购、销售、库存全都挂在商品 ID 上。实体类通常长这样public class Product { private Long id; private String name; // 商品名称 private Long categoryId; // 分类外键 private String barcode; // 条码收银扫码用 private BigDecimal purchasePrice; // 进价 private BigDecimal salePrice; // 售价 private Integer stock; // 当前库存 private Integer warningStock; // 库存预警阈值 private Integer status; // 1上架 0下架 }stock字段直接放在商品表里是最简单的做法适合中小超市如果要做多仓库就得拆出独立的库存表按仓库维度存。warningStock是库存预警的阈值库管登录后首页一般会列出低于这个值的商品这是进销存系统里很实用但常被忽略的功能。商品新增时barcode要做唯一校验否则收银扫码会扫出两条记录这个坑我在实际项目里踩过后面避坑章细说。3.2 采购入库库存增加的唯一入口采购模块的流程是选供应商 → 填采购单多个商品明细→ 提交 → 库存增加 → 生成入库记录。核心在 Service 层的事务处理Service public class PurchaseService { Autowired private PurchaseOrderMapper orderMapper; Autowired private ProductMapper productMapper; Transactional(rollbackFor Exception.class) public void createPurchase(PurchaseOrder order, ListPurchaseItem items) { // 1. 保存采购主单 orderMapper.insert(order); for (PurchaseItem item : items) { item.setOrderId(order.getId()); // 2. 保存明细 orderMapper.insertItem(item); // 3. 库存增加用 SQL 原子更新避免并发覆盖 int rows productMapper.increaseStock(item.getProductId(), item.getQuantity()); if (rows 0) { throw new RuntimeException(商品不存在采购失败); } } } }关键点在Transactional和increaseStock的 SQL。采购单和明细必须在一个事务里任何一条明细失败整单回滚否则会出现「单子建了但库存没加」的脏数据。库存更新不要用「先查再改」的写法直接UPDATE product SET stock stock #{qty} WHERE id #{id}让数据库保证原子性。参数上quantity要做正整数校验负数入库等于变相出库这是业务漏洞。3.3 销售出库与库存扣减并发下的超卖防线销售模块比采购更危险因为收银是高频并发操作。核心逻辑是「先校验库存够不够再扣减」但校验和扣减之间如果有时间差就会超卖。合格的做法是把校验塞进 UPDATE 语句里// ProductMapper.xml 中的扣减 SQL // UPDATE product SET stock stock - #{qty} // WHERE id #{id} AND stock #{qty}Transactional(rollbackFor Exception.class) public void createSale(SaleOrder order, ListSaleItem items) { for (SaleItem item : items) { int rows productMapper.decreaseStock(item.getProductId(), item.getQuantity()); if (rows 0) { // 影响行数为 0说明库存不足或商品不存在 throw new RuntimeException(库存不足 item.getProductId()); } saleMapper.insertItem(item); } saleMapper.insert(order); }WHERE stock #{qty}这一句是防超卖的核心数据库行锁保证同一商品的并发扣减串行执行影响行数为 0 就抛异常回滚。金额计算用BigDecimalsalePrice.multiply(new BigDecimal(qty))绝不能用 double否则收银对账时会出现几分钱的误差日积月累就是一笔糊涂账。销售单还要记录收银员 ID 和销售时间方便后面做日结报表。3.4 用例图与权限控制角色决定能点什么用例图里的四个角色落到代码里就是一套基于拦截器或 Spring Security 的权限控制。简单项目常用「登录后把角色存 Session拦截器判断 URL 前缀」的做法public class AuthInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest req, HttpServletResponse resp, Object handler) { User user (User) req.getSession().getAttribute(loginUser); if (user null) { resp.sendRedirect(/login); return false; } String uri req.getRequestURI(); // 采购相关只允许采购员和店长访问 if (uri.startsWith(/purchase) !PURCHASER.equals(user.getRole()) !MANAGER.equals(user.getRole())) { resp.sendRedirect(/403); return false; } return true; } }这段和用例图是对应的采购员能进采购模块收银员只能进销售和商品查询库管管库存盘点店长看报表。权限粒度粗一点没关系但一定要有否则任何账号都能改库存系统就失去了可信度。二次开发时如果要加角色改拦截器里的判断和数据库角色表即可不用动业务代码。4. 避坑与排查那些跑不通和跑歪了的地方4.1 启动报数据库连接失败现象是启动日志里Communications link failure或Access denied。原因通常是application.yml里的账号密码没改、MySQL 没启动、或者 8.0 版本驱动类名和时区参数没配。解决确认spring.datasource.url带上serverTimezoneAsia/Shanghai驱动用com.mysql.cj.jdbc.Driver先在命令行用同样账号密码连一次库验证。4.2 页面能开但静态资源 404现象是登录页样式全丢、按钮没反应。原因是模板里引用的/static/路径和实际目录不匹配或者项目用了上下文路径server.servlet.context-path而前端写死了根路径。解决看浏览器 Network 面板里 404 的具体 URL对照static目录结构改引用或者把 context-path 去掉先跑通。4.3 库存对不上账现象是采购入库后库存没变或者销售后库存变成负数。原因多半是库存更新没走事务、或者用了「先查再改」的写法在并发下被覆盖。解决检查 Service 方法有没有Transactional库存 SQL 是否用stock stock ± qty的原子写法销售扣减是否带stock qty条件。4.4 条码重复导致收银扫错商品现象是扫码枪扫一个条码系统弹出两个商品让选。原因是商品表barcode没加唯一索引历史数据里重复录入了。解决给barcode加唯一约束导入前先SELECT barcode, COUNT(*) FROM product GROUP BY barcode HAVING COUNT(*) 1查出重复数据人工合并。4.5 金额出现小数误差现象是对账时总金额差几分钱。原因是金额字段用了float/double或者 Java 里用 double 运算。解决数据库字段改decimal(10,2)Java 实体用BigDecimal所有乘加运算走BigDecimal的multiply/add/setScale别偷懒用 double。5. 二次开发把它改成你自己店能用的系统拿到这套源码直接上线大概率不够用因为每家店的业务流程都有差异。我一般从三个方向改第一是加字段比如商品表加「保质期」和「产地」生鲜超市必须要有改法是实体类加属性、Mapper XML 加列、页面表单加输入框三步走完第二是加报表店长最关心的是「今日销售额」「滞销商品 Top10」在service里写聚合查询controller暴露接口前端加个页面即可SQL 用GROUP BY加日期范围条件第三是改权限模型如果店里就老板一个人管所有事可以把拦截器里的角色判断简化成「登录即可访问」省得来回切账号。验证改造是否成功我的习惯是跑一遍完整业务闭环新建商品 → 采购入库 10 件 → 销售 3 件 → 查库存应为 7 → 再销售 8 件应提示库存不足 → 查流水记录是否完整。这条链路走通基本功能就没问题。改库存相关代码时尤其要小心我吃过一次亏为了图快把扣减逻辑改成先查后改测试时单线程没问题一上收银高峰就超卖后来老老实实改回原子 SQL 并加了单元测试。从那以后我每次动库存和金额相关的代码都强制走一遍「并发扣减 对账」的验证不敢省这一步。希望这套拆解能帮你少走点弯路把这份带用例图的进销存系统真正跑成自己能用的东西。本文还有配套的精品资源点击获取