010-53388338

美团买菜优惠券系统设计:功能实现、风控、优化及部署监控全解析

分类:IT频道 时间:2026-03-03 19:15 浏览:11
概述
    一、功能概述    美团买菜系统的优惠券通用功能需要实现以下核心能力:  1.支持多种类型的优惠券(满减券、折扣券、无门槛券等)  2.跨品类通用(蔬菜、水果、肉禽、日用品等均可使用)  3.灵活的发放和使用规则  4.有效的防刷和风控机制    二、系统架构设计    1.核心模块划分  
内容
  
   一、功能概述
  
  美团买菜系统的优惠券通用功能需要实现以下核心能力:
  1. 支持多种类型的优惠券(满减券、折扣券、无门槛券等)
  2. 跨品类通用(蔬菜、水果、肉禽、日用品等均可使用)
  3. 灵活的发放和使用规则
  4. 有效的防刷和风控机制
  
   二、系统架构设计
  
   1. 核心模块划分
  
  ```
  优惠券系统
  ├── 优惠券模板管理
  ├── 优惠券实例管理
  ├── 优惠券发放服务
  ├── 优惠券核销服务
  ├── 优惠券查询服务
  └── 监控与统计模块
  ```
  
   2. 数据库设计
  
  优惠券模板表(coupon_template)
  ```
  id | name | coupon_type | discount_amount | min_order_amount | valid_start_time | valid_end_time | total_count | remaining_count | status | create_time | update_time
  ```
  
  优惠券实例表(coupon_instance)
  ```
  id | template_id | user_id | coupon_code | status | get_time | used_time | order_id | expire_time
  ```
  
  优惠券使用范围表(coupon_scope)
  ```
  id | template_id | category_id | is_exclude (是否排除该品类)
  ```
  
   三、核心功能实现
  
   1. 优惠券模板创建
  
  ```java
  public class CouponTemplateDTO {
   private String name;
   private CouponType type; // 满减、折扣、无门槛
   private BigDecimal discountAmount;
   private BigDecimal minOrderAmount; // 满减门槛
   private LocalDateTime validStartTime;
   private LocalDateTime validEndTime;
   private Integer totalCount;
   private List applicableCategoryIds; // 适用品类ID列表
   private List excludeCategoryIds; // 排除品类ID列表
   // 其他业务规则...
  }
  
  public void createCouponTemplate(CouponTemplateDTO dto) {
   // 1. 参数校验
   validateTemplateParams(dto);
  
   // 2. 创建模板记录
   CouponTemplate template = convertToEntity(dto);
   templateRepository.save(template);
  
   // 3. 保存适用范围
   saveCouponScopes(template.getId(), dto.getApplicableCategoryIds(), dto.getExcludeCategoryIds());
  }
  ```
  
   2. 优惠券发放
  
  ```java
  public List issueCoupons(Long templateId, List userIds) {
   // 1. 检查模板状态和库存
   CouponTemplate template = templateRepository.findById(templateId)
   .orElseThrow(() -> new BusinessException("优惠券模板不存在"));
  
   if (template.getRemainingCount() <= 0) {
   throw new BusinessException("优惠券已发放完毕");
   }
  
   // 2. 生成优惠券实例
   LocalDateTime now = LocalDateTime.now();
   List instances = userIds.stream().map(userId -> {
   CouponInstance instance = new CouponInstance();
   instance.setTemplateId(templateId);
   instance.setUserId(userId);
   instance.setStatus(CouponStatus.UNUSED);
   instance.setGetTime(now);
   instance.setExpireTime(template.getValidEndTime());
   // 生成唯一优惠券码(可选)
   instance.setCouponCode(generateCouponCode());
   return instance;
   }).collect(Collectors.toList());
  
   // 3. 批量保存并更新模板库存
   instanceRepository.saveAll(instances);
   template.setRemainingCount(template.getRemainingCount() - userIds.size());
   templateRepository.save(template);
  
   return instances;
  }
  ```
  
   3. 优惠券核销(下单时使用)
  
  ```java
  public boolean useCoupon(Long userId, Long couponInstanceId, BigDecimal orderAmount, List categoryIds) {
   // 1. 校验优惠券有效性
   CouponInstance instance = instanceRepository.findByIdAndUserId(couponInstanceId, userId)
   .orElseThrow(() -> new BusinessException("优惠券不存在或不属于当前用户"));
  
   if (instance.getStatus() != CouponStatus.UNUSED) {
   throw new BusinessException("优惠券不可用");
   }
  
   CouponTemplate template = templateRepository.findById(instance.getTemplateId())
   .orElseThrow(() -> new BusinessException("优惠券模板不存在"));
  
   // 2. 检查是否过期
   if (LocalDateTime.now().isAfter(template.getValidEndTime())) {
   throw new BusinessException("优惠券已过期");
   }
  
   // 3. 检查使用门槛
   if (template.getMinOrderAmount() != null && orderAmount.compareTo(template.getMinOrderAmount()) < 0) {
   throw new BusinessException("订单金额不满足使用条件");
   }
  
   // 4. 检查品类限制
   if (!checkCategoryScope(template.getId(), categoryIds)) {
   throw new BusinessException("优惠券不适用于当前商品品类");
   }
  
   // 5. 更新优惠券状态
   instance.setStatus(CouponStatus.USED);
   instance.setUsedTime(LocalDateTime.now());
   instanceRepository.save(instance);
  
   return true;
  }
  
  private boolean checkCategoryScope(Long templateId, List orderCategoryIds) {
   // 获取优惠券适用和排除的品类
   List scopes = scopeRepository.findByTemplateId(templateId);
   Set applicableCategories = new HashSet<>();
   Set excludeCategories = new HashSet<>();
  
   scopes.forEach(scope -> {
   if (scope.getIsExclude()) {
   excludeCategories.add(scope.getCategoryId());
   } else {
   applicableCategories.add(scope.getCategoryId());
   }
   });
  
   // 如果设置了适用品类,则订单品类必须全部在适用范围内
   if (!applicableCategories.isEmpty()) {
   boolean allApplicable = orderCategoryIds.stream()
   .allMatch(applicableCategories::contains);
   if (!allApplicable) {
   return false;
   }
   }
  
   // 如果设置了排除品类,则订单品类不能包含任何排除品类
   return orderCategoryIds.stream()
   .noneMatch(excludeCategories::contains);
  }
  ```
  
   四、高级功能实现
  
   1. 优惠券风控机制
  
  ```java
  public class CouponRiskControl {
  
   // 防止同一用户短时间内领取大量优惠券
   public boolean checkIssueFrequency(Long userId, Long templateId) {
   LocalDateTime oneHourAgo = LocalDateTime.now().minusHours(1);
   long count = instanceRepository.countByUserIdAndTemplateIdAndGetTimeAfter(
   userId, templateId, oneHourAgo);
   return count < MAX_COUPONS_PER_HOUR;
   }
  
   // 防止优惠券被刷
   public boolean checkDeviceRisk(HttpServletRequest request) {
   String deviceId = request.getHeader("X-Device-Id");
   String ip = request.getRemoteAddr();
  
   // 检查设备ID和IP是否在黑名单中
   if (blacklistService.isBlacklisted(deviceId) || blacklistService.isBlacklisted(ip)) {
   return false;
   }
  
   // 检查同一设备/IP短时间内请求次数
   // ...
  
   return true;
   }
  }
  ```
  
   2. 优惠券优先级策略
  
  ```java
  public class CouponSelector {
  
   // 根据订单信息选择最优优惠券
   public List selectBestCoupons(Long userId, BigDecimal orderAmount, List categoryIds) {
   List usableCoupons = findUsableCoupons(userId, orderAmount, categoryIds);
  
   // 按优惠力度排序:无门槛 > 折扣 > 满减
   usableCoupons.sort((c1, c2) -> {
   CouponTemplate t1 = getTemplate(c1.getTemplateId());
   CouponTemplate t2 = getTemplate(c2.getTemplateId());
  
   // 无门槛券优先
   if (t1.getMinOrderAmount() == null && t2.getMinOrderAmount() != null) return -1;
   if (t1.getMinOrderAmount() != null && t2.getMinOrderAmount() == null) return 1;
  
   // 然后比较折扣力度
   if (t1.getType() == CouponType.DISCOUNT && t2.getType() != CouponType.DISCOUNT) return -1;
   if (t1.getType() != CouponType.DISCOUNT && t2.getType() == CouponType.DISCOUNT) return 1;
  
   // 同类型比较优惠金额
   return t2.getDiscountAmount().compareTo(t1.getDiscountAmount());
   });
  
   return usableCoupons;
   }
  
   private List findUsableCoupons(Long userId, BigDecimal orderAmount, List categoryIds) {
   // 实现略...
   }
  }
  ```
  
   五、性能优化建议
  
  1. 缓存策略:
   - 缓存优惠券模板信息(Redis)
   - 缓存用户可用优惠券列表
  
  2. 异步处理:
   - 优惠券发放采用异步消息队列
   - 优惠券使用后的统计数据异步处理
  
  3. 数据库优化:
   - 对常用查询字段建立索引(user_id, status, expire_time等)
   - 考虑分表策略(如按用户ID分表)
  
  4. 批量操作:
   - 批量发放优惠券
   - 批量查询用户优惠券
  
   六、测试用例示例
  
  1. 正常场景测试:
   - 用户领取通用优惠券
   - 使用通用优惠券下单(满足所有条件)
   - 多个品类商品使用通用优惠券
  
  2. 异常场景测试:
   - 使用过期优惠券
   - 使用不属于用户的优惠券
   - 订单金额不满足门槛
   - 商品品类不适用
  
  3. 边界条件测试:
   - 刚好满足满减门槛的订单
   - 优惠券刚好在有效期最后一天使用
   - 大量用户同时领取优惠券
  
   七、部署与监控
  
  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