news 2026/10/17 12:36:23

Spring Boot 3 + Vue 3 智能家居商城实战:从架构设计到部署上线

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Spring Boot 3 + Vue 3 智能家居商城实战:从架构设计到部署上线

1. 项目概览:为什么选智能家居商城这个方向

智能家居这几年已经从极客玩家的玩具变成了普通家庭装修清单里的常规项。智能门锁、摄像头、灯光控制、环境监测设备,几乎每个家庭都在添置这类产品。做电商系统,选这个细分赛道有个很明显的优势——设备和配件种类多、客单价高、复购率也不错,用户一旦入了某个生态,后续的传感器、网关、配件基本都会回到同一个平台购买。

我实现的这套系统,定位是面向智能家居设备销售的商城平台,采用前后端分离架构。后端使用 Spring Boot 提供 RESTful API,前端使用 Vue 3 构建单页面应用,数据库使用 MySQL,缓存层和分布式会话使用 Redis,文件存储走本地磁盘加 Nginx 托管。系统涵盖了电商最常见的完整链路:用户注册登录、商品浏览检索、购物车、订单创建与管理、支付流程对接、后台商品管理和订单管理,同时针对智能家居商品的特点,额外实现了设备接入信息登记和用户设备绑定功能。

这套系统的设计思路和实现细节其实可以复用到绝大多数“Spring Boot + Vue”的中后台业务系统里。哪怕是没接触过智能家居的人,看完这篇文章,也能把电商核心链路跑通。因为从数据库设计到接口拆分,我做的都是很通用的方案,只有设备绑定那部分稍微特殊一点。

适合阅读这篇文章的读者,我默认有 Java 基础和基本的 Vue 使用经验。如果你刚学完 Spring Boot,想找个完整的实践项目练手,这个选题非常合适——它既有常规管理系统的增删改查,又有库存扣减、支付回调、设备状态推送这些真实业务难点,比单纯做学生管理系统或者博客系统能学到的东西多得多。

2. 技术选型思路:2026 年这套组合拳怎么打

2.1 后端为什么锁定 Spring Boot 3.x 而不是 2.x

2026 年再新建项目,我建议直接上 Spring Boot 3.x 系列。3.x 的基线是 Spring Framework 6 和 JDK 17,默认使用 Jakarta EE 命名空间,很多老项目升级时会遇到的 javax 到 jakarta 的包名迁移问题,新项目根本不存在。Spring Boot 3.2 以后对虚拟线程(Virtual Threads)支持也趋于稳定,对于商城这类 IO 密集型应用,虚拟线程能在不增加太多配置成本的情况下显著提升并发吞吐量。

我在项目中使用的具体版本组合是这样的:

JDK 17 Spring Boot 3.2.5 MyBatis-Plus 3.5.7 MySQL 8.0.36 Redis 7.2 Vue 3.4 Vite 5 Pinia 2.1 Element Plus 2.7

MyBatis-Plus 在这个项目里省了大量基础 CRUD 代码。单看表结构,用户表、商品表、分类表、订单表,加起来十几张表,如果用原生 MyBatis,每张表都要写 XML 和实体映射,工作量会翻一倍不止。MyBatis-Plus 的 BaseMapper 直接给了 selectById、insert、updateById 这些方法,自定义查询走 LambdaQueryWrapper,代码可读性和维护性都好很多。

2.2 前端为什么选 Vue 3 而不是 React

不能说 React 不好,但在国内的中后台项目里,Vue 的生态成熟度和团队上手成本确实有优势。Vue 3 的组合式 API(Composition API)配合<script setup>语法,组件逻辑复用比 Options API 优雅太多。商城项目的页面数量不多,但每个页面的交互密度很高——商品列表有筛选条件、购物车有全选和数量联动、结算页有地址切换和优惠计算,这种情况下组合式函数(Composables)能非常干净地抽取公共逻辑。

