news 2026/10/13 2:48:39

gpmall 营销服务(coupon-service)实战解析:营销活动、优惠券与优惠码的数据库设计与服务建模

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
gpmall 营销服务(coupon-service)实战解析:营销活动、优惠券与优惠码的数据库设计与服务建模
  • 后端
  • 电商
  • 微服务
  • 前端

【免费下载链接】gpmall

【咕泡学院实战项目】-基于SpringBoot+Dubbo构建的电商平台-微服务架构、商城、电商、微服务、高并发、kafka、Elasticsearch

项目地址:https://gitcode.com/gh_mirrors/gp/gpmall
点击查看免费下载

导读:本文以 gpmall 电商微服务项目中coupon-service/README.md营销服务设计文档为核心,系统讲解营销活动与优惠券的业务场景、功能需求、核心服务接口划分以及tb_sale_acti、tb_sale_rule、tb_sale_coupon、tb_sale_coupon_code、tb_queue_msg五张核心表的完整设计。读者将理解 gpmall 中"满减/满折/满赠"活动规则如何落地、优惠券如何通过"冻结-解冻"状态机配合订单生命周期、优惠码如何批量生成与兑换,并看到该模块在源码中的实际建模情况(含其"草稿"定位的局限)。

模块定位:营销服务在 gpmall 中的角色

在 gpmall 微服务架构中,coupon-service(营销服务)承担的是电商平台最核心的运营工具——营销活动与优惠券的管理和计算职责。与订单、支付、商品等"交易主链路"服务不同,营销服务属于典型的横向支撑型业务:它不直接面对终端用户,而是通过 RPC 接口被OrderService(订单服务)等上游服务调用,在用户下单、结算、支付的关键节点上完成"算优惠"的动作。

从仓库目录结构看,coupon-service沿用了 gpmall 各业务域统一的api / provider 双层拆分模式:

  • coupon-api:对外发布的 Dubbo 接口定义与 DTO(数据传输对象),供订单等其他服务依赖;
  • coupon-provider:营销服务的实际提供者(Provider),包含 Spring Boot 启动类、Druid 数据源配置、MyBatis 实体与 Mapper、营销策略类等;
  • sketch-sql:四张核心业务表的 MySQL 建表脚本草稿(Navicat 导出格式);
  • README.md:本文所依据的模块设计文档,其中明确标注了关键前提——"优惠券 coupon-api 模块目前仍为草稿,不建议 install 到本地包使用"。也就是说,该模块当前更接近"设计稿 + 数据表雏形"的阶段,业务代码尚未完整实现,这一点在阅读下文接口与实体时会反复印证。

模块的技术底座与其他 provider 保持一致:coupon-provider/pom.xml引入了dubbo、zookeeper/curator-recipes(注册中心)、mybatis-spring-boot-starter、druid、tk.mybatis mapper、pagehelper、redisson等依赖,启动类CouponProviderApplication通过@ComponentScan(basePackages = "com.gpmall.coupon")与@MapperScan("com.gpmall.coupon.dal.persistence")完成包扫描,数据源由 DruidConfig.java 以spring.datasource前缀绑定配置。

业务场景:营销服务要解决什么问题

原设计文档将营销服务的场景划分为"活动"与"优惠券"两大部分,两者相互关联、共同构成完整的营销闭环。

活动场景

活动是营销的"场"。用户在活动期间购买参与活动的商品,即可享受优惠价格(满减、满折等);同时用户可以通过浏览活动页领取优惠券,实现"逛活动页 → 领券 → 下单核销"的转化路径。

优惠券场景

优惠券是营销的"券",其生命周期覆盖"领取 → 使用 → 核销/释放"。文档列举了五种领券方式:

  1. 新用户注册送券:通过系统自动绑定优惠券,降低新用户首单门槛;
  2. 消费满额送券:用户订单金额消费满一定数值后自动发放优惠券,促进复购;
  3. 管理后台绑定:运营人员在管理端手工为用户绑定优惠券(定向营销);
  4. 活动页点击送券:在活动落地页直接领取;
  5. 批量生成兑换码,凭码领券:支持线下/异业渠道发放兑换码,用户凭码兑换,适合大规模投放。

