多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

基于SSM+Vue的超市管理系统毕业设计全攻略

基于SSM+Vue的超市管理系统毕业设计全攻略 每年到五六月我的私信里就会高频出现同一个问题“毕业设计到底做什么题目能稳一点通过、又不至于把宿舍日子过成工地”这种问题没法给标准答案因为每个人的水平和时间都不一样。但如果对方说Java Web基础有一点前端会写一点想在两周内搞定一个能演示、能讲故事、还能扛住老师五分钟追问的系统那我脑子里第一个冒出来的选择就是——基于SSM Vue的超市管理系统。这个题目很像一个“软件工程样板间”。后端是Spring、SpringMVC、MyBatis三个框架的组合简称SSM前端用Vue配合Element UI实现管理界面数据库用MySQL存业务数据。业务上它是超市的进销存加收银场景表面看起来不复杂但商品、库存、订单、供应商、会员、员工这些关系型数据来回流转恰好能把大学四年攒下的课程知识串起来工作量也处于“一个人能完成、展示起来又不像玩具”的甜点区。这篇文章就以这个题目为线索把从选题、模块拆解、数据库设计、后端编码、前端页面、联调打包到答辩准备的全过程都捋一遍。不管你是在网上找了一套源码准备二次开发还是打算从零手写一个都能在这里找到可以直接照抄的部分。1. 选题与组合逻辑为什么“SSM Vue”成了毕设常青树1.1 SSM框架的生命力在哪里先聊后端。SSM不是一个新东西Spring、SpringMVC、MyBatis这三个组件从Java Web刚开始流行就一直活跃在校园和企业里。很多同学担心“都什么年代了还写SSM”但现实是技术选型不是追热度而是看稳定性和学习价值。Spring解决的是对象管理问题你不需要自己new对象、维护对象依赖交给IOC容器去管AOP可以抽出日志、事务这类通用逻辑。SpringMVC把请求路径、参数、返回值之间的关系理清楚了一个方法对应一个URL前端传什么参数方法就能拿到什么。MyBatis则是把SQL写在XML或者注解里比Hibernate这类全自动ORM更透明调优SQL也有掌控感。对于毕业设计答辩来说这三块内容都有很清晰的“知识点”可以讲老师问起来也能对答如流。而且说实话SSM的学习成本相对低网上资料多问题随便搜都有答案。它的生命周期很长不会因为换了一版框架你就找不到参考。1.2 Vue在前端带来了什么前端如果还用JSP加jQuery并不是不能做但页面一多就会变得很痛苦。JSP负责渲染页面Java和HTML混在一起改样式可能都要重启服务前后端也不容易分离。换成Vue之后前后端就彻底解耦了。后端只负责提供JSON数据前端用Vue的组件化方式把页面拆成一个个独立部分商品列表、新增弹窗、订单详情、统计数据都是组件。Vue Router处理页面跳转Vuex或者本地存储保存登录状态Axios负责和后台接口通信。再加上Element UI这一套现成的组件库表格、表单、弹窗、分页、日期选择器基本是开箱即用。一个后台管理页面熟练的话一两天就能搭出来而且观感很现代。这正好填补了SSM项目“后台很硬、前台很土”的老问题。1.3 超市管理系统为什么是“稳过”的题目选择一个题目不只是选一个名字是选一套“好讲的故事”。图书管理系统太普遍老师一眼就能猜到套路网上商城又太重涉及购物车、订单状态、支付回调一个人往往写不利索。超市管理系统正好在中间业务场景真实、模块边界清晰、数据关系立体。超市最核心的流程是“进货—入库—上架—销售—库存变动”围绕这个主链条可以展开出商品管理、类别管理、供应商管理、订单管理、会员管理、统计报表等模块。做出来的系统既能展示增删改查基本功也能展示订单事务、库存预警、图表统计这些“有深度”的东西。论文也好写围绕进销存这条线展开逻辑天然顺畅。而且对本科生来说这个系统不会大到失控一个人专心做两周是能跑通的但也不会小到没内容写光数据库表就十来张画ER图、写系统设计都够用。2. 业务与模块拆解把超市运营翻译成系统设计2.1 功能模块全景超市管理系统的功能模块可以从“人、货、钱、数据”四个维度去划分这样在答辩时讲需求分析会特别清晰。人管理员、收银员、仓库管理员。不同角色看到的页面和能做的操作不同。货商品类别、商品信息、入库记录、库存预警、供应商。钱订单主表、订单明细、支付方式、每日营业额统计。数据首页仪表盘、近七日销售趋势、库存排行榜、会员积分报表。落点到具体页面至少需要下面这些模块核心功能登录与登录态账号密码校验、角色识别、退出登录商品类别管理类别树、新增、编辑、删除商品信息管理商品列表、条形码检索、新增编辑、上下架库存管理入库出库流水、库存数量调整、低库存预警供应商管理供应商档案、联系人、合作记录订单管理收银台下单、订单列表、订单详情、退款会员管理会员档案、积分变动、余额查询统计报表今日销售额、订单量、库存预警数量、销售趋势图当然具体功能可以根据自己精力裁剪。但我建议核心的进销存链路一定要完整否则答辩时会被问“如果把这个模块去掉你的系统和其他系统有什么本质区别”。2.2 核心表结构超市业务的数据地基数据库是整个项目的地基。表设计得好后面写代码会顺畅很多设计乱了SQL写起来全是痛苦。我按实体关系梳理一下核心表。第一张是管理员表用来支撑登录和权限。字段类型说明admin_idint主键自增usernamevarchar(50)用户名唯一passwordvarchar(64)密码建议MD5后存储real_namevarchar(30)真实姓名phonevarchar(20)手机号role_idint角色编号1超管2收银员3仓管第二张是商品类别表因为超市商品多必须有分类。字段类型说明category_idint主键category_namevarchar(50)类别名称parent_idint父类别0表示顶级第三张是商品表它是整个系统的中心。字段包括商品ID、类别ID、商品名称、条形码、进价、售价、库存、预警库存、单位、状态、创建时间。其中条形码建议加唯一索引因为超市场景里扫码枪就是靠它来认商品的。售价和小数位要用decimal不要用float避免出现金额精度问题。系统初始化的时候可以给常见的饮料、零食、日用品各录十几条数据这样演示起来不至于空荡荡。商品的库存字段可以直接在商品表里维护但任何库存变动都要留痕这就引出后面的入库表和订单表。第四张是供应商表和入库单表。供应商表存供应商名称、联系人、电话、地址。入库单表每次进货都生成一条记录写明商品、供应商、数量、进价、总额、入库时间和操作员。这里有一个很重要的设计原则不要因为库存字段在商品表里就只去update商品表的stock否则以后想查“某个商品最近几次进货分别是多少钱”就查不到。入库流水就是仓库的“记账本”。第五张是订单主表和订单明细表。订单主表记录订单编号、收银员、支付方式、总金额、创建时间订单明细表记录每个订单里有哪些商品、数量、单价、小计。主从结构是典型的一对多关系在MySQL里体现为外键关联但不建议在物理外键上过度约束演示系统用逻辑关联就够了写SQL时手动控制一致性。第六张是会员表。字段包括会员编号、姓名、手机号、等级、积分、余额、注册时间。超市系统带了会员就能体现“你不只会增删改查还能处理积分累计与消费联动”的亮点。数据库讲到这里可能有人觉得表好多。没关系这些表其实是一环扣一环的画一遍ER图就能理清楚。建议用工具或表格先把ER草图画好再写建表SQL。2.3 关键业务逻辑背后的考虑设计完表有几个业务点需要在写代码前想明白。库存扣减必须带条件。商品下单时一条语句完成“扣库存防止超卖”update tb_product set stock stock - #{quantity} where product_id #{id} and stock #{quantity}。如果受影响行数为0说明库存不足直接报错回滚。订单编号不要直接拿自增ID当订单号用容易被猜出业务量而且显得不正式。可以用时间戳加随机数或者业务规则生成。比如“当前日期 四位流水”的方式查问题也方便。库存预警不是单独存一张表而是查询的时候用条件判断stock warn_stock就算预警。这一招既省表又灵活预警阈值还能随商品单独设置。这样的设计做完以后你会发现业务逻辑有主线、有闭环写代码时知道每一步在干嘛而不是对着空页面发呆。3. 环境准备与技术选型跑通项目前的硬核前置3.1 开发环境清单开始编码前先把环境凑齐。我的建议版本组合是这样的工具建议版本说明JDK1.8最稳SSM项目经典搭档Maven3.6.x管理依赖和打包Tomcat8.5或9.0部署war包MySQL5.7或8.05.7最省心8.0要改驱动配置Node.js14以上跑Vue工程必须IDEA最新社区版即可后端开发主力VS Code任意版本前端写代码顺手这里特别说两个容易栽的细节。JDK千万别一上来就装17甚至21SSM项目毕竟是老技术栈JDK8兼容性最佳省得后面出现莫名其妙的编译问题。MySQL如果用了8.0驱动类名要改成com.mysql.cj.jdbc.Driver并且连接串加上serverTimezoneAsia/Shanghai和useSSLfalse否则启动直接报时区错误。3.2 Maven依赖怎么选SSM项目的依赖搭配网上版本五花八门我给出一个亲身使用过、能稳定运行的组合properties spring.version5.2.5.RELEASE/spring.version /properties dependencies dependency groupIdorg.springframework/groupId artifactIdspring-webmvc/artifactId version${spring.version}/version /dependency dependency groupIdorg.springframework/groupId artifactIdspring-jdbc/artifactId version${spring.version}/version /dependency dependency groupIdorg.mybatis/groupId artifactIdmybatis/artifactId version3.5.5/version /dependency dependency groupIdorg.mybatis/groupId artifactIdmybatis-spring/artifactId version2.0.5/version /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version5.1.48/version /dependency dependency groupIdcom.alibaba/groupId artifactIddruid/artifactId version1.1.22/version /dependency dependency groupIdcom.fasterxml.jackson.core/groupId artifactIdjackson-databind/artifactId version2.11.4/version /dependency /dependencies版本号老一点没有关系这套组合在大量项目里跑过踩坑成本最低。加上Lombok可以少写很多getter/setter但记得在IDEA里装Lombok插件。3.3 前端工程初始化前端这边建议用Vue CLI创建工程。命令很简单npm install -g vue/cli vue create supermarket-web npm install element-ui axios npm install echarts --save创建完项目后把src下面的目录规划一下。views放页面组件router放路由配置api放所有请求封装utils放一些工具函数。Element UI在main.js里全局注册一次图表用ECharts按需引入。前端的坑通常不在代码而在依赖安装。如果npm install卡到崩溃直接换镜像源再试npm config set registry https://registry.npmmirror.com这样一套流程下来前后端两个工程就都立起来了。后端工程跑在8080端口前端工程默认跑在8081或者5173开发阶段直接跨域访问联调通过后再打包集成。4. 实操拆解后端结构与前端页面如何协作4.1 后端分层所有代码都有自己该待的地方拿到一套能跑的源码第一件事不是急着启动而是先把包结构看清楚。一套规范的SSM后端包结构长这样com.example.supermarket ├── controller # 接收请求、组装参数、返回结果 ├── service # 业务逻辑接口 │ └── impl # 业务逻辑实现 ├── dao # MyBatis的Mapper接口 │ └── mapper # XML文件目录 ├── entity # 实体类 ├── common # 统一返回结果、异常类 ├── config # 配置类、拦截器 └── interceptor # 登录拦截器Controller层只做一件事把前端传过来的参数交给Service再把Service返回的数据用统一格式包装一下。Service层写业务规则比如下单时要同时操作订单表、订单明细表和商品库存那就加上事务注解Transactional。DAO层只负责和数据库打交道里面是根据SQL映射出来的方法。4.2 统一返回结果前后端的沟通协议前后端分离开发最怕每个接口返回的数据格式都不一样。这个接口返回{success:true, items:[]}那个接口返回{code:200, data:[]}前端自己就先晕了。所以我建议后端所有接口都用一个Result实体包装public class ResultT { private Integer code; private String msg; private T data; public static T ResultT success(T data) { ResultT result new Result(); result.setCode(200); result.setMsg(操作成功); result.setData(data); return result; } public static T ResultT error(String msg) { ResultT result new Result(); result.setCode(500); result.setMsg(msg); return result; } }前端接的时候统一判断code是否等于200。等于则正常处理不等于就直接弹msg。这个“约法三章”能省掉一半前后端联调的沟通成本。4.3 登录与权限校验被问了无数次的模块登录功能是每个管理系统的门面。实现方案建议走“Token”模式而不是传统的每次请求都带着sessionId。具体流程是前端登录页把用户名、密码POST给后端后端查管理员表校验密码。如果正确就生成一个uuid作为token存到内存里的一个Map中key是token、value是当前用户信息然后把token返回给前端。前端把token存到localStorage之后每次请求都在Header里带上。后端写一个拦截器拦截所有/api/开头的请求先检查Header里的token查不到或者过期就直接返回401。public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String token request.getHeader(token); if (token null || !TokenContainer.isValid(token)) { response.setStatus(401); return false; } return true; }这个方案比JWT简单适合毕设场景而且答辩时能讲清楚“为什么不用session而是用token”因为前后端分离部署在不同端口Session天然的跨域问题要处理Token是纯文本传递更符合前后端分离的架构。4.4 商品分页与搜索最经典的列表场景商品列表是所有管理页面里最典型的场景表格展示、分页、模糊搜索。后端的Mapper写法可以这样select idfindProductPage resultTypeentity.Product select product_id, product_name, barcode, price, stock, warn_stock, unit, status from tb_product where if testproductName ! null and productName ! and product_name like concat(%, #{productName}, %) /if if testcategoryId ! null and categoryId ! and category_id #{categoryId} /if /where order by product_id desc limit #{offset}, #{pageSize} /select同时再写一个count查询查询条件完全一样但没有limit。Service把两句话的结果组装成一个PageResult返回给前端。这里不建议偷懒用select *明明确确写出字段名SQL执行效率高一点答辩时被问SQL优化也有话说。前端表格页用el-table绑定列表数据用el-pagination做分页用el-input的clearable配合keyup.enter触发搜索。整套组合是所有后台管理系统的模板做熟了以后其他页面都能照抄。4.5 订单提交与事务控制让老师看到“硬实力”订单模块是系统里最有技术含量的部分。超市收银台扫码结算时前端把商品列表和数量一次性传给后端Transactional public void createOrder(OrderDTO orderDTO) { // 1. 生成订单号格式yyyyMMddHHmmss 随机数 // 2. 插入订单主表 // 3. 遍历商品明细插入订单明细表 // 4. 扣减库存stock quantity才允许扣 }事务注解是关键。因为下单涉及多张表的写操作如果插入订单成功但扣库存失败或者扣库存成功但插入明细失败数据就不一致了。加上Transactional之后任何一个步骤抛异常所有操作全部回滚数据依然保持一致。扣库存那一行用我之前说过的带条件UPDATE。这条SQL一定要自己在数据库里提前演示几遍验证库存不足时的表现是否符合预期。它是整个系统技术深度的体现答辩老师往往会在这里追问并发问题哪怕回答得没那么深入只要说清楚“用update条件判断库存余量可以避免超卖”就已经能拿到不错的印象分了。4.6 前端页面的组织方式前端页面不要把所有代码都塞到一个vue文件里。我习惯按业务拆开Login.vue登录表单处理登录成功跳转。Home.vue首页仪表盘展示今日销售额、订单数、库存预警数和七日内销售趋势柱状图。ProductList.vue商品管理包含表格、搜索框、新增弹窗、编辑弹窗、删除确认。OrderList.vue订单列表详情通过抽屉或弹窗展示。SupplierList.vue供应商管理相对简单纯增删改查。每个页面通过api目录下的js文件发送请求不直接在组件里写axios。例如api/product.js里import request from /utils/request export const getProductPage (params) { return request({ url: /api/product/page, method: get, params }) }request封装统一设置baseURL和Header里带token。这样切环境时只需要改一个文件不用全局搜索替换。5. 联调、打包、部署与避坑指南最折磨人的三天5.1 前后端联调最容易踩的坑把后端和前端分别跑起来你以为很快就能看到完整页面实际上通常会经历好几个小时的折磨。高频问题我总结出一张速查表现象原因解决方案前端请求后页面显示跨域错误前后端端口不一致后端加CORS配置允许指定源访问接口返回时间乱码日期格式序列化异常配置Jackson的日期格式化或实体里用JsonFormat数据库连不上URL或密码不对、时区设置缺失检查连接串MySQL8要加serverTimezone中文乱码Tomcat和项目编码不一致统一UTF-8在web.xml里设置编码过滤器MyBatis报Invalid bound statementXML文件没被扫描或namespace写错检查namespace与接口全限定名一致npm install卡住不动网络源问题设置国内容镜像源404但接口路径看着没问题项目上下文路径和请求不匹配检查Tomcat部署路径和前端baseURL具体到解决方案最简单的跨域配置在SpringMVC配置类里直接写Configuration public class CorsConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/**) .allowedOriginPatterns(http://localhost:8081) .allowedMethods(*) .allowedHeaders(*); } }日期格式乱码的话在application的springmvc配置里加一个消息转换器或者实体导入JsonFormat(pattern yyyy-MM-dd HH:mm:ss, timezone GMT8) private Date createTime;5.2 打包部署让系统在演示当天不翻车毕业设计答辩通常不会只看IDEA里的运行效果很多老师会要求同学把系统部署到Tomcat里从浏览器直接访问。所以打包部署这关必须提前排演。后端如果是war包可以右键Maven命令执行mvn clean package然后把war包拷到Tomcat的webapps目录下启动Tomcat自动解压。访问路径一般是http://localhost:8080/项目名/api/xxx。如果你不想带项目名可以直接把war包改名为ROOT.war部署。前端打包是另一个容易迷糊的点。npm run build之后生成dist目录里面是纯静态文件需要被Tomcat或者Nginx托管。最简单的做法是把dist目录整体拷贝到Tomcat的webapps/supermarket-web目录下然后浏览器访问http://localhost:8080/supermarket-web/。注意这时前端接口请求路径不能写localhost:8081而要写localhost:8080/项目名baseURL要同步改掉。如果不想处理war包也可以把后端打成jar包再用java -jar运行但SSM项目传统上还是war包部署到Tomcat里更顺手。两种方式演示前都提前跑通一次别到答辩现场手忙脚乱。5.3 答辩前必须做好的几个准备能跑起来只算及格答辩表现决定了分数天花板。我有几个建议第一准备一个演示脚本。按照“超级管理员登录—查看首页统计—添加一个新商品—修改库存—模拟下单—查看订单详情—查看销售趋势图”这个顺序走一遍每一步想清楚要点是什么。尤其新增商品后马上去下单里搜索这个商品形成闭环老师会觉得你对系统理解很深。第二数据库里多准备点真实感强的数据。别只有三条测试记录尽量造出几十个商品、几百条订单。图表统计模块如果没有数据画出来就是一条平线观感很差。第三预演几个必问问题。比如为什么用SSM不用Spring Boot就回答“SSM是经典Java Web技术栈分层清晰在学习阶段更容易理解底层原理”为什么用MyBatis不用JPA就回答“SQL可控优化起来方便使用门槛也低”。这些问题提前想好比临场发挥强一百倍。5.4 拿来源码后最有效的二次开发思路如果你是下载了一套现成的源码我强烈建议不要直接交上去就完事。查重和老师追问都会很尴尬。真正有效的做法是先从头到尾看一遍核心代码把登录、商品、订单这条主链路跑通然后挑选两三个地方做属于自己的改动。改动方向可以有很多。把商品列表加一个“批量导入导出Excel”功能技术门槛不高但工作量看得见或者首页仪表盘换一种图表组件让视觉观感与众不同再或者把原本的密码明文校验改成加盐MD5体现安全意识。这些改动都会在演示和论文中变成你独有的亮点而不是千篇一律的模板作品。最后再分享一点个人体会这个题目做下来我最大的感受是毕业设计并不是越复杂越好而是要恰到好处地展示“你会什么、你理解了哪些技术”。SSM加Vue的组合刚好覆盖了后端分层、数据库设计、前后端分离、事务控制、权限校验、图表可视化这些关键点每一个点拆开都能讲上几分钟。对于即将走上工作岗位的同学来说这套项目经历写进简历里也是拿得出手的。如果你正在为这套系统熬夜建议先把数据库那张ER图画明白再动手写代码。地基稳了后面就顺了。祝顺顺利利答辩一次通过。
返回列表