Vite 作为构建工具已经是 2026 年的绝对主流。开发服务器的热更新速度比 Webpack 快一个数量级,配置也更简洁。Element Plus 组件库的 Table、Form、Dialog 等组件能覆盖后台管理 90% 的界面需求,不需要自己造轮子。

2.3 中间件选型的几个重要决策

Redis 是必选项,不是可选项。它在这个项目里承担了三个职责:存储登录令牌和用户信息、缓存商品热门数据和分类树、控制订单创建时的分布式锁。这三个场景对 Redis 的需求都不一样,但都是高频访问路径,没有 Redis,MySQL 的压力会陡增,尤其秒杀或者大促场景下,单表查询商品详情很容易把数据库打爆。

RabbitMQ 我放在了扩展位。支付回调处理和设备状态上报这两个场景,最稳妥的做法是先把请求落库或者进消息队列,再异步处理业务逻辑。如果项目只是学习和演示,可以先用 JDK 线程池或者 Spring 的 @Async 做简单异步,但要是考虑生产环境,RabbitMQ 这种专业消息中间件是少不了的。

3. 数据库建模:智能家居商城比普通商城多出的那些设计

3.1 基础电商表怎么设计不出错

用户表、商品分类表、商品表、购物车表、订单主表、订单明细表、收货地址表,这是电商系统的基础表,所有电商项目都绕不开。几张关键表的字段设计我直接列出来:

用户表核心字段:id、username、password(BCrypt 加密后)、phone、email、avatar、status。这里有个容易踩的坑——不能用手机号当主键。手机号虽然具有唯一性,但用户可能修改手机号,而且手机号的索引长度比自增整型主键长得多,联表查询时性能会明显差一截。

商品分类表我用了一套很经典的自关联设计:id、parent_id、name、sort_order、level。parent_id 为 0 的是顶级分类,支持三级分类嵌套。智能家居的品类其实是比较适合这种结构的,比如“智能家居 -> 智能门锁 -> 指纹锁”,实际体验下来层级控制在三级内,用户浏览效率最高。

商品表是信息量最大的表:id、category_id、name、sub_title、main_image、detail_html、price、stock、sales、status。为了让列表页不那么单调,我还加了 product_type 字段标识设备类型(传感器类、控制类、安防类、影音类),在前端列表页可以根据这个字段显示不同的标签颜色,这个属于视觉体验优化,不影响核心逻辑。

3.2 设备属性扩展表:智能家居商品的难点

普通商城不需要额外建模设备属性,但智能家居商品不一样。一个智能摄像头和一个智能灯泡,它们的参数维度完全不同。摄像头有分辨率、夜视功能、存储方式、云台角度;灯泡有功率、色温、光通量、智能协议。如果把这些参数全部塞进商品表的固定字段里,那商品表的字段会膨胀到没法维护,而且每加一类新产品就要改表结构。

我的做法是设计一张商品参数表product_attribute:

id, product_id, attribute_name, attribute_value, sort_order

商品详情页按需查询该商品的所有参数键值对,前端动态渲染成表格。这种 EAV(Entity-Attribute-Value)模式虽然不是关系型数据库的常规做法,但用在商品参数这种“不同品类字段差异极大”的场景下,灵活性远高于固定字段方案。查询的时候确实要多一次关联,不过商品参数只会在详情页展示,查询频率不高,性能损失完全在可接受范围内。

设备控制指令的描述也用了类似方案。智能设备商品需要描述它支持的协议类型(Wi-Fi、Zigbee、蓝牙 Mesh)和接入方式,这些字段在不同设备间差异同样很大,统一放商品表同样不合适。实践下来的经验是:核心通用字段放主表,差异化字段用 EAV 表,这样兼顾查询性能和数据灵活性。

3.3 订单表设计和高频查询优化

