恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
SpringBoot+Vue前后端分离:艺术品电商系统设计与实现全解析
首页
资讯中心
/
SpringBoot+Vue前后端分离:艺术品电商系统设计与实现全解析
SpringBoot+Vue前后端分离:艺术品电商系统设计与实现全解析
发布时间:2026/9/17 8:49:25
我花费了两周时间把一个基于 SpringBoot Vue 前后端分离的艺术品网上商城系统从零搭建、联调、一直部署到云服务器。做之前我以为这跟普通电商网站没什么区别无非是拿个开源商城脚手架改改页面。真正动手才发现艺术品这种非标品、高客单价、一物一库存的商品在很多核心环节都跟卖手机、卖日用品的思路完全相反。这篇文章把我的完整设计思路、数据库建模过程、接口实现方案、Vue 前端的关键交互以及开发过程中踩过的坑全部摊开来讲。项目的代码不多但每个模块背后为什么这么设计才是真正值得收藏的部分。如果你正准备做电商类毕业设计或者想练手前后端分离项目又恰好对艺术品垂直领域有兴趣这篇文章可以直接抄作业。1. 先想清楚艺术品商城和普通电商差在哪1.1 业务本质没有 SKU库存永远只有 1普通电商最核心的数据模型是 SKU。一件 T 恤有颜色、尺码、库存数量SKU 表一铺开规格组合出来了库存加减、购物车结算全部围绕 SKU 流转这套体系非常成熟。但艺术品完全走不通这套逻辑。一幅画就是一件世界上没有第二件同款没有红色 L 码这种概念也没有库存 10 件这种状态。库存只可能是 1卖掉了就没了连补货的可能都不存在。这个业务特点直接决定了艺术品表结构的设计思路。为艺术品建一张独立的 artwork 表而不是试图套用商品 SKU 的通用电商模型。字段上不需要 sku_id、不需要多规格映射核心就围绕这件作品是谁的、什么材质、多大尺寸、有多少张图、卖多少钱、现在还在不在卖。库存字段stock可以保留但恒为 1它存在的意义不是为了配合 SKU 逻辑而是为了在下单事务里做并发安全的库存扣减判断。这个细节后面细讲。1.2 决策链路长收藏和购物车比普通商城更关键艺术品的客单价动辄几百几千甚至更高用户绝对不会像买日用品那样看了就下单。他大概率会先收藏反复翻看细节图把商品加进购物车隔几天再来看一眼甚至拿给朋友参谋一下最后才决定付款。这意味着收藏、购物车、浏览记录这些浅层意向模块在艺术品商城里的重要程度远比普通商品要高。从产品设计上说收藏按钮要在详情页最显眼的位置购物车的入口要在页面顶部常驻从后端接口设计上说收藏列表、购物车列表、订单列表这几个接口的响应速度要快页面要能在一次请求里拿到完整数据不能出现过长的 loading。我后面在前端状态管理里专门设计了 cart 模块和 favorite 模块会具体展开。1.3 强视觉依赖图片就是商品的实物体验买手机可以看参数表买艺术品只能看图片。买家对着屏幕判断一幅画的笔触、色彩、质感图片的清晰度、加载速度、展示方式直接影响了购买决策。这个特点给系统带来的技术影响是前端需要支持多图展示主图切换、缩略图、局部放大是必备功能图片要做懒加载艺术品详情页少则三四张、多则八九张大图一次性加载完白屏时间会非常久后端要处理好图片的存储和访问路径图片上传、静态资源映射都要提前设计不能把图片存进数据库也不能把文件路径写死成某个临时目录。1.4 一口价还是拍卖要明确范围艺术品电商平台的玩法比普通电商多常见的有几种一口价购买、拍卖竞价、私人定制、寄托代卖。其中拍卖是最吸引眼球也最复杂的模式涉及出价记录、倒计时、实时状态推送、保证金冻结、超时处理技术难度比一口价高出好几个量级。如果这个项目是毕设或者个人练手我强烈建议把范围控制在一口价交易闭环艺术品上架、用户浏览、收藏、加入购物车、下单、模拟支付、订单管理、后台管理把这个闭环做扎实比堆砌一堆半吊子功能有价值得多。艺术品种类的抽象也要合理。书画、油画、陶瓷、雕塑、玉石这些品类的共性字段有作品名称、作者、创作年代、尺寸、材质、风格、描述、图片。完全可以用一张表加 category 字段统一建模不必每个品类建一张表。后续新增品类只加枚举值不必改表结构。2. 系统架构与数据模型设计先能把一件艺术品描述清楚2.1 技术选型为什么锁定 SpringBoot Vue这套组合在目前的中小型管理系统和电商项目里覆盖率极高不是没有原因的。SpringBoot 的最大优势是启动即用内置 Tomcat自动装配把大量繁琐配置吃掉了服务端开发人员可以集中精力写业务代码不需要再面对一堆 XML 配置。Vue 的优势是组件化开发加响应式数据绑定商品展示、购物车、筛选条件这些交互密集的页面用 Vue 写起来非常顺手代码组织也很清楚。我也考虑过用 SSMSpring SpringMVC MyBatis或者 JSP Servlet但最后放弃了。最核心的原因是前后端是否分离。SSM 和 JSP 那套渲染方式页面和后端接口强耦合后期想加一个小程序端或者 App 端后端接口和页面要一起动维护成本很高。SpringBoot 提供 RESTful JSON 接口Vue 负责页面渲染两边并行开发互不干涉同一套后端接口以后可以支撑多个前端入口。版本选择上有一个强烈建议SpringBoot 用 2.7.x不要一上来就追 3.x。SpringBoot 3.x 基于 Jakarta EE很多旧依赖坐标、旧教程写法都不兼容新手遇到兼容性问题会非常头疼。Vue 这边项目用的是 Vue 2.7 Vue Router 3 Vuex如果你是新开项目用 Vue 3 Pinia Vue Router 4 也完全可以核心业务逻辑没有差别只差组合式 API 的写法和生态差异。2.2 数据库表结构核心五张表的设计细节数据库用的 MySQL 8.0字符集 utf8mb4。整个系统核心表有五张用户表、艺术品表、购物车表、收藏表、订单表。用户表users字段id、username、password、nickname、avatar、phone、email、roleadmin/user、create_time。这里有一个红线密码绝对不能明文存储。项目里用 BCryptPasswordEncoder 对密码做 BCrypt 加密注册时加密入库登录时把用户输入的明文密码和库里密文做校验。艺术品表artworks是整个系统的核心字段设计如下字段类型说明idbigint主键titlevarchar(120)作品名称artistvarchar(80)作者/艺术家categoryvarchar(30)品类painting/calligraphy/ceramics/sculpture/jadematerialvarchar(30)材质宣纸、油画布、陶瓷等stylevarchar(30)风格流派写意、工笔、印象派等size_descvarchar(50)尺寸描述68x136cm 这类格式year_createdint创作年代descriptiontext作品描述cover_imgvarchar(255)封面图 URLdetail_imgsvarchar(1000)详情图画 URL用逗号分隔pricedecimal(10,2)售价stockint库存当前固定为 1statusint0 在售、1 已售、2 下架sales_countint累计销量create_timedatetime上架时间关于库存字段再做一点补充。单件艺术品库存恒等于 1有人会问直接用 status 区分在售和已售不行吗不行。下单过程中要做扣减库存这个动作用一个带条件判断的 UPDATE 语句配合事务才能从根本上防止并发超卖。如果只有 status 一个字段两个请求同时读到在售状态然后同时创建订单就卖重了。保留 stock 字段SQL 里写stock 0条件数据库行锁帮我们挡住并发问题status 只作为展示状态用。购物车表carts和收藏表favorites结构都比较简单都是 user_id artwork_id create_time重点是要给 (user_id, artwork_id) 加唯一约束防止用户手抖点两次收藏生成两条重复记录。订单表orders需要特别注意两个冗余字段artwork_title 和 artwork_cover。它们属于订单快照。艺术品可能被下架、改价、甚至修改标题但订单一旦生成展示给用户的必须永远是当时下单时看到的商品信息。这个订单快照思路是电商系统的基本素养虽然冗余了字段破坏了范式但它保证的是业务正确性。2.3 管理端与用户的权限边界后台管理功能和用户端功能我是放在同一个后端项目里的通过 role 字段区分权限。管理端接口统一使用/admin/**前缀后端拦截器检查当前登录用户的 role 是否为 admin不是就直接返回无权限。用户端所有需要登录的接口统一用 token 校验。有一个容易被忽视的点前后端分离项目里前端隐藏删除按钮不算安全措施真正的防线在后端。哪怕前端不显示任何管理入口用户照样可以拿着管理端接口地址直接请求。所以每个管理端接口都要在服务端校验角色不能只在页面上做控制。3. SpringBoot 后端落地从接口设计到核心链路实现3.1 项目结构和依赖别再把所有类塞进四个包用 IDEA 创建 SpringBoot 项目建议先调整项目结构。网上很多老教程喜欢建 entity、mapper、service、controller 四个包然后所有业务逻辑全部塞进去项目只要稍微变大这几个包就变成巨型垃圾场。我采用的是按业务模块划分的方式com.art.mall ├── config // 配置类跨域、拦截器、静态资源映射、Redis配置 ├── controller // 接口层 ├── service // 业务层 ├── mapper // MyBatis Mapper 接口 ├── entity // 数据库实体 ├── dto // 入参出参封装 ├── common // 统一返回结果、全局异常、业务异常 └── util // 工具类这样每个模块的相关类都聚合在一起查找和维护的路径更短。依赖方面核心几个spring-boot-starter-web、mybatis-spring-boot-starter或者 mybatis-plus-boot-starter、mysql-connector-j、lombok、spring-boot-starter-validation、spring-security-crypto、spring-boot-starter-data-redis。登录权限这块没有引入完整的 Spring Security只引入 spring-security-crypto 里的加密工具登录校验自己做。对一个商城系统来说这个组合足够灵活又不会被 Spring Security 的过滤器链配置折磨到崩溃。3.2 统一返回结构和全局异常处理前后端分离项目里最怕接口返回格式五花八门前端每个接口都要单独处理特殊格式。我定义了一个通用的 Result 类三个字段code、msg、data。code 为 200 表示成功其他值对应业务错误或者参数错误。所有 Controller 方法的返回值都包装成 Result前端拿到的永远是同一套结构处理逻辑就可以统一封装在 request.js 里。配合统一返回结构的是全局异常处理。用 RestControllerAdvice 加 ExceptionHandler 实现参数校验异常MethodArgumentNotValidException返回参数错误业务异常自定义的 BusinessException把 messages 里的具体提示返回给前端兜底异常Exception返回服务器繁忙同时记录日志方便排查。这个设计最大的好处是业务代码里可以放心写throw new BusinessException(该作品已售出)前端直接弹一个提示框显示这句话不需要前端理解任何状态码含义。3.3 艺术品列表动态条件查询和防注入的细节艺术品列表接口是用户端使用频率最高的接口内容上它要支持分页、按品类筛选、按作者搜索、按价格区间过滤。用 MyBatis 写动态 SQL 的时候有几个点必须说清楚。分页不要自己手写 LIMIT 拼接。引入 PageHelper插件通过拦截器自动改写 SQL 完成分页不用在业务代码里关心 start、offset 这些参数也不容易出参数错乱这种低级 bug。动态 where 条件用where标签来包而不是在每个条件前手动拼and更不要用where 11这种写法。where标签会自动处理首个条件前面的 and写出来的 SQL 干净也不容易遗漏条件。关键词搜索这里有个常见的坑like %#{keyword}%这种写法在 MyBatis 里是不能用的。#{} 是预编译参数不能把它嵌在字符串中间SQL 解析阶段就会报错。正确写法是like concat(%, #{keyword}, %)。我第一次实现搜索功能时就在这上面栽了花了半个多小时排查 SQL 报错最后发现是语法位置不对。3.4 下单接口事务、库存扣减和并发安全的完整链路下单模块是整个后端最需要小心的地方逻辑链路是校验用户登录状态、校验艺术品状态、扣减库存、创建订单、如果有需要再清空对应的购物车记录。这几步必须放在一个事务里要么全部成功要么全部失败。关于并发艺术品库存虽然只有 1但两个用户同时看到在售状态、同时点击购买是真实会发生的事情。防止超卖的核心是一条带条件判断的 UPDATE SQLUPDATE artworks SET status 1, stock stock - 1 WHERE id #{artworkId} AND status 0 AND stock 0这条 SQL 执行后返回的影响行数如果是 0说明作品已经被别人买走或者已下架接口直接返回该作品已售出。这个方案背后的原理是数据库行锁同一时刻只有一条更新语句能成功其他请求必须等待事务结束后发现条件不满足影响行数就是 0。相比先 SELECT 再 UPDATE 的方案这个更简洁也更强壮不用考虑分布式锁。事务方面有一个网上踩坑率极高的细节Transactional 默认只在 RuntimeException 下回滚。如果业务代码自己 catch 了异常然后正常返回事务不会回滚最终结果就是库存扣了但订单没建成功或者订单建了但库存没扣。处理方式有两种不在 Service 里 catch 需要回滚的异常让 Spring 的链路来处理或者在 Transactional 上指定 rollbackFor Exception.class强制所有异常都触发回滚。3.5 接口安全权限拦截器和防越权登录校验用的是拦截器 token 方案。用户登录成功后后端生成一个 token用 UUID 或者 JWT 都行存入 Redis 并设置过期时间前端后续请求在 Header 里携带这个 token。拦截器里先从请求头取 token再查 Redis 确认是否有效无效则返回 401前端收到 401 统一跳转登录页。权限这块上面提过管理端接口用 /admin/** 前缀拦截器里加一道角色判断。订单模块还要做一层访问控制用户只能查询自己的订单后端查询时不能拿前端传的订单号直接查询而是要校验当前登录用户的 ID 和订单归属的 user_id 是否一致不然用户之间可以直接看到别人的订单信息这是典型的水平越权漏洞。收藏、购物车的删除接口同理只能操作自己名下的数据。3.6 图片上传与静态资源映射艺术品图片是核心资产但存储方案不需要复杂。我没有引入对象存储服务而是把图片保存到服务器磁盘数据库存相对路径通过 SpringBoot 的静态资源映射对外提供访问。spring.web.resources.static-locationsclasspath:/static/,file:${upload.path} upload.path/data/art-mall/images/上传接口里限制文件类型和大小只允许 jpg、png、webp单张不超过 5MB。前端上传时同步做一遍校验避免用户花了很长时间上传完才发现格式不对。这里有一个部署层面的教训图片目录一定要和 jar 包目录分开。如果图片被存到项目运行目录下重新部署时整个目录被覆盖所有历史图片全部 404。我后期专门把图片路径改成了固定目录彻底解决这个问题。3.7 Redis 在系统中的三个实际用途Redis 在这个项目里承担了三个职责每一个都是独立配置、独立 key 前缀。一是缓存艺术品列表和详情。艺术品的基础信息不是高频变化的数据很适合缓存我设置了 30 分钟过期时间后台修改作品信息后主动删除对应缓存。需要注意缓存穿透问题如果用户传了一个不存在的艺术品 id查询结果为空Redis 里不会写入任何值每次请求都会打到数据库。处理方式是查不到数据时在 Redis 里写一个空值设置较短过期时间比如 60 秒后续同样的请求直接返回空数据库压力就降下来了。二是登录 token 的存储。token 存 Redis 的好处是失效时间可以由后端控制用户修改密码、管理员封禁用户时删除 Redis 里的 token 就能让已经登录的会话立刻失效。三是验证码存储。登录验证码和注册验证码生成后存 Redis设置 2 分钟过期时间校验时从 Redis 取比对后无论成败都删除保证验证码是一次性的。用 Redis 存验证码比用 session 存更通用以后把系统扩展成多实例部署验证码逻辑也不用改。4. Vue 前端把艺术品的展示感做出来4.1 环境搭建和依赖安装的真实经验前端项目用 Vue CLI 创建命令是vue create art-mall-web。环境上最烦的问题是 npm 安装依赖特别慢甚至卡死。新建项目前建议先把 npm 镜像切到国内源npm config set registry https://registry.npmmirror.com网络问题解决之后大概率会遇到另一个问题node 版本和依赖不兼容。如果 npm install 过程总是在某个依赖上报错优先考虑是不是 node 版本太老或太新用 nvm 切换 node 版本再试。实在找不到原因时删掉 node_modules 和 package-lock.json重新执行npm install很多时候能解决莫名其妙的依赖安装问题。4.2 路由结构和权限控制路由按用户端和管理端分成两组。用户端有首页、列表页、详情页、购物车、订单列表、收藏、登录注册管理端有作品管理、上架编辑、订单管理、用户管理。路由配置里每个页面标记meta字段比如requiresAuth和requiresAdmin在路由守卫里统一做判断没有 token 且访问了需要登录的页面跳转登录页附带 redirect 参数登录完跳回原目标有 token 但不是 admin 却访问了管理端页面跳转一个 403 页面已经登录了还访问登录页直接跳回首页。路由模式我用的 hash 模式。history 模式的路由 URL 更好看但部署环境需要额外配置 Nginx 把所有路径都重写到 index.html否则刷新页面就直接 404。为了减少部署的坑hash 模式是更稳妥的选择。4.3 详情页的视觉与交互策略艺术品详情页是整个系统里最能决定转化率的页面我在设计上没有套普通商品详情页的模板。页面顶部是左侧大图展示区主图加缩略图切换再配一张细节图的放大效果。右侧是作品的核心信息名称、作者、价格、尺寸、材质、创作年代、库存状态。价格用大号字体突出显示状态用颜色区分在售绿色已售灰色。下方是作品详情区域放多张细节图和一段作者与作品的背景描述。图片加载用了懒加载。实现上不用额外引入复杂的库Vue 自定义一个指令监听元素进入视口再替换图片地址或者直接用现成的 v-lazy 指令。每个图片用比较窄的占位背景色加载完再显示真实图片体验上不会出现一坨白屏。详情页底部固定一个悬浮操作栏三个核心动作收藏、加入购物车、立即购买。收藏按钮要能实时反映收藏状态用户点击收藏后按钮变成已收藏颜色变化这个状态存在 Vuex 里从详情页跳走再回来状态不会丢失。4.4 购物车、下单和模拟支付的完整链路购物车页面的交互需要处理勾选、数量虽然数量恒为 1、合计金额、删除。艺术品商城不需要批量结算购物车本质上是一个稍后购买的暂存区实际操作时只支持选中一件商品去结算。这样设计既符合业务场景也简化了下单逻辑。下单链路是购物车选中商品点击去结算跳到订单确认页这个页面展示商品信息、收货地址、订单金额确认后调创建订单接口后端返回订单号跳转到收银台页面。支付功能我做了模拟支付页面上一个模拟支付按钮点击后调用支付确认接口把订单状态从待付款改成已付款。将来接真实支付时只需要把这个步骤替换成对接微信/支付宝的预下单和回调接口其余链路不用变。4.5 管理端艺术品上架的表单和图片上传管理端最常用的是艺术品上架编辑页。表单字段比较多可以分区块组织基本信息区名称、作者、品类、材质、风格、规格区尺寸、创作年代、价格、内容区描述、封面图、详情图。el-upload 组件自定义 http-request这样能拿到上传进度做进度条上传成功后把返回的 URL 回填到表单里。这里有一个异步回显的坑编辑页打开时要根据当前作品 id 请求详情接口把数据填充到表单。如果表单初始化时机不对数据还没回来表单已经创建了就会出现页面空白数据没显示的问题。解决方式是加一个v-if判断详情数据是否加载完成数据回来后再渲染表单或者表单组件内部 watch 数据变化后再 setFieldsValue。4.6 打包部署后布局异常和接口 404 的排查思路开发环境一切正常npm run build上线后页面白屏或者样式错乱这是 Vue 项目里非常经典的一类问题。排查顺序可以这样第一打开浏览器开发者工具看 Network是不是有很多静态资源 404。如果是问题出在 publicPath 配置。默认打包后的资源引用路径是根路径/如果网站不是部署在域名根目录而是部署在一个子路径下就全部 404。解决方式是在 vue.config.js 里设置publicPath: ./用相对路径加载资源。第二如果刷新某个页面出现 404大概率是 history 路由在服务器端没有配置重写规则。hash 模式不存在这个问题这也是我选择 hash 模式的原因。第三接口全部 404 的话先看前端请求的实际 URL 和后端接口定义是否一致再检查 Nginx 的 reverse proxy 配置。注意proxy_pass末尾是否带/会直接影响后端拿到的路径带/表示去除前缀转发不带/表示原样转发。这个细节非常绕我前后端联调时因为这个问题排查了快一个小时。5. 花钱的事不能马虎高价值交易的安全加固5.1 接口幂等性防止重复下单高客单价商品的重复下单问题比普通商品严重得多。用户点了一次立即购买按钮也禁用掉了但网络慢用户手一抖刷新了页面或者前端没来得及禁用按钮的时候连点两下订单可能就重复创建了。解决思路是后端做幂等控制。前端在下单页面加载时向后端申请一个 orderToken后端存进 Redis 并设置 5 分钟过期。提交订单时前端把这个 token 一起传上去后端先执行 Redis 的 setnx 操作如果 key 不存在说明这是第一次请求setnx 成功继续执行下单逻辑如果 key 已经存在说明这个 token 已经处理过直接返回重复提交提示。这个方案实现成本很低但能非常有效地挡住重复下单和恶意刷单。5.2 登录防刷和验证码登录接口永远是被脚本攻击的头号目标。我的防护方案是验证码加失败次数限制。验证码用 Redis 存2 分钟过期用户输错一次就换新的。连续输错超过 5 次锁定该账号 15 分钟锁定期间即使密码正确也不允许登录。这个机制能挡住绝大多数暴力破解尝试。同时用户密码这种敏感信息在传输过程中最好做一层非对称加密或者至少使用 HTTPS。如果项目还没有上 HTTPS至少保证密码是 BCrypt 加密后入库不能让明文密码直接出现在数据库里。5.3 文本内容的安全过滤艺术品的评论、留言、描述这些用户输入内容在存储到数据库之前必须做过滤防止 XSS 注入。攻击者如果在提交表单时输入了一段scriptalert(xss)/script后端如果不处理前端渲染评论区域时这段脚本就会被浏览器执行轻则弹窗骚扰用户重则窃取用户登录凭证。处理方式不复杂写一个工具类把提交内容里的、、script等危险字符做转义或者替换存入数据库的是安全文本。前端渲染时统一用文本插值不用 v-html 展示用户内容。这两个手段加在一起基本能把常见的注入路径堵死。6. 联调、部署与开发过程中踩过的具体坑6.1 跨域问题环境和生产环境不同的解决方式开发阶段前端跑在 8080后端跑在 9090跨域是必然的。后端的解决方案是注册一个 CorsFilter 全局过滤器允许本地前端的 origin 访问。需要注意 allowedOrigins 不能配成 *因为allowCredentials true和通配符 origin 在浏览器规范里是冲突的必须写具体的地址比如http://localhost:8080。生产环境里我不再依赖后端跨域配置而是由 Nginx 统一转发。前端打包后的 dist 目录放到 Nginx 的站点目录下后端 Java 服务跑在 127.0.0.1:9090Nginx 把 /api 前缀的请求反向代理到后端。这样做的好处是浏览器访问的始终是同源的地址不存在跨域问题后端也不用再暴露 CORS 规则。6.2 SpringBoot 版本太高带来的兼容性烦恼用 IDEA 的 Spring Initializr 创建项目时默认版本往往是最新的。有段时间我直接用了默认的 SpringBoot 3.x然后搜索springboot 整合 mybatis 教程跟着 2.7 的写法走启动直接报错。原因是对应 starter 的自动配置类发生了变更很多包从 javax 命名空间改成了 jakarta导入错误、注解扫描不到。最后我把项目版本改回 2.7.18所有问题迎刃而解。所以我的建议非常明确做毕业设计、练习项目优先选 2.7.x资料多、踩坑记录全、遇到问题好解决。如果你所在的公司已经有统一的 SpringBoot 版本规范那当然优先跟团队版本一致但个人项目选 2.7.x 是风险最小的选择。6.3 上线前一定要过一遍的检查清单开发完到真正部署上线中间还有一段路。我自己梳理了一份检查清单发布前逐项来一遍能避免大部分低级事故数据库密码和管理端账号密码不要硬编码在配置里通过环境变量注入application.yml 里不要开启 devtools 热部署生产环境默认关闭配置日志输出路径至少保留 error 级别日志方便线上排查管理端接口和用户端接口的权限校验再单独确认一遍统一返回结构和全局异常处理在 Controller 层是否已经生效图片上传目录是否已迁移到 fix 路径和 jar 包目录分开Redis 和 MySQL 都设置了密码并且不允许公网裸奔前端 request.js 的 baseURL 是否通过环境变量区分开发和生产环境。每条看起来都是小事情出问题时全是通宵级故障。比如图片目录和项目目录没分开每次重新部署图片就丢用户在详情页看到一片碎裂的图标这种体验非常伤产品口碑。6.4 从部署回归到业务理解这个项目从零到最终上线我的一个深刻体会是技术难度并没有预想的那么高真正的复杂度来自对业务的理解。同样叫商城普通商品和艺术品因为商品属性不同表结构、页面设计、下单逻辑、安全策略全都不一样。技术的通用方案在社区里都能找到标准答案但这个系统的艺术品到底应该怎么展示、怎么交易、怎么防恶意操作这些东西没有统一的模板可以抄必须自己把业务规则打通之后才能定下来。如果你也想做一个类似的 SpringBoot Vue 前后端分离项目我的建议是动手写代码之前先花半天时间把业务规则想清楚一件艺术品能不能被加购两次已售作品为什么还要留在详情页订单里为什么要存商品快照这些问题的答案会直接指导你的数据库设计和接口设计。想明白了这些代码本身反而是顺理成章的事。