Java毕业设计实战:超市进销存系统(SpringBoot+Vue)含可运行源码、数据库脚本与双端部署指南
本文还有配套的精品资源,点击获取
简介:直接上手就能跑的超市进销存管理系统,专为Java课程设计和毕业项目准备。后端用SpringBoot开发,兼容JDK8及以上版本,Maven 3.6+构建,支持Tomcat7/8部署;前端基于Vue实现,界面简洁,操作流程清晰。包里有完整源码(src目录)、pom.xml配置文件、war包打包专用pom-war.xml、IDEA项目配置文件(.classpath/.project等)、Navicat可导入的MySQL 5.7建库建表脚本(springboots5264.sql),还有两份《部署说明.txt》——从环境安装、数据库导入,到前后端分别启动路径都写清楚了:后台地址是localhost:8080/项目名/admin/dist/index.html,前台是localhost:8080/项目名/front/index.html。额外附带LW格式答辩PPT,方便汇报展示。所有Java和Vue代码都带中文注释,本地调试通过,无需二次修改即可一键运行。
1. 项目概述:为什么这个超市进销存系统值得你花两小时认真读完
我带过六届Java方向的毕业设计,每年都会遇到至少二十个学生卡在“选题—搭建—部署—答辩”这条链路上。不是代码写不出来,而是从环境配不起来、数据库连不上、前后端跨域报错,到打包后页面空白、登录跳转404……一套流程走下来,人没毕业,心态先毕设了。直到去年我把这套超市进销存系统从零重跑三遍、补全所有隐性坑点、重写部署逻辑并录下完整调试录像后,才真正把它变成一个“学生拿到就能跑、跑通就能讲、讲完就能过”的闭环方案——它不是教学Demo,而是一个真实可交付的小型业务系统缩影。
关键词里“超市进销存”四个字听着普通,但它恰恰是检验Java工程能力的黄金切口:它必须处理商品多级分类(食品/日化/生鲜)、库存动态扣减(采购入库→销售出库→盘点调账)、角色权限隔离(管理员/仓管员/收银员)、单据生命周期(采购单→入库单→销售单→退货单),还要支撑基础报表(月度销量TOP10、滞销品预警)。这些不是SpringBoot文档里的@RequestBody示例,而是真实业务中会触发事务回滚、并发超卖、时间戳冲突的实战场景。而“SpringBoot+Vue”组合,正是当前企业招聘JD里出现频率最高的技术栈组合之一——它不追求炫技,但要求你真正理解分层架构怎么落地、RESTful接口如何定义、前后端如何协同调试、静态资源路径怎么映射、跨域到底在哪一层解决。
这套资料最硬核的地方在于:它把“能运行”这件事拆解到了原子级。比如你看到pom-war.xml这个文件,它不是摆设——它是为Tomcat传统war包部署专门剥离的Maven配置,和主pom.xml完全解耦;你看到两个《部署说明.txt》,其实一份讲开发机本地调试(前端用npm run serve独立启动,后端mvn spring-boot:run),另一份讲生产环境war包部署(前端dist目录打包容器,后端编译成war丢进Tomcat webapps);你看到springboots5264.sql脚本里建表语句末尾都加了ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci,这不是凑字数,而是为后续可能的emoji商品名(比如“榴莲🥭”)和中文模糊搜索预留编码空间。这些细节,教科书不写,视频教程不讲,但你在答辩现场被老师问“为什么用InnoDB不用MyISAM?”“为什么前端要单独开服务而不是用SpringBoot静态资源映射?”时,就是拉开差距的关键。
如果你是大三下刚学完SSM想过渡到SpringBoot的学生,这套系统能让你第一次亲手把“Controller接收参数→Service调用DAO→Mapper执行SQL→返回JSON给Vue”这条链路从代码走到浏览器;如果你是正在写开题报告的毕业生,它的模块划分(采购管理、库存管理、销售管理、基础资料、系统设置)可以直接作为你论文第三章“系统设计”的骨架;如果你已经卡在部署环节三天,那接下来的内容,就是为你量身写的排障手册——我们不讲原理,只讲你Ctrl+C/V后立刻生效的操作。
2. 整体架构与技术选型逻辑:为什么是SpringBoot+Vue,而不是其他组合
2.1 后端为何锁定SpringBoot而非传统SSM或SpringCloud
很多同学看到“毕设”二字,第一反应是“得用高大上的技术”,于是去搜SpringCloud微服务、Dubbo分布式、甚至K8s容器化。但现实是:你的毕设答辩老师大概率不会追问“Eureka和Nacos注册中心选型差异”,却一定会盯着你application.yml里数据库密码是否明文、登录接口有没有防暴力破解、库存扣减是否用了@Transactional。SpringBoot在这里不是技术噱头,而是工程效率的压舱石。
首先看依赖管理。对比传统SSM项目需要手动引入spring-context、spring-webmvc、mybatis-spring等十余个jar包,还要协调版本兼容性(比如Spring4.3.20和MyBatis3.4.6的组合经常导致@SelectProvider失效),SpringBoot通过spring-boot-starter-web、spring-boot-starter-jdbc等Starter一键整合,底层自动装配DataSource、SqlSessionFactory、RequestMappingHandlerMapping等Bean。我实测过:在JDK8+Maven3.6环境下,mvn dependency:tree | grep spring输出的依赖树深度比SSM项目浅4层,这意味着出问题时排查路径更短——当你遇到NoSuchBeanDefinitionException,SpringBoot的启动日志会明确告诉你“Failed to load ApplicationContext due to missing bean ‘xxxMapper’”,而SSM项目往往只报NullPointerException,你需要翻三遍xml配置才能定位到MapperScannerConfigurer漏写了basePackage。
再看配置简化。传统SSM的web.xml+spring-mvc.xml+spring-dao.xml三件套,光是<context:component-scan>的base-package写错一级目录就会导致Controller不生效。SpringBoot用@SpringBootApplication注解+application.yml统一配置,数据库连接池、日志级别、静态资源路径全部集中管理。特别关键的是server.servlet.context-path配置项——它直接决定了你后面部署时URL路径的根目录。比如设为/supermarket,那么后台管理页地址就是localhost:8080/supermarket/admin/dist/index.html,这和你压缩包里《部署说明.txt》写的路径完全对应。而SSM项目需要在web.xml里配<servlet-mapping>,稍有不慎就会出现“访问404但控制台无报错”的玄学问题。
最后是部署友好性。SpringBoot内嵌Tomcat,mvn spring-boot:run命令一键启动,适合开发调试;同时支持mvn clean package生成可执行jar包,或通过pom-war.xml切换为war包部署到独立Tomcat。这种“开发即部署”的特性,让毕设答辩前的环境复现变得极其简单——你不需要向老师解释“我的项目必须用IDEA启动,因为Tomcat插件配置了特殊参数”。
提示:不要被网上“SpringBoot已过时”的言论误导。截至2024年,国内中小型企业80%以上的Java Web项目仍基于SpringBoot 2.x(对应JDK8),它的稳定性、生态成熟度和学习曲线平缓度,依然是毕设场景的最优解。强行上SpringBoot 3.x(要求JDK17)反而会因Lombok版本冲突、Hibernate Validator弃用等问题增加不必要的调试成本。
2.2 前端为何选择Vue2而非Vue3或React
压缩包里前端代码基于Vue2.6.14(查看package.json中的"vue": "^2.6.14"),这个选择背后有明确的教学考量。Vue2的Options API(data/methods/computed)结构清晰,this.xxx的响应式绑定逻辑直观,非常适合初学者理解“数据驱动视图”的本质。而Vue3的Composition API虽然更灵活,但setup()函数里ref()/reactive()/onMounted()的组合,对没接触过函数式编程的同学来说,容易陷入“为什么变量要包一层ref”“为什么computed要return”的认知混乱。
更重要的是生态兼容性。这套系统的UI组件基于Element UI(查看main.js中import ElementUI from 'element-ui'),这是Vue2时代最成熟的PC端组件库,文档完善、案例丰富、社区问答海量。当你在答辩时被问“这个表格分页怎么实现的?”,你可以直接打开src/views/inventory/StockList.vue,指着<el-pagination>标签和handleSizeChange方法说:“分页参数通过page-size和current-page传给后端,后端用PageHelper插件做物理分页”。而如果换成Vue3的Element Plus,其<el-pagination>的事件名从size-change变成了update:page-size,这种细节差异会让答辩陈述变得支离破碎。
至于为什么不是React?核心在于学习成本错位。React的JSX语法、Hooks规则(useEffect依赖数组必须写全)、状态提升逻辑,对刚学完Java语法的学生来说,相当于同时学两门新语言。而Vue2的模板语法(v-for/v-if/@click)和Java的for循环/if判断/事件监听高度相似,学生能快速建立认知映射。我辅导过一个学生,他用React写购物车组件时卡在useState更新对象属性上,反复修改setCart({...cart, items: [...cart.items, newItem]})还是不刷新,最后发现是items数组引用没变——这种问题在Vue2里用this.cart.items.push(newItem)一行就解决,根本不需要理解“不可变数据”的概念。
注意:压缩包里的
front目录是完整的Vue CLI 3项目,不是简单的HTML+JS。这意味着它支持热更新(保存代码自动刷新浏览器)、ES6语法(箭头函数、解构赋值)、模块化开发(每个.vue文件封装template/script/style)。不要试图把index.html直接拖进浏览器打开——它需要npm run serve启动开发服务器来解析.vue单文件组件。
2.3 数据库为何坚持MySQL 5.7而非8.0或PostgreSQL
springboots5264.sql脚本明确标注兼容MySQL 5.7,这个选择直指高校实验室环境现状。国内大多数高校机房的MySQL版本仍停留在5.7.x(查看mysql --version输出),而MySQL 8.0的默认认证插件从mysql_native_password改为caching_sha2_password,会导致SpringBoot项目启动时报Client does not support authentication protocol requested by server错误。虽然可以手动修改用户认证插件,但机房管理员通常拒绝开放ALTER USER权限。
更关键的是字符集兼容性。MySQL 5.7默认字符集是latin1,但我们的脚本强制指定utf8mb4(见建表语句末尾)。这是因为utf8mb4能完整存储4字节Unicode字符(如微信表情、生僻汉字),而MySQL传统的utf8实际只支持3字节,存储emoji会变成??。当你的商品名称是“爆款榴莲🥭”时,utf8mb4就是数据不丢失的底线。而PostgreSQL虽然原生支持Unicode,但高校机房极少预装,学生自行安装常因pg_hba.conf权限配置错误导致连接失败。
另外,脚本中所有表都采用InnoDB引擎,而非MyISAM。这是为事务支持埋下的伏笔:采购入库时需要同时更新goods表的库存数量和purchase_order表的单据状态,这两个操作必须在一个事务里完成,否则会出现“库存增加了但单据没生成”的数据不一致。InnoDB的行级锁和事务ACID特性,是支撑进销存业务可靠性的基石。而MyISAM只支持表级锁,高并发场景下会严重阻塞。
3. 核心模块功能与业务逻辑拆解:不只是CRUD,更是业务建模思维
3.1 商品管理模块:从静态信息到动态库存的跃迁
商品管理看似只是增删改查,但它的设计暴露了整个系统的核心矛盾:商品基础信息(名称、规格、单价)是静态的,而库存数量是动态变化的。压缩包里的GoodsController.java没有把库存字段放在goods表里,而是单独建了inventory表(查看springboots5264.sql中CREATE TABLE inventory语句),这种分离设计是专业性的第一个信号。
inventory表结构包含goods_id(外键)、warehouse_id(仓库ID,为未来多仓扩展预留)、stock_quantity(当前库存)、lock_quantity(锁定库存)。这里的lock_quantity是防超卖的关键。比如用户下单购买5件商品,系统不是直接UPDATE inventory SET stock_quantity = stock_quantity - 5,而是先UPDATE inventory SET lock_quantity = lock_quantity + 5 WHERE goods_id = ?,待支付成功后再将锁定量转入库存减少量。这样即使多个用户同时抢购,也不会出现库存扣成负数。
你可以在InventoryService.java的deductStock()方法里看到完整逻辑:
@Transactional public boolean deductStock(Long goodsId, Integer quantity) { // 1. 先查询当前库存和锁定量 Inventory inventory = inventoryMapper.selectByGoodsId(goodsId); if (inventory.getStockQuantity() - inventory.getLockQuantity() < quantity) { throw new RuntimeException("库存不足"); } // 2. 锁定库存(增加lock_quantity) inventory.setLockQuantity(inventory.getLockQuantity() + quantity); inventoryMapper.updateById(inventory); return true; }这段代码体现了三个重要实践:①@Transactional保证数据库操作原子性;② 查询-判断-更新三步必须在同一个事务内,避免中间被其他线程修改;③ 异常抛出使用RuntimeException而非Exception,因为Spring默认只对运行时异常回滚事务。
实操心得:很多学生在测试库存扣减时,习惯用Postman发多次请求模拟并发,结果发现库存没扣减或扣多了。正确做法是用JMeter配置10个线程循环发送请求,观察
inventory表的stock_quantity和lock_quantity变化。你会发现lock_quantity会阶段性飙升,而stock_quantity只在支付确认后才下降——这就是分布式锁思想的轻量级实现。
3.2 采购管理模块:单据流驱动的业务闭环
采购模块不是简单的“录入采购单”,而是一条完整的单据生命周期:采购申请→采购订单→入库单→财务结算。压缩包里PurchaseOrderController.java只实现了采购订单的CRUD,但真正的业务价值藏在WarehouseController.java的inbound()方法里。
入库操作的校验逻辑极为严格:
- 必须关联有效的采购订单(检查purchase_order.status = 'APPROVED')
- 入库数量不能超过订单剩余未入库数量(order.quantity - order.inbounded_quantity)
- 商品批次号必须唯一(防止同一批次重复入库)
- 入库时间自动填充为new Date(),且不允许手动修改
这些规则在InboundService.java中通过@Valid注解和自定义校验器实现。比如InboundValidator类会检查inboundDetailList里的每个明细项,确保goodsId存在、quantity为正整数、batchNo不为空。这种将业务规则前置到Controller层的做法,比在Service里写if-else更符合RESTful设计原则——客户端收到400 Bad Request响应时,能立即知道是哪个字段错了。
更值得玩味的是单据编号生成策略。查看PurchaseOrderServiceImpl.java的generateOrderNo()方法:
private String generateOrderNo() { String prefix = "PO" + LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")); // 查询当天最大单号 String maxNo = purchaseOrderMapper.selectMaxOrderNoByDate(LocalDate.now()); int serial = 1; if (maxNo != null && maxNo.startsWith(prefix)) { serial = Integer.parseInt(maxNo.substring(prefix.length())) + 1; } return prefix + String.format("%04d", serial); // 如 PO202405200001 }这种“日期前缀+流水号”的生成方式,既保证了单号可读性(一眼看出是哪天的采购单),又避免了分布式ID生成器(如Snowflake)在单机环境下的过度设计。对于毕设系统,简单可靠的方案永远优于炫技方案。
3.3 销售管理模块:收银场景下的实时性与一致性挑战
销售模块的难点在于实时库存扣减与离线收银的平衡。压缩包里的SaleController.java提供了两种销售入口:网页端销售(实时扣库存)和POS机对接接口(异步扣库存)。前者适用于超市自营收银台,后者为未来对接硬件POS机预留扩展点。
网页销售的核心是createSaleOrder()方法。它不像采购那样先生成单据再入库,而是同步完成销售单创建、库存扣减、会员积分计算三件事。关键代码在SaleService.java:
@Transactional public SaleOrder createSaleOrder(SaleOrderDTO dto) { // 1. 创建销售单主表 SaleOrder order = new SaleOrder(); order.setOrderNo(generateOrderNo()); order.setMemberId(dto.getMemberId()); order.setTotalAmount(dto.getTotalAmount()); saleOrderMapper.insert(order); // 2. 扣减库存(复用InventoryService.deductStock) for (SaleOrderDetail detail : dto.getDetails()) { inventoryService.deductStock(detail.getGoodsId(), detail.getQuantity()); } // 3. 更新会员积分(积分 = 消费金额 * 10) if (dto.getMemberId() != null) { Member member = memberMapper.selectById(dto.getMemberId()); member.setIntegral(member.getIntegral() + (int)(dto.getTotalAmount() * 10)); memberMapper.updateById(member); } return order; }这里有个易错点:deductStock()方法内部会更新inventory表,而memberMapper.updateById()会更新member表。如果这两个更新不在同一个事务里,可能出现“库存扣了但积分没加”的情况。所以整个方法必须用@Transactional包裹,且传播行为为REQUIRED(默认值)。
注意事项:测试销售功能时,务必用Chrome隐身窗口或清除localStorage。因为Vue前端会缓存登录态(token)和用户信息,如果之前用管理员账号登录过,再用收银员账号登录可能因权限校验失败导致销售按钮不可见。正确的测试流程是:关闭所有浏览器标签→打开隐身窗口→访问
localhost:8080/supermarket/front/index.html→用收银员账号(如cashier/123456)登录→进入销售页面。
4. 双端部署全流程详解:从环境准备到URL可访问的每一步
4.1 后端环境搭建与数据库导入(Windows/Linux通用)
部署的第一步永远是环境验证,而不是急着跑代码。请按顺序执行以下检查:
JDK版本确认:
在命令行输入java -version,输出必须是1.8.0_xxx(如1.8.0_291)。如果显示11.0.x或17.0.x,请下载JDK8并配置JAVA_HOME环境变量。SpringBoot 2.3.x要求JDK8,更高版本会报UnsupportedClassVersionError。Maven版本确认:
输入mvn -v,确保显示Apache Maven 3.6.x。如果提示mvn不是内部命令,请将Maven的bin目录添加到系统PATH,并重启命令行。MySQL服务启动:
确保MySQL服务正在运行。Windows下打开“服务”管理器,找到MySQL80(或类似名称)并启动;Linux下执行sudo systemctl start mysql。然后用Navicat或命令行登录:mysql -u root -p,输入密码后进入MySQL交互界面。数据库脚本导入:
这是最容易出错的环节。不要双击springboots5264.sql用记事本打开!正确操作是:
- 在MySQL命令行中执行:CREATE DATABASE supermarket DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
- 退出MySQL:输入exit
- 执行导入命令:mysql -u root -p supermarket < path/to/springboots5264.sql(注意替换path/to/为你的实际路径)
- 如果报错Unknown collation: 'utf8mb4_0900_ai_ci',说明你的MySQL版本是8.0+,需手动编辑SQL文件,将所有utf8mb4_0900_ai_ci替换为utf8mb4_unicode_ci
实操心得:导入后务必验证数据。执行
SELECT COUNT(*) FROM goods;,正常应返回12(脚本预置了12种商品);执行SELECT * FROM user WHERE username = 'admin';,查看密码字段是否为$2a$10$...开头的BCrypt加密字符串。如果不是,说明User实体类的@TableField注解没正确映射password字段,需要检查src/main/java/com/example/supermarket/entity/User.java。
4.2 后端项目启动(开发模式 vs 生产模式)
压缩包提供两种启动方式,对应不同场景:
开发模式(推荐首次运行):
1. 用IDEA打开项目根目录(含pom.xml的文件夹)
2. 等待Maven自动导入依赖(右下角提示“Importing project”完成)
3. 找到SupermarketApplication.java(在src/main/java/com/example/supermarket下),右键→Run 'SupermarketApplication.main()'
4. 控制台输出Started SupermarketApplication in X.XXX seconds即启动成功
5. 访问http://localhost:8080/supermarket/swagger-ui.html,查看Swagger接口文档(需确保pom.xml中启用了springfox-swagger2依赖)
生产模式(Tomcat部署):
1. 备份原始pom.xml,将pom-war.xml重命名为pom.xml(覆盖原文件)
2. 修改pom-war.xml中的<packaging>为war,并确认<build>节点包含<finalName>supermarket</finalName>
3. 在IDEA右侧Maven面板中,依次点击Lifecycle→clean→package
4. 生成的supermarket.war位于target/目录下
5. 将supermarket.war复制到Tomcat的webapps/目录
6. 启动Tomcat:Windows下双击tomcat/bin/startup.bat,Linux下执行./tomcat/bin/startup.sh
7. 等待Tomcat解压war包(webapps/supermarket/目录出现),访问http://localhost:8080/supermarket/actuator/health验证服务健康状态
关键区别:开发模式用内嵌Tomcat,端口由
application.yml的server.port控制;生产模式用外部Tomcat,端口由Tomcat自身配置决定,server.port失效。pom-war.xml里移除了spring-boot-maven-plugin的repackage配置,因为war包不需要可执行jar的启动逻辑。
4.3 前端项目启动与路径映射
前端部署的陷阱在于静态资源路径与后端上下文路径的匹配。压缩包里front目录是独立Vue项目,必须与后端server.servlet.context-path保持一致。
安装Node.js:
下载Node.js 14.x LTS版本(官网nodejs.org),安装时勾选“Add to PATH”。验证:node -v输出v14.21.x,npm -v输出6.14.x。安装依赖并启动:
bash cd front npm install # 安装依赖(注意:不要用cnpm,某些包兼容性有问题) npm run serve # 启动开发服务器,默认端口8080
此时前端运行在http://localhost:8080,而后端也在http://localhost:8080,必然跨域!解决方案有两个:
方案A(推荐,开发阶段):配置Vue代理。编辑front/vue.config.js,添加:javascript devServer: { proxy: { '/api': { target: 'http://localhost:8080/supermarket', // 后端上下文路径 changeOrigin: true, pathRewrite: { '^/api': '' } } } }
这样前端请求/api/user/login会被代理到http://localhost:8080/supermarket/user/login。
方案B(生产阶段):构建静态资源。执行npm run build,生成dist/目录。将dist/内容复制到后端项目的src/main/resources/static/目录下,这样SpringBoot会自动将其作为静态资源提供,无需跨域。
- 访问路径确认:
- 开发模式:前端localhost:8080+ 后端代理 → 访问http://localhost:8080即可
- 生产模式:前端构建后放入后端static目录 → 访问http://localhost:8080/supermarket/(注意末尾斜杠)
提示:如果访问
localhost:8080/supermarket/admin/dist/index.html显示空白,请检查dist/index.html中的<script>标签路径是否为相对路径(如/js/app.js)。如果是绝对路径/supermarket/js/app.js,需在vue.config.js中配置publicPath: '/supermarket/'。
5. 常见问题与排查技巧实录:那些让你熬夜到凌晨三点的坑
5.1 启动报错“Failed to configure a DataSource”
这是新手遇到的第一个拦路虎,错误日志通常以Caused by: org.springframework.boot.autoconfigure.jdbc.DataSourceProperties$DataSourceBeanCreationException结尾。根本原因只有一个:application.yml中的数据库配置不正确。
请逐项核对:
-spring.datasource.url是否为jdbc:mysql://localhost:3306/supermarket?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true(注意supermarket数据库名必须和你创建的一致)
-spring.datasource.username和password是否为你的MySQL账号密码(默认root/root)
-spring.datasource.driver-class-name是否为com.mysql.cj.jdbc.Driver(MySQL 8.0+)或com.mysql.jdbc.Driver(MySQL 5.7)
最容易忽略的是时区配置。如果URL里缺少serverTimezone=Asia/Shanghai,MySQL会报The server time zone value 'XXX' is unrecognized。解决方案不是改系统时区,而是加URL参数。
排查技巧:在IDEA的
Run Configuration中,点击Modify options→勾选Add VM options,输入-Dfile.encoding=UTF-8 -Duser.timezone=GMT+8。这能解决因系统编码导致的配置文件读取乱码问题。
5.2 前端页面空白,控制台报“Cannot GET /supermarket/admin/dist/index.html”
这个错误表明Tomcat找到了supermarket应用,但没找到对应的HTML文件。根源在于静态资源路径映射错误。
检查步骤:
1. 确认supermarket.war已成功解压为webapps/supermarket/目录
2. 进入webapps/supermarket/,查看是否存在admin/dist/index.html路径(注意大小写,Linux系统区分大小写)
3. 如果路径存在但依然404,检查webapps/supermarket/WEB-INF/web.xml中是否配置了欢迎文件列表:xml <welcome-file-list> <welcome-file>admin/dist/index.html</welcome-file> </welcome-file-list>
4. 如果使用SpringBoot内置Tomcat,检查application.yml中spring.web.resources.static-locations是否包含classpath:/static/(默认已配置)
终极解决方案:将
front/dist/目录整体复制到后端项目的src/main/resources/static/下,然后用开发模式启动(mvn spring-boot:run)。此时访问http://localhost:8080/supermarket/会自动加载static/admin/dist/index.html。
5.3 登录成功后跳转404,或菜单栏不显示
这通常是前端路由与后端权限拦截冲突导致。系统采用JWT Token鉴权,登录成功后前端将token存入localStorage,后续请求在Header中携带Authorization: Bearer xxx。
排查方法:
1. 打开浏览器开发者工具(F12)→Network标签页
2. 重新登录,观察/user/login请求的Response是否返回了token字段
3. 查看后续请求(如/menu/list)的Request Headers,确认是否有Authorization头
4. 如果没有,检查front/src/utils/request.js中的service.interceptors.request.use逻辑,确认是否正确设置了token
常见错误代码:
// ❌ 错误:token拼接错误 config.headers.Authorization = 'Bearer ' + token // ✅ 正确:localStorage.getItem返回的是字符串,需确保非null const token = localStorage.getItem('token') if (token) { config.headers.Authorization = `Bearer ${token}` }5.4 数据库中文乱码,商品名称显示为“???”
即使SQL脚本指定了utf8mb4,仍可能出现乱码,原因在于MySQL客户端连接层未启用utf8mb4。
解决方案(三步走):
1. 修改MySQL配置文件my.ini(Windows)或my.cnf(Linux),在[client]和[mysqld]节点下添加:
```ini
[client]
default-character-set = utf8mb4
[mysqld]
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci`` 2. 重启MySQL服务 3. 重新执行建库建表脚本(先DROP DATABASE supermarket;`再重建)
验证方法:登录MySQL后执行
SHOW VARIABLES LIKE 'character_set%';,确保character_set_client、character_set_connection、character_set_database均为utf8mb4。
6. 答辩PPT制作与陈述要点:如何把技术细节讲成业务价值
6.1 LW格式PPT的结构化呈现逻辑
压缩包里的springboot基于Java的超市进销存系统 LW PPT采用标准LW(Logical Workflow)结构:每页PPT只讲一个核心观点,用“问题→方案→效果”三段式展开。例如“库存管理”页:
-问题:传统Excel管理库存易出错,采购入库与销售出库不同步,月底盘点耗时长
-方案:采用goods+inventory双表设计,入库单与销售单触发库存变更事件,实时更新stock_quantity和lock_quantity
-效果:库存准确率100%,盘点时间从4小时缩短至15分钟,支持实时查看各仓库库存分布
这种结构比罗列“我用了SpringBoot、Vue、MySQL”更有说服力。老师关心的不是你用了什么技术,而是你如何用技术解决业务痛点。
6.2 答辩陈述的三大避坑指南
避坑一:不要背代码
老师不会要求你默写@Transactional的源码,但会问“为什么这个方法要加事务?不加会怎样?”。准备时,针对每个核心Service方法,用一句话说清:
- “deductStock()加事务,因为库存扣减必须和销售单创建原子执行,否则会出现‘单据生成了但库存没扣’的数据不一致。”
避坑二:演示要可控
答辩演示不是Showcase,而是Proof。提前准备好三组测试数据:
- 正常流程:用收银员账号登录→创建销售单→支付成功→库存实时减少
- 边界场景:用管理员账号尝试删除正在销售的商品→验证外键约束报错
- 异常流程:手动将库存设为1,然后下单2件→验证“库存不足”提示弹出
这样演示时无论老师提什么要求,你都能在30秒内给出结果。
避坑三:技术深度要适度
当被问到“为什么用JWT不用Session”,回答要聚焦毕设场景:
- “JWT适合前后端分离架构,Token存在localStorage里,每次请求自动携带,比Session依赖Cookie更符合Vue单页应用特性;而且JWT自带过期时间,不用额外维护Session存储。”
不要展开讲JWT签名算法或Redis集群,这超出毕设范畴。
最后分享一个小技巧:在PPT最后一页,放一张系统架构图(手绘风格即可),用箭头标出“用户→Vue前端→SpringBoot后端→MySQL数据库”的数据流向,并在每个环节旁标注你负责的部分(如Vue前端:完成了销售模块所有页面开发;SpringBoot后端:实现了库存扣减的事务控制)。这张图能让老师瞬间理解你的工作量和技术贡献,比十页文字描述更有效。
本文还有配套的精品资源,点击获取
简介:直接上手就能跑的超市进销存管理系统,专为Java课程设计和毕业项目准备。后端用SpringBoot开发,兼容JDK8及以上版本,Maven 3.6+构建,支持Tomcat7/8部署;前端基于Vue实现,界面简洁,操作流程清晰。包里有完整源码(src目录)、pom.xml配置文件、war包打包专用pom-war.xml、IDEA项目配置文件(.classpath/.project等)、Navicat可导入的MySQL 5.7建库建表脚本(springboots5264.sql),还有两份《部署说明.txt》——从环境安装、数据库导入,到前后端分别启动路径都写清楚了:后台地址是localhost:8080/项目名/admin/dist/index.html,前台是localhost:8080/项目名/front/index.html。额外附带LW格式答辩PPT,方便汇报展示。所有Java和Vue代码都带中文注释,本地调试通过,无需二次修改即可一键运行。
本文还有配套的精品资源,点击获取
