Spring Boot+Vue超市进销存系统:毕业设计完整源码与部署指南
发布时间:2026/9/16 14:33:46来源:尧图网络
简介基于JavaSpring BootVueMySQL的超市进销存系统是一套完整的高分毕业设计项目面向计算机相关专业学生可用于毕业设计、课程设计或期末大作业。系统围绕超市日常运营覆盖商品管理、库存监控、销售管理、采购管理和报表统计等核心功能界面简洁、操作直观并充分考虑系统的稳定性与可扩展性。资源包共480个文件压缩后约17.91MB其中147个Java文件承担后端业务逻辑53个Vue文件组成前端界面161个SVG与多张PNG/JPG用于界面素材SQL脚本完成数据库初始化另有XML/Properties配置、JS逻辑、CSS样式、Maven脚本及文档资料整体结构清晰。项目采用前后端分离开发通过AJAX交互下载后使用IDEA、Navicat等工具即可运行源码、数据库脚本、软件工具与论文相关文档一并包含已经严格调试无需修改即可部署。目前已有55人学习使用适合需要快速搭建可运行项目或参考高分毕设做法的学习者。1. 超市进销存系统一个能直接跑起来的Spring BootVue毕业设计如果你正在找一份“Java Spring Boot Vue MySQL”的完整项目作为毕业设计或课程设计最怕的就是下载下来缺文件、跑不起来、代码结构混乱。这份超市进销存系统源码包恰好避开了这些坑前后端代码齐全附带MySQL数据库脚本和开发工具解压后按照脚本顺序执行就能启动。它不是那种只有增删改查的玩具项目而是覆盖了商品管理、库存监控、销售流、采购订单和报表统计五个核心模块并且采用了前后端分离模式后端用Spring Boot提供RESTful接口前端用Vue Axios做数据交互。对于想学习企业级开发流程的人或者需要快速交付一个可演示系统的学生这份源码的参考价值都很直接。2. 数据库建模与进销存核心表结构设计2.1 业务模块如何映射到数据库表超市进销存系统的业务闭环是“进货—入库—销售—出库—盘点—统计”。在设计表结构时我建议把“商品信息”作为主数据围绕它展开库存流水、销售订单和采购订单。这套源码里的表结构大致分为五类模块核心表关键字段关联关系商品管理productid,name,category_id,price,costcategory_id关联分类表库存管理stockid,product_id,quantity,warning_value与product一对一采购管理purchase_orderid,supplier_id,order_no,status明细表存商品销售管理sale_orderid,customer_name,total_amount,create_time明细表存商品报表统计聚合查询按日/月汇总销售额、毛利依赖销售明细表实际建表时采购和销售需要拆分成主表和明细表否则商品数量无法关联。比如销售单sale_order只需要记录订单总额和客户信息而sale_order_item记录每个商品的单价、数量和小计。这样设计的好处是统计“某段时间内哪个商品卖得好”时直接对明细表做GROUP BY就很高效。2.2 建表脚本中的关键 SQL 片段下载包里附带db_supermarket.sql在 MySQL 5.7 以上版本执行即可。核心的商品表和库存流水表脚本如下CREATE TABLE product ( id int(11) NOT NULL AUTO_INCREMENT, name varchar(100) NOT NULL COMMENT 商品名称, category_id int(11) DEFAULT NULL COMMENT 商品分类ID, price decimal(10,2) NOT NULL COMMENT 销售价, cost decimal(10,2) NOT NULL COMMENT 成本价, status tinyint(1) DEFAULT 1 COMMENT 1上架 0下架, create_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE stock_record ( id int(11) NOT NULL AUTO_INCREMENT, product_id int(11) NOT NULL, change_type tinyint(1) NOT NULL COMMENT 1入库 2出库 3盘点调整, quantity int(11) NOT NULL COMMENT 变动数量正数增加负数减少, before_stock int(11) NOT NULL, after_stock int(11) NOT NULL, remark varchar(255) DEFAULT NULL, create_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_product (product_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;stock_record是库存管理的核心。每次入库或销售出库时先更新商品对应的库存数量再插入一条流水记录。通过before_stock和after_stock可以回溯任意时刻的库存变化这也为后续做报表统计提供了原始数据。注意change_type用tinyint而不是字符串是为了节省空间查询时再通过 Java 枚举翻译成中文。2.3 权限相关的用户表与角色表系统集成登录认证时用户表不能只存一个密码字段。源码里使用sys_user、sys_role、sys_user_role三表关联支持管理员和收银员两种角色。密码存储用的是BCryptPasswordEncoder加密后的哈希值而不是明文。如果你要在面试中讲解这个项目可以强调这一点登录时校验password字段用 Spring Security 的BCryptPasswordEncoder.matches()方法比对而不是简单地equals()。3. Spring Boot 后端接口开发与事务控制3.1 分层结构与核心依赖后端采用标准的 Controller-Service-Mapper 三层架构包结构如下com.supermarket ├── controller # REST API 入口 ├── service # 业务逻辑事务边界 ├── mapper # MyBatis-Plus 的 Mapper 接口 ├── entity # 数据库实体 ├── dto # 前端接收参数对象 ├── config # 安全配置、跨域配置 └── common # 统一返回结果、异常处理pom.xml里引入的关键依赖有spring-boot-starter-web、mybatis-plus-boot-starter、mysql-connector-java和spring-boot-starter-security。其中 MyBatis-Plus 让我省掉了大量 XML 写 SQL 的时间分页查询直接调Page对象即可。对于这个体量的系统用 MyBatis-Plus 比 JPA 更直观因为生成的 SQL 可控且学生更容易向导师解释。3.2 登录认证与 JWT 令牌实现登录接口采用 JWTJSON Web Token无状态认证。用户成功登录后后端签发一个 Token前端在请求头里带上Authorization: Bearer token后端通过拦截器解析用户身份。核心代码如下Service public class UserService { // 注入密码加密器 private final BCryptPasswordEncoder passwordEncoder new BCryptPasswordEncoder(); public String login(String username, String password) { SysUser user userMapper.findByUsername(username); if (user null || !passwordEncoder.matches(password, user.getPassword())) { throw new BusinessException(用户名或密码错误); } // 生成 JWT有效期 24 小时 String token Jwts.builder() .setSubject(user.getUsername()) .claim(role, user.getRoleId()) .setExpiration(new Date(System.currentTimeMillis() 86400000)) .signWith(SignatureAlgorithm.HS512, secretKey) .compact(); return token; } }上述代码里有两个关键点。第一passwordEncoder.matches()是比对明文密码和哈希密码的唯一正确方式千万不能重新加密明文再比对因为 BCrypt 每次生成的盐不同。第二JWT 的secretKey需要放在配置文件里不要硬编码在类中。实际生产环境还会用jjwt或auth0库但原理一致。3.3 进货入库与销售出库的事务边界库存调整必须保证操作前后的一致性。比如销售出库时需要同时完成“插入销售订单”“插入销售明细”“扣减库存”“插入库存流水”四个操作任何一个失败都应该回滚。在 Spring Boot 中直接使用Transactional注解Transactional(rollbackFor Exception.class) public void createSaleOrder(SaleOrderDTO dto) { // 1. 生成销售单计算总金额 SaleOrder saleOrder new SaleOrder(); saleOrder.setCustomerName(dto.getCustomerName()); saleOrder.setCreateTime(new Date()); saleOrderMapper.insert(saleOrder); // 2. 记录销售明细并扣减库存 for (SaleItemDTO item : dto.getItems()) { Product product productMapper.selectById(item.getProductId()); if (product null) { throw new BusinessException(商品不存在); } // 明细记录 SaleOrderItem saleItem new SaleOrderItem(); saleItem.setOrderId(saleOrder.getId()); saleItem.setProductId(product.getId()); saleItem.setPrice(product.getPrice()); saleItem.setQuantity(item.getQuantity()); saleItemMapper.insert(saleItem); // 3. 扣减库存 Stock stock stockMapper.findByProductId(product.getId()); int afterStock stock.getQuantity() - item.getQuantity(); if (afterStock 0) { throw new BusinessException(库存不足 product.getName()); } // 更新库存 stock.setQuantity(afterStock); stockMapper.updateById(stock); // 4. 写入库存流水 stockRecordMapper.insert(buildStockRecord(product.getId(), item.getQuantity(), 2, stock.getQuantity(), 销售出库)); } }这段代码的rollbackFor Exception.class很关键因为 Spring 默认只在 RuntimeException 时回滚而这里自定义的BusinessException通常继承自 RuntimeException所以能触发回滚。如果你在项目里看到Exception没有指定rollbackFor记得追问一句这是很多面试官喜欢挖的地方。3.4 报表统计的 SQL 实现报表模块不需要额外建表可以用聚合查询完成每日销售额和毛利SELECT DATE(create_time) AS report_date, COUNT(*) AS order_count, SUM(total_amount) AS sales_amount, SUM(total_amount - cost_amount) AS gross_profit FROM sale_order WHERE create_time #{startDate} AND create_time #{endDate} GROUP BY DATE(create_time) ORDER BY report_date DESC;这里cost_amount可以在生成销售单时通过商品成本价乘以数量计算好冗余存储在销售主表里。虽然违反三范式但在业务系统里这种冗余能大幅提升查询速度因为报表查询不需要再关联明细表去实时计算成本。4. Vue 前端页面实现与路由传参细节4.1 前端项目结构与运行脚本前端代码在frontend目录下使用 Vue CLI 生成组件结构如下src ├── api # 按模块封装的请求接口 ├── assets ├── components # 公共组件侧边栏、头部、面包屑 ├── router # 路由配置 ├── store # Vuex 状态管理 ├── views # 页面 │ ├── product # 商品管理 │ ├── stock # 库存管理 │ ├── sale # 销售管理 │ └── dashboard # 报表中心 ├── App.vue └── main.js下载包里的IndexMain.vue.bak、IndexHeader.vue.bak这些.bak文件是开发者调试时备份的旧版本。它们不影响运行但建议清理掉避免被后端代码扫描工具误判。真正的前端入口在main.js路由配置在router/index.js。4.2 路由配置中的动态传参商品管理和库存管理页面之间经常需要传递商品ID。Vue 路由传参有两种方式这里使用query方式因为页面刷新后参数不会丢失// 在商品列表页跳转到库存详情 this.$router.push({ path: /stock/detail, query: { productId: row.id, productName: row.name } }); // 库存详情页接收参数 this.$route.query.productIdquery传参适合不敏感且需要可收藏的URL。而如果参数是订单号、用户名这类不适合暴露在地址栏的信息建议用params配合name路由跳转。很多 Vue 面试题会问这两种方式的区别掌握了这个场景就很好答。4.3 Axios 请求封装与后端联调前后端分离开发时跨域问题是第一个坑。后端已经在config里配置了 CORS 策略允许所有来源。前端的api/request.js简单封装如下import axios from axios; const request axios.create({ baseURL: http://localhost:8080/api, timeout: 10000, withCredentials: true }); // 请求拦截器自动在头信息附加 token request.interceptors.request.use(config { const token localStorage.getItem(token); if (token) { config.headers.Authorization Bearer ${token}; } return config; }); // 响应拦截器统一处理 code 和 HTTP 错误 request.interceptors.response.use( response { const res response.data; if (res.code ! 200) { alert(res.msg || 请求失败); return Promise.reject(new Error(res.msg)); } return res.data; }, error { if (error.response.status 401) { this.$router.push(/login); } return Promise.reject(error); } );注意baseURL要与后端配置文件里的server.servlet.context-path保持一致。后端接口前缀是/api所以前端请求写成/product/list拼接后就是http://localhost:8080/api/product/list这样不会出现少一层路径的问题。4.4 商品管理页面的表格与表单联调商品管理视图是典型的“搜索表格 弹窗表单”结构。表格使用el-table表单使用el-dialog嵌套el-form。添加商品时表单数据通过POST请求发送到后端修改时通过PUT请求。关键代码如下el-table :datatableData v-loadingloading el-table-column propname label商品名称 width180/el-table-column el-table-column propprice label销售价/el-table-column el-table-column label操作 template slot-scopescope el-button sizemini clickhandleEdit(scope.row)编辑/el-button el-button sizemini typedanger clickhandleDelete(scope.row)删除/el-button /template /el-table-column /el-tableasync handleEdit(row) { // 打开弹窗之前先回填数据 this.form { ...row }; this.dialogVisible true; }删除操作要提示确认框避免误删。一个实用的做法是删除前先检查该商品是否存在于未完成的采购单或销售单后端对应接口会拦截并返回提示。前端只需要把message展示出来即可。5. 本地部署与运行安装顺序、报错排查和参数调整5.1 三批启动脚本的执行逻辑下载解压后根目录下有1-install.bat、2-run.bat、3-build.bat。它们的执行顺序不能乱# 1-install.bat安装后端依赖并初始化数据库 mvn clean install -DskipTests mysql -uroot -p123456 db_supermarket.sql # 2-run.bat启动后端服务 mvn spring-boot:run # 3-build.bat构建前端并启动开发服务器 cd frontend npm install npm run serve1-install.bat里的mysql命令依赖系统环境变量。如果你没有配置 MySQL 的bin目录到 PATH脚本会报“mysql 不是内部或外部命令”。解决办法是显式指定 MySQL 安装路径例如C:\Program Files\MySQL\MySQL Server 5.7\bin\mysql.exe -uroot -p123456 db_supermarket.sql5.2 最常见的三个启动失败原因第一端口被占用。后端默认使用8080端口前端使用8081。如果启动时提示Web server failed to start. Port 8080 was already in use在application.yml里换一个端口server: port: 9090注意前端request.js里的baseURL也要同步改成http://localhost:9090/api。第二MySQL 连接失败。检查application.yml中的数据库密码是否为123456如果不是统一修改。Spring Boot 2.4 之后spring.datasource.url需要加上serverTimezoneAsia/Shanghai和useSSLfalse否则会报时区错误spring: datasource: url: jdbc:mysql://localhost:3306/supermarket?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghaiuseSSLfalse第三前端 npm 安装依赖卡死。如果npm install速度慢或报错切换到淘宝镜像npm config set registry https://registry.npmmirror.com5.3 让项目在演示时更出彩的小改动这个系统默认的管理员账号是admin密码123456。演示前可以先把部分商品分类的icon字段替换成 emoji 或图片链接前端侧边栏会显示对应图标视觉上比纯文字更专业。再一个技巧是调整库存预警阈值在stock表里把warning_value设为 10然后打开首页的库存预警统计当某个商品库存低于这个值时仪表盘会出现醒目的红色标记这样能直观展示业务流。如果愿意深入一点可以在报表模块加一个导出 Excel 功能。后端用EasyExcel写一个GET /report/export接口前端通过window.open直接下载。这个功能在毕设答辩时属于加分项而且实现成本很低。最后强调一个容易被忽略的点.bak文件是备份不要把它们提交到 Git最好在.gitignore里加上*.bak避免仓库混乱。本文还有配套的精品资源点击获取
网站建设高端定制企业官网