搞Java Web电商类的项目这两年最常见的需求就是“给我一个能跑、能看、能交差的全栈商城”。而网上服装商城这类带业务闭环的项目正好是面试和毕设里出镜率最高的一种。今天这篇我打算把手头这套SpringBoot2 Vue3 MyBatis-Plus MySQL8.0的服装商城系统按我的理解拆开揉碎讲一遍从技术选型、数据模型、关键模块实现到前后端对接和部署阶段的注意事项全流程捋清楚给打算复现或者二次开发的朋友一条相对顺的路径。开篇先把话说清楚这套系统不是什么大厂级别的分布式架构它更像是一个典型的单体全栈实战项目适合用来搞懂电商基础业务闭环也适合作为求职作品集里的“主推项目”。后端基于SpringBoot 2.x搭建RESTful API负责用户体系、商品管理、购物车、订单流转、支付回调模拟等核心逻辑前端用Vue3 Composition API配合基础UI组件库独立工程对接接口数据库采用MySQL 8.0配合MyBatis-Plus做数据访问和业务查询。整套代码里我最看重的是它的模块边界清楚、注释完整还有配套的说明文档这对初学者和想快速扩展的开发者都相当友好。下面我分六个部分讲从选型逻辑开始一路到实际运行中的经验教训。1. 技术栈组合的底层逻辑为什么是SpringBoot2 Vue3 MyBatis-Plus MySQL8.0先聊选型。很多人看到这套组合觉得“挺常规的”但常规组合背后恰恰有它合理的匹配关系。理解这层匹配关系比单纯记住框架名字有用得多。1.1 SpringBoot 2.x稳定、生态成熟、上手曲线平滑SpringBoot 2.x目前仍然是企业级Java后端的中坚版本。相比3.x它有几个实际优势一是兼容的第三方库范围非常广很多老牌的权限框架、工具包在2.x下几乎零成本集成二是社区资料极多遇到问题搜一下基本都有现成方案三是对新手来说2.x的自动配置机制和起步依赖体系更友好不容易被一堆底层细节劝退。在这套商城系统中SpringBoot 2.x承担的核心职责是提供RESTful接口统一返回JSON结构管理业务Bean的生命周期注入Service、Mapper等组件通过Spring Security或拦截器机制完成认证与权限校验集成MyBatis-Plus简化数据访问层的开发量我个人觉得选SpringBoot 2.x还有一个隐性的考虑绝大多数院校的课程和大部分企业的存量项目还停留在2.x时代用这套技术栈做项目经验迁移成本低面试时被追问的深度也相对可控。1.2 Vue3组合式API带来的工程化舒适感Vue3相比Vue2最大的变化在于组合式API。对于商城这种页面状态多、组件复用需求高的场景组合式API能把“某个业务相关的所有状态和处理函数”集中在一起代码阅读体验比Options API分散写法要好很多。这套系统前端采用Vue3 Vite构建配合Vue Router和Pinia或Vuex管理路由与全局状态。实际开发时Vue3的setup语法糖让组件逻辑非常紧凑比如商品列表页的加载状态、分页参数、筛选条件全部可以塞进一个setup函数里思路清晰改动也方便。Vue3还有一个细节值得夸它的响应式系统基于Proxy实现对于数组和对象的增删操作检测更加彻底。商城购物车、SKU选择这类高频修改对象结构的场景Vue3比Vue2少了很多“修改了数据但视图不更新”的坑。1.3 MyBatis-Plus单表CRUD的减负神器复杂查询的坚实底座MyBatis-Plus不是银弹但在商城这种“大量单表操作少量复杂联表统计”的项目里它的性价比极高。官方提供的BaseMapper内置了insert、deleteById、selectById、selectPage等方法意味着用户表、商品表、轮播图表这些基础实体的增删改查几乎不用手写SQL。实际开发时MyBatis-Plus几个特性一定要用熟条件构造器QueryWrapper / LambdaQueryWrapper动态拼查询条件非常方便比如商品列表按分类筛选、按价格排序、按关键词模糊搜索用LambdaQueryWrapper几行代码搞定而且类型安全不会出现字段名写错的情况。分页插件PaginationInnerInterceptor商城后台的商品列表、订单列表基本都要分页配置好MybatisPlusInterceptor后Mapper层直接返回IPage对象前端传pageNum和pageSize后端返回总记录数和数据列表。逻辑删除服装商城的商品、分类数据运营过程中往往需要“下架”而不是“物理删除”。配置TableLogic注解后MyBatis-Plus会自动把delete操作转成update逻辑删除字段查询时自动过滤已删除记录安全又省事。自动填充创建时间、更新时间、创建人等公共字段用MetaObjectHandler统一处理业务代码里完全不用手动set。1.4 MySQL 8.0窗口函数、JSON能力与优化的默认字符集MySQL 8.0相比5.7有几个值得利用的能力。第一是默认字符集变成utf8mb4存储emoji和生僻字毫无压力这对商品名称、用户昵称等字段非常重要。第二是支持窗口函数做商品销量排行、订单金额累计等分析型查询更顺手。第三是JSON数据类型虽然这套系统里没有重度使用但如果后期要扩展商品自定义属性、规格参数JSON字段定位会是很好的方向。数据库连接层面记得在JDBC连接串中显式设置serverTimezoneAsia/Shanghai和useSSLfalse否则容易出现时区报错和SSL握手警告。字符集连接参数characterEncodingutf8也要配好不然中文乱码问题会逼疯人。2. 服装商城业务模块拆解用户端与后台管理端的核心边界商城系统的业务模块本质上是围绕“用户—商品—订单”这三条主线展开的。这套项目把用户端和管理后台分开设计账密体系共用一套用户表通过角色字段区分权限范围。下面我按模块说明数据模型与核心交互。2.1 用户端模块注册登录、商品浏览、购物车、下单支付用户端是to C的主战场接口设计要偏向“场景化”。核心数据表至少包括用户表user用户名、密码BCrypt加密存储、昵称、头像、手机号、性别、生日、角色标识。商品表product商品名称、主图、轮播图、详情描述、分类ID、价格、库存、销量、上下架状态、逻辑删除标记。商品分类表category分类名称、父级ID、排序值。服装商城因为SKU往往带颜色、尺码所以商品规格维度我建议用独立的规格表和SKU表来维护。购物车表cart用户ID、商品ID、SKU ID、数量、选中状态。订单表orders订单编号、用户ID、订单总金额、实付金额、状态字段待付款/待发货/待收货/已完成/已取消、收货人信息。商城系统最关键的关联表。订单明细表order_item订单ID、商品ID、SKU ID、商品快照名称、单价、数量、小计金额。收货地址表address用户ID、收货人、手机号、省市区、详细地址、默认标记。用户端的核心交互流程是注册/登录 → 浏览首页与商品列表 → 点击商品进入详情 → 选择SKU与数量 → 加入购物车 → 提交订单 → 模拟支付 → 查看订单状态。每一步都对应一组RESTful接口接口命名建议按资源风格来比如/api/user/login、/api/product/page、/api/cart/add、/api/order/submit。2.2 后台管理端模块商品管理、订单处理、分类维护、用户管理管理后台是to B的视角核心追求是“高效操作数据可视”。模块划分如下仪表盘Dashboard)统计今日订单数、销售额、用户增长量、热销商品TOP5等指标。商品管理商品列表分页、新增/编辑商品含SKU维护、上下架操作、库存调整。分类管理维护商品分类树支持二级甚至三级分类。订单管理按状态筛选订单、查看订单明细、发货操作修改物流状态、处理退款/售后入口。用户管理查看用户列表、禁用/启用账号、重置密码。管理员端与用户端共用同一套后端服务通过角色的权限拦截器来区分可访问的接口路径。比如/api/admin/**开头的接口只放行管理员角色/api/user/**和/api/cart/**等普通用户接口则登录即放行。2.3 服装商品SKU建模颜色、尺码维度怎么落表服装类商品和3C类商品在SKU建模上差异很大。一个T恤可能有3种颜色、4个尺码组合出12个SKU。如果为每个SKU单独建商品主记录后台维护会非常痛苦。合理的做法是商品表和SKU表分离product表存放商品基础信息比如标题、主图、详情、分类、默认价格。这里的“默认价格”仅用于列表展示实际下单按SKU价格计算。product_sku表每一条记录对应一个具体的颜色尺码组合包含SKU编码、价格、库存、规格图片、规格属性JSON。前端详情页在渲染时拿到商品下所有SKU列表根据用户选择的颜色和尺码组合筛选出唯一SKU再展示对应价格和库存。这套设计不仅符合服装行业的真实习惯也为后续扩展“满减促销”“优惠券”等营销能力留了余地。3. 后端落地细节与方法论鉴权、购物车、订单状态机和库存扣减后端部分我重点讲四个容易被忽视但非常影响体验的点认证授权方案、购物车合并逻辑、订单状态机设计、库存超卖问题。3.1 认证授权JWT与拦截器配合实现无状态鉴权这套系统用的是JWTJSON Web Token方式。用户登录成功后后端生成包含用户ID、用户名、角色等信息的Token返回给前端前端存储到localStorage或pinia中之后每个请求在请求头携带Authorization: Bearer token字段。后端通过一个全局拦截器HandlerInterceptor做三件事放行登录注册接口、首页商品浏览接口等公开路由校验请求头Token是否存在且有效无效则直接返回401解析Token后把用户信息放入ThreadLocal或Request Attribute供后续业务代码使用。密码存储一定要用BCrypt加密千万不能明文存数据库。哪怕项目只在本机跑这个习惯也必须养成。BCrypt每次加密的盐值不同相同密码得到不同密文安全性远高于简单的MD5加盐拼接。3.2 购物车从“未登录临时加购”到“登录合并”的体验问题很多入门项目把购物车做得太简单只有登录状态才能加购。但真实用户的行为是先随便逛逛加了几件商品到购物车然后才登录。如果登录后购物车清空了体验就很糟糕。一个务实的方案是未登录时购物车临时存储在前端本地localStorage或IndexedDB用户登录后前端把本地购物车数据一次性提交到后端调用购物车合并接口后端按“同一用户同一SKU”维度合并数量并返回最新的购物车列表前端用后端返回的数据替换本地数据完成状态同步。这个方案在这类单体项目中实现成本不高但对产品体验提升显著。如果是毕设项目这一条完全可以在文档里作为“体验优化亮点”写出来。3.3 订单状态机用状态字段驱动后续动作而不是散落一地的if else订单状态是电商系统的灵魂。这套系统里我建议用整型状态字段来管理流转因为可读性和可扩展性更好。状态定义如下状态值含义后续动作0待付款超时自动取消 / 用户取消1待发货用户支付成功等待商家发货2待收货商家已发货等待用户确认收货3已完成用户确认收货订单流程结束4已取消用户取消或超时未支付5售后中用户申请退款/退货等待处理状态流转务必通过封装的方法来实现比如cancelOrder()、payOrder()、shipOrder()、confirmReceipt()每个方法内部先校验当前状态是否允许目标状态再更新状态。一定不要直接在Controller里写order.setStatus(1)否则后续要加“状态变更日志”“消息通知”时改动量会非常大。3.4 库存扣减先查后改要不得数据库原子更新才是底线教材里经常出现的“先select库存再if库存够再update库存”写法在高并发下一定会出问题。两个人同时下单都查到库存剩1件都判断能买结果超卖。正确做法是直接执行原子更新SQLUPDATE product_sku SET stock stock - #{count} WHERE sku_id #{skuId} AND stock #{count}这条SQL利用数据库的行锁和条件判断只有当库存大于等于购买数量时才会更新成功影响行数为1则扣减成功为0则库存不足。MyBatis-Plus中通过自定义Mapper方法执行上述SQL即可。订单创建整体还需要事务包裹保证“扣库存生成订单生成明细”要么全部成功要么全部回滚。3.5 支付模块没有真实支付渠道时怎么模拟回调真实对接支付宝或微信支付需要商户号、证书等资质很多学习场景不具备这些条件。这套系统的做法是模拟支付前端点击“立即支付”按钮调用支付接口后端直接生成“已支付”状态并记录订单的交易流水号与支付时间。在说明文档中可以写明未来替换真实支付时仅需将支付接口改成“发起支付请求 - 接收第三方异步回调 - 修改订单状态”即可其他业务逻辑完全复用。4. Vue3前端工程化实践接口层设计、路由守卫与页面状态管理前端这块很多人只顾着“把页面画出来”忽略了工程结构。其实一个清晰的前端工程能极大降低联调和后期维护成本。4.1 接口层封装与请求拦截器推荐在src/api目录下按业务模块拆分接口定义文件例如product.js、cart.js、order.js、user.js。每一个接口函数返回Promise统一走封装的request实例。request实例的核心逻辑基于axios创建实例设置baseURL指向后端服务地址请求拦截器里从本地存储获取Token并设置请求头响应拦截器里统一处理后端返回的code字段非0状态码提示错误信息捕获HTTP 401状态跳转登录页并清理本地登录状态。这一层封装好之后页面组件里不需要关心Token拼装、错误弹窗这些横切逻辑业务代码干净很多。4.2 路由守卫控制页面访问权限Vue Router的全局前置守卫是权限控制的核心。未登录用户访问需要身份认证的页面如订单确认页、个人中心、后台管理直接重定向到登录页并携带redirect参数。管理员访问后台路由时再从Store中取出当前用户角色做二次校验角色不符时跳转首页并给出无权限提示。router.beforeEach((to, from, next) { const token localStorage.getItem(token); if (to.meta.requiresAuth !token) { next({ path: /login, query: { redirect: to.fullPath } }); return; } if (token to.path /login) { next(/); return; } next(); });4.3 商品详情与SKU选中组件的思路SKU选择是服装商城前端相对复杂的交互。我的实现思路是页面挂载时请求商品详情接口拿到product信息和skuList页面上维护两个选中状态当前选中颜色、当前选中尺码。当颜色或尺码变化时计算函数遍历skuList找到同时匹配当前颜色尺码的SKU记录更新展示价格和库存。如果找不到匹配项则提示当前组合不可选。这样一个纯前端的联动逻辑无需后端参与响应速度快用户体验也正常。4.4 购物车与订单页状态同步和地址联动购物车页面需要支持修改数量、选中/取消选中、删除和计算总价。每次修改数量后前端重新计算选中商品总价。提交订单时把选中商品的SKU ID、数量、收货地址ID传给后端后端再根据SKU价格实时计算金额。注意金额校验必须以后端计算为准前端传的total只是展示用防止用户篡改请求参数。订单确认页还需要联动地址管理展示默认选中第一个地址用户可切换地址、新增地址、编辑地址。地址保存和列表接口都属于普通用户权限登录后即可调用。5. MySQL8.0在商城系统中的设计实践索引优化、事务边界和初始化数据数据库设计的好坏直接影响系统能跑多顺。这个章节我讲讲项目启动时的库表设计、初始化脚本编写、以及运行过程中的优化思路。5.1 建表规范与公共字段设计每张业务表都建议包含以下几个公共字段idbigint自增主键MyBatis-Plus默认TableId(type IdType.AUTO)。create_timedatetime插入时自动填充。update_timedatetime更新时自动填充。deletedtinyint逻辑删除标记默认0。商品表、订单表这类高频查询的表还要根据查询场景设计好索引。比如商品表加category_id索引、status索引订单表加user_id索引、status索引订单明细表加order_id索引。索引不是越多越好每个索引都会增加写入成本覆盖主要查询场景即可。5.2 初始化SQL脚本让项目开箱即跑一个可以直接运行的初始化数据库脚本是这个项目“含文档”价值的重要组成部分。脚本内容包括建库语句CREATE DATABASE IF NOT EXISTS shop DEFAULT CHARACTER SET utf8mb4;建表语句所有业务表结构一次性创建。初始化数据管理员账号用户名 admin密码默认为加密后的123456、测试用户、商品分类示例数据、若干条服装商品记录T恤、牛仔裤、连衣裙等、SKU记录、轮播图配置。初始化数据这一段最实用的效果是前端页面跑起来后不是空架子而是能看到完整分类、商品、图片占位哪怕没有真实图片资源也不影响理解界面布局。5.3 事务边界哪些操作必须放在事务里商城系统里明确要加事务的典型场景订单提交生成订单主记录 插入订单明细 扣减库存 清空对应购物车记录。四步操作必须一个事务。注册用户插入用户记录 初始化默认收货地址后者即使失败用户也应该能注册成功所以这一步的事务范围可以缩小或不做强绑定。商品上架更新商品状态 更新所有SKU状态推荐放事务中。SpringBoot中使用Transactional注解即可默认情况下只有在抛出RuntimeException时才会回滚受检异常不会回滚。所以业务方法内部如果需要对受检异常处理要么向上抛出RuntimeException要么在注解中指定rollbackFor Exception.class。5.4 分页查询优化的一个细节避免深分页后台订单列表运营久了之后数据量大翻到后面几页时会发现查询变慢。原因是深分页场景下MySQL要扫描大量偏移行。常见优化方法有两种前端限制最大页码后台不让翻到过深页数查询时增加“上一页最大ID”条件利用主键索引跳跃定位。对于这套系统方法一就够用。后台列表一般不会真的有人翻到几百页限制到50页以内体验正常实现也简单。6. 从源码到部署运行完整的复现步骤与常见坑排雷光看不跑等于零。最后一章我按顺序列出从拿到源码到浏览器跑通的完整过程以及我在实操中遇到的几个典型问题。6.1 环境准备清单环境项版本建议备注JDK1.8及以上推荐JDK8或JDK11Maven3.6及以上用于后端依赖管理Node.js14及以上Vue3工程构建需要MySQL8.0字符集选择utf8mb4IDEIDEA / VS Code后端和前端可分开打开前端包管理器npm / yarn / pnpmpnpm安装依赖更快6.2 后端启动步骤创建数据库并执行init.sql脚本确认库名与后端application.yml配置一致。修改application.yml中的数据源配置包括数据库地址、用户名、密码。用IDEA以Maven方式导入后端工程等待依赖下载完成。启动SpringBoot主类观察控制台日志确认Tomcat端口默认8080正常启动。用接口测试工具推荐Apifox或Postman先验证登录接口是否返回Token。6.3 前端启动步骤在vue工程根目录运行npm install安装依赖。检查src/utils/request.js中的baseURL确保指向后端项目实际地址通常是http://localhost:8080。执行npm run dev启动开发服务器。浏览器访问Vite提示的本地地址通常是http://localhost:5173先走一遍注册、登录、浏览商品、加购、下单流程。6.4 实操中遇到的典型问题及解决问题一数据库时区报错启动SpringBoot时如果看到关于serverTimezone的报错是因为MySQL 8.0默认时区与JDBC驱动不一致。解决办法是在JDBC连接串中追加serverTimezoneAsia/Shanghai。问题二端口被占用8080端口被其他进程占用的情况很常见。要么在前端request.js中把baseURL改成自定义端口要么在后端application.yml中修改server.port。改后端端口时要同步改前端配置千万别只改一端。问题三依赖下载慢或失败国内网络访问Maven中央仓库速度不稳定建议在settings.xml中配置阿里云公共仓库镜像。前端依赖同理可以配置npm或pnpm的淘宝镜像源。这个问题不解决新环境拉代码后可能半天跑不起来。问题四跨域问题前后端分离部署时必然出现跨域请求。后端要么通过CORS配置类统一放行要么在前端Vite的server.proxy中配置代理。开发环境用Vite代理更简单生产环境则建议后端统一配置CORS。问题五上传图片后无法访问商品图片是外部URL或本地路径需要确认SpringBoot的静态资源映射是否配置了对应目录。很多项目使用本地磁盘存储图片通过虚拟路径映射来访问这一步漏配的话详情页图片就会裂掉。问题六接口返回BigDecimal金额导致前端精度丢失Java后端返回订单金额时如果直接返回BigDecimal数值前端JavaScript有可能出现浮点精度问题比如19.99变成19.989999999。解决办法是在后端对金额字段统一进行格式化返回字符串类型或者让前端接收后调用toFixed(2)处理。6.5 二次开发的合理方向建议如果拿到这套源码想做二次开发我的建议是有三个方向性价比最高优惠券与促销模块在订单计算环节增加优惠明细表扩展满减与折扣逻辑。商品评论与评分新增评论表关联用户和SKU在商品详情页展示评论列表。数据统计可视化借助MySQL8.0的窗口函数统计每日销售额、分类销售占比在管理后台用图表展示。这三个方向都围绕核心业务链条展开改动范围清晰也容易在文档里写出亮点。7. 最后说点实在经验这套系统我从拿到源码到完整跑通前后大概花了一个晚上加一个上午。最耗时的反而不是代码本身而是环境细节数据库时区配置、前端代理设置、图片目录映射这三个坑每个都可能消耗一两个小时。如果你在复现过程中卡住了优先检查这三处。有一点我觉得值得单独提一下项目附带的文档一定要认真看一遍再动手。它不只是给你讲“怎么启动”里面的接口文档、数据库设计说明、功能清单能让你在动手之前就对整个系统结构有个整体认知。盯着一行行代码猜逻辑效率远低于先看文档再回头验证代码。最后再补一句关于学习方式的建议。如果是打算拿这个项目去面试不要只停留在“能跑通”至少要把订单状态机、库存扣减、JWT鉴权这三个点的设计思路自己梳理一遍做到能跟别人讲清楚“为什么这么做”。框架前后端分离的项目多如牛毛能体现区分度的恰恰是这些业务关键点上的理解和取舍能力。
阅读完成 · 觉得有帮助?