订单主表的字段设计遵循一个原则——能冗余就冗余。很多新手在设计订单表时,喜欢在关联查询时再 join 用户表和商品表,但订单生成后用户昵称、商品名称、商品快照这些信息都是不能变的,必须冗余到订单表里。我在订单明细表里存了goods_name、goods_image、goods_price这几个冗余字段,这样订单列表页不需要 join 商品表就能完整展示,既减轻数据库压力,也避免商品改名或下架后历史订单显示异常。

高频查询优化上,我做了一个很关键的决定:订单表按状态建立组合索引。商城的订单列表页最常见的查询是“查某用户的所有订单”和“查某状态下的订单”,对应的索引设计是(user_id, status, create_time)联合索引,覆盖了列表页的主要查询场景。

4. 后端核心模块拆解:从登录到支付这样一步步落地

4.1 登录认证方案:JWT + Redis 双层会话管理

登录认证我采用的是 JWT 和 Redis 结合的方式,而不是传统的 Session 方案。流程是这样的:

用户提交用户名密码,后端校验通过后生成一个 JWT 令牌,同时把用户的 ID 和令牌的 jti(JWT ID)写入 Redis,并设置过期时间。前端每次请求在 Authorization 头携带 JWT,后端通过拦截器解析 JWT,再从 Redis 里校验该用户是否仍然有效。

这个双层方案解决了两个单层方案各自的缺点。纯 JWT 的问题在于无法主动失效。用户修改密码、管理员封禁账号、用户退出登录时,只要令牌还没到期,它依然有效,这在真实业务里是不安全的。纯 Redis Session 的问题在于每个请求都要查 Redis,Redis 挂了之后所有请求都会失败。结合方案里,Redis 只负责校验会话有效性,一旦 Redis 不可用,JWT 自带的签名和过期时间仍然能兜底放行登录状态,系统可用性高一个层次。

注册登录部分,我用 BCrypt 做密码哈希,加盐和哈希都在同一个算法内完成,比 MD5 加自定义盐的方式安全得多。为了防爆破,登录接口还接了一个简单的限流逻辑:同一个 IP 一分钟内失败超过 5 次就锁定 5 分钟,这个用 Redis 的 INCR + EXPIRE 就能实现,代码量不到 20 行。

4.2 商品列表与详情查询的缓存策略

商品列表页是商城流量最大的页面,数据库压力通常也最大。我用 Redis 做了两级缓存:分类树缓存和商品列表缓存。

分类树缓存比较简单。分类数据基本不怎么变动,但每次加载首页或者列表页左侧分类栏时都要查库。我把树形分类数据序列化成 JSON 存进 Redis,设置一个小时的过期时间,后台管理员调整分类时主动删除缓存,下次请求自动重建。

商品列表缓存稍微复杂一点。我保留了分类 + 排序 + 分页的查询维度,直接以查询参数拼接成 Redis key,缓存查询结果列表的前 3 页数据。因为前 3 页是用户访问最集中的区域,缓存命中率最高。翻到后面页数的用户很少,直接查数据库也完全没有压力。

这里要提醒一句,缓存和数据库的一致性问题是开发中必须要考虑的。我用的策略是 Cache-Aside:更新数据库后主动删除缓存,等下次请求再回填。而不是在更新数据库的同时同步更新缓存,因为后者在并发写入时很容易产生脏数据。删除缓存虽然会有一次缓存穿透打到数据库,但只要不是热点 key,影响很小。

4.3 购物车设计:登录态和用户行为的统一

购物车数据我没用数据库存储,而是直接存在 Redis 的 Hash 结构里,key 是cart:userId,field 是商品 ID,value 是商品数量。这个方案省去了购物车表的 CRUD,而且 Redis 的 Hash 结构天然支持单个商品的增减和整个购物车的清空,性能也远高于 MySQL。

购物车接口需要注意的一个细节是:加购时要做商品状态校验。商品下架、商品库存为零或者用户在别处把商品删了,都需要及时反馈给前端。我在加购接口返回了三种状态码:正常加购、商品已下架、库存不足,前端拿到不同状态码后给用户不同的提示文案。这个细节很多人容易忽略,但其实是购物车体验的重灾区。

