ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

SpringBoot+Vue网上超市毕设系统:从RESTful接口到订单状态机的完整实战

SpringBoot+Vue网上超市毕设系统:从RESTful接口到订单状态机的完整实战 1. 毕设场景下的题目判断网上超市为什么是个性价比选择1.1 这个题目覆盖的技术点正好是面试爱考的每年三月中旬开始我的私信里就会冒出一批同款问题毕设做什么题目好SpringBoot项目能不能给我一份参考Vue到底要学到什么程度才敢动手写问这些问题的人处境几乎一样——学了一学期Java Web觉得什么都碰过但真要独立从零搭一个能通过答辩的系统又不知道从哪下手。网上超市这个题目我前前后后帮人跑通过几十次可以负责任地说它不是最有创意的题目但绝对是性价比很高的选择。原因很简单SpringBoot Vue MySQL这个技术组合覆盖了Java后端和前端开发两条线上最主流的技能要求。答辩时老师问你用了什么技术栈你说SpringBoot、Vue、MyBatis-Plus、MySQL、JWT没有一个是冷门东西老师不会觉得你在挑战认知边界也不会觉得你什么都没做。这恰恰是毕设选题的核心逻辑老师看重的不是你用了多新颖的技术而是你有没有把一个完整业务闭环跑通。网上超市天然具备用户浏览商品→加入购物车→提交订单→后台发货这条完整链路比单纯做一个图书管理、学生管理这种单表CRUD的项目有说服力得多。图书管理系统做完你只会写增删改查网上超市做完你会接触到订单状态流转、库存扣减、权限控制、购物车数据存储这些真实业务问题这些才是以后工作里天天遇到的东西。1.2 难度区间与工作量衡量标准很多人问我这个项目三个月做得完吗我的回答是正常水平下每天投入两三个小时六到八周完全够用。前提是你别自己给自己加戏。我给你拆一下工作量。网上超市核心可以分为用户端和管理端。用户端包含注册登录、商品浏览、商品搜索、分类筛选、购物车、下单、订单查看、个人信息维护管理端包含商品管理、分类管理、订单处理、用户管理、轮播图管理。如果只做这些基础功能后端大概二十来张接口前端十几个页面。这正好是毕设的正常体量。但我也见过不少同学做着做着就跑偏了非要上什么分布式、微服务、秒杀系统结果自己被复杂度和环境问题拖死。我的建议是先把基础版本完整跑通再谈锦上添花。基础版本稳了你答辩就有底气。后面有时间想加分往Redis缓存热门商品、WebSocket消息通知这种方向扩风险和收益比控制得更好。2. 功能需求梳理把用户端与管理端的边界划清楚再动手2.1 角色权限设计很多同学一上来就写代码写到一半发现这里缺个功能、那里权限没控制再回头改改到崩溃。所以开工前第一件事就是把角色和功能边界想清楚。网上超市的项目角色设计成两类就够了普通用户USER和管理员ADMIN。不要一上来就把角色拆成会员、加盟商、超级管理员那是商业项目做的事毕设场景下只会增加无谓的开发量。权限控制怎么做最务实的办法是后端接口用拦截器校验JWT令牌再根据token里的角色字段判断是否放行。比如商品查询接口允许所有已登录用户访问而商品新增、修改、删除接口只允许管理员访问。前端路由层面再做一层配合管理端的页面单独抽出来配置路由守卫用户没有管理员权限就跳转到404或者首页。两层控制缺一不可只做前端控制不安全只做后端控制体验很差。这里有一个很多人踩过的坑前端路由守卫只能管看不到页面管不了接口被直接调用。有些人测试的时候发现自己用普通用户的token也能调管理员接口就慌了。这是因为后端拦截器里只校验了token是否存在没有校验角色。所以你写拦截器的时候一定要在token解析后把角色信息拿出来对比不光看是不是登录了还要看有没有权限做这件事。2.2 核心业务流程与订单状态机网上超市的核心业务流串起来就是一句话用户加购→结算生成订单→管理员发货→用户确认收货。这个流程里最值得花心思设计的是订单状态。我强烈建议用数字枚举来管理订单状态不要用字符串散着写。比如状态值含义后续操作0待付款用户可取消订单支付后进入待发货1待发货管理员可发货2待收货用户可确认收货3已完成交易闭环4已取消用户主动取消或超时未支付自动取消这套状态机写清楚之后后端Service层的逻辑就非常清晰了。比如支付订单这个方法先校验订单是否存在再校验当前状态是不是0然后才允许改成1。每个状态流转都做前置校验能挡掉一大半异常数据。很多老师答辩的时候就喜欢问如果一个订单已经在待发货状态用户还能不能取消你只要在取消方法里加上状态判断就能很自然地回答这个问题——不能因为状态机的流转是单向受限的。还有个业务细节也值得处理购物车里的商品在下单成功之后必须从购物车移除。这个逻辑看起来简单但很多人会忘记导致用户下单之后购物车里还有旧数据演示的时候非常尴尬。3. 数据库表设计订单与订单明细拆开的理由很重要3.1 表结构清单与字段说明数据库设计是答辩时老师最常盯着看的部分也是后面开发的地基。网上超市按最小可用原则建议建这么几张表user用户表字段包含id、username、password、nickname、avatar、phone、roleUSER/ADMIN、create_time、update_time、deletedcategory商品分类表id、name、sort、create_time、update_timeproduct商品表id、category_id、name、subtitle、main_image、detail、price、stock、sales、status上架/下架、create_time、update_time、deletedcart购物车表id、user_id、product_id、quantity、checked、create_time、update_timeorder订单表id、order_no、user_id、total_amount、pay_amount、status、consignee_name、consignee_phone、consignee_address、pay_time、deliver_time、confirm_time、create_time、update_timeorder_item订单明细表id、order_id、product_id、product_name、product_image、current_price、quantity、total_amountaddress收货地址表id、user_id、name、phone、province、city、district、detail_address、is_default我见过不少同学为了省事把订单和订单明细合成一张表每个商品一行重复存收货人信息。这在大数据量场景下一定是错误设计。因为一个订单包含多个商品如果把商品明细直接塞在订单表里json字段或重复行都无法保证数据一致性。拆成两张表order表存一次收货信息和订单总金额order_item表每行存一个商品快照通过order_id关联。这样无论从数据库设计规范还是业务扩展性来讲都说得通。3.2 金额字段、索引和逻辑删除的细节有几个数据库细节我建议你在设计阶段就注意不然改起来麻烦。第一金额字段必须用DECIMAL不要用FLOAT或DOUBLE。这不是洁癖问题而是浮点数在Java和MySQL里都存在精度丢失问题0.1加0.2可能等于0.30000000000000004。金额涉及真金白银哪怕你做的是模拟支付也必须在数据层面保证精确。线上超市商品价格和订单总金额全部用DECIMAL(10,2)存储Java实体类对应BigDecimal。第二索引不要乱建但关键的索引必须有。order表经常按user_id查用户的订单列表所以user_id要建索引order_item表经常按order_id查明细所以order_id要建索引。product表经常按category_id筛选category_id建索引也合理。其他的字段除非你明确知道查询会用到否则别一股脑全建索引尤其在建索引时要注意区分场景索引能加速查询但写数据时也要维护索引结构还占用额外存储索引太多让简单更新sql都变慢答辩时也容易露怯。第三逻辑删除vs物理删除要想清楚。我的建议是用户、商品这两个核心主数据表用逻辑删除加一个deleted字段默认为0删除时update为1。因为商品一旦被订单引用物理删除会导致订单明细里的关联数据悬空或报错。而购物车、日志这类边缘数据物理删除问题不大。实际取舍重点是业务中是否有历史数据必须保留、是否有关联外键会限制删除而不是一律物理删除或一律逻辑删除。4. SpringBoot后端先把骨架搭对再谈业务代码4.1 分层结构与统一返回体后端的项目结构建议按照常见的分层方式来组织controller、service、mapper、entity、dto、vo、config、common。分包方式不止这一种但按这个结构做老师一看就知道你接受过正规的工程训练。common包里放统一返回体Result类这是整个后端最核心的公共类之一。所有接口返回的数据都统一封装成一个对象大概长这样public class ResultT { private Integer code; private String message; private T data; public static T ResultT success(T data) { ResultT result new Result(); result.setCode(200); result.setMessage(success); result.setData(data); return result; } public static T ResultT error(String message) { ResultT result new Result(); result.setCode(500); result.setMessage(message); return result; } }这个类的好处是前端Axios拦截器统一判断code就能知道请求是否成功不用每个接口单独处理错误。同时结合全局异常处理器把业务异常、参数校验异常、未知异常统一转换成语义明确的返回信息前端拿到任何非200结果都能弹出一个能看懂的错误提示。没有这套统一处理系统里会出现系统繁忙这类让答辩老师印象减分的提示语。4.2 登录鉴权JWT拦截器的处理逻辑登录功能几乎所有管理系统都有但实现方式差别很大。Session方案在前后端分离项目里不好使因为浏览器和服务端跨域Session管理麻烦。JWT方案是目前最主流的选择——服务端不保存登录状态用户登录成功后签发一个token前端存起来每次请求放在请求头Authorization里后端拦截器解析验证并获取用户信息。关键代码逻辑分三块登录接口里根据用户名查出用户记录用BCrypt校验密码是否匹配。匹配成功就生成JWT token返回给前端。这里有一个很多人忽略的点密码千万不要明文存储也不要只用MD5加盐处理推荐直接用BCrypt。Spring Security里自带BCryptPasswordEncoder单独引入一个工具包也可以。BCrypt每次加密结果不同、自带盐值即使两个用户密码相同数据库里存的内容也不一样安全性比MD5好一个量级。拦截器配置里定义一个类实现HandlerInterceptor在preHandle方法里取出请求头中的token解析验证是否过期、签名是否合法。验证通过就把解析出的用户ID和角色放到ThreadLocal或request attribute里方便后面的业务代码直接取用。最后把这个拦截器注册到WebMvcConfigurer里并配置放行路径——登录、注册、商品查询、图片访问这些不需要登录就能访问的接口必须显式排除掉。我见过有人忘了配置放行路径结果自己前端登录页都调不通登录接口排查了半天才发现是被拦截器拦了。4.3 下单事务扣库存与生成订单的一致性网上超市项目里后端业务复杂度和含金量最高的接口就是提交订单。这个接口要做的事情包括查询购物车勾选的商品、校验商品是否上架、计算总金额、生成订单主表记录、生成订单明细记录、扣减商品库存、清空购物车对应商品。这几个操作必须同时成功或同时失败否则会出现订单生成了但库存没扣或库存扣了但订单没生成的数据不一致问题。解决办法就是著名的Transactional注解加在Service方法上。Spring会把方法包裹在一个事务里任何一步抛出RuntimeException整个事务回滚。Transactional(rollbackFor Exception.class) public OrderVO createOrder(Long userId, ListLong cartItemIds) { // 1.查询购物车中选中的商品 // 2.校验商品状态、计算金额 // 3.生成订单主表记录 // 4.循环生成订单明细记录 // 5.扣减商品库存注意判库存不足 // 6.删除购物车记录 return orderVO; }这里有个值得单独拿出来说的点扣库存的时候一定要加库存充足的前置判断否则会出现库存变成负数的情况。更稳的做法是在更新库存的SQL里加上WHERE stock #{quantity}这样一条附加条件如果影响行数为0说明库存不够主动抛出异常触发回滚。这样即使并发请求同时到来也不会超卖。虽然毕设场景并发量很低但把这个思路解释给老师听会显得你理解得比同龄人深。订单号也值得说一说。主键id一般用数据库自增但订单号不能直接用id因为订单号会暴露系统每天的订单量而且也需要更长的随机性。推荐用时间戳加随机数生成比如yyyyMMddHHmmss加四位随机数再加用户id尾号保证唯一性且可读性好。5. Vue前端页面是皮路由守卫和请求封装是骨5.1 项目初始化的推荐姿势前端部分环境准备是让很多新手卡住的地方。Node.js的安装其实不难难的是版本和各种依赖的兼容性。我的建议是Node.js用16或18的稳定版本npm随附即可。创建项目推荐用官方脚手架UI组件库我推荐Element Plus表格、表单、弹窗、分页都有现成组件对快速搭建管理后台非常有帮助。脚手架创建完项目后第一件事不是写页面而是把两个基础设施做好。第一封装Axios请求工具。新建一个request.js配置baseURL和拦截器。请求拦截器里从localStorage取token加到请求头响应拦截器里统一处理后端返回的Result结构code为200就返回data非200就弹出错误提示并reject。这样后续每个页面的请求代码只需要几行就能完成全局风格也统一。第二配置开发环境代理。前后端分离开发时前端跑在8080端口Vite默认5173后端跑在8080或9090端口。直接在代码里写死后端地址请求会跨域开发阶段最简单的方案是在vite.config.js里配置proxy把/api开头的请求都代理到后端地址server: { proxy: { /api: { target: http://localhost:9090, changeOrigin: true } } }这样开发环境不会出现跨域问题生产环境也只需要把后端接口统一挂在/api前缀下nginx反向代理配置起来非常方便。5.2 登录状态保持与路由守卫用户登录成功后前端要做两件事把token存到localStorage把用户信息存到Pinia或Vuex状态管理仓库里。为什么分开存因为token用于请求鉴权每次请求都要带用户信息用于页面展示和权限判断刷新页面后需要从后端重新拉取。路由守卫是前端的权限门面在router配置里加一个beforeEach钩子router.beforeEach((to, from, next) { const token localStorage.getItem(token); if (to.meta.requiresAuth !token) { next(/login); } else if (to.meta.requiresAdmin) { const userInfo useUserStore(); if (userInfo.role ! ADMIN) { next(/404); } else { next(); } } else { next(); } });管理端页面在路由meta里标记requiresAdmin普通用户就算手动改URL也进不去。登录页和注册页标记为免登录商品浏览页也放行——用户可以不用登录就逛商品但加入购物车或下单时必须登录这个产品逻辑更符合真实电商习惯答辩时也可以作为一个小亮点讲出来。5.3 商品列表、购物车和订单页的联调要点页面开发从商品列表开始最合理。商品列表页的核心是分类筛选 分页 关键词搜索后端接口设计成GET /api/product/list?categoryId1keywordxpageNum1pageSize8即可。前端拿到分页数据结构后把数据绑到el-table管理端或el-card网格用户端再用el-pagination绑定total和current-page。购物车页面需要注意一个数据同步的问题购物车里商品数量增减应该实时调后端接口更新数据库而不是只改前端存的数量。否则用户刷新页面后数量又变回去了演示时非常尴尬。我的做法是每次点击加减号调用PUT /api/cart/update接口传cartId和quantity后端校验quantity不能小于1更新成功后再回写前端数据。订单提交页是用户端联调最关键的地方。页面上展示勾选的商品清单、收货地址、订单总金额。用户点击提交订单后前端把cartItemIds和addressId传给后端后端返回生成的订单号。然后页面跳转到订单详情页或支付模拟页。模拟支付不需要对接真实支付平台把支付做成一个按钮点击后调POST /api/order/pay/{orderNo}接口后端把订单状态从待付款改成待发货即可。答辩时可以这样讲清楚业务流程老师也不会揪着你没对接微信支付不放因为毕设重点在业务逻辑完整闭环而不在商业外部依赖。管理端页面的核心是表格搜索弹窗表单的组合。商品管理页就是el-table展示商品列表每一行有编辑和删除按钮新增/编辑用el-dialog嵌el-form。这里表单校验一定要做商品名称为空、价格小于等于0、库存为负数这些情况必须在前端就拦截掉否则脏数据进了数据库后面后端接口也要跟着补校验。我的建议是前端用Element Plus的rules规则做基础必填校验后端再用Validated注解做二次校验前端防止无意义请求后端保证数据安全两层都不可少。6. 本地跑通启动报错排查从0到1的完整过程6.1 环境准备清单拿到源码之后很多人的第一反应是直接双击启动结果报错一片然后心态崩了。这里我给你一个完整的跑通顺序按这个顺序来能省掉80%的无效折腾。环境清单如下软件版本建议说明JDK8或11多数毕设项目稳定在这两个版本不要一上来上JDK 17Maven3.8.x配置国内镜像源否则依赖下载能等到怀疑人生MySQL5.7或8.08.0注意驱动配置差异Node.js16或18对应Vue3和Vite的兼容性开发工具IDEA / VS Code后端用IDEA前端用VS Code术业有专攻安装这块有个连锁坑JDK和Node.js装好后一定要配环境变量。很多同学的报错根源就是环境变量没配对java -version和node -v在命令行里执行不出来。配完之后记得新开一个命令行窗口再验证因为环境变量不会自动刷新到已打开的窗口里。6.2 后端和前端启动步骤后端启动的正确顺序是先用Navicat或命令行工具创建数据库然后导入项目里提供的SQL文件。导入成功后修改application.yml里的数据库连接配置重点是URL、用户名、密码三项。这里有个高频问题MySQL 8.0版本的JDBC驱动和连接URL写法跟5.7不一样8.0的driver是com.mysql.cj.jdbc.DriverURL里建议加serverTimezoneAsia/ShanghaiuseUnicodetruecharacterEncodingutf8不然容易报时区的错误。改完配置在IDEA里打开项目等Maven导入依赖完成后运行主类看到Started日志基本就成功了。前端启动相对简单在项目根目录执行npm install安装依赖同样建议用国内npm镜像然后npm run serve或npm run dev启动。启动成功后浏览器自动打开页面。如果页面能打开但登录或列表请求报错基本都是代理配置或后端没启动的问题。有个排查技巧打开浏览器开发者工具切到Network标签页看请求的URL和返回状态。如果请求返回404检查后端接口路径是否和前端代理路径一致如果返回500去后端控制台看报错堆栈日志里通常会明确告诉你问题出在SQL还是业务逻辑。6.3 高频报错与解决方案把这两年帮人处理过的报错做个小汇总你可以直接对照排查报错现象根本原因解决办法启动时端口被占用8080或9090被其他进程占用杀掉占用进程或在配置里改端口Access denied for user root数据库密码配置错误核对application.yml中的用户名密码Unknown database数据库没导入或库名不一致确认SQL文件已导入库名与配置一致Public Key Retrieval is not allowedMySQL 8.0的加密规则问题JDBC URL追加allowPublicKeyRetrievaltrueFailed to configure DataSource数据源自动配置失败检查ja包连接配置和驱动依赖是否引入CORS blocked by CORS policy开发环境跨域配置Vite proxy或后端CorsFilterMapper method not foundMapper接口没被扫描启动类加MapperScan或Mapper加Mappernpm install报错依赖下载失败切换npm镜像源后重新执行前端页面打开了但接口请求404前端代理未生效检查vite.config.js代理配置及接口前缀关于SpringBoot版本太高的问题这几年问的人也很多。现在新项目一拉下来就是SpringBoot 3.x它要求JDK 17及以上很多同学的旧教程是基于JDK 8的SpringBoot 2.x写的两者API有些差异。我的建议是如果你是按教程走教程用什么版本你就用什么版本别最新最稳跟着已验证的路径走能少踩好多兼容性坑。7. 答辩前的演示验收清单与后续扩展方向7.1 演示流程设计答辩演示不是随便点点页面建议提前设计一条讲故事的演示线。我的推荐顺序是先用管理员账号登录给老师展示商品管理、订单处理的能力强调后台的完整性和数据处理能力再退出登录切换普通用户视角从注册登录开始走一遍浏览商品、加入购物车、提交订单、模拟支付、查看订单状态的完整流程。最后再回到管理后台把刚才用户下的订单发货再切回用户端确认收货。一条闭合链路走完整个系统的价值全部体现出来了。演示之前必须检查几个地方数据库里一定要有足够的测试数据商品图片要能正常显示网络保持稳定电脑提前充好电。我见过有人答辩现场临时启动项目Maven在众目睽睽之下下载了五分钟依赖场面非常尴尬。建议前一天晚上把项目完整启停验证三次确保每个环节都能稳定复现。7.2 老师高频提问思路答辩时老师的问题其实有规律可循。我把问过最多的几个问题整理一下你心里先有个底订单状态是怎么管理的对应状态机设计从状态字段到流转校验答一遍。为什么用JWT不用Session答无状态、前端跨域友好、分布式场景扩展方便。购物车数据存哪里为什么答存数据库用户换设备数据不丢失。库存不够怎么办答下单事务里做库存校验不足则抛异常回滚。密码安全性怎么保证答BCrypt加密明文不落库。如果以后用户量大了性能怎么优化答加Redis缓存热点数据、加索引、订单分表、引入消息队列削峰。这些问题没有一个超纲只要你亲手写过都能答得上来。怕的就是那种只把源码跑通但代码一行没看过的同学老师随便问一个业务逻辑就露馅了。7.3 想拿高分可以做的三个扩展如果你时间和精力有余基础版本已经跑通了想做点差异化内容我推荐三个扩展方向按性价比排序第一给热门商品加Redis缓存。商品详情页每次请求都查数据库数据量大时性能是问题。用Redis缓存商品信息设置合理过期时间缓存命中直接返回。这个扩展代码量不大但能讲的东西很多比如缓存穿透、缓存雪崩的应对思路非常加分。第二订单超时自动取消。用户下单后30分钟未支付订单自动从待付款变成已取消。实现方案可以讲定时任务扫描也可以讲延时消息队列。毕设场景下用Spring的Scheduled定时任务扫描即可思路清楚又不复杂。第三销量和库存的可视化统计。管理端增加一个首页数据看板展示今日订单量、销售额Top5商品、库存预警列表用ECharts画几张图表。这个视觉冲击力很强演示时一打开就有完整管理系统的感觉。我自己带过的项目里凡是认真做了上面任意一个扩展的同学答辩成绩都比同组做纯CRUD的高一截。原因不是功能本身多厉害而是它证明了你对技术有主动探索的意识这恰恰是毕业设计最想考察的东西。如果这篇文章能帮你少走一点弯路少加几个小时的班那就值了。
返回列表