1. 项目概述:全栈电商系统的技术选型与实践
这套基于SpringBoot+Vue3+MyBatis的电子产品销售系统,是当前企业级电商开发的典型技术组合。采用前后端分离架构,前端使用Vue3组合式API开发,后端基于SpringBoot快速构建RESTful接口,数据持久层选用MyBatis实现灵活SQL映射,配合MySQL关系型数据库完成业务数据存储。这种技术栈选择既保证了开发效率,又能满足电商系统对高并发和复杂业务逻辑的处理需求。
我在实际电商项目开发中发现,这套技术组合特别适合中小型电商平台的快速迭代。Vue3的响应式特性让前端开发效率提升40%以上,而SpringBoot的自动配置机制可以减少约30%的后端样板代码。MyBatis的XML映射文件虽然需要手动编写SQL,但在复杂多表查询场景下反而比JPA等ORM框架更灵活可控。
2. 技术架构深度解析
2.1 前后端分离架构设计
系统采用经典的前后端分离模式,通过清晰的职责划分实现高效并行开发:
- 前端:Vue3 + TypeScript + Pinia状态管理
- 后端:SpringBoot 2.7 + JDK 11
- 通信:RESTful API + JWT认证
- 数据层:MyBatis-Plus + MySQL 8.0
这种架构的优势在于:
- 开发效率:前后端可以同步进行开发,只需约定好API接口
- 性能优化:前端静态资源可通过CDN加速,减轻服务器压力
- 技术栈灵活:前后端可以独立进行技术升级
实际项目中常见的问题是接口规范不一致。我们采用Swagger UI自动生成API文档,并约定响应体统一为:
{ "code": 200, "data": {}, "message": "success" }2.2 数据库设计与优化
针对电子产品销售场景,数据库主要包含以下核心表:
| 表名 | 字段示例 | 索引设计 | 备注 |
|---|---|---|---|
| product | id, name, price, stock | 主键id, name全文索引 | 商品SPU表 |
| product_sku | sku_id, product_id, specs | 联合索引(product_id, specs) | 商品SKU表 |
| order | order_no, user_id, total_amount | 唯一索引order_no | 订单主表 |
| order_item | order_no, sku_id, quantity | 联合索引(order_no, sku_id) | 订单明细 |
在MySQL性能优化方面,我们主要采取以下措施:
- 使用InnoDB引擎并合理设置缓冲池大小
- 对高频查询字段建立复合索引
- 大文本字段(如商品详情)使用垂直分表
- 定期执行
OPTIMIZE TABLE维护碎片
3. 核心功能实现细节
3.1 商品模块实现
商品模块采用SPU+SKU的数据模型,前端使用Vue3的setup语法糖实现响应式表单:
<script setup> const formState = reactive({ name: '', categoryId: null, price: 0, description: '', skuList: [{ specs: {}, price: 0, stock: 0 }] }) const handleAddSku = () => { formState.skuList.push({ specs: {}, price: formState.price, stock: 0 }) } </script>后端采用MyBatis的动态SQL处理复杂查询条件:
<select id="selectProductPage" resultMap="ProductResult"> SELECT * FROM product <where> <if test="name != null and name != ''"> AND name LIKE CONCAT('%', #{name}, '%') </if> <if test="minPrice != null"> AND price >= #{minPrice} </if> <if test="maxPrice != null"> AND price <= #{maxPrice} </if> </where> ORDER BY create_time DESC </select>3.2 购物车与订单流程
购物车设计考虑了几个关键点:
- 未登录用户使用浏览器localStorage存储
- 已登录用户同步到服务端数据库
- 采用Redis缓存商品价格,防止下单时价格变动
订单状态机设计:
public enum OrderStatus { PENDING_PAYMENT, // 待支付 PAID, // 已支付 SHIPPED, // 已发货 COMPLETED, // 已完成 CANCELLED // 已取消 }分布式事务处理采用本地消息表+定时任务补偿机制,确保订单创建和库存扣减的一致性。
4. 安全与性能优化实践
4.1 系统安全防护
认证授权:JWT + Spring Security
- 使用HS512算法签名
- Token设置15分钟过期时间
- 采用refreshToken机制续期
接口防护:
- 使用Spring注解进行权限控制
@PreAuthorize("hasRole('ADMIN')") @PostMapping("/products") public Result addProduct(@RequestBody Product product) { // ... }- 敏感参数过滤XSS攻击
- 使用Hutool工具类进行SQL注入检测
数据安全:
- 密码使用BCrypt加密存储
- 敏感信息如手机号进行AES加密
- 数据库定时备份到OSS
4.2 性能优化方案
缓存策略:
- 商品详情:Redis缓存 + 本地Caffeine二级缓存
- 热点数据:预先加载到Redis
- 缓存雪崩防护:随机过期时间
数据库优化:
- 读写分离:主库写,从库读
- 大表分片:按时间范围分片
- 慢查询监控:开启MySQL慢查询日志
前端优化:
- 图片懒加载
- 路由懒加载
const ProductDetail = () => import('@/views/product/Detail.vue')- 使用Webpack分包策略
5. 部署与监控方案
5.1 容器化部署
采用Docker Compose编排服务:
version: '3' services: mysql: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: ${DB_PASSWORD} volumes: - ./mysql/data:/var/lib/mysql backend: build: ./backend ports: - "8080:8080" depends_on: - mysql frontend: build: ./frontend ports: - "80:80"5.2 监控与日志
监控体系:
- Spring Boot Actuator暴露健康指标
- Prometheus + Grafana监控JVM指标
- ELK收集分析日志
报警机制:
- 异常日志企业微信通知
- 接口响应时间超过1秒触发告警
- 数据库连接池使用率监控
6. 典型问题排查实录
6.1 跨域问题解决方案
开发环境配置:
@Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("*") .allowedMethods("*") .maxAge(3600); } }生产环境推荐使用Nginx反向代理解决跨域:
location /api/ { proxy_pass http://backend:8080/; add_header 'Access-Control-Allow-Origin' '$http_origin'; }6.2 MyBatis缓存问题
一级缓存导致的数据不一致问题:
@Transactional public void updateProduct(Product product) { // 更新操作会清空一级缓存 productMapper.updateById(product); // 必须重新查询获取最新数据 Product newProduct = productMapper.selectById(product.getId()); }二级缓存配置注意事项:
<cache eviction="LRU" flushInterval="60000" size="1024"/> <!-- 需要序列化的实体类 --> <mapper namespace="com.example.mapper.ProductMapper"> <cache-ref namespace="com.example.mapper.ProductMapper"/> </mapper>6.3 Vue3响应式陷阱
解构导致的响应式丢失:
// 错误做法 const { name, price } = reactive(product) // 正确做法 const productRef = ref(product) const name = computed(() => productRef.value.name)数组更新检测:
// Vue3不再需要特殊方法 skuList.value[index] = newValue // 自动触发更新