1. 项目背景与核心价值
宠物经济近年来呈现爆发式增长,根据行业数据显示,2022年中国宠物市场规模已突破3000亿元。在这个背景下,传统线下宠物店面临着服务半径有限、运营效率低下等问题。我们团队开发的这套宠物商城管理系统,正是为了解决这些痛点而生。
这个系统最核心的价值在于:
- 为消费者提供24小时在线的购物体验,从宠物食品到医疗用品一站式购齐
- 为商家打造完整的数字化运营解决方案,包括商品管理、订单处理、用户分析等
- 采用前后端分离架构,既保证了系统性能又提升了开发效率
技术选型上我们特别考虑了中小型宠物商家的实际需求,没有盲目追求最新技术栈,而是选择了SpringBoot+Vue这样成熟稳定的组合。
2. 技术架构设计
2.1 后端技术栈解析
后端采用SpringBoot 2.7 + MyBatis-Plus 3.5的组合,这是经过多个项目验证的黄金搭配。具体配置如下:
java复制// pom.xml关键依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
这样配置的优势在于:
- MyBatis-Plus的自动CRUD功能可以减少30%以上的重复代码
- 内置的分页插件完美支持复杂查询
- 代码生成器可以快速生成基础模块
2.2 前端技术选型
前端采用Vue3 + Element Plus的组合,具体技术特点:
- 使用Vite作为构建工具,开发环境启动速度提升5倍以上
- Pinia状态管理替代传统的Vuex,代码更简洁
- Element Plus组件库提供完善的UI解决方案
- Axios封装了统一的请求拦截和错误处理
javascript复制// 典型的API请求封装
const service = axios.create({
baseURL: import.meta.env.VITE_APP_BASE_API,
timeout: 5000
})
service.interceptors.response.use(
response => {
return response.data
},
error => {
return Promise.reject(error)
}
)
3. 数据库设计与优化
3.1 核心表结构设计
系统主要包含8张核心表,这里重点说明用户表和商品表的特殊设计:
用户表(user_profile)优化点:
- 密码字段使用BCrypt加密存储
- 添加了last_login_time字段用于分析用户活跃度
- 使用BIGINT作为主键避免溢出
sql复制CREATE TABLE `user_profile` (
`user_id` bigint NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL,
`password_hash` varchar(100) NOT NULL,
`email` varchar(100) NOT NULL,
`phone_number` varchar(20) DEFAULT NULL,
`register_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`last_login_time` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`user_id`),
UNIQUE KEY `idx_username` (`username`),
UNIQUE KEY `idx_email` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
商品表(product_details)的特殊处理:
- 价格使用DECIMAL(10,2)确保精度
- 添加了fulltext索引支持商品搜索
- 使用TEXT类型存储详细描述
3.2 索引优化方案
针对宠物商城的高频查询场景,我们设计了如下索引:
- 商品分类ID的普通索引
- 商品名称的全文本索引
- 订单表的用户ID和创建时间联合索引
sql复制ALTER TABLE product_details ADD FULLTEXT INDEX ft_index (product_name,description);
ALTER TABLE order_transaction ADD INDEX idx_user_time (user_id, payment_time);
4. 核心功能实现
4.1 商品展示模块
前端采用虚拟滚动技术处理大量商品展示:
vue复制<template>
<el-table
:data="tableData"
height="500"
row-key="id"
@row-click="handleRowClick"
>
<el-table-column prop="product_name" label="商品名称" />
<el-table-column prop="price" label="价格" width="120" />
</el-table>
</template>
后端接口特别注意了分页性能优化:
java复制@GetMapping("/products")
public R list(@RequestParam Map<String, Object> params) {
PageUtils page = productService.queryPage(params);
return R.ok().put("data", page);
}
// Service层实现
@Override
public PageUtils queryPage(Map<String, Object> params) {
QueryWrapper<ProductDetailsEntity> wrapper = new QueryWrapper<>();
// 构建查询条件
IPage<ProductDetailsEntity> page = this.page(
new Query<ProductDetailsEntity>().getPage(params),
wrapper
);
return new PageUtils(page);
}
4.2 购物车设计
购物车采用Redis缓存+数据库持久化的双写方案:
- 用户添加商品时先写入Redis
- 定时任务每5分钟同步到MySQL
- 用户结算时强制同步
java复制public void addToCart(Long userId, CartItem item) {
String key = "cart:" + userId;
// Redis操作
redisTemplate.opsForHash().put(key, item.getProductId(), item);
// 异步写入数据库
cartAsyncService.asyncSaveToDB(userId, item);
}
5. 支付系统集成
5.1 支付流程设计
我们设计了状态机来管理订单支付流程:
code复制待支付 → 支付中 → 支付成功/失败 → 发货中 → 已完成
状态转换的核心代码:
java复制public enum OrderStatus {
UNPAID,
PAYING,
PAID,
DELIVERING,
COMPLETED,
CANCELLED
}
public void changeStatus(Long orderId, OrderStatus newStatus) {
OrderStatus current = getCurrentStatus(orderId);
if (transitionValid(current, newStatus)) {
updateStatus(orderId, newStatus);
} else {
throw new IllegalStateException("无效的状态转换");
}
}
5.2 支付结果回调处理
特别注意了支付结果通知的幂等性处理:
java复制@PostMapping("/notify")
public String paymentNotify(@RequestBody NotifyData data) {
// 1. 验证签名
if (!verifySign(data)) {
return "fail";
}
// 2. 检查是否已处理过
if (orderService.isNotifyProcessed(data.getNotify_id())) {
return "success";
}
// 3. 处理业务逻辑
orderService.handlePaymentSuccess(data);
return "success";
}
6. 性能优化实践
6.1 缓存策略
采用多级缓存方案:
- 本地Caffeine缓存热点数据
- Redis集群缓存通用数据
- MySQL持久化存储
java复制@Cacheable(value = "products", key = "#productId")
public ProductDetailsEntity getProductDetail(Long productId) {
return baseMapper.selectById(productId);
}
6.2 SQL优化案例
发现商品分类查询较慢后,通过EXPLAIN分析优化:
优化前的慢查询:
sql复制SELECT * FROM product_details WHERE category_id = 5 ORDER BY create_time DESC;
优化方案:
- 添加复合索引(category_id, create_time)
- 改写为覆盖索引查询
sql复制ALTER TABLE product_details ADD INDEX idx_category_time (category_id, create_time);
SELECT product_id, product_name, price
FROM product_details
WHERE category_id = 5
ORDER BY create_time DESC;
优化后查询时间从1200ms降至50ms。
7. 安全防护措施
7.1 常见安全漏洞防护
- XSS防护:前端使用vue-dompurify净化HTML
- CSRF防护:Spring Security默认启用
- SQL注入:MyBatis使用预编译
- 密码安全:BCrypt加密存储
密码加密实现:
java复制public class PasswordEncoder implements org.springframework.security.crypto.password.PasswordEncoder {
private static final BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
@Override
public String encode(CharSequence rawPassword) {
return encoder.encode(rawPassword);
}
@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
return encoder.matches(rawPassword, encodedPassword);
}
}
7.2 接口限流设计
使用Guava RateLimiter保护核心接口:
java复制@RestController
@RequestMapping("/api")
public class ProductController {
private final RateLimiter limiter = RateLimiter.create(100.0); // 每秒100个请求
@GetMapping("/hot-products")
public R listHotProducts() {
if (!limiter.tryAcquire()) {
throw new BizException("请求过于频繁,请稍后再试");
}
return R.ok().put("data", productService.listHotProducts());
}
}
8. 部署与监控
8.1 容器化部署
使用Docker Compose编排服务:
yaml复制version: '3'
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: pet123456
volumes:
- mysql_data:/var/lib/mysql
redis:
image: redis:6
ports:
- "6379:6379"
backend:
build: ./backend
ports:
- "8080:8080"
depends_on:
- mysql
- redis
8.2 监控方案
- Spring Boot Actuator暴露健康指标
- Prometheus收集指标数据
- Grafana展示监控图表
关键配置:
properties复制# application.properties
management.endpoints.web.exposure.include=health,metrics,prometheus
management.metrics.tags.application=pet-store
9. 开发中的经验教训
-
MyBatis-Plus的坑:
自动填充功能需要特别注意字段注解,我们曾经因为忘记加@TableField导致创建时间没有自动填充。 -
Vue的响应式问题:
直接通过索引修改数组元素不会触发视图更新,必须使用Vue.set或splice方法。 -
MySQL编码问题:
表情符号存储需要utf8mb4编码,建表时一定要显式指定。 -
接口设计建议:
前后端接口定义一定要先写Swagger文档,我们中途修改接口导致前后端联调浪费了2天时间。 -
缓存一致性问题:
商品库存更新时要同步清理缓存,我们曾因此出现超卖问题。最终采用Redisson分布式锁解决。
10. 项目扩展方向
-
小程序端开发:
可以基于uni-app快速开发微信小程序版本,复用现有API接口。 -
推荐系统集成:
加入基于用户行为的商品推荐算法,提升转化率。 -
物流跟踪功能:
对接第三方物流API,实现订单物流实时跟踪。 -
会员积分体系:
设计积分获取和兑换规则,提升用户粘性。 -
数据分析看板:
使用ECharts构建销售数据分析可视化大屏。