购物车选择商品去结算时,前端会提交选中的商品 ID 列表和数量,后端生成一个临时结算 token 存入 Redis,有效期 15 分钟,提交订单时必须携带这个 token。这个设计能防止用户一边看结算页一边重新加购导致的数据错乱,也避免订单接口被刷。

4.4 订单创建:库存扣减与并发防超卖

订单创建是整个系统里最考验并发控制的部分。用户点击提交订单后,后端要做的事包括:校验用户登录态、读取结算 token、查询商品信息、锁定库存、生成订单号和订单明细、记录支付流水。里面最容易出问题的就是库存扣减。

我对比过三种库存扣减方案:

第一种是先查库存再判断再更新。这种自然不用,并发下必然超卖。

第二种是乐观锁更新,也就是UPDATE goods SET stock = stock - #{num} WHERE id = #{id} AND stock >= #{num}。这条 SQL 语句的原子性保证了库存不会扣成负数,同时返回的影响行数是 0 时说明库存不足。这个方案在大多数场景下够用,而且没有加锁开销。

第三种是 Redis 预扣库存。先把库存同步到 Redis,扣减时用 Lua 脚本保证原子性,订单创建成功后异步减少数据库库存。这个方案适合秒杀场景,能抗极高的瞬时流量。

我这个项目选的是第二种方案,但在商品表里加了version字段做乐观锁的扩展。因为未来如果要上线秒杀活动,stock >= num这个条件防住了超卖,但是防不住 ABA 问题。有了 version 字段,更新时同时带上期望版本号,就能保证数据在读取到更新之间没有被其他事务改过。订单表的并发控制我用 Redis 分布式锁,锁的 key 是用户维度,防止同一用户同时提交多个订单,这种场景下用分布式锁比数据库悲观锁更合适,也不会拖累所有用户的订单创建性能。

订单号生成我实现了一个简单但够用的方案:时间戳 + 用户 ID 后四位 + Redis 自增序号。格式类似202403151030301234001,这个订单号不但唯一,还能从号里直接解析出下单时间,排查问题时非常方便。

4.5 支付模块设计:模拟支付与回调闭环

支付对接真实支付渠道在开发阶段不容易实现,我用一个模拟支付接口代替,但回调处理的整个流程是完全按照真实支付来设计的。支付流程设计成这样:

用户点击支付后,后端生成支付单,携带订单号和金额跳转到模拟支付页面。模拟支付页面展示订单信息并提供一个“确认支付”按钮。点击确认后,后端将订单状态改为“已支付”,生成支付流水,通过消息队列异步执行后续业务操作:扣减商品库存、清空购物车中已支付的商品、给用户发送通知。

关键设计在回调接口上。真实支付场景中,支付渠道的异步回调和后端返回的同步结果往往是两个独立过程,如果同步展示层先返回了“支付成功”,但异步回调还没到,这时订单状态其实还没更新。我在设计时把同步响应的状态设置为“支付处理中”,等异步回调确认后再更新为“支付成功”,前端通过轮询或 WebSocket 获取最终状态。这个设计体现了支付回调的核心思想——以支付渠道的异步通知为准,而不是以同步返回为准。

回调接口还做了幂等处理,防止同一笔支付通知到达多次导致库存重复扣减。实现方式是在支付流水表加transaction_id唯一索引,插入时如果冲突就直接返回成功,避免下游业务重复执行。

4.6 智能家居设备绑定:商城和设备的桥接

设备绑定是这个项目区别于普通商城的特色功能。用户在商城购买智能设备后,需要将设备与自己的账号进行绑定,绑定后才能在“我的设备”页面看到设备状态并进行控制。

设备绑定的数据结构比较特殊。用户在订单明细中购买了某个设备商品后,会在“我的订单”页面看到一个“绑定设备”按钮。点击绑定后,后端生成一个绑定二维码,二维码内容是一个带有绑定凭证的 URL。用户在手机 App 或者小程序中扫描二维码后,向服务端发送绑定请求,服务端校验凭证和订单归属关系后完成绑定。

