ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

SpringBoot+Vue3零食商铺全栈实践:从前后端分离到部署避坑指南

2026/9/18 4:12:41 拓冰建站 浏览量
SpringBoot+Vue3零食商铺全栈实践:从前后端分离到部署避坑指南 1. 项目背景与核心需求拆解做这个“基于SpringBootVue小零食商铺系统”其实是在一个很典型的场景下开始的一边要交课程设计/毕业设计的成果一边又不想随便糊弄一个“增删改查演示系统”交差。零食商铺这种主题看着轻量但该有的商业系统要素一个都不少做出来之后无论用于答辩还是用于写进简历颗粒度都够用。更重要的是它不需要凑那种假大空的复杂业务可以让你把精力集中在SpringBoot后端接口设计、Vue前端交互、前后端联调这些真正核心的事情上。从需求层面拆解一个零食商铺系统至少要覆盖两条业务线用户侧游客浏览、用户登录注册、商品分类查看、商品详情、购物车管理、下单支付模拟、订单查询、个人中心和管理侧管理员登录、商品管理、分类管理、订单处理、轮播图配置、用户管理。如果你只做单角色CRUD那这个项目做完基本等于白做——面试官和答辩老师最反感的就是没有角色边界和业务状态的“假系统”。所以我从一开始就把用户端和管理端的权限边界、数据可见性分开设计。标题里点名了SpringBoot和Vue这也直接决定了这套系统的技术形态是前后端分离。前端独立部署通过HTTP接口跟后端通信而不是传统JSP那套服务端渲染。这种做法已经成为行业主流做这个项目的过程本质上就是一次完整的全栈协作训练你既要写后端又要写前端等于一个人把前端工程师、后端工程师、产品经理三个角色全干了。那到底适合谁来参考我觉得有三类人特别适合照着做一是正在准备毕业设计/课程设计的学生这个选题难度适中、演示效果好二是从Java后端想往全栈方向走、但没有完整项目经验的新人系统地跑一遍前后端联调能补齐你对接口设计、跨域、数据交互的认知盲区三是已经学了Vue但只会对着文档写静态页面的前端初学者通过项目把Vue Router、Axios、状态管理串起来才能真正理解这些库是干什么的。2. 整体设计思路与技术选型解析2.1 后端为什么锁死SpringBoot后端选SpringBoot已经不是选择题而是默认项了。SpringBoot最大的价值在于“自动装配”机制——它通过starter依赖和条件化配置把繁琐的Spring XML配置、Tomcat部署配置全部收编让你用最少的配置就把项目跑起来。很多初学者一开始不理解SpringBoot内部做了什么其实你可以把它想象成一个“自带水电煤的精装房”以前用SpringMVC像拿毛坯房从瓷砖到水管都要自己铺而SpringBoot把Web容器、数据源、事务管理器全部预装好了你只管拎包入住写业务代码。版本选择上这里我要特意强调一个坑不要盲目用最新的SpringBoot 3.x。SpringBoot 3.0基于Jakarta EE规范包名从javax.*变成了jakarta.*很多老教程的代码直接复制过来就编译报错。而且SpringBoot 3.x要求JDK 17及以上如果你的开发环境还是JDK 8老老实实用SpringBoot 2.7.x就好。热词里“springboot版本太高”这个搜索热度很高说明有太多人一上来就踩了版本坑。我的建议是SpringBoot 2.7.18 JDK 8这是兼容性最好、网上资料最多、遇到问题最容易查到的组合。这个组合对一个小零食系统来说性能绰绰有余完全没有追新的必要。2.2 前端Vue版本和配套工具的取舍Vue这边同样有版本纠结Vue 2还是Vue 3我的选择是Vue 3 Vite。原因很简单官方已经停止对Vue 2的维护了现在新项目再开Vue 2相当于从第一天起就欠着技术债。Vue 3的组合式APIComposition API让逻辑复用和组织代码的方式更干净setup语法糖写起来也舒服。这里要点名一个高频搜索词“vue安装及环境配置”——很多人卡在第一步。完整的环境配置是安装Node.js建议16以上Vite需要、用npm或pnpm安装依赖、然后用Vite创建项目。我推荐用npm create vitelatest的方式创建Vue 3项目而不是传统的vue create因为Vite的冷启动速度和热更新体验比Webpack好太多尤其是开发阶段改一行代码秒级刷新能极大减少等待的烦躁感。配套工具方面路由用Vue Router 4状态管理用PiniaVuex在Vue 3里虽然也能用但Pinia更轻量TS支持更友好。HTTP请求用Axios这个没什么悬念拦截器机制特别适合统一处理token注入、错误提示这类通用逻辑。2.3 数据库模型设计把小系统按商城的骨架搭很多人做这类系统时最容易犯的错是把所有字段塞进一两张表里觉得“反正功能简单”。这个想法很危险。数据库表结构反映的是你对业务的理解深度哪怕是小项目该拆的表也必须拆清楚。我设计的核心表有这些用户表user、商品分类表category、零食商品表snack、轮播图表banner、购物车表cart、收货地址表address、订单表orders、订单明细表order_item。简单解释一下这么拆的逻辑购物车和订单必须分开因为购物车是“草稿状态”订单是“最终状态”订单和订单明细也必须分开因为一个订单会包含多种商品如果把商品信息直接冗余在订单表里你后面想统计“哪个零食卖得最好”就得解析字符串那还不如不做。商品表字段设计上我建议至少要包含名称、图片、描述、价格、原价用来做划线价、库存、销量、上架状态、创建时间。价格字段用DECIMAL(10,2)千万别用float——浮点数做金额计算会出现0.10.2不等于0.3的经典问题这在支付场景下是不可接受的。订单表的状态字段是整个系统的核心状态机我用tinyint存储在代码里定义枚举常量0待付款、1待发货、2待收货、3已完成、4已取消。每次订单状态的变更都要做前置状态校验比如“已取消”的订单不能直接跳到“已完成”必须走完整的流转路径这样业务逻辑才严谨。2.4 前后端分离的目录结构和部署形态前后端分离之后项目结构上最忌讳的就是把前端源码塞进后端的resources/static目录里。一开始可能图省事想“打成一个jar包算了”但这种做法会让前后端的构建过程互相污染部署时也不方便独立扩展。我的做法是建立两个独立的目录snack-server后端SpringBoot工程和snack-web前端Vue工程中间只通过接口通信。开发时用Vite的代理解决跨域问题生产环境用Nginx把/api路径反向代理到后端服务前端静态资源交给Nginx托管。3. 核心功能模块设计与实操要点3.1 后端分层架构与统一接口规范后端的代码组织建议严格按照Controller→Service→Mapper三层来分Controller只做参数接收和结果包装Service层写业务逻辑Mapper层跟数据库打交道。很多新手喜欢把业务逻辑全堆在Controller里一个方法写一二百行看起来是“省事”了后面维护、加功能就是灾难。我见过太多这类烂代码凡是Service拆分清楚的后面改需求基本半小时搞定堆在一起的改一个字段要全局搜索。这种直观的对比做一次项目就能深刻体会到。接口设计上强烈建议封装一个统一的返回体ResultT。我写的是比较简单的版本包含三个字段code状态码、message提示信息、data数据。正常返回时code为200业务异常时返回自定义错误码比如401表示未登录、403表示无权限、500表示服务端错误。这样做的好处是前端Axios拦截器可以统一判断code不用在每一个请求回调里重复写错误处理逻辑。3.2 用户认证与权限控制JWT 拦截器的实践登录认证这个环节我用的是JWTJSON Web Token。选择JWT而不是Session核心原因是前后端分离架构下Session的“服务器端保存状态”策略天然不适用——前端和后端可能部署在不同的域名和端口下跨域时Cookie的携带和处理都异常麻烦而JWT是无状态的后端只需要在收到请求时验证Token的合法性和时效性即可。具体实现流程是用户登录成功后后端生成一个有效期2小时的JWT返回给前端前端拿到Token后存储在localStorage里并在Axios请求拦截器中自动加上Authorization: Bearer token头后端定义一个拦截器拦截需要登录的接口解析Token如果解析失败直接返回401。这里有几个细节要注意。第一Token里只放userId和用户名这类非敏感信息不要手贱把密码放进Token的payload里——JWT本身是Base64编码是可以被解码的不是加密的。第二管理端接口和用户端接口的权限要分开校验比如/admin/**路径的接口只允许管理员调用这可以在JWT里加一个role字段拦截器先判断角色再放行。3.3 商品分类与检索实现商品分类我用的是简单的父子级分类设计表里用parent_id字段标识层级。现实中零食分类一般是两级结构比如“坚果炒货”下面有“瓜子”“花生”。前端导航栏展示一级分类点击后通过路由传递分类ID商品列表页根据分类ID查询子分类下的所有商品。商品检索这块我做了两套方案一个是通过分类ID查询另一个是关键词模糊搜索“首页搜索框输入零食名称”SQL用LIKE %关键字%即可。这个体量的数据量完全不需要上Elasticsearch这种重量级搜索引擎用MySQL的模糊查询就够了。答辩的时候如果被问到“搜索性能优化”你可以回答数据量大时可以引入索引优化、分库分表但现在属于合理设计。3.4 购物车逻辑前端临时态还是后端存储购物车是这个项目最有设计感的地方。我见过很多学生直接把购物车数据存在Vue的localStorage里这样刷新不丢失实现还简单。但这样做有一个致命问题用户换一台设备登录购物车就空了而且数据不安全。更合理的方案是把购物车数据维护在后端每次加减商品都调用接口同步到数据库前端只负责展示和触发操作。购物车表设计的核心字段是用户ID、商品ID、购买数量。加购接口的逻辑是先判断该用户购物车里是否已存在该商品如果存在则数量加1不存在则新增一条记录。这个逻辑很简单但要注意一个容易忽略的问题——下单前必须校验商品的库存。我在设计时用户点击“去结算”时后端会把购物车里的商品和库存一一比对库存不足的商品直接提示用户“XX零食库存不足”而不是让订单带着错误数据生成。3.5 订单流程设计从下单到收货的全状态流转订单模块是整个系统的业务重点花的时间也最多。用户从购物车勾选商品进入结算页填写收货地址、选择“支付方式”这个项目是模拟支付我直接接了一个假的支付按钮点击后订单状态从“待付款”变为“待发货”。提交订单的后端逻辑是事务性的生成订单主表记录、批量插入订单明细、扣减对应商品库存、清空购物车——这四个操作必须在一个Transactional事务里任何一个失败就整体回滚防止出现“订单建了但库存没扣”这种数据不一致的脏情况。订单列表的查询也值得设计一下。用户端需要按状态筛选待付款、待发货等所以我在订单表上建了user_id和status的联合索引。管理端的订单列表则不同它是全量所有用户的订单而且需要和用户表关联查询展示“买家昵称”。这里我用的是MyBatis-Plus的分页查询配合VO类把关联查询结果直接映射到展示对象避免在Service层做大量的字段拷贝。3.6 文件上传商品图片怎么存、怎么访问商品图片上传是一件看似简单但坑很多的事。我在设计时考虑了两种方案一种是传到本地服务器的/upload目录另一种是传到OSS云存储。为了演示方便和可控性我先实现了本地存储的方式后端提供一个/api/upload接口接收MultipartFile把文件保存到服务器的指定目录文件名用UUID重命名防止冲突然后把可访问的URL存到数据库商品表里。这里有个很隐蔽的坑需要特别提醒前端开发时代理和后端返回的图片URL协议、域名、端口一定要一致。我一开始遇到的情况是上传成功后后端返回的图片地址是http://localhost:8080/upload/xxx.jpg但前端页面跑在http://localhost:5173下直接访问这个地址会报跨域错误。解决办法是在Vite的server.proxy里把/upload路径也代理到后端前端图片地址就统一写相对路径/upload/xxx.jpg由代理转发。生产环境同理Nginx配置里要把图片访问路径和/api一起代理到后端不然就会出现“商品列表有图、图片加载不出来”的问题。4. 前端核心页面与交互实现细节4.1 前端工程初始化与路由设计Vue项目初始化这块我推荐用Vite创建之后手动装上Vue Router、Pinia和Axios。安装依赖时如果遇到版本冲突大概率是Node版本太低或太高Vite 4及以上对Node版本有要求。这个环节我踩过Node版本坑后来直接装了一个Node 16.20.2的LTS版本才稳定下来。你的开发环境最好是保持LTS版本不建议追最新的奇数版本比如19、21这种——那些是实验版本装了不少包会提示不兼容。路由设计方面我采用了经典的“用户端管理端”双布局结构前台用户端页面商城首页/home、商品列表/category/:id、商品详情/snack/:id、购物车/cart、订单确认页/checkout、订单列表/orders、个人中心/profile、登录页/login、注册页/register。后台管理端页面数据概览仪表盘/admin/dashboard、商品管理/admin/snack、分类管理/admin/category、订单管理/admin/order、用户管理/admin/user、轮播图配置/admin/banner。路由里有两个技术细节值得关注。一个是页面级路由守卫在beforeEach钩子里判断用户是否登录如果访问的是购物车、订单这类需要登录的页面而用户未登录直接重定向到登录页同时带一个redirect参数记住来源登录成功后跳回原页面。这个体验细节很加分答辩时可以说“我考虑了用户操作流程的连贯性”。另一个是路由懒加载使用动态import()让Vue Router按需加载组件避免首屏一次性打包所有页面导致首屏加载过慢——这一点在大项目里是优化重点在小项目里养好习惯也是对的。4.2 商品列表页分类联动、排序筛选商品列表页是我花了不少心思设计交互的地方。顶部是搜索框和分类标签用户点不同的分类标签路由参数同步变化页面重新请求接口。排序方式我做了三个选项默认排序、按价格从低到高、按销量降序。后端接口接收sortType参数在SQL层做ORDER BY条件的动态拼接。还有个体验优化是加载状态处理。每次请求商品列表时先用ref变量控制加载动画显示数据返回后延时隐藏。在网速慢的环境下这个细节能让用户感知到“系统在干活”而不是点了没反应。状态管理的活儿我用Pinia的store来保管购物车数量和用户信息这类全局共享数据避免多个组件间通过事件层层传递。4.3 商品详情页轮播图、数量选择与加入购物车商品详情页的骨架是上方商品图片轮播、商品名称、价格、销量库存、数量选择器、“加入购物车”和“立即购买”按钮。数量选择器前端可以做加减但提交给后端的数量必须在后端再次校验——前端永远只是体验层后端才是数据可靠性的兜底。这个思想我在后面很多地方都坚持落实。“立即购买”按钮在功能上设计成直接进入订单确认页并且只携带当前这一件商品的信息不走购物车。实际上它和后端对接时在请求体里传一个snackId和quantity参数后端在创建订单时单独处理这种“直接购买”场景。“去购物车结算”则是传一个cartIds数组后端根据这些购物车记录的ID批量生成订单。两种下单路径最终的落表逻辑是同一套Service方法只是入参不同。详情页里还有一个零食详情介绍的视频位置展示零食制作过程。视频格式上我发现很多现成链接是m3u8格式这是流媒体切片格式浏览器原生video标签不支持直接播放需要引入hls.js在video标签上监听canplay事件用Hls.isSupported()判断浏览器是否支持然后动态绑定视频源。这个属于踩过的坑——一开始我直接扔了个m3u8地址给video标签白屏半天之后才去查了才知道要加hls.js。4.4 购物车页勾选、全选、修改数量和实时合计购物车页面的交互逻辑是所有页面里最“绕”的。用户勾选一个商品时需要有“已选数量”和“已选总价”的实时反馈。前端数据结构是购物车列表数组每一项包含checked字段。我写了三个计算属性checkedItems筛选出勾选的项、checkedCount勾选数量、totalPrice勾选总价。全选框的状态用checkedItems.length cartList.length来判断半选状态用indeterminate控制。修改数量时前端立即显示乐观更新的数量同时防抖调用后端更新接口。执行删除操作时删除成功后要同步更新全局的购物车角标总数。这个购物车角标在导航栏上放在Pinia里管理任何页面都能直接访问。还有个体验彩蛋当购物车为空时显示一个零食空袋子插画和“去逛逛”按钮比直接白屏友好得多。4.5 订单提交流程和支付模拟订单确认页核心是展示商品清单、填写或选择收货地址、提交订单。收货地址我支持“新增地址”弹窗用表单收集姓名、电话、详细地址校验手机号规则。提交订单时前端把地址ID传给后端后端在订单表里冗余存储一份地址快照姓名、电话、地址文本避免用户之后改了默认地址历史订单的收货信息也被篡改——这个设计细节说出来能让答辩老师眼前一亮。支付模拟环节我做了两种方式一种是在线模拟支付弹窗展示“微信支付-模拟环境”的界面点击“确认支付”后调用后端的支付回调接口传入订单号把订单状态从“待付款”改为“待发货”另一种是“货到付款”直接下单成功后跳到“待发货”状态。无论哪种都涉及到一个核心点支付成功后要确认事务一致性不能出现“钱付了但状态还是待付款”的情况。4.6 管理后台的“够用就好”设计管理后台我没有做得太重因为核心展示点还是在前台购物流程。后台的重点模块是商品管理商品列表、新增/编辑弹窗、图片上传、上下架切换、库存修改、订单管理按状态筛选、查看明细、发货按钮、统计概览今日订单数、销售额、商品总数、用户总数用4个数字卡片展示。管理端的表单元件我用的是Element Plus组件库表格、弹窗、表单校验这些成熟组件能省掉大量手写UI的时间。组件库版本要注意和Vue版本匹配Element Plus对应Vue 3Element UI对应Vue 2——装错了页面直接渲染不出来这是又一个常见低级错误。4.7 前后端联调与跨域问题处理前面写到的各个功能模块最后要打通必须解决联调时的跨域问题。开发环境下我在Vite配置文件里设置了代理server: { port: 5173, proxy: { /api: { target: http://localhost:8080, changeOrigin: true }, /upload: { target: http://localhost:8080, changeOrigin: true } } }这段配置的意思是前端请求/api/xxx时Vite开发服务器把这个请求转发到http://localhost:8080/api/xxx浏览器看到的还是同源请求自然不会触发跨域拦截。changeOrigin: true很关键它会把请求头里的Host字段改成目标地址否则后端在获取请求头时可能会拿到错误的来源。生产环境下我在服务器上装了Nginx配置了类似的代理规则location /api/ { proxy_pass http://127.0.0.1:8080; } location /upload/ { proxy_pass http://127.0.0.1:8080; }这套“开发用Vite代理、生产用Nginx代理”的组合拳是前后端分离项目的标准玩法。理解了这个机制后面无论接什么样的后端服务你都有排查问题的底气。5. 常见问题排查与避坑指南5.1 版本兼容问题这个项目里最容易翻车的就属版本兼容问题了。我把几个强相关的版本选择做成速查表你照着选基本能避坑组件推荐版本/组合说明JDK8 或 11兼容性最稳SpringBoot 2.7全支持SpringBoot2.7.x别用3.xjavax迁移到jakarta坑太多Node.js16 LTS 或 18 LTS需要支持Vite 4/5Vue3.x配合Vite别用Vue 2了UI库Element Plus对应Vue 3Element UI是Vue 2时代的MyBatis-Plus3.5.x跟SpringBoot 2.7兼容好热词里“springboot版本太高”的搜索热度一直没降说明这是一个普遍痛点。我的经验是新手做项目绝不追新。框架的“新”不能带来业务价值的提升反而会消耗大量时间在排查兼容性问题上。等到你有足够经验评估新版运行时再迁移不迟。5.2 图片上传后访问404这类问题基本跑不出三个原因文件没保存成功、保存到了但不是预期路径、路径映射没配置。我排查时的方法是先看后端日志确认上传接口是否返回了保存路径然后直接在浏览器单独访问这个图片地址看返回什么。如果404检查WebMvcConfigurer里是否加了静态资源映射。上传路径如果放在项目运行目录外比如/home/upload/SpringBoot默认的静态资源处理器是访问不到这个目录的需要在配置类里手动添加registry.addResourceHandler(/upload/**) .addResourceLocations(file:/home/upload/);这一步是图片能正常访问的关键。生产环境我强烈建议把图片目录放在和项目解耦的外部路径不要放在jar包内部的resources下因为打包后写入和读取都麻烦升级时还可能把用户上传的图片冲掉。5.3 Vue打包后布局异常热词里“vue打包后布局异常”也上榜了这个问题的核心原因是publicPath配置错误。默认打包时资源引用是绝对路径/assets/xxx.css如果你把打包后的dist目录部署在Nginx的某个子路径下资源请求会落到根路径上导致404页面自然就样式全无。解决办法是在Vite配置文件里设置base: ./让打包产物使用相对路径引用资源。另外还有一类“布局异常”是首页能打开但刷新就404这属于前端路由history模式导致的。刷新时浏览器实际请求的是/home这个路径但Nginx没有对应的静态文件就返回404了。需要在Nginx里配置try_files $uri $uri/ /index.html;把没有匹配到的请求全部回退到前端入口文件这招叫“history fallback”是SPA部署的标配。5.4 跨域请求被拦截开发时跨域问题可以用Vite代理搞定但有些时候你会发现代理配置了还是不生效。我遇到过的几种情况是前端请求路径里代理目标写错、后端接口没有统一以/api开头导致有些请求没匹配到代理规则、或者后端CorsFilter和前端的代理规则同时生效起了冲突。我的建议是开发阶段只要用了代理后端就不要额外开CORS跨域配置否则双重配置容易出一些隐蔽的请求头丢失问题。5.5 日期时间格式问题后端返回的时间字段默认是Java的时间格式比如2024-05-28T15:30:00前端直接显示非常难看。我在JSON序列化配置里统一设置了时间格式spring: jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT8同时后端所有时间字段统一用LocalDateTime类型不要用Date避免和前端交互时出现时区偏移——这个坑可能排查大半天才发现是时区少8小时。5.6 购物车和订单的并发一致性问题热词里有“Redis在SpringBoot中的使用”这类题虽然没有在这个项目强制用到但购物车场景确实值得思考一下。两个浏览器同时买同一个商品的最后一件库存会不会超卖在单体应用阶段最简单的兜底方案是扣库存的SQL语句写成原子操作UPDATE snack SET stock stock - #{quantity} WHERE id #{snackId} AND stock #{quantity}这条语句在数据库层面保证了“扣减数量不超过当前库存”即使并发请求同时打过来数据库的行锁也会让它们排队执行后到的请求会因受影响行数为0而返回库存不足。我在下单Service里除了事务控制还用了这条SQL作为最后的防线。如果你的项目需要更高并发可以把库存扣减异步化用Redis的DECR命令先扣预扣库存——不过对课设和中小型商铺系统来说数据库原子更新已经非常够用了。5.7 一个重要笔误前后端字段命名不一致联调时最让人抓狂的是“前端拿到的数据是undefined”。排了半天发现是后端返回的字段名是user_name下划线风格前端访问的是userName驼峰风格。如果你用MyBatis-Plus可以在application.yml里开启驼峰映射mybatis-plus: configuration: map-underscore-to-camel-case: true这样user_name字段能自动映射为Java类里的userName属性JSON输出也是驼峰风格和前端JavaScript的命名习惯天然对齐。前后端字段命名统一能省掉大量联调时互相扯皮的口水。6. 从这个小系统里能延伸出的扩展方向很多人做完一个课设项目就停下来了其实这个“小零食商铺”可以延伸的深度远超想象。我自己在实际迭代中至少想过而且要推荐你尝试这几个方向按性价比排序第一接入真实运营数据。给商品表多建一些字段比如产地、净含量、保质期、口味标签模拟出和真实电商平台接近的商品信息。用脚本插入几百条零食数据后列表加载、分类筛选的体验和用三两条测试数据完全不是一个量级。第二引入Redis做会话管理和缓存。这个系统的验证码登录、购物车数量缓存、首页热点商品缓存都可以用Redis处理。比如把验证码以5分钟有效期的形式存入Redis登录时校验比对这是面试官特别爱问的场景。SpringBoot整合Redis的套路很固定加依赖、配连接、写一个RedisConfig配置序列化器然后StringRedisTemplate直接用。第三消息队列的引入。订单创建后的“延迟关闭”场景就可以用RabbitMQ的延迟队列实现——用户下单15分钟不支付自动把订单状态改成已关闭释放库存。这个功能很能体现你对电商业务的理解深度。第四部署上云。本地跑通之后买一台轻量云服务器把MySQL、Nginx、后端jar包、前端dist目录全部部署上去用域名加HTTPS访问。这个过程能逼着你把Linux操作、防火墙配置、进程守护systemd或nohup、日志管理这些实战技能全过一遍。我实际参与过的不少项目都是从“本地能跑”到“部署上线”这一步让参与者的工程能力拉开了差距。就我个人重做这类全栈项目时的体会而言最大的收获其实不是“会用了SpringBoot和Vue”而是建立了一套调试和排查问题的思维逻辑从页面现象倒推网络请求、从网络请求倒推后端日志、从后端日志倒推到SQL和数据。这个过程每走一遍你对系统的掌控力就上了一个台阶。做这个零食商铺系统时我大概花了三分之一的时间写业务代码剩下三分之二的时间全在处理上面这些小坑和边界情况——但这部分时间的产出恰恰是最高价值的经验积累。最后分享一个我一直在用的小技巧任何接口写完先别急着写前端页面用接口调试工具把边界情况都测一遍——把参数传错类型、把必填字段留空、把库存改成负数、把订单状态乱跳看看后端会不会返回友好的错误提示。一个后端接口稳不稳就看它在非法输入面前是否依然从容。小零食系统的体量刚好够你把这些基本功练扎实又不会淹没在复杂的业务逻辑里做完之后你会发现再去接触更大的电商系统很多思路都是相通的。