1. 项目概述
数码产品购物商城是一个典型的B2C电商平台,专注于3C数码产品在线销售。这个基于SpringBoot+Vue的前后端分离项目,是我在开发实践中总结出的一套高可用电商解决方案。相比传统单体架构,这种分离设计让前端展示更灵活,后端服务更稳定,特别适合需要快速迭代的电商业务场景。
在实际开发中,我发现数码产品商城有几个特殊需求:SKU属性复杂(比如手机有颜色、内存等组合)、高并发秒杀场景、精准的参数对比功能。这些都需要在架构设计阶段就做好技术选型。SpringBoot的自动配置和starter机制能快速搭建微服务,而Vue的组件化开发完美适配商品详情页的多变需求。
2. 技术架构设计
2.1 后端SpringBoot技术栈
采用SpringBoot 2.7作为基础框架,其内嵌Tomcat容器和约定优于配置的特性,让项目初始化时间从传统SSM的3天缩短到2小时。关键依赖包括:
- Spring Security OAuth2:处理第三方登录和权限控制
- MyBatis-Plus 3.5:简化DAO层开发,内置分页插件
- Redis 6.2:缓存热点数据和实现分布式锁
- Elasticsearch 7.17:商品搜索服务
- RabbitMQ 3.9:异步处理订单消息
数据库设计采用分库分表策略:
CREATE TABLE `product_sku` ( `id` bigint NOT NULL AUTO_INCREMENT COMMENT '复合主键', `spu_id` bigint NOT NULL COMMENT '商品ID', `attributes` json NOT NULL COMMENT 'SKU属性JSON', `price` decimal(10,2) NOT NULL COMMENT '实际售价', `stock` int NOT NULL DEFAULT '0' COMMENT '库存', PRIMARY KEY (`id`), KEY `idx_spu` (`spu_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='SKU表';2.2 前端Vue技术栈
使用Vue 3组合式API开发管理后台和H5端,主要技术组合:
- Vite 4:极速的开发服务器启动
- Element Plus:后台管理系统UI组件库
- Pinia 2:状态管理替代Vuex
- Axios 1.3:封装了自动重试的HTTP客户端
- Vue Router 4:实现动态路由权限控制
商品详情页的典型组件结构:
// 参数对比组件 const compareTable = computed(() => { return selectedSKUs.value.map(sku => ({ name: sku.spuName, attributes: Object.entries(sku.attributes) .map(([key, val]) => `${key}:${val}`) })) })3. 核心功能实现
3.1 商品系统设计
数码产品的商品模型比普通商品更复杂,采用SPU+SKU两级结构:
- SPU(Standard Product Unit):如"iPhone 14"
- SKU(Stock Keeping Unit):如"iPhone 14 128GB 黑色"
后端采用组合模式实现:
public class ProductSpu { private Long id; private String name; private List<SpecGroup> specGroups; // 规格参数组 private List<ProductSku> skus; // SKU列表 } public class ProductSku { private Long id; private Map<String,String> specs; // 规格值键值对 private BigDecimal price; private Integer stock; }前端使用Vue的递归组件渲染规格选择器:
<template> <div v-for="group in specGroups" :key="group.id"> <h3>{{ group.name }}</h3> <SpecSelector :specs="group.specs" @select="handleSpecSelect" /> </div> </template>3.2 高并发库存控制
秒杀场景下采用分层校验策略:
- 前端限流:按钮点击后立即禁用,防止重复提交
- 缓存校验:Redis预减库存
- 异步下单:RabbitMQ消息队列削峰
- 数据库最终一致性:乐观锁更新
库存扣减的Redis Lua脚本:
local key = KEYS[1] local num = tonumber(ARGV[1]) local stock = tonumber(redis.call('GET', key)) if stock >= num then return redis.call('DECRBY', key, num) else return -1 end3.3 支付与订单系统
采用状态机模式管理订单生命周期:
public enum OrderStatus { UNPAID(1, "待支付") { @Override public boolean canChangeTo(OrderStatus status) { return status == PAID || status == CANCELLED; } }, PAID(2, "已支付") { @Override public boolean canChangeTo(OrderStatus status) { return status == SHIPPED || status == REFUNDING; } }; // 其他状态... }支付回调处理采用策略模式:
@Service public class PaymentCallbackStrategy { @Resource private Map<String, PaymentHandler> handlers; public void handle(String paymentType, CallbackData data) { handlers.get(paymentType).process(data); } }4. 性能优化实践
4.1 缓存设计策略
采用多级缓存架构:
- 本地缓存(Caffeine):缓存用户个性化数据
- 分布式缓存(Redis):缓存热点商品数据
- 静态化(Nginx):商品详情页HTML静态化
缓存Key设计规范:
业务前缀:数据维度:唯一标识 示例:product:detail:1234.2 数据库优化
针对商品列表页的深度分页问题,采用游标分页:
SELECT * FROM product WHERE id > #{lastId} AND status = 1 ORDER BY id ASC LIMIT #{size}建立组合索引时遵循最左前缀原则:
ALTER TABLE `order` ADD INDEX `idx_user_status` (`user_id`, `status`);4.3 前端性能优化
- 图片懒加载:
<img v-lazy="product.image" alt="商品图">- 组件异步加载:
const ProductDetail = defineAsyncComponent(() => import('./views/ProductDetail.vue') )- Webpack分包策略:
configureWebpack: { optimization: { splitChunks: { chunks: 'all', maxSize: 244 * 1024 // 244KB } } }5. 部署与监控
5.1 容器化部署
使用Docker Compose编排服务:
version: '3' services: app: image: openjdk:17-jdk ports: - "8080:8080" volumes: - ./logs:/app/logs environment: - SPRING_PROFILES_ACTIVE=prod redis: image: redis:6.2-alpine ports: - "6379:6379"5.2 监控告警系统
SpringBoot Actuator集成Prometheus:
management: endpoints: web: exposure: include: health,metrics,prometheus metrics: tags: application: ${spring.application.name}配置Grafana监控看板,重点关注:
- JVM内存使用率
- 接口QPS/RT
- Redis命中率
- 数据库连接池状态
6. 踩坑经验分享
6.1 跨域问题解决方案
开发环境使用Webpack代理:
devServer: { proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true } } }生产环境配置Nginx:
location /api/ { proxy_pass http://backend; add_header 'Access-Control-Allow-Origin' $http_origin; add_header 'Access-Control-Allow-Credentials' 'true'; }6.2 微信支付签名错误
注意参数排序和编码问题:
public String generateSign(SortedMap<String,String> params) { StringBuilder sb = new StringBuilder(); params.forEach((k,v) -> { if (StringUtils.isNotEmpty(v)) { sb.append(k).append("=").append(v).append("&"); } }); sb.append("key=").append(apiKey); return DigestUtils.md5Hex(sb.toString()).toUpperCase(); }6.3 订单超时处理
使用延迟队列实现:
@Bean public Queue orderDelayQueue() { return QueueBuilder.durable("order.delay.queue") .withArgument("x-dead-letter-exchange", "order.event.exchange") .withArgument("x-dead-letter-routing-key", "order.cancel") .withArgument("x-message-ttl", 1800000) // 30分钟 .build(); }7. 扩展功能建议
- 商品对比工具:使用IndexedDB存储用户选择的对比商品
- AR展示:集成Three.js实现3C产品的3D展示
- 智能推荐:采用协同过滤算法实现个性化推荐
- 直播带货:集成WebRTC实现直播功能
在实现商品搜索时,Elasticsearch的mapping设计要注意:
{ "properties": { "name": { "type": "text", "analyzer": "ik_max_word" }, "attributes": { "type": "nested", "properties": { "key": {"type": "keyword"}, "value": {"type": "keyword"} } } } }