这个流程里有一个必须处理的问题:绑定凭证的有效期。我生成的绑定二维码包含了一个短期有效的随机 token,存储在 Redis 中,有效期 10 分钟。超时后自动失效,能防止用户截图转发导致的安全风险。另外,一个设备商品只能绑定一个用户,绑定完成后再次扫码会提示“设备已被绑定”。

5. 前端实现亮点:Vue 3 状态管理与页面交互细节

5.1 路由设计:用户端和管理端分开

前端路由我用了典型的单应用多角色架构。所有路由分为两部分:用户端路由(首页/home、商品列表/goods、商品详情/goods/:id、购物车/cart、订单列表/order、支付页/pay)和管理端路由(后台/admin/dashboard、商品管理、订单管理、用户管理)。

路由守卫是权限控制的关键点。我在router.beforeEach守卫里做了三件事:检查目标路由是否需要登录态、检查用户角色是否满足访问条件、根据登录状态调整默认跳转页面。前端守卫不能作为唯一安全防线,真正的权限控制必须依赖后端接口的鉴权,前端守卫只是优化体验和减少无效请求。

/admin前缀下的所有路由都配了 meta.requiresAdmin = true,路由守卫里发现当前用户不是管理员就跳转到首页。这个判断会同时校验前端存储的角色信息,后端接口也会二次拦截。双端校验的方式属于安全设计的基本功。

5.2 Pinia 状态管理:用户状态、购物车和全局配置

Vue 3 项目我用 Pinia 取代了 Vuex。Pinia 的类型提示和模块化设计比 Vuex 舒服很多,而且代码量更少。

用户状态模块存储了 token、用户基本信息和角色。登录成功后,后端返回的 token 和用户信息写入 Pinia,同时持久化到 localStorage。刷新页面时,通过一个 init 方法从 localStorage 恢复状态,并请求一次后端接口校验 token 是否仍然有效。这个过程看起来简单,但很多项目栽在“已经登录但刷新后状态丢失”的问题上,实现时要注意 Pinia store 的初始化和路由守卫的执行顺序。

购物车状态模块是前端交互复杂度最高的部分。全选、单选、数量增减、删除商品、已选商品合计金额,这五个操作之间有着复杂的联动关系。我用了 getters 计算已选商品列表和合计金额,mutations 统一修改商品数量,这样所有数量变化都会触发选中状态的重新计算,不会出现全选框状态和实际商品勾选状态不一致的问题。

5.3 Element Plus 表格与表单的高级用法

后台管理页面的开发效率很大程度依赖于 Element Plus 组件的正确用法。商品管理页我用了el-table配合el-pagination,每页 10 条数据,支持按名称搜索和按分类筛选。表格的列用formatter函数格式化状态和价格字段,不需要在数据层面上预先处理。

表单验证是另一个容易出问题的点。商品新增和编辑的表单里,价格字段要求必须大于 0,库存字段要求必须是非负整数,名称长度限制在 50 个字符内。Element Plus 的el-form规则对象写起来虽然有点啰嗦,但比在接口层做参数校验后返回错误信息再弹窗提示,用户体验好得多。前端做一层校验,后端再做一层校验,两边都不信任对方,这是前后端分离项目的安全准则。

5.4 设备状态实时展示:WebSocket 在前端的接入

智能家居设备列表页需要实时展示设备状态。设备是否在线、电量是否充足、最新上报数据是多少,这些信息如果靠轮询接口获取,每 5 秒请求一次不仅浪费资源,对服务器压力也大。我用了原生 WebSocket 实现服务端推送。

后端有一个 WebSocket 端点,用户登录后根据用户 ID 关联设备,设备状态变化时服务端主动推送消息到前端。前端在进入设备列表页时建立 WebSocket 连接,离开页面时关闭连接。设备列表页面收到状态消息后,只更新对应设备的状态字段,不刷新整个列表,这样用户体验非常流畅,而且几乎没有额外请求。

