SpringBoot+Vue前后端分离服装销售平台系统全栈设计与实现

发布时间:2026/9/17 23:35:54
SpringBoot+Vue前后端分离服装销售平台系统全栈设计与实现 做Java后端开发这几年SpringBoot Vue 的前后端分离组合几乎成了接手Web系统最常见的标配。今天要拆解的“衣依”服装销售平台管理系统就是用 SpringBoot 做后端、Vue 写前端、MySQL 存数据、MyBatis 管持久层的完整项目涵盖了商品浏览、购物车、订单流转、库存扣减、后台数据统计这些电商业务里最典型的功能模块。如果你是准备毕业设计、想在校招简历里放一个能打的全栈项目或者刚入门前后端分离但缺一份完整源码参考这篇拆解值得你花十分钟看完。我会按自己实际做这个项目时的思路来复盘先讲业务怎么梳理、功能边界怎么切再讲技术选型背后的取舍然后是数据库表怎么设计、核心功能怎么落地最后把部署和排查问题的方法也一并交代清楚。整个过程不追求炫技只求把每一步的来龙去脉讲明白让你拿到源码之后能真正改得动、跑得起来。1. 项目定位与需求拆解1.1 业务边界先想清楚再决定写哪些功能做这类管理系统的第一件事不是写代码而是把“这个平台到底给谁用、解决什么问题”画清楚。“衣依”是一个服装销售平台它的业务本质是一个服装品牌或中小型商家想把线下门店的商品搬到线上让用户在线逛、在线下单同时还需要一个后台来管理商品、处理订单、看销售数据。想清楚这一点功能边界就很自然了。我把它分成两条线用户端前台注册登录、商品分类浏览、商品搜索、商品详情、加入购物车、提交订单、查看订单、个人资料修改。管理端后台管理员登录、分类管理、商品管理增删改查上下架、订单管理发货、查看详情、会员管理禁用/启用用户、数据看板销售额、订单数、热销商品。很多同学会把用户端做得特别复杂比如加上优惠券、拼团、秒杀。我的建议是如果目标是毕业设计或简历项目先把基础闭环做扎实。上面列出的功能已经能把“用户从登录到下单、管理员从接单到发货”整条链路跑通这就够了。优惠券和秒杀是加分项有精力再加不要一开始就铺太大否则容易烂尾。1.2 核心业务场景与角色权限划分一个系统如果连权限都理不清后面写接口必然一团乱麻。这个项目里我做的是经典双角色模型普通用户和管理员。角色权限范围典型操作游客可浏览商品、搜索商品查看列表、查看详情普通用户游客权限 个人操作注册、登录、加购、下单、查看订单管理员全部后台权限管理商品、分类、订单、用户、数据统计这里有一个很关键的设计并不是所有接口都能被所有人访问。比如“生成订单”“修改购物车”必须登录才能调“商品上架”“订单发货”必须管理员才能调。我当时用的是最轻量的一条路前端根据登录状态控制按钮显示后端用拦截器校验请求头里的 token。前端隐藏按钮只是用户体验的优化真正的安全防线在后端。这个意识很重要因为很多毕设答辩老师会专门问“你这个权限控制是怎么做的”你要是只答“前端判断了用户类型”基本就露馅了。1.3 这个项目适合用来学什么“衣依”这个项目最大的学习价值不在于某个单一技术多高深而在于它把 Java 全栈开发里最常用的一整套路子完整串联了起来用 SpringBoot 搭建 RESTful API理解 Controller-Service-Mapper 分层用 MyBatis 写灵活 SQL理解结果映射、动态 SQL、主键回填用 MySQL 做数据建模理解表关联、索引、事务用 Vue 组件化开发页面理解组件通信、路由守卫、Axios 封装用 JWT 拦截器实现登录鉴权理解无状态认证的完整流程。如果你能把一个项目从头到脚自己复现一遍再把里面几个核心点比如订单事务、权限拦截、库存扣减讲清楚面试官对你的评价通常不会低。2. 技术选型背后的思路2.1 为什么选 SpringBoot MyBatis MySQL而不是别的这个组合看起来“普通”但它恰恰是当前中小型管理系统最务实的搭配。我尝试过用 JPA 做数据持久层开发速度确实快可一旦遇到需要多表联查、统计报表的场景JPA 生成的 SQL 就很别扭。MyBatis 呢把 SQL 交给开发者自己掌控写个复杂查询、调优性能都很有底气。SpringBoot 的存在则把传统 SSM 里那些繁琐的配置全部干掉。以前搭一个 SpringMVC MyBatis 项目要配 web.xml、dispatcher-servlet.xml、数据源、事务管理器稍不注意就起不来。换成 SpringBoot 之后一个启动类加一个 application.yml一个能跑起来的项目就到位了这对写业务代码来说省下的时间非常可观。MySQL 就更不必说作为关系型数据库的经典选择它的吞吐能力和稳定性对一个小型服装销售平台来说绰绰有余而且社区资料极多遇到问题一查就有答案。整套选型组合在一起就一句话稳定、通用、好招人。企业里跑着的项目大量是这个组合你简历里写它起码不会让人觉得你做的项目脱离实际。另外前后端分离的选择也很重要。传统 JSP 那种服务端渲染的方式后端既写接口又套页面开发和维护都很痛苦。用 Vue 把前端彻底独立出来之后前端专注页面交互后端专注业务接口结构清晰团队协作也方便。就算只有你一个人开发分离开的代码结构也远比揉在一起好维护。2.2 前端工程与后端工程怎么配合一体化的前后端分离开发在本地通常让 SpringBoot 跑在 8080 端口Vue 开发服务器跑在 8081 端口前端开发环境下把接口地址代理到后端。这样两边可以独立开发调试互不干扰。我在项目里给前端定了几个关键目录src/api统一放所有接口请求一个模块一个文件src/router前端路由同时配置全局守卫src/store用 Vuex 管理全局状态比如用户登录信息、购物车数量src/views页面组件按 admin 和 user 分开目录。这样一来整个前端的职责非常单一。要做登录页就去 views 里加页面、在 api 里加对应接口、在 store 里存 token要控制页面访问就去 router 的守卫里判断角色。每个文件都是“各管一摊”后续改起来很舒服。2.3 项目目录层级如何划分最顺手后端我是严格按分层模式来的package 结构如下com.yiyi ├── controller # 接收请求、参数校验、返回结果 ├── service # 业务逻辑、事务控制 ├── mapper # MyBatis 的 Mapper 接口 ├── entity # 数据库实体映射 ├── dto # 前端交互的数据传输对象 ├── config # 跨域、拦截器、WebMvc 配置 ├── common # 统一返回结果、异常处理、常量 └── utils # JWT、日期处理等工具类这套结构是 Java Web 项目最经典的写法好处是“每一层只关心自己的事”。Controller 只做参数接入Service 只写业务规则Mapper 只负责数据库交互一旦出了问题顺着调用链很快就能定位。前端目录我上面说了再补充一点关于封装的思路——Axios 不要每个页面单独引入而是统一封装一个 request.js 文件配置基础 URL、请求拦截器自动带上 token、响应拦截器统一处理 401、500 等状态码。这样所有页面发请求都是同一个入口遇到问题只需改一处这是让项目代码变得“能看”的关键一步。3. 数据库设计与核心表结构3.1 业务表拆解从“买衣服”这个动作反推数据库设计我一般不从表开始而是从“业务流程”反推。用户进入“衣依”后要做的事情是注册登录 → 逛分类 → 看商品 → 加购物车 → 提交订单 → 等发货。每个动作背后至少对应一张表用户表user记录账号、密码、昵称、手机号、头像、角色分类表category记录服装分类比如男装、女装、童装商品表product记录商品名称、价格、库存、主图、详情、所属分类购物车表cart记录某个用户加入的某商品、数量、勾选状态订单表order记录订单号、下单用户、总金额、状态、收货信息订单明细表order_item记录订单内每个商品的快照信息轮播图表banner记录首页广告图方便运营替换。这里我要强调一个细节订单明细必须存商品快照而不是只存商品 ID。为什么因为商品价格和名称是可以变的如果用户下单后商家调高了价格订单明细里如果关联原商品表那用户看到的订单金额就和下单时不一致了。把“商品名、单价、图片、数量”原样复制进订单明细里才能保证历史订单的不可变性。这个细节在面试时提出来是很加分的。3.2 关键字段设计与状态机一张表设计得如何直接决定了后续代码好不好写。我说几个关键约定主键统一用自增INT简单稳定金额字段全部用DECIMAL(10,2)不用浮点类型避免精度丢失时间字段用DATETIME统一由后端生成逻辑删除字段is_deleted用TINYINT删除操作改为更新操作保留数据可回溯。订单状态用TINYINT存数字配合常量或枚举类管理。订单状态是整个项目里最需要想清楚的点。我设计了这么一套状态机状态值含义可流转到的状态0待支付1已支付、5已取消1已支付待发货2已发货2已发货3已完成3已完成无5已取消无状态不写死成字符串而用数字是为了后续扩展方便。比如后续要加“退款中”“退款完成”只要补两个数字编号就行。3.3 分页查询和索引设计商品列表和订单列表都必须分页。有的同学会直接在 Mapper 里用LIMIT start, pageSize手写分页那样每张表都要写一遍重复逻辑。我建议引入PageHelper这个分页插件一行代码就能完成分页实用性很强。索引方面核心表不需要加太多索引但有几个字段基本是必需的user.id、product.id、category.id这类主键系统自带索引product.category_id加普通索引分类筛选商品时能明显提速order.user_id加普通索引用户查看自己的订单列表是高频操作cart.user_id加普通索引购物车读取频繁。这里要小心一个“索引失效”的坑如果商品搜索需求用LIKE %keyword%这种写法索引是不生效的数据量小的时候无所谓但心里要有数。真到数据量大的时候就得换 Elasticsearch 或 MySQL 全文索引了那是后话。4. 核心功能的实操实现4.1 登录鉴权JWT 拦截器的完整落地登录鉴权我选了 JWT 方案而不是传统的 Session。原因是前后端分离的结构里后端接口不关心“客户端是谁”只需要验证“请求里的 token 是否有效、属于谁”。JWT 天然适合这种无状态场景。生成 token 的逻辑很简单public String generateToken(Long userId) { return Jwts.builder() .claim(userId, userId) .setExpiration(new Date(System.currentTimeMillis() 7 * 24 * 60 * 60 * 1000)) .signWith(SignatureAlgorithm.HS256, SECRET_KEY) .compact(); }用户登录成功后就返回这个 token前端把它存到localStorage并在后续每个请求的 header 里带上Authorization: Bearer token。后端拦截器是权限控制的关键我写了一个JwtInterceptor实现HandlerInterceptor接口Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 放行登录、注册、商品浏览等公开接口 if (isPublicApi(request.getRequestURI())) { return true; } String token request.getHeader(Authorization); if (!StringUtils.hasText(token)) { throw new BusinessException(401, 未登录); } // 解析 token校验有效性 Claims claims JwtUtil.parseToken(token.replace(Bearer , )); request.setAttribute(userId, claims.get(userId)); return true; }这里有一个我踩过的坑拦截器里如果拦截了全部接口那么登录接口本身也会被拦截造成死循环。解决方案就是在上面的代码里维护一个公开接口白名单比如/api/user/login、/api/user/register、/api/product/**都不需要 token 才能访问。这样游客可以浏览商品但下单、购物车这些操作就必须登录。管理员的鉴权也类似在拦截器里解析出 token 之后再查一下用户的角色字段非管理员直接拒绝。4.2 商品模块Vue 列表页到 MyBatis 动态 SQL商品列表页是前台最核心的页面。前端用 Vue 发请求拿数据后端用 MyBatis 动态拼接条件查询。一个典型的列表接口后端 Controller 长这样GetMapping(/api/product/list) public Result getProductList(RequestParam(defaultValue 1) Integer pageNum, RequestParam(defaultValue 12) Integer pageSize, RequestParam(required false) Integer categoryId, RequestParam(required false) String keyword) { PageHelper.startPage(pageNum, pageSize); ListProductVO list productService.getProductList(categoryId, keyword); return Result.success(new PageInfo(list)); }注意这里我返回的是ProductVO而不是直接返回实体类。原因很简单展示列表时一般只需要 id、名称、主图、价格、销量这几个字段直接返回整个实体既浪费流量还可能把不该暴露的字段比如库存、状态泄露出去。前面我提到 MyBatis 的动态 SQL 很灵活这一段是关键。分类筛选和关键词搜索可以写在同一个 Mapper XML 里select idgetProductList resultTypecom.yiyi.entity.Product SELECT * FROM product where if testcategoryId ! null AND category_id #{categoryId} /if if testkeyword ! null and keyword ! AND (name LIKE CONCAT(%, #{keyword}, %) OR description LIKE CONCAT(%, #{keyword}, %)) /if AND is_deleted 0 /where ORDER BY create_time DESC /selectwhere标签会自动处理多余的 AND这个细节很实用你手写 SQL 的时候很容易因为第一个条件为空导致 SQL 语法错误MyBatis 的动态 SQL 恰好把这个问题解决了。前端用 Category 组件切换分类时只需要重新传categoryId请求一次接口就行这是最直观的“前后端数据交互”体验。4.3 购物车与订单提交事务与防超卖购物车最核心的动作是加购和结算。加购的逻辑很直接先查当前用户的购物车是否已有该商品有就数量加 1没有就插入一条新记录。这里要注意一个细节修改数量时不能简单地前端传什么就存什么而应该在后端做一次数量上限校验比如单个商品不能超过 99 件防止用户恶意刷单。用户点了“去结算”之后后端要做一串连续的操作校验购物车里选中的商品是否还有库存根据商品实时价格计算总金额生成订单主表和订单明细表扣减商品库存移除购物车中对应的记录。这一串操作只要任何一步失败前面做的都不能生效。所以必须加事务注解我用的是 Spring 的声明式事务Transactional(rollbackFor Exception.class) public Long submitOrder(OrderSubmitDTO dto) { // 1. 查购物车选中明细 // 2. 遍历校验库存、计算金额 // 3. 插入 order 表 // 4. 批量插入 order_item 表 // 5. 批量扣减库存 update product set stock stock - ? where id ? // 6. 删除对应购物车记录 // 返回订单号 }关于库存扣减我先说一个最简单的版本也是这个项目能跑通的版本先查出商品库存判断够不够够则执行UPDATE product SET stock stock - #{count} WHERE id #{productId}。但直接这么写在高并发下会产生“超卖”问题。如果你想在项目里体现出思考深度可以把 SQL 改成乐观锁方案UPDATE product SET stock stock - #{count} WHERE id #{productId} AND stock #{count}用受影响行数来判断是否扣减成功如果返回 0 说明库存不足就不再继续出单。这是现阶段最容易被面试官认可的做法实现成本也低。另一个可行方案是给商品表加一个version字段做乐观锁但判断逻辑会更绕建议先把握住上面那条 SQL 的精髓。4.4 管理端数据看板几条统计 SQL 撑起的首页后台首页的数据看板是我个人很喜欢的模块因为它数据和业务交叉最能体现你对 SQL 的掌握程度。销售额统计可以按“最近 7 天的每日支付金额”来展示SQL 长这样SELECT DATE(create_time) AS day, SUM(total_amount) AS amount FROM order WHERE status IN (1, 2, 3) AND create_time DATE_SUB(CURDATE(), INTERVAL 6 DAY) GROUP BY DATE(create_time) ORDER BY day这里要说明的是为什么要筛状态订单只有支付之后才真正算销售额“待支付”“已取消”的订单都不能计入统计。如果你统计口径搞错了后台的数字会非常难看答辩时被问到会很尴尬。热销商品排行则是按销量聚合SELECT p.name, SUM(oi.quantity) AS sales_count FROM order_item oi LEFT JOIN product p ON oi.product_id p.id GROUP BY oi.product_id ORDER BY sales_count DESC LIMIT 10前端用 Vue ECharts 画折线图和柱状图配上 Element UI 的后台布局整个数据看板的效果非常出彩。这个模块投入产出比很高强烈建议你一定要做。5. 部署上线与高频问题排查5.1 本地从零跑起来的完整步骤不管你是拿源码学习还是做毕设演示先让项目在本地跑起来是第一步。我列一下自己的标准操作流程第一步准备环境。JDK 1.8、Maven 3.6、MySQL 5.7、Node.js 14版本不要乱选我验证过这套组合稳定。MySQL 安装后要创建一个数据库比如yiyi_db把项目里的sql脚本导入进去。第二步改后端配置。重点看application.yml里的数据源信息spring: datasource: url: jdbc:mysql://localhost:3306/yiyi_db?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: 123456这里有个容易踩的坑serverTimezone必须配置否则高版本 MySQL 驱动连接时会出现 8 小时时差的问题。另外useSSLfalse建议也加上本地开发环境没必要走 SSL减少不必要的问题。第三步启动后端。用 IDEA 打开后端工程等 Maven 依赖下载完直接运行启动类。看到控制台打印出 Tomcat started on port 8080 就说明成功了。第四步启动前端。命令行进入前端目录npm install npm run serve这里我再提醒一次Vue 的npm install经常因为网络问题卡住。如果你在国内最好把镜像源切到淘宝镜像npm config set registry https://registry.npmmirror.com实测下载速度快很多。第五步浏览器访问前端地址用系统里已有的管理员账号登录后台用普通用户账号走一遍“浏览商品 → 加购 → 下单”的流程验证整条链路是否正常。5.2 高频报错与排查技巧实录做这个项目时我把踩过的坑整理成了几个类型每个都值得单独说跨域问题。前后端分离开发时最常见的报错是浏览器提示 CORS error。解决的办法有很多比如在 Controller 上加CrossOrigin注解或者配置一个全局跨域配置类。我自己的做法是写一个WebMvcConfigurer的配置类统一设置允许跨域的路径、头部和方法。这种全局方案的好处是以后新增接口不用再一个个加注解。SpringBoot 版本与 MyBatis Starter 不兼容。很多同学一上来就把 SpringBoot 拉到最新版结果引入mybatis-spring-boot-starter后启动报错其实就是版本匹配问题。我的建议是别追新选一个经过大量项目验证的稳定组合比如 SpringBoot 2.7.x MyBatis Spring Boot Starter 2.2.x这套闭着眼睛都能跑起来。等到后面你对版本管理有经验了再考虑升级到 SpringBoot 3.x 也不迟。Vue 打包后布局异常 / 刷新 404。这是前端部署最常见的两个问题。布局异常通常是静态资源路径写成了绝对路径把vue.config.js里的publicPath改成相对路径./就行刷新 404 则是前端用了 history 路由模式但服务器没有把未知路径重定向到 index.html。本地开发时配置devServer的historyApiFallback: true部署到服务器则要在 Nginx 里配置try_files。MyBatis 参数传递问题。有次我写 Mapper 接口方法只传了一个参数进去直接用了#{id}结果 MyBatis 报“参数不匹配”。原因是多参数方法必须加Param注解ListOrder selectOrders(Param(userId) Long userId, Param(status) Integer status);这个规则很简单但没有经验的人第一次很容易卡住。你在写所有的 Mapper 方法时只要方法里有超过一个参数就老老实实加Param不要偷懒。5.3 排查问题的心法与思路最后我还想聊一个比具体操作更重要的东西遇到 Bug 时怎么定位。很多新手喜欢到处打断点调试看一堆变量搞了半天没头绪。我的习惯永远是从日志和请求链路入手。前端打开浏览器开发者工具先看 Network 面板里请求的状态码。如果接口 500直接复制后端控制台里的报错堆栈去搜如果请求都没发出去那就是前端路由或 Axios 封装的问题如果请求发出去了但没返回数据就看后端接口入参和 MyBatis 打印的 SQL对照数据库里的数据排查。说到 SQLMyBatis 的 SQL 日志配置一定要开mybatis: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl开了之后所有查询语句都会打印到控制台。排查数据问题的时候直接复制打印出来的 SQL 到数据库工具里手动执行一眼就能看出是条件写错、关联写错、还是数据本身有问题。这个办法几乎能解决 80% 的表关联和数据记录问题。另一个我觉得很实用的经验是改代码要“小步快跑”。一次只改一个点然后立刻跑到对应接口验证不要一口气改十个文件再编译运行。否则出了问题你连是哪一步引起的都找不到。6. 几个值得再打磨的细节方向到这里这个项目的主体功能和运维经验基本都讲完了。如果你想把项目的完成度再往上提一档我建议从下面几个方向入手投入不大但收益明显。订单支付模块目前大多是“模拟支付”也就是点击支付按钮后直接把订单状态改成已支付。如果想体现更强的业务能力可以在订单流程里加一个支付回调的模拟接口核心在于理解“支付结果由服务端主动回调修改订单状态而不是前端如果支付成功就自己改状态”。这个思路放到真实项目中非常重要值得自己去设计一下。权限控制现在只区分了普通用户和管理员两个角色如果想做得更深可以考虑引入更完整的权限框架把“角色”和“权限点”解耦。比如管理员能访问哪些接口不是写死在代码里而是用数据库配置做一个简单的 RBAC 模型。这个升级对理解权限设计会有一个质的提升。商品搜索目前是 SQL 的模糊匹配在数据量小的场景下完全够用。如果你想让搜索更智能可以做关键字分词、搜索热度统计等但这些更多是业务上的锦上添花不影响系统的核心闭环。很多同学跑来问我“这个项目做完了简历上该怎么写”我的建议是不要只写“基于 SpringBoot 和 Vue 开发了服装销售平台”太单薄。你要写清楚自己具体做了什么遇到什么问题怎么解决的。比如使用 JWT 拦截器实现无状态登录鉴权区分普通用户和管理员权限通过乐观锁方案解决订单提交时的库存超卖问题设计订单状态机保证订单从待支付到完成的流转一致性搭建后台数据看板通过 SQL 聚合统计销售数据并可视化展示。这几条才是能打动面试官的内容因为它们体现了你的思考深度和解决问题的能力。我自己在实际带项目的时候最深的体会是做全栈项目最大的障碍往往不是某个技术点不会而是不知道整个系统应该长成什么样。代码写一半发现表设计不合理改表就要连带改接口、改前端接口返回的数据结构不统一前端每个页面都要单独处理权限漏了校验又回头补登录判断。这些坑我都踩过。所以如果你现在正卡在某个环节不要着急怀疑自己解决一个问题的过程就是对这个知识体系的一次补全。把“衣依”这个项目从头到尾跑一遍再自己动手改一改、加一个功能你对 Java 全栈开发的理解会比单纯看十篇教程都深刻得多。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询