在使用侧,用户下单时可以选择一张或多张优惠券;而已使用的优惠券在订单成功支付或取消订单之前,不可再次使用——这条约束直接决定了下文优惠码表status字段的"冻结中"状态设计,是营销服务与订单服务协作的基石。

功能需求:活动与优惠券的能力清单

活动需求

  1. 允许管理人员创建、修改、删除营销活动;活动可针对单一具体商品,也可以是覆盖全部商品的全场活动;
  2. 允许查询正在进行中的活动列表以及所有活动列表(对应IActivityQueryService的queryAll与queryActiveActivityList);
  3. 活动具有起止时间,活动类型包括:满减、满赠、满折、秒杀等。文档对前三类给出了明确定义:
类型规则说明
满减订单金额满足指定数值时,减金额
满赠订单金额满足指定数值时,赠送产品
满折订单金额满足指定数值时,按总金额打折计算

在源码中,这一枚举被建模为SaleTypeEnum(SaleTypeEnum.java):

public enum SaleTypeEnum { FULL_REDUCE, // 满减 FULL_DISCOUNT, // 满折 FULL_GIFT // 满赠商品 }

可以看到当前枚举只落地了满减/满折/满赠三类,文档中提到的"秒杀"尚未进入代码实现,属于预留能力。

优惠券需求