WebSocket 连接本身的网络异常恢复处理是我特别留意的点。断线后需要自动重连,我写了一个简单的重连逻辑:连接关闭后 3 秒尝试重连,重连失败退避到 5 秒、10 秒,最多重连 5 次,防止服务端异常时前端疯狂重连打挂服务器。这个小细节在真实项目中很重要。

6. 开发部署与问题排查:我踩过的坑和解决办法

6.1 环境配置:从零搭建开发环境

开发环境搭建这一步看起来简单,实际上坑最多。JDK 17 装好之后,要确认环境变量配置正确。Spring Boot 3.x 项目里如果使用 Lombok,需要注意 Lombok 版本必须支持 JDK 17,旧版本的 Lombok 在 JDK 17 下会导致编译失败。MyBatis-Plus 3.5.7 搭配 Spring Boot 3.2 没有兼容性问题,但如果用 3.5.3 之前的老版本,会遇到类型处理器注册失败的问题。

前端环境相对简单,Node.js 需用 18 以上版本,Vite 5 最低要求就是 Node 18。npm install 阶段如果网络不好,可以配置镜像源,但要注意镜像源的版本同步可能滞后,装到最新依赖时报错需要回退版本时,切换回官方源再试一次。

数据库初始化我用了一个 SQL 脚本,包含建库建表语句和基础测试数据。开发阶段每次修改表结构都会手动执行增量 SQL,而不是重新执行全量脚本,因为全量脚本会清空已有的测试数据,每次都要重新造数据,浪费大量时间。

6.2 后端启动常见问题:端口占用、数据库连接和缓存连接

后端启动报错的频率不算高,但报错时排查方向很固定。

端口占用是最常见的启动问题。Spring Boot 默认端口 8080,如果本机已经有程序占用了 8080 端口,启动会失败,日志里会显示Port 8080 was already in use。解决方案是改application.yml里的server.port,或者用命令行参数--server.port=8081临时指定端口。项目开发时我习惯多开几个服务做联调,所以会在 IDEA 的启动配置里给不同模块设置不同端口。

数据库连接失败比较直接。报错信息会明确指出连接被拒绝或者认证失败。这类问题九成是 MySQL 服务没启动、账号密码错误、或者数据库名写错。检查顺序是:ping数据库地址,确认 MySQL 服务运行;用数据库客户端尝试连接,确认账号密码正确;检查application.yml的 URL 里数据库名是否和实际库名一致。我在项目中遇到过 URL 里少了时区参数导致连接异常的问题,后来在 JDBC URL 里统一加了serverTimezone=Asia/Shanghai,这个参数在 MySQL 8 的驱动里是必填项或者强烈建议填写项。

Redis 连接失败同样是常见问题。没有配置密码时默认连接本机 6379 端口,如果 Redis 服务没启动,Spring Boot 启动时会报连接异常。Redis 6 以上版本默认开启了 protected mode,如果从远程连接,必须在配置文件里设置bind和requirepass,仅用密码来保护连接是不够的。

6.3 前端接口联调问题:跨域和请求拦截

前后端分离开发时,跨域问题是必然要面对的。开发环境下前端的地址是http://localhost:5173,后端的地址是http://localhost:8080,浏览器默认会拦截跨域请求。

后端解决跨域我用了一个CorsConfig配置类,实现WebMvcConfigurer接口,重写addCorsMappings方法。允许的来源设置为http://localhost:5173,允许的请求方法包含 GET、POST、PUT、DELETE、OPTIONS,允许携带凭证。这个配置只在开发阶段使用,生产环境下前后端通过 Nginx 同源部署,根本不需要跨域配置。

请求拦截是前端联调的另一个重点。我在 Axios 实例的请求拦截器里统一添加 Authorization 请求头,从 localStorage 读取 token 拼接到请求上。响应拦截器做了两件事:状态码 401 时清除本地登录状态并跳转到登录页;业务状态码非 200 时统一弹出错误提示。这样的统一处理让业务代码里不需要重复判断错误情况,代码干净很多。

