美团买菜优惠券系统设计:功能、架构与实现全解
分类:IT频道
时间:2026-01-22 05:40
浏览:9
概述
一、功能概述 优惠券通用功能是电商系统(包括美团买菜这类生鲜电商)的核心营销工具之一,主要实现以下目标: -支持多种优惠券类型(满减券、折扣券、无门槛券等) -实现优惠券的发放、领取、使用、核销全流程管理 -支持通用优惠券(全平台可用)和定向优惠券(特定商品/品类可用) -提供
内容
一、功能概述
优惠券通用功能是电商系统(包括美团买菜这类生鲜电商)的核心营销工具之一,主要实现以下目标:
- 支持多种优惠券类型(满减券、折扣券、无门槛券等)
- 实现优惠券的发放、领取、使用、核销全流程管理
- 支持通用优惠券(全平台可用)和定向优惠券(特定商品/品类可用)
- 提供优惠券有效期、使用条件等灵活配置
二、系统架构设计
1. 数据库设计
```sql
-- 优惠券模板表
CREATE TABLE `coupon_template` (
`id` bigint NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL COMMENT 优惠券名称,
`type` tinyint NOT NULL COMMENT 类型:1满减券 2折扣券 3无门槛券,
`discount_amount` decimal(10,2) DEFAULT NULL COMMENT 满减金额/无门槛金额,
`discount_rate` decimal(5,2) DEFAULT NULL COMMENT 折扣率(百分比),
`min_order_amount` decimal(10,2) DEFAULT NULL COMMENT 最低消费金额,
`valid_days` int DEFAULT NULL COMMENT 有效天数(从领取算起),
`expire_time` datetime DEFAULT NULL COMMENT 固定过期时间,
`scope_type` tinyint NOT NULL COMMENT 使用范围:1全平台 2指定品类 3指定商品,
`scope_ids` varchar(1000) DEFAULT NULL COMMENT 适用范围ID(品类或商品ID列表),
`total_count` int NOT NULL COMMENT 发放总量,
`remaining_count` int NOT NULL COMMENT 剩余数量,
`status` tinyint NOT NULL COMMENT 状态:0未启用 1启用 2停用,
`create_time` datetime NOT NULL,
`update_time` datetime NOT NULL,
PRIMARY KEY (`id`)
);
-- 用户优惠券表
CREATE TABLE `user_coupon` (
`id` bigint NOT NULL 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 NOT NULL COMMENT 状态:0未使用 1已使用 2已过期 3已冻结,
`get_time` datetime NOT NULL COMMENT 领取时间,
`start_time` datetime NOT NULL COMMENT 生效时间,
`end_time` datetime NOT NULL COMMENT 过期时间,
`order_id` bigint DEFAULT NULL COMMENT 关联订单ID,
`use_time` datetime DEFAULT NULL COMMENT 使用时间,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_coupon_code` (`coupon_code`)
);
```
2. 核心服务模块
1. 优惠券模板服务:管理优惠券的创建、修改、查询等
2. 优惠券发放服务:处理优惠券的发放逻辑(主动领取、系统发放等)
3. 优惠券使用服务:验证优惠券是否可用,计算优惠金额
4. 优惠券核销服务:标记优惠券为已使用状态
三、核心功能实现
1. 优惠券发放实现
```java
public class CouponService {
// 用户领取优惠券
public UserCouponDTO receiveCoupon(Long userId, Long templateId) {
// 1. 验证优惠券模板是否存在且可领取
CouponTemplate template = couponTemplateRepository.findById(templateId)
.orElseThrow(() -> new BusinessException("优惠券不存在"));
if (template.getRemainingCount() <= 0) {
throw new BusinessException("优惠券已领完");
}
// 2. 检查用户是否已领取过该类型优惠券(根据业务需求)
// ...
// 3. 创建用户优惠券记录
UserCoupon userCoupon = new UserCoupon();
userCoupon.setUserId(userId);
userCoupon.setTemplateId(templateId);
userCoupon.setCouponCode(generateCouponCode());
userCoupon.setStatus(CouponStatus.UNUSED);
userCoupon.setStartTime(calculateStartTime(template));
userCoupon.setEndTime(calculateEndTime(template, userCoupon.getStartTime()));
// 4. 更新模板剩余数量
couponTemplateRepository.decreaseRemainingCount(templateId);
// 5. 保存用户优惠券
userCoupon = userCouponRepository.save(userCoupon);
return convertToDTO(userCoupon);
}
private String generateCouponCode() {
// 生成唯一优惠券码
return "CPN" + System.currentTimeMillis() + RandomStringUtils.randomNumeric(6);
}
private Date calculateStartTime(CouponTemplate template) {
// 根据模板配置计算生效时间(立即生效或指定时间)
// ...
}
private Date calculateEndTime(CouponTemplate template, Date startTime) {
// 根据模板配置计算过期时间(固定日期或领取后N天)
if (template.getExpireTime() != null) {
return template.getExpireTime();
} else {
Calendar calendar = Calendar.getInstance();
calendar.setTime(startTime);
calendar.add(Calendar.DAY_OF_MONTH, template.getValidDays());
return calendar.getTime();
}
}
}
```
2. 优惠券使用验证实现
```java
public class CouponValidator {
public CouponValidateResult validateCoupon(Long userId, String couponCode,
BigDecimal orderAmount, List orderItemIds) {
CouponValidateResult result = new CouponValidateResult();
// 1. 查询用户优惠券
UserCoupon userCoupon = userCouponRepository.findByUserIdAndCouponCode(userId, couponCode)
.orElseThrow(() -> new BusinessException("优惠券不存在"));
if (userCoupon.getStatus() != CouponStatus.UNUSED) {
throw new BusinessException("优惠券不可用");
}
if (userCoupon.getEndTime().before(new Date())) {
throw new BusinessException("优惠券已过期");
}
// 2. 查询优惠券模板
CouponTemplate template = couponTemplateRepository.findById(userCoupon.getTemplateId())
.orElseThrow(() -> new BusinessException("优惠券模板不存在"));
// 3. 验证使用条件
// 验证最低消费金额
if (template.getMinOrderAmount() != null &&
orderAmount.compareTo(template.getMinOrderAmount()) < 0) {
throw new BusinessException("订单金额不满足最低消费要求");
}
// 验证适用范围(如果是定向优惠券)
if (template.getScopeType() != ScopeType.ALL) {
List scopeIds = Arrays.asList(template.getScopeIds().split(","))
.stream().map(Long::valueOf).collect(Collectors.toList());
// 检查订单商品是否在适用范围内
boolean allMatch = orderItemIds.stream()
.allMatch(itemId -> scopeIds.contains(itemId));
if (!allMatch) {
throw new BusinessException("该优惠券不适用于订单中的商品");
}
}
// 4. 计算优惠金额
BigDecimal discountAmount = calculateDiscountAmount(template, orderAmount);
result.setValid(true);
result.setDiscountAmount(discountAmount);
result.setCouponId(userCoupon.getId());
result.setTemplateId(template.getId());
return result;
}
private BigDecimal calculateDiscountAmount(CouponTemplate template, BigDecimal orderAmount) {
switch (template.getType()) {
case CouponType.FIXED_DISCOUNT:
return template.getDiscountAmount();
case CouponType.PERCENTAGE_DISCOUNT:
return orderAmount.multiply(template.getDiscountRate().divide(new BigDecimal(100)));
case CouponType.NO_THRESHOLD:
return template.getDiscountAmount();
default:
return BigDecimal.ZERO;
}
}
}
```
3. 优惠券核销实现
```java
public class CouponUsageService {
@Transactional
public void useCoupon(Long userId, Long couponId, Long orderId) {
// 1. 查询用户优惠券
UserCoupon userCoupon = userCouponRepository.findById(couponId)
.orElseThrow(() -> new BusinessException("优惠券不存在"));
if (userCoupon.getUserId().longValue() != userId.longValue()) {
throw new BusinessException("无权使用该优惠券");
}
if (userCoupon.getStatus() != CouponStatus.UNUSED) {
throw new BusinessException("优惠券状态异常");
}
if (userCoupon.getEndTime().before(new Date())) {
throw new BusinessException("优惠券已过期");
}
// 2. 更新优惠券状态为已使用
userCoupon.setStatus(CouponStatus.USED);
userCoupon.setOrderId(orderId);
userCoupon.setUseTime(new Date());
userCouponRepository.save(userCoupon);
// 3. 记录优惠券使用日志(可选)
// ...
}
}
```
四、前端交互设计
1. 优惠券领取页面
- 展示可领取的优惠券列表
- 显示优惠券面额、使用条件、有效期等信息
- 提供"立即领取"按钮
2. 订单结算页面
- 展示用户持有的可用优惠券
- 支持按优惠券类型、面额等筛选
- 显示使用优惠券后的实付金额
- 提供"使用"按钮
3. 我的优惠券页面
- 分类展示未使用、已使用、已过期的优惠券
- 显示优惠券详细信息和使用条件
- 已过期优惠券提供"查看详情"功能
五、性能优化考虑
1. 缓存策略:
- 缓存热门优惠券模板信息
- 缓存用户可用优惠券列表
2. 数据库优化:
- 对优惠券模板表和用户优惠券表进行适当分表
- 对常用查询字段建立索引
3. 异步处理:
- 优惠券发放可考虑异步队列处理,避免高并发时数据库压力过大
4. 限流措施:
- 对优惠券领取接口进行限流,防止恶意刷券
六、安全考虑
1. 防刷机制:
- 同一用户对同一优惠券的领取频率限制
- IP限制防止批量领取
2. 数据校验:
- 严格校验优惠券码格式
- 防止SQL注入和XSS攻击
3. 审计日志:
- 记录优惠券的发放、使用等关键操作
七、扩展功能建议
1. 优惠券分享功能:支持用户将优惠券分享给好友
2. 优惠券组合使用:支持多张优惠券叠加使用(需设计复杂规则)
3. 优惠券任务系统:用户完成特定任务后获得优惠券
4. 优惠券数据分析:统计优惠券的领取、使用情况,优化营销策略
通过以上设计,可以实现一个功能完善、性能良好的美团买菜系统优惠券通用功能,支持各种营销场景和业务需求。
评论