  1. 允许管理人员创建、修改、删除优惠券(对应ICouponCoreService中的 admin 系列注释);
  2. 购物车结算时,获取用户可用的优惠券列表(对应ICouponQueryService.queryActiveByUserId);
  3. 创建订单后,检查优惠券是否满足使用条件,满足则锁定已勾选的优惠券,将其设置为冻结状态;待订单支付完成或取消订单后,再次修改优惠券状态。

第三条需求是整个营销服务与订单服务协作的核心契约,文档给出了明确的服务交互描述:

OrderService 传递活动 id、优惠码 code 给 SaleService,SaleService 冻结优惠券、计算优惠金额,返回优惠总金额、赠送产品 id、营销类型等数据给 OrderService,由 OrderService 处理后续业务。

这条契约表明:优惠金额的计算归属营销服务,而订单后续的落库与支付流程仍由 OrderService 负责,营销服务只做"判定 + 冻结 + 算钱"这三件事。

服务接口划分:API 层设计(含草稿定位说明)

coupon-api模块按"核心操作 / 查询"两个维度拆分了四个 Dubbo 接口,全部位于com.gpmall.coupon包下,且文档与源码均标注了**"此接口暂为草稿"**:

活动服务

IActivityCoreService.java 负责活动的写操作:

public interface IActivityCoreService { CreateActiResponse create(CreateActiRequest request); // 创建营销活动 void update(); // 修改活动 void delete(); // 删除活动 }

IActivityQueryService.java 负责活动的读操作:

public interface IActivityQueryService { List queryAll(); // 查询所有活动 List queryActiveActivityList(); // 查询正在进行中的活动 void checkActivityIsValid(Integer id); // 检查创建订单时传递的活动id是否有效 }

其中checkActivityIsValid对应订单创建链路中"校验活动是否真实有效"的防伪需求——订单服务在接收用户传来的活动 id 后,必须先经营销服务校验,避免伪造活动参与优惠。

优惠券服务

ICouponCoreService.java 是优惠券生命周期的心脏,集中体现了"冻结/解冻"与"发券"逻辑:

public interface ICouponCoreService { // admin创建/修改/删除优惠券 void freezeCoupon(); // 订单支付过程中 冻结优惠券 void unfreezeCoupon(); // 订单取消后, 解冻优惠券 void generateCouponCode(Integer couponId); // 根据优惠券id生成优惠码 void dispatchCoupon(Integer couponId, Integer... userId); // 派发优惠券 void exchangeCoupon(); // 优惠码兑换优惠券 }

ICouponQueryService.java 提供查询与校验:

public interface ICouponQueryService { void queryAll(); // 查询所有优惠券 void queryAllByUserId(); // 根据userId查询所有优惠券 void queryActiveByUserId(); // 根据userId查询所有可用优惠券 void checkCouponIsValid(Integer... ids); // 检查创建订单时传递的优惠券id是否有效 }

DTO 与参数校验

草稿阶段已经落地了两个代表性 DTO,可窥见其设计思路:

CreateActiRequest.java 继承自gpmall-commons的AbstractRequest(AbstractRequest.java),通过重写requestCheck()实现创建活动时的参数校验:

public class CreateActiRequest extends AbstractRequest { private String name; private SaleTypeEnum saleType; private String desc; @Override public void requestCheck() { if (StringUtils.isEmpty(name)) { throw new ValidateException("缺少name参数"); } if (saleType == null) { throw new ValidateException("缺少type参数"); } } }

UseCouponRequest.java 以订单明细列表作为入参,携带List<OrderItemDto>;OrderItemDto.java 定义了orderId、price(BigDecimal)、num三个字段——这正是SaleStrategy判定"是否满 X"所需的原始输入。策略基类 SaleStrategy.java 已预留抽象方法:

public abstract class SaleStrategy { public abstract boolean match(UseCouponRequest request); // 匹配规则(是否满足满减/满折条件) public abstract void perform(); // 执行优惠计算 }

从结构看,设计者意图用策略模式承载"满减/满折/满赠"三类算法的差异(对应SaleTypeEnum的三个枚举值),但具体策略子类尚未实现,属于明确的待办区域。

数据库设计:五张核心表

数据库设计是本模块最完整、最可落地的部分,原文档给出了五张表的字段草图,仓库sketch-sql/目录下同时提供了四张业务表的完整建表 SQL(tb_sale_acti.sql、tb_sale_rule.sql、tb_sale_coupon.sql、tb_sale_coupon_code.sql),provider 侧的 MyBatis 实体类(dal/entitys)也与之一一对应。以下按表逐一展开。

1. 营销活动表 tb_sale_acti

活动主表,记录一次营销活动的基本信息与生命周期。

字段类型说明
idbigint主键,自增
namevarchar(255)活动名称,非空
typetinyint活动类型
statustinyint状态:0 未开始、1 进行中、2 已结束
start_time / end_timedatetime活动起止时间
descvarchar(255)活动描述
created / updateddatetime创建/更新时间

对应实体 SaleActivity.java,其中status注释为"0 未开始 1 进行中 2 已结束"。完整的建表语句见 tb_sale_acti.sql。status的三态设计配合start_time/end_time,天然支撑IActivityQueryService.queryActiveActivityList()的"进行中活动"查询。

2. 活动规则关联表 tb_sale_rule

这是营销服务最关键的一张表,承载"满 X 减 Y / 满 X 折 / 满 X 赠 Z"的具体规则数值,通过acti_id关联活动,实现"一个活动、多条阶梯规则"的模型。

字段类型说明
idbigint主键,自增
acti_idbigint活动 id;若是优惠券规则,此字段为 null
item_idbigint满足规则条件的商品 id
full_pricedecimal(10,2)满金额阈值
discount_pricedecimal(10,2)抵扣金额
discount_ratedecimal(10,2)折扣比例
gift_item_idbigint赠送产品 id
overlapbit(1)是否可叠加规则,默认 b'0'
descvarchar(255)规则描述
created / updateddatetime创建/更新时间

对应实体 SaleRule.java,建表脚本见 tb_sale_rule.sql。几个关键设计点值得展开:

  • acti_id 可空:注释明确"活动规则需要绑定 acti_id,如果是优惠券规则,此字段为 null"。这意味着优惠券同样挂在规则表上——优惠券通过rule_id指向一条tb_sale_rule,从而实现"满减券"(对应 discount_price)、"折扣券"(对应 discount_rate)等券种复用同一套规则数值结构;
  • item_id 支持单品级活动:字段可空,为空时即"全场活动",非空时限定具体商品,恰好支撑文档中"单一具体商品 / 全场活动"两种活动形态;
  • overlap 控制叠加:bit(1) 类型决定该规则能否与其他优惠叠加,是多券并行计算的前提开关;
  • 三值字段互斥使用:full_price是门槛(满 X),discount_price、discount_rate、gift_item_id分别对应满减、满折、满赠三类产出,由活动的type(即SaleTypeEnum)决定取用哪个字段。

3. 优惠券表 tb_sale_coupon

优惠券主表,描述"券"本身(名称、类型、有效期、数量),并通过rule_id关联具体优惠规则。

字段类型说明
idbigint主键,自增
namevarchar(100)优惠券名称,非空
descvarchar(255)优惠券描述
typetinyint券类型:1 满减券、2 通用 0 元减价券
rule_idbigint关联的规则 id
is_visiblebit(1)是否可用,默认 b'1'
countint可生成的优惠码数量
grab_start_time / grab_end_timedatetime抢券起止时间(领券中心备用)
start_time / end_timedatetime优惠券有效期
created / updateddatetime创建/更新时间

对应实体 SaleCoupon.java,建表脚本见 tb_sale_coupon.sql。注意两点:

  • rule_id在注释中直接写为"优惠金额",实际语义是"关联的规则 id"(对应tb_sale_rule),表结构体现的是"券 → 规则 → 数值"的二级关联;
  • grab_start_time/grab_end_time注释明确为"抢券开始时间,领券中心备用",即预留了"定点抢券"这种高并发营销玩法,但当前并未使用;
  • is_visible是运营侧"上下架"开关,控制券是否对用户可见可领。

4. 优惠码表 tb_sale_coupon_code

优惠码是"批量发券"的载体,这张表记录了码的完整生命周期状态机,是整个营销模块中状态设计最精细的一张表:

字段类型说明
idbigint主键,自增
codevarchar(255)优惠码(按码领券)
coupon_idbigint关联的优惠券 id
statustinyint0 未领取、1 已领取未使用、2 冻结中、3 已使用、4 已过期
user_idbigint关联用户
order_idbigint消费的订单明细 id
consume_timedatetime使用时间
created / updateddatetime创建/更新时间

对应实体 SaleCouponCode.java,建表脚本见 tb_sale_coupon_code.sql。

状态机与订单生命周期的对应关系是这张表的设计精髓,也是前文"优惠券需求第 3 条"的落地载体:

状态值含义触发时机
0未领取批量生成兑换码后、用户凭码兑换前
1已领取未使用用户凭码领取 / 系统派发后
2冻结中用户下单选中该券,OrderService 调 SaleService 冻结
3已使用订单支付成功,优惠正式核销
4已过期超过有效期未使用

其中"2 冻结中"正是文档强调的"已使用的优惠券在订单成功支付或取消订单之前,不可再次使用":下单时从 1 → 2(冻结),支付成功后 2 → 3(已使用),订单取消后 2 → 1(解冻),对应ICouponCoreService的freezeCoupon()/unfreezeCoupon()。order_id记录了冻结它的订单,保证一张券在同一时刻只可能被一个订单占用。

5. 消息队列消息表 tb_queue_msg(异常消息补偿)

这是营销模块针对分布式事务可靠性的补充设计。字段草图如下:

字段类型说明
idbigint主键
queuevarchar队列名称
topicvarchar队列主题
methodvarchar执行的方法
argsvarchar方法参数
finish_timedatetimehandle 执行完成时间
createddatetime创建时间

对应实体 QueueMsg.java。其作用正如文档注释所言:"消息队列消息表(异常消息补偿)"。在微服务环境下,"冻结优惠券→生成订单→支付成功→核销"横跨多个服务,任何一环失败都可能导致券状态与订单状态不一致。这张表以"队列名 + topic + 方法名 + 参数"记录待补偿的 MQ 消息,finish_time标记处理完成时间,供补偿程序(如定时任务)扫描未完成记录、重新投递执行。coupon-provider/service/MQMessageHandler.java的类注释"处理订单支付成功的 MQ 信息"印证了营销服务确实计划通过 MQ 消费订单支付成功事件来驱动券状态流转。

模块现状与落地局限

基于以上源码梳理,需要对该模块给出客观的现状评估:

  • API 层为草稿:README 明确声明"coupon-api 模块目前仍为草稿,不建议 install 到本地包使用",四个服务接口中的多数方法只有签名与注释,尚无 provider 侧的@Service实现类(coupon-provider下目前仅有MQMessageHandler空类与SaleStrategy抽象基类);
  • 数据层最完整:四张业务表的实体、Mapper 接口与 XML(位于 dal/persistence)以及 sketch-sql 建表脚本均已就绪,是全模块中可直接复用/运行的部分;
  • 策略模式已定型:SaleTypeEnum+SaleStrategy的"枚举定类型、策略做算法"骨架已确立,后续只需为满减/满折/满赠各实现一个策略子类并注册即可;
  • 订单协作契约已定义:OrderService 传活动 id 与优惠码 code,SaleService 冻结券、算优惠、回传优惠金额/赠品 id/营销类型,这一接口契约与tb_sale_coupon_code的状态机完全吻合,可作为后续双端联调的基准。

从全仓视角看,前端 coupon.vue("我的优惠"页)目前仅展示"您目前还没有优惠券"的空态占位,路由与入口已预留;这进一步说明营销服务的端到端打通仍处于"设计先行、实现待续"的阶段。若要在本仓库基础上继续推进该模块,合理路径是:先以sketch-sql完成建库,再按IActivityCoreService→ICouponCoreService的顺序补齐 provider 实现,并以SaleStrategy策略子类作为优惠计算的扩展点,最后通过 MQ 消费订单支付事件完成券状态机闭环。

  • 后端
  • 电商
  • 微服务
  • 前端

【免费下载链接】gpmall

【咕泡学院实战项目】-基于SpringBoot+Dubbo构建的电商平台-微服务架构、商城、电商、微服务、高并发、kafka、Elasticsearch

项目地址:https://gitcode.com/gh_mirrors/gp/gpmall
点击查看免费下载

相关推荐

上一篇:SD-WebUI Forge 提示词权重与长提示词分块指南
下一篇:komorebi `manage` 命令深度解析:强制接管前台窗口并纳入平铺管理

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/13 2:48:30

使用 @theme-ui/tailwind 将 Theme UI 主题转换为 Tailwind 静态 CSS

前端UI组件设计系统 【免费下载链接】theme-ui Build consistent, themeable React apps based on constraint-based design principles 项目地址&#xff1a; https://gitcode.com/gh_mirrors/th/theme-ui 点击查看 免费下载 theme-ui/tailwind 是 Theme UI 仓库中一个专注于…

作者头像 李华
网站建设 2026/10/13 2:48:09

SpriteJS 3D 扩展之 Plane 平面元素:完整 API 解析与实战应用

图形学3D渲染 【免费下载链接】spritejs A cross platform high-performance graphics system. 项目地址&#xff1a; https://gitcode.com/gh_mirrors/sp/spritejs 点击查看 免费下载 Plane 是 SpriteJS Next 3D 扩展库&#xff08;spritejs.ext3d&#xff09;中用于创建三维…

作者头像 李华
网站建设 2026/10/13 2:48:01

OAuth2.0认证体系搭建:Swagger与WireMock的RESTful API调试准备

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/13 2:47:12

语义分割各类别mIoU计算详解:从混淆矩阵到PyTorch实战与避坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华