6.4 部署发布:打包、镜像构建和 Nginx 配置

项目部署我推荐用 Docker 容器化。后端打包成 jar 文件,用 Dockerfile 构建镜像,JDK 使用 17 基础镜像,启动命令直接设置环境变量来覆盖配置。前端用 Vite 构建出静态文件,构建产物输出到dist目录,通过 Nginx 托管。

Nginx 配置有一个关键点:前端路由是 History 模式,如果直接刷新/goods/123这类路径,Nginx 会返回 404。解决办法是在location /块里配置 try_files,实现前端路由的回退:

location / { root /usr/share/nginx/html; index index.html; try_files $uri $uri/ /index.html; }

后端接口通过 Nginx 反向代理转发,把/api前缀的请求转发到 Spring Boot 服务。代理配置里要注意设置合适的超时时间,订单提交和支付回调这类接口可能处理时间较长,超时设置过短会导致请求被nginx中断。

7. 项目体验优化与安全加固:上线前一定要做的事

7.1 接口层统一返回格式与全局异常处理

开发接口时最容易犯的错误是每个接口返回格式不统一。有的接口返回对象、有的返回数组、有的接口直接把异常堆栈抛给前端,这样前端处理起来就会非常痛苦。我定义了一个统一的返回结构Result<T>,包含 code、message、data 三个字段,所有控制层方法都返回这个类型。

全局异常处理用@RestControllerAdvice实现。业务异常类BizException携带错误码和提示信息,被全局异常处理器捕获后转成Result对象返回。参数校验异常MethodArgumentNotValidException单独捕获,把字段校验失败的默认消息返回给前端。系统异常统一记录日志并返回“服务器开小差了”这类用户友好提示,而不是把堆栈信息暴露给用户。

统一异常处理的好处不仅是对用户友好,对开发者排查问题也很有帮助。日志里记录完整堆栈,接口返回干净结构,前后端联调时不会再出现“接口报了 500 但前端看不到任何信息”的尴尬局面。

7.2 SQL 注入、XSS 和敏感数据处理的防护

项目里 MyBatis-Plus 的${}字符串拼接要尽量避免,所有的动态条件都使用#{}预编译参数。MyBatis-Plus 的 LambdaQueryWrapper 本身就会把用户输入参数作为预编译占位符传入 SQL,天然防注入。但有一类场景要特别注意:如果为了灵活性使用了apply()方法拼接自定义 SQL 片段,传入的字符串如果是用户可控的,就存在注入风险。这种场景一律改用 QueryWrapper 的条件方法,不要图省事直接拼字符串。

XSS 防护方面,我在前端对用户输入做了限制和管理端表单校验。真正稳妥的是后端对输出做编码,Vue 的模板语法默认会转义插入的文本,富文本编辑器里的 HTML 则需要在渲染时单独处理。后台商品详情字段中允许使用内联样式,但这部分内容属于管理员可控范围,风险相对可控。

用户密码在数据库存储的是 BCrypt 哈希值,打印日志时敏感字段也要脱敏。手机号分页查询接口返回时会掩码,例如138****1234,这个逻辑用 Jackson 的序列化注解就能实现,不需要在每个接口里手动处理。

7.3 性能优化方向:数据库慢查询、Redis 缓存和大页面的首屏加载

商城项目上线后性能瓶颈通常集中在数据库查询。我用 MySQL 的慢查询日志配合EXPLAIN分析执行计划,找出没有走索引的查询。实践中排在前几位的慢查询基本都是订单列表查询和商品搜索未命中索引导致的。加上(user_id, status, create_time)联合索引和商品名称的LIKE查询优化之后,数据库整体压力降了接近一半。

