1. 项目背景与技术选型
宠物商城平台是一个典型的B2C电子商务系统,面向宠物主人提供宠物用品、食品、医疗用品等商品的在线购买服务。这类系统需要处理商品展示、购物车、订单管理、支付对接等核心功能,同时还需要考虑宠物行业的特殊需求,如宠物档案管理、宠物医疗服务预约等扩展功能。
技术栈选择SpringBoot+Vue的组合主要基于以下考虑:
-
前后端分离架构优势:SpringBoot负责后端API开发,Vue负责前端展示,两者通过RESTful API交互,这种架构模式具有清晰的职责划分和良好的扩展性。
-
SpringBoot的核心价值:
- 自动配置简化了传统Spring项目的繁琐配置
- 内嵌Tomcat容器,简化部署流程
- 丰富的Starter依赖,快速集成MyBatis、Redis等常用组件
- Actuator提供完善的监控端点
-
Vue.js的适用性:
- 响应式数据绑定特别适合电商类频繁交互的场景
- 组件化开发便于复用商品卡片、分类导航等UI元素
- Vue Router实现前端路由,提供流畅的单页应用体验
- Vuex集中管理购物车、用户登录等全局状态
2. 系统架构设计
2.1 整体架构分层
code复制├── 前端层(Vue)
│ ├── 用户界面
│ ├── 路由管理
│ └── 状态管理
├── 网关层(Nginx)
│ ├── 请求转发
│ └── 负载均衡
├── 应用层(SpringBoot)
│ ├── 控制层
│ ├── 服务层
│ └── 数据访问层
└── 数据层
├── MySQL
├── Redis
└── Elasticsearch
2.2 核心模块划分
-
用户模块
- 注册/登录(JWT认证)
- 个人信息管理
- 宠物档案管理(特有功能)
-
商品模块
- 商品分类体系(多级分类)
- 商品搜索(Elasticsearch集成)
- 商品评价系统
-
订单模块
- 购物车服务(Redis缓存)
- 订单状态机设计
- 支付对接(支付宝/微信)
-
运营模块
- 促销活动管理
- 优惠券系统
- 数据统计看板
3. 数据库设计要点
3.1 核心表结构
sql复制-- 商品表
CREATE TABLE `product` (
`id` bigint NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL COMMENT '商品名称',
`category_id` int NOT NULL COMMENT '分类ID',
`price` decimal(10,2) NOT NULL COMMENT '售价',
`stock` int NOT NULL COMMENT '库存',
`pet_type` tinyint COMMENT '适用宠物类型(0-通用 1-狗 2-猫...)',
`detail` text COMMENT '商品详情',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 宠物档案表(特色表)
CREATE TABLE `pet_profile` (
`id` bigint NOT NULL AUTO_INCREMENT,
`user_id` bigint NOT NULL,
`pet_name` varchar(50) NOT NULL,
`pet_type` tinyint NOT NULL COMMENT '宠物类型',
`birthday` date COMMENT '出生日期',
`weight` decimal(5,2) COMMENT '体重(kg)',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
3.2 设计注意事项
-
商品分类设计:建议采用闭包表(Closure Table)实现多级分类,便于查询任意级别的子分类
-
购物车优化:高频访问的购物车数据应存储在Redis中,采用Hash结构:
code复制key: cart:{userId} field: {productId} value: {quantity} -
订单分表策略:按用户ID哈希分表,避免单表过大影响查询性能
4. 关键功能实现
4.1 商品搜索实现
java复制// ElasticsearchRepository示例
public interface ProductRepository extends ElasticsearchRepository<ProductEsDTO, Long> {
// 多字段搜索+宠物类型过滤
@Query("{\"bool\": {\"must\": [{\"multi_match\": {\"query\": \"?0\", \"fields\": [\"name^2\", \"keywords\"]}}], \"filter\": [{\"term\": {\"petType\": ?1}}]}}")
Page<ProductEsDTO> findByKeywordAndPetType(String keyword, Integer petType, Pageable pageable);
}
4.2 购物车服务核心逻辑
java复制@Service
public class CartServiceImpl implements CartService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Override
public void addToCart(Long userId, Long productId, Integer quantity) {
String key = "cart:" + userId;
// 使用Hash结构存储,避免重复添加相同商品
redisTemplate.opsForHash().put(key, productId.toString(), quantity);
// 设置过期时间30天
redisTemplate.expire(key, 30, TimeUnit.DAYS);
}
@Override
public List<CartItemVO> getCart(Long userId) {
String key = "cart:" + userId;
Map<Object, Object> entries = redisTemplate.opsForHash().entries(key);
// 转换并查询商品详情...
}
}
4.3 订单状态机设计
java复制// 使用Spring StateMachine实现订单状态流转
@Configuration
@EnableStateMachineFactory
public class OrderStateMachineConfig extends StateMachineConfigurerAdapter<String, String> {
@Override
public void configure(StateMachineStateConfigurer<String, String> states) throws Exception {
states
.withStates()
.initial("UNPAID")
.states(EnumSet.of(
OrderStatus.UNPAID,
OrderStatus.PAID,
OrderStatus.SHIPPED,
OrderStatus.COMPLETED,
OrderStatus.CANCELLED
));
}
@Override
public void configure(StateMachineTransitionConfigurer<String, String> transitions) throws Exception {
transitions
.withExternal()
.source("UNPAID").target("PAID")
.event("PAY")
.and()
.withExternal()
.source("PAID").target("SHIPPED")
.event("SHIP");
}
}
5. 部署与优化实践
5.1 前端部署方案
-
生产环境构建:
bash复制
npm run build生成的dist目录包含静态资源,可通过Nginx直接托管
-
Nginx配置示例:
nginx复制server { listen 80; server_name petmall.example.com; location / { root /usr/share/nginx/html/dist; index index.html; try_files $uri $uri/ /index.html; } location /api { proxy_pass http://backend-server; proxy_set_header Host $host; } }
5.2 后端性能优化
-
缓存策略:
- 商品详情使用多级缓存:Redis → Caffeine → DB
- 热点数据预加载:每日销量Top100商品预热到缓存
-
SQL优化:
java复制// 避免N+1查询问题 @EntityGraph(attributePaths = {"skuList", "category"}) @Query("select p from Product p where p.id = :id") Product findDetailById(@Param("id") Long id); -
异步处理:
java复制// 使用@Async处理非核心流程 @Async public void asyncUpdateProductStatistics(Long productId) { // 更新商品统计信息... }
6. 特色功能扩展建议
-
智能推荐系统:
- 基于用户浏览历史的协同过滤推荐
- 基于宠物档案的个性化推荐(不同品种/年龄的宠物推荐不同商品)
-
宠物健康服务:
- 疫苗接种提醒
- 宠物BMI计算工具
- 附近宠物医院地图
-
社区功能:
- 宠物照片分享
- 养宠经验交流论坛
- 在线宠物医生咨询
7. 开发环境搭建指南
7.1 后端环境
-
基础环境:
- JDK 1.8+
- Maven 3.6+
- MySQL 5.7+
-
关键配置:
yaml复制# application.yml示例 spring: datasource: url: jdbc:mysql://localhost:3306/petmall?useSSL=false username: root password: 123456 redis: host: localhost port: 6379
7.2 前端环境
-
安装依赖:
bash复制
npm install -g @vue/cli npm install -
开发运行:
bash复制
npm run serve -
跨域配置:
javascript复制// vue.config.js module.exports = { devServer: { proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true } } } }
8. 常见问题解决方案
-
Vue跨域问题:
- 开发环境:配置devServer.proxy
- 生产环境:Nginx反向代理
-
SpringBoot文件上传大小限制:
yaml复制spring: servlet: multipart: max-file-size: 10MB max-request-size: 100MB -
Redis缓存穿透防护:
java复制public Product getProduct(Long id) { // 布隆过滤器初步拦截 if (!bloomFilter.mightContain(id)) { return null; } // 缓存查询逻辑... } -
订单超时处理:
java复制// 使用延迟队列处理未支付订单 @Scheduled(fixedDelay = 60000) public void cancelUnpaidOrders() { List<Order> orders = orderRepository.findByStatusAndCreateTimeBefore( OrderStatus.UNPAID, LocalDateTime.now().minusMinutes(30)); orders.forEach(order -> { order.cancel(); orderRepository.save(order); }); }
