010-53388338

美团买菜优惠券系统设计:涵盖功能、架构、实现、规则及性能优化

分类:IT频道 时间:2026-02-11 07:55 浏览:18
概述
    一、功能概述    美团买菜系统的优惠券通用功能需要实现以下核心能力:  1.支持多种类型优惠券(满减券、折扣券、无门槛券等)  2.跨品类通用(蔬菜、水果、肉禽、日用品等)  3.灵活的发放与使用规则  4.精准的优惠计算与叠加规则  5.完善的优惠券生命周期管理    二、系统架构设计 
内容
  
   一、功能概述
  
  美团买菜系统的优惠券通用功能需要实现以下核心能力:
  1. 支持多种类型优惠券(满减券、折扣券、无门槛券等)
  2. 跨品类通用(蔬菜、水果、肉禽、日用品等)
  3. 灵活的发放与使用规则
  4. 精准的优惠计算与叠加规则
  5. 完善的优惠券生命周期管理
  
   二、系统架构设计
  
   1. 核心模块划分
  
  ```
  优惠券系统
  ├── 优惠券模板管理
  ├── 优惠券实例管理
  ├── 优惠券发放服务
  ├── 优惠券使用服务
  ├── 优惠券计算引擎
  └── 优惠券监控与统计
  ```
  
   2. 数据库设计
  
  优惠券模板表(coupon_template)
  ```sql
  CREATE TABLE coupon_template (
   id BIGINT PRIMARY KEY AUTO_INCREMENT,
   name VARCHAR(100) NOT NULL COMMENT 优惠券名称,
   type TINYINT NOT NULL COMMENT 类型(1:满减 2:折扣 3:无门槛),
   discount_type TINYINT COMMENT 折扣类型(1:百分比 2:固定金额),
   discount_value DECIMAL(10,2) NOT NULL COMMENT 优惠值,
   min_order_amount DECIMAL(10,2) COMMENT 最低订单金额,
   valid_start_time DATETIME NOT NULL COMMENT 有效期开始时间,
   valid_end_time DATETIME NOT NULL COMMENT 有效期结束时间,
   total_count INT DEFAULT 0 COMMENT 总发放数量,
   remaining_count INT DEFAULT 0 COMMENT 剩余数量,
   user_limit INT DEFAULT 1 COMMENT 每人限领数量,
   scope TINYINT DEFAULT 1 COMMENT 使用范围(1:全品类 2:指定品类),
   category_ids VARCHAR(255) COMMENT 适用品类ID列表,
   status TINYINT DEFAULT 1 COMMENT 状态(1:启用 2:禁用),
   create_time DATETIME NOT NULL,
   update_time DATETIME NOT NULL
  );
  ```
  
  用户优惠券表(user_coupon)
  ```sql
  CREATE TABLE user_coupon (
   id BIGINT PRIMARY KEY AUTO_INCREMENT,
   user_id BIGINT NOT NULL COMMENT 用户ID,
   template_id BIGINT NOT NULL COMMENT 模板ID,
   coupon_code VARCHAR(32) NOT NULL COMMENT 优惠券码,
   status TINYINT DEFAULT 1 COMMENT 状态(1:未使用 2:已使用 3:已过期),
   order_id BIGINT COMMENT 关联订单ID,
   get_time DATETIME NOT NULL COMMENT 领取时间,
   use_time DATETIME COMMENT 使用时间,
   expire_time DATETIME NOT NULL COMMENT 过期时间,
   INDEX idx_user (user_id),
   INDEX idx_status (status),
   INDEX idx_expire (expire_time)
  );
  ```
  
   三、核心功能实现
  
   1. 优惠券发放服务
  
  ```java
  public class CouponDistributionService {
  
   @Autowired
   private CouponTemplateRepository templateRepository;
  
   @Autowired
   private UserCouponRepository userCouponRepository;
  
   @Transactional
   public void distributeCoupon(Long templateId, List userIds) {
   CouponTemplate template = templateRepository.findById(templateId)
   .orElseThrow(() -> new RuntimeException("优惠券模板不存在"));
  
   // 检查剩余数量
   if (template.getRemainingCount() <= 0) {
   throw new RuntimeException("优惠券已发放完毕");
   }
  
   // 生成用户优惠券
   List coupons = new ArrayList<>();
   Date now = new Date();
   for (Long userId : userIds) {
   // 检查用户已领取数量
   int userCount = userCouponRepository.countByUserIdAndTemplateIdAndStatus(
   userId, templateId, CouponStatus.UNUSED.getCode());
   if (userCount >= template.getUserLimit()) {
   continue; // 跳过已达上限的用户
   }
  
   UserCoupon coupon = new UserCoupon();
   coupon.setUserId(userId);
   coupon.setTemplateId(templateId);
   coupon.setCouponCode(generateCouponCode());
   coupon.setStatus(CouponStatus.UNUSED.getCode());
   coupon.setGetTime(now);
   coupon.setExpireTime(template.getValidEndTime());
   coupons.add(coupon);
   }
  
   if (!coupons.isEmpty()) {
   userCouponRepository.saveAll(coupons);
   // 更新模板剩余数量
   template.setRemainingCount(template.getRemainingCount() - coupons.size());
   templateRepository.save(template);
   }
   }
  
   private String generateCouponCode() {
   // 生成唯一优惠券码逻辑
   return UUID.randomUUID().toString().replace("-", "").substring(0, 16).toUpperCase();
   }
  }
  ```
  
   2. 优惠券使用服务
  
  ```java
  public class CouponUsageService {
  
   @Autowired
   private UserCouponRepository userCouponRepository;
  
   @Autowired
   private CouponTemplateRepository templateRepository;
  
   @Autowired
   private OrderRepository orderRepository;
  
   public UserCoupon useCoupon(Long userId, String couponCode, Long orderId) {
   // 验证订单属于当前用户
   Order order = orderRepository.findByIdAndUserId(orderId, userId)
   .orElseThrow(() -> new RuntimeException("订单不存在或不属于当前用户"));
  
   // 查找用户优惠券
   UserCoupon userCoupon = userCouponRepository.findByUserIdAndCouponCodeAndStatus(
   userId, couponCode, CouponStatus.UNUSED.getCode())
   .orElseThrow(() -> new RuntimeException("优惠券不存在或不可用"));
  
   CouponTemplate template = templateRepository.findById(userCoupon.getTemplateId())
   .orElseThrow(() -> new RuntimeException("优惠券模板不存在"));
  
   // 验证有效期
   if (new Date().after(template.getValidEndTime())) {
   throw new RuntimeException("优惠券已过期");
   }
  
   // 验证使用范围
   if (template.getScope() == CouponScope.SPECIFIC_CATEGORY.getCode()) {
   List categoryIds = Arrays.asList(template.getCategoryIds().split(","))
   .stream().map(Long::valueOf).collect(Collectors.toList());
  
   // 检查订单商品是否都属于指定品类
   List items = orderRepository.findOrderItemsByOrderId(orderId);
   boolean allMatch = items.stream()
   .allMatch(item -> categoryIds.contains(item.getCategoryId()));
  
   if (!allMatch) {
   throw new RuntimeException("该优惠券仅适用于指定品类商品");
   }
   }
  
   // 验证最低订单金额
   if (template.getMinOrderAmount() != null &&
   order.getTotalAmount().compareTo(template.getMinOrderAmount()) < 0) {
   throw new RuntimeException("订单金额未达到使用条件");
   }
  
   // 更新优惠券状态
   userCoupon.setStatus(CouponStatus.USED.getCode());
   userCoupon.setUseTime(new Date());
   userCoupon.setOrderId(orderId);
   userCouponRepository.save(userCoupon);
  
   return userCoupon;
   }
  }
  ```
  
   3. 优惠券计算引擎
  
  ```java
  public class CouponCalculator {
  
   public OrderDiscountResult calculateDiscount(Order order, UserCoupon userCoupon) {
   CouponTemplate template = getTemplateById(userCoupon.getTemplateId());
   OrderDiscountResult result = new OrderDiscountResult();
  
   switch (CouponType.valueOf(template.getType())) {
   case FIXED_DISCOUNT:
   // 固定金额满减券
   result.setDiscountAmount(template.getDiscountValue());
   result.setDiscountType(DiscountType.FIXED);
   break;
  
   case PERCENTAGE_DISCOUNT:
   // 百分比折扣券
   BigDecimal discount = order.getTotalAmount()
   .multiply(template.getDiscountValue().divide(new BigDecimal("100")));
   // 通常折扣券有最大优惠金额限制
   if (template.getMaxDiscount() != null &&
   discount.compareTo(template.getMaxDiscount()) > 0) {
   discount = template.getMaxDiscount();
   }
   result.setDiscountAmount(discount);
   result.setDiscountType(DiscountType.PERCENTAGE);
   break;
  
   case NO_THRESHOLD:
   // 无门槛券
   result.setDiscountAmount(template.getDiscountValue());
   result.setDiscountType(DiscountType.FIXED);
   break;
   }
  
   // 确保优惠金额不超过订单总额
   if (result.getDiscountAmount().compareTo(order.getTotalAmount()) > 0) {
   result.setDiscountAmount(order.getTotalAmount());
   }
  
   result.setFinalAmount(order.getTotalAmount().subtract(result.getDiscountAmount()));
   return result;
   }
  }
  ```
  
   四、关键业务规则实现
  
   1. 优惠券叠加规则
  
  ```java
  public class CouponCombinationRule {
  
   public boolean canCombine(List coupons) {
   if (coupons.size() > 3) { // 最多叠加3张券
   return false;
   }
  
   Set types = new HashSet<>();
   for (UserCoupon coupon : coupons) {
   CouponTemplate template = getTemplateById(coupon.getTemplateId());
   types.add(CouponType.valueOf(template.getType()));
   }
  
   // 不能同时使用满减券和折扣券
   if (types.contains(CouponType.FIXED_DISCOUNT) &&
   types.contains(CouponType.PERCENTAGE_DISCOUNT)) {
   return false;
   }
  
   // 无门槛券不能与其他券叠加
   if (types.contains(CouponType.NO_THRESHOLD) && types.size() > 1) {
   return false;
   }
  
   return true;
   }
  }
  ```
  
   2. 优惠券有效期管理
  
  ```java
  @Scheduled(cron = "0 0 0 * * ?") // 每天凌晨执行
  public class CouponExpiryJob {
  
   @Autowired
   private UserCouponRepository userCouponRepository;
  
   @Transactional
   public void processExpiredCoupons() {
   Date now = new Date();
   List expiredCoupons = userCouponRepository.findByStatusAndExpireTimeBefore(
   CouponStatus.UNUSED.getCode(), now);
  
   if (!expiredCoupons.isEmpty()) {
   for (UserCoupon coupon : expiredCoupons) {
   coupon.setStatus(CouponStatus.EXPIRED.getCode());
   }
   userCouponRepository.saveAll(expiredCoupons);
   }
   }
  }
  ```
  
   五、前端交互设计
  
   1. 优惠券领取流程
  
  1. 用户进入优惠券中心页面
  2. 系统展示可领取的优惠券列表(包括通用券和品类券)
  3. 用户点击"立即领取"按钮
  4. 后端验证并发放优惠券
  5. 返回领取结果(成功/失败原因)
  
   2. 优惠券使用流程
  
  1. 用户进入订单确认页面
  2. 系统自动匹配适用的优惠券(考虑商品品类、订单金额等)
  3. 用户选择要使用的优惠券
  4. 系统重新计算订单金额并显示优惠信息
  5. 用户提交订单完成购买
  
   六、性能优化考虑
  
  1. 缓存策略:
   - 缓存热门优惠券模板信息
   - 缓存用户可用的优惠券列表
  
  2. 数据库优化:
   - 为常用查询字段建立索引(用户ID、状态、过期时间等)
   - 考虑分表策略(如按用户ID分表存储用户优惠券)
  
  3. 异步处理:
   - 优惠券发放采用异步消息队列处理
   - 优惠券使用后的统计数据异步更新
  
  4. 限流措施:
   - 对高并发领取场景实施限流
   - 防止恶意刷券行为
  
   七、测试用例示例
  
  1. 正常场景测试:
   - 用户领取全品类满减券并成功使用
   - 用户领取指定品类折扣券并在符合条件的订单中使用
  
  2. 异常场景测试:
   - 尝试使用已过期的优惠券
   - 在订单金额不足时使用满减券
   - 在包含非指定品类商品时使用品类券
   - 尝试叠加不兼容的优惠券类型
  
  3. 边界条件测试:
   - 刚好达到最低订单金额时使用满减券
   - 使用折扣券时订单金额接近零的情况
   - 优惠券刚好在领取后过期的情况
  
  通过以上设计,美团买菜系统可以实现一个灵活、高效、可扩展的优惠券通用功能,支持各种营销活动需求,同时保证系统稳定性和用户体验。
评论
  • 下一篇

  • Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 8192 bytes) in /www/wwwroot/www.sjwxsc.com/config/function.php on line 274