Redis 缓存默认过期时间是 30 分钟,但商品库存数据是强实时数据,不能设置这种缓存,必须直接读库。商品详情的浏览量和商品基础信息更适合缓存,刷新量和更新频率都要低于库存数据,对实时性的要求也低一层。合理的缓存粒度划分需要结合具体业务场景来决定,不能全量缓存也不能什么都不缓存。

前端首屏加载速度也是体验优化的重要方向。Vite 构建后的产物默认是按路由懒加载拆分的,但首页涉及的第三方库仍然比较多。Element Plus 按需导入、路由组件懒加载、图片懒加载是三个基本手段。首页的图片我用了懒加载指令,页面上的商品图不会在初始加载时全部请求,滚动到视口范围内才开始加载,首屏加载速度明显改善。

写在最后

这套系统我从建表到部署完整走下来,最深的一个体会是:技术选型不求新,但求稳。Spring Boot 3 + Vue 3 是目前生态最成熟、资料最全的组合,用它能专注在业务逻辑上,而不是跟框架折腾。智能家居商城这个题材,也和普通电商拉开了差距——设备绑定、状态推送这些点,让整个项目有了超出教科书的真实生产感。

如果你准备拿这个项目练手,我建议的开发顺序是:先把数据库建好,再把后端接口按模块逐个打通,最后集中精力做前端页面。前后端联调过程中遇到的问题,记录的笔记会比任何教程都有价值。后续想继续扩展,优先级最高的方向是接入真实的支付渠道沙箱环境,以及把 RabbitMQ 用起来处理订单超时自动关闭和设备数据上报。这两个点做完,项目的完成度就非常接近一线的商用系统了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/17 12:36:20

小模型替代大模型的完整实践路径:成本、延迟与场景决策

做模型选型这几年&#xff0c;我越来越觉得“小模型替代大模型”这件事被很多人想复杂了。不是说没有技术含量&#xff0c;而是大家一上来就聊蒸馏、聊微调、聊路由&#xff0c;却很少有人先把一件最基础的事情想清楚&#xff1a;你的场景里&#xff0c;大模型到底在扮演什么角…

作者头像 李华
网站建设 2026/10/17 12:35:59

金融服务业技术实践:从合规、实时到安全的工程落地

我无法根据当前输入生成符合要求的博文。原因如下&#xff1a;项目标题为"financial-services"&#xff0c;但未提供任何实质性的项目正文、关键词或摘要描述&#xff1b;所有字段&#xff08;项目正文、关键词、摘要描述&#xff09;均为空&#xff1b;提供的“相关…

作者头像 李华
网站建设 2026/10/17 12:35:47

多层感知机从原理到实战:前向传播、反向传播与调参指南

1. 多层感知机到底在解决什么问题1.1 从单个神经元说起我接触机器学习的第一课&#xff0c;基本都是从线性模型开始。线性回归预测房价&#xff0c;逻辑回归做分类&#xff0c;它们背后的数学表达其实就一行&#xff1a;y f(wx b)。这个结构放到神经网络语境里&#xff0c;就…

作者头像 李华
网站建设 2026/10/17 12:34:39

Visual Studio一键化C++开发:CMake与vcpkg构建自动化实践

1. 为什么需要一套“一键化”流程&#xff1a;从手动编译的痛点说起1.1 大多数团队的开发流程到底卡在哪我接手过不少类似 OpenClaw 风格的项目——源码结构不大复杂&#xff0c;但每次从拉取代码到真正跑起来&#xff0c;中间隔着七八个手工步骤&#xff1a;先要安装依赖、配置…

作者头像 李华
网站建设 2026/10/17 12:34:30

Pandas字符串提取:用str.extract()高效解析结构化文本

1. 项目概述&#xff1a;为什么字符串提取要靠正则&#xff0c;而不是split或find&#xff1f;“42_Pandas字符串中提取正则表达式来生成新列”——这个标题里藏着一个被很多新手低估、却被老手天天用的硬核技能点&#xff1a;不是所有字符串都能靠str.split(.)或str.contains(…

作者头像 李华