1. 项目背景与核心价值
生鲜团购管理系统是近年来社区电商和本地生活服务领域的热门需求。随着线上购物习惯的普及,消费者对生鲜食品的即时性和新鲜度要求越来越高。这个基于SpringBoot+Vue的系统设计,正是为了解决传统生鲜销售中的几个痛点:
- 库存周转效率低:生鲜商品保质期短,需要精准的销量预测和快速周转
- 价格敏感度高:消费者对生鲜价格变动非常敏感,需要灵活的促销手段
- 配送时效性强:需要协调供应商、仓储和配送资源
优惠券模块作为系统的核心功能之一,直接关系到用户粘性和复购率。我们团队在实际开发中发现,一个设计良好的优惠券系统可以提升30%以上的用户活跃度。
2. 技术架构设计
2.1 后端技术选型
SpringBoot 2.7.x作为后端框架,主要基于以下考虑:
- 自动配置简化了SSM框架的整合
- 内嵌Tomcat方便部署
- Actuator提供完善的监控端点
- 与Spring生态无缝集成
关键依赖配置:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>1.4.6</version> </dependency>2.2 前端技术栈
Vue 3.x + Element Plus的组合提供了:
- 响应式数据绑定
- 组件化开发体验
- 丰富的UI组件库
- 更小的打包体积
特别针对优惠券模块,我们使用了Vuex进行状态管理,确保跨组件的数据一致性。
3. 核心功能实现
3.1 优惠券系统设计
优惠券模块的数据库设计:
CREATE TABLE `coupon` ( `id` bigint NOT NULL AUTO_INCREMENT, `name` varchar(100) NOT NULL COMMENT '优惠券名称', `type` tinyint NOT NULL COMMENT '1-满减 2-折扣 3-无门槛', `value` decimal(10,2) NOT NULL COMMENT '优惠值', `min_order_amount` decimal(10,2) DEFAULT NULL COMMENT '最低使用金额', `start_time` datetime NOT NULL COMMENT '生效时间', `end_time` datetime NOT NULL COMMENT '过期时间', `total_count` int NOT NULL COMMENT '发放总量', `remaining_count` int NOT NULL COMMENT '剩余数量', `status` tinyint NOT NULL DEFAULT '1' COMMENT '1-有效 0-无效', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;3.2 优惠券发放策略
我们实现了多种发放方式:
- 新用户注册自动发放
- 达到指定消费金额触发
- 定时任务批量发放
- 手动定向发放
核心发放逻辑代码片段:
public Result distributeCoupon(Long userId, Long couponId) { // 校验优惠券状态 Coupon coupon = couponMapper.selectById(couponId); if(coupon.getRemainingCount() <= 0) { return Result.fail("优惠券已领完"); } // 校验用户是否已领取 if(userCouponMapper.exists(userId, couponId)) { return Result.fail("已领取过该优惠券"); } // 扣减库存 couponMapper.decreaseRemaining(couponId); // 记录用户优惠券 UserCoupon userCoupon = new UserCoupon(); userCoupon.setUserId(userId); userCoupon.setCouponId(couponId); userCoupon.setStatus(0); // 未使用 userCouponMapper.insert(userCoupon); return Result.success(); }4. 关键技术难点与解决方案
4.1 高并发下的优惠券超发问题
采用Redis+Lua脚本实现原子操作:
local couponKey = KEYS[1] local userId = ARGV[1] local couponId = ARGV[2] -- 检查库存 local remaining = redis.call('HGET', couponKey, 'remaining_count') if tonumber(remaining) <= 0 then return 0 end -- 检查是否已领取 local userKey = 'user_coupon:'..userId if redis.call('SISMEMBER', userKey, couponId) == 1 then return 0 end -- 扣减库存 redis.call('HINCRBY', couponKey, 'remaining_count', -1) -- 记录用户领取 redis.call('SADD', userKey, couponId) return 14.2 优惠券核销的幂等性设计
采用唯一事务ID保证幂等:
@Transactional public Result useCoupon(Long userId, Long couponId, String transactionId) { // 检查事务ID是否已处理 if(transactionLogMapper.exists(transactionId)) { return Result.fail("请勿重复提交"); } // 核销逻辑... // 记录事务日志 transactionLogMapper.insert(new TransactionLog(transactionId)); return Result.success(); }5. 系统优化实践
5.1 缓存策略优化
采用多级缓存架构:
- 本地缓存(Caffeine):存储热点优惠券信息
- Redis缓存:存储全量优惠券数据
- 数据库:持久化存储
缓存更新策略:
@CacheEvict(value = "coupon", key = "#couponId") public void updateCoupon(Coupon coupon) { couponMapper.updateById(coupon); }5.2 性能压测数据
使用JMeter进行压力测试:
- 单机QPS:1200+
- 平均响应时间:<50ms
- 错误率:<0.1%
6. 安全防护措施
6.1 防刷策略
- IP限流:每个IP每分钟最多请求5次
- 用户限流:每个用户每天最多领取10张优惠券
- 验证码:敏感操作需验证
实现代码:
@RateLimiter(value = 5, key = "#ip") public Result getCoupon(Long couponId, String ip) { // 领取逻辑 }6.2 数据安全
- 敏感数据加密存储
- 接口权限控制
- SQL注入防护
7. 部署架构
采用Docker Compose部署方案:
version: '3' services: mysql: image: mysql:5.7 environment: MYSQL_ROOT_PASSWORD: root ports: - "3306:3306" redis: image: redis:6 ports: - "6379:6379" backend: build: ./backend ports: - "8080:8080" depends_on: - mysql - redis frontend: build: ./frontend ports: - "80:80"8. 监控与告警
- Spring Boot Actuator暴露健康指标
- Prometheus采集指标数据
- Grafana可视化监控
- 关键异常企业微信告警
9. 实际运营数据
上线3个月后的关键指标:
- 优惠券领取率:68%
- 优惠券使用率:42%
- 带动GMV增长:23%
- 用户复购率提升:35%
10. 经验总结与避坑指南
- 优惠券过期处理要使用延迟队列,不要用定时任务扫描
- 金额计算务必使用BigDecimal,避免浮点数精度问题
- 前端展示剩余数量要做缓存,不能实时查询数据库
- 优惠券模板和用户优惠券要分开设计
- 分布式环境下要处理好定时任务的幂等性
一个典型的坑:我们最初使用@Scheduled定时关闭过期优惠券,在集群环境下会导致多次执行。后来改用Redis的键空间通知完美解决了这个问题。