美团买菜优惠券系统设计:功能实现、风控、优化及部署监控全解析
分类: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. 日志记录:
- 优惠券领取、使用、过期等关键操作日志
- 优惠券风控拦截日志
通过以上设计,美团买菜系统可以实现一个灵活、高效、安全的优惠券通用功能,支持各种业务场景和营销活动。
评论