From 39d3230bfd86d11528d7504416d133fc80d1318e Mon Sep 17 00:00:00 2001 From: zhangsan <646228430@qq.com> Date: Sat, 19 Jul 2025 18:11:16 +0800 Subject: [PATCH] =?UTF-8?q?7.19=20=E6=8B=BC=E5=9B=A2=E6=88=90=E5=8A=9F?= =?UTF-8?q?=E5=9B=9E=E8=B0=83=E6=B7=BB=E5=8A=A0MQ=E6=B6=88=E6=81=AF?= =?UTF-8?q?=E9=80=9A=E7=9F=A5=E6=96=B9=E5=BC=8F=EF=BC=8C=E5=90=8C=E6=97=B6?= =?UTF-8?q?=E5=85=BC=E5=AE=B9=E5=8E=9F=E6=9D=A5http=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mysql/sql/0719group_buying_sys.sql | 276 ++++++++++++++++++ .../sql => sql-back}/0716group_buying_sys.sql | 10 + .../api/dto/LockMarketPayOrderRequestDTO.java | 36 ++- .../java/edu/whut/config/RabbitMQConfig.java | 3 +- .../mybatis/mapper/group_buy_order_mapper.xml | 10 +- .../mybatis/mapper/notify_task_mapper.xml | 11 +- .../TradeSettlementOrderServiceTest.java | 8 +- .../trigger/MarketTradeControllerTest.java | 16 + .../adapter/repository/ITradeRepository.java | 2 +- .../model/entity/GroupBuyTeamEntity.java | 5 +- .../trade/model/entity/NotifyTaskEntity.java | 8 + .../trade/model/entity/PayDiscountEntity.java | 6 +- .../TradeSettlementRuleFilterBackEntity.java | 5 +- .../trade/model/valobj/NotifyConfigVO.java | 30 ++ .../trade/model/valobj/NotifyTypeEnumVO.java | 22 ++ .../service/ITradeSettlementOrderService.java | 11 + .../TradeSettlementOrderService.java | 32 +- .../adapter/port/TradePort.java | 19 +- .../adapter/repository/TradeRepository.java | 50 +++- .../infrastructure/dao/po/GroupBuyOrder.java | 4 +- .../infrastructure/dao/po/NotifyTask.java | 4 + .../trigger/http/MarketTradeController.java | 21 +- 22 files changed, 546 insertions(+), 43 deletions(-) create mode 100644 docs/dev-ops/mysql/sql/0719group_buying_sys.sql rename docs/dev-ops/{mysql/sql => sql-back}/0716group_buying_sys.sql (98%) create mode 100644 group-buying-sys-domain/src/main/java/edu/whut/domain/trade/model/valobj/NotifyConfigVO.java create mode 100644 group-buying-sys-domain/src/main/java/edu/whut/domain/trade/model/valobj/NotifyTypeEnumVO.java diff --git a/docs/dev-ops/mysql/sql/0719group_buying_sys.sql b/docs/dev-ops/mysql/sql/0719group_buying_sys.sql new file mode 100644 index 0000000..4781fbc --- /dev/null +++ b/docs/dev-ops/mysql/sql/0719group_buying_sys.sql @@ -0,0 +1,276 @@ +/* + Navicat Premium Data Transfer + + Source Server : group_buy_local + Source Server Type : MySQL + Source Server Version : 80042 + Source Host : localhost:13306 + Source Schema : group_buying_sys + + Target Server Type : MySQL + Target Server Version : 80042 + File Encoding : 65001 + + Date: 19/07/2025 18:10:09 +*/ + +SET NAMES utf8mb4; +SET FOREIGN_KEY_CHECKS = 0; + +-- ---------------------------- +-- Table structure for crowd_tags +-- ---------------------------- +DROP TABLE IF EXISTS `crowd_tags`; +CREATE TABLE `crowd_tags` ( + `id` int UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增ID', + `tag_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '人群ID', + `tag_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '人群名称', + `tag_desc` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '人群描述', + `statistics` int NOT NULL COMMENT '人群标签统计量', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`id`) USING BTREE, + UNIQUE INDEX `uq_tag_id`(`tag_id` ASC) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '人群标签' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of crowd_tags +-- ---------------------------- +INSERT INTO `crowd_tags` VALUES (1, 'RQ_KJHKL98UU78H66554GFDV', '潜在消费用户', '潜在消费用户', 28, '2025-06-26 09:12:22', '2025-06-28 11:02:00'); + +-- ---------------------------- +-- Table structure for crowd_tags_detail +-- ---------------------------- +DROP TABLE IF EXISTS `crowd_tags_detail`; +CREATE TABLE `crowd_tags_detail` ( + `id` int UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增ID', + `tag_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '人群ID', + `user_id` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户ID', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`id`) USING BTREE, + UNIQUE INDEX `uq_tag_user`(`tag_id` ASC, `user_id` ASC) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 21 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '人群标签明细' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of crowd_tags_detail +-- ---------------------------- +INSERT INTO `crowd_tags_detail` VALUES (20, 'RQ_KJHKL98UU78H66554GFDV', 'zy123', '2025-06-28 10:53:23', '2025-06-28 10:53:23'); +INSERT INTO `crowd_tags_detail` VALUES (21, 'RQ_KJHKL98UU78H66554GFDV', 'smile', '2025-06-28 10:53:23', '2025-06-28 10:53:23'); + +-- ---------------------------- +-- Table structure for crowd_tags_job +-- ---------------------------- +DROP TABLE IF EXISTS `crowd_tags_job`; +CREATE TABLE `crowd_tags_job` ( + `id` int UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增ID', + `tag_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '标签ID', + `batch_id` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '批次ID', + `tag_type` tinyint(1) NOT NULL DEFAULT 1 COMMENT '标签类型(参与量、消费金额)', + `tag_rule` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '标签规则(限定类型 N次)', + `stat_start_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '统计数据,开始时间', + `stat_end_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '统计数据,结束时间', + `status` tinyint(1) NOT NULL DEFAULT 0 COMMENT '状态;0初始、1计划(进入执行阶段)、2重置、3完成', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`id`) USING BTREE, + UNIQUE INDEX `uq_batch_id`(`batch_id` ASC) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '人群标签任务' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of crowd_tags_job +-- ---------------------------- +INSERT INTO `crowd_tags_job` VALUES (1, 'RQ_KJHKL98UU78H66554GFDV', '10001', 0, '100', '2025-06-26 09:13:31', '2025-06-26 09:13:31', 0, '2025-06-26 09:13:31', '2025-06-26 09:13:31'); + +-- ---------------------------- +-- Table structure for group_buy_activity +-- ---------------------------- +DROP TABLE IF EXISTS `group_buy_activity`; +CREATE TABLE `group_buy_activity` ( + `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增', + `activity_id` bigint NOT NULL COMMENT '活动ID', + `activity_name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '活动名称', + `discount_id` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '折扣ID', + `group_type` tinyint(1) NOT NULL DEFAULT 0 COMMENT '拼团方式(0自动成团、1达成目标拼团)', + `take_limit_count` int NOT NULL DEFAULT 1 COMMENT '拼团次数限制', + `target` int NOT NULL DEFAULT 1 COMMENT '拼团目标', + `valid_time` int NOT NULL DEFAULT 15 COMMENT '拼团时长(分钟)', + `status` tinyint(1) NOT NULL DEFAULT 0 COMMENT '活动状态(0创建、1生效、2过期、3废弃)', + `start_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '活动开始时间', + `end_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '活动结束时间', + `tag_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '人群标签规则标识', + `tag_scope` varchar(4) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '人群标签规则范围(多选;1可见限制、2参与限制)', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`id`) USING BTREE, + UNIQUE INDEX `uq_activity_id`(`activity_id` ASC) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '拼团活动' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of group_buy_activity +-- ---------------------------- +INSERT INTO `group_buy_activity` VALUES (1, 100123, '测试活动', '25120207', 0, 1, 3, 60, 1, '2025-06-19 10:19:40', '2025-07-31 10:19:40', 'RQ_KJHKL98UU78H66554GFDV', '1,2', '2025-06-19 10:19:40', '2025-07-03 18:25:55'); +INSERT INTO `group_buy_activity` VALUES (2, 100124, '测试活动2', '25120207', 0, 1, 1, 60, 1, '2025-07-05 13:39:52', '2025-09-28 13:39:34', 'RQ_KJHKL98UU78H66554GFDV', '1,2', '2025-07-05 13:39:52', '2025-07-05 13:40:06'); + +-- ---------------------------- +-- Table structure for group_buy_discount +-- ---------------------------- +DROP TABLE IF EXISTS `group_buy_discount`; +CREATE TABLE `group_buy_discount` ( + `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增ID', + `discount_id` int NOT NULL COMMENT '折扣ID', + `discount_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '折扣标题', + `discount_desc` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '折扣描述', + `discount_type` tinyint(1) NOT NULL DEFAULT 0 COMMENT '折扣类型(0:base、1:tag)', + `market_plan` varchar(4) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT 'ZJ' COMMENT '营销优惠计划(ZJ:直减、MJ:满减、ZK:折扣、N元购)', + `market_expr` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '营销优惠表达式', + `tag_id` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '人群标签,特定优惠限定', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`id`) USING BTREE, + UNIQUE INDEX `uq_discount_id`(`discount_id` ASC) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '折扣配置' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of group_buy_discount +-- ---------------------------- +INSERT INTO `group_buy_discount` VALUES (1, 25120207, '直减优惠20元', '直减优惠20元', 0, 'ZJ', '20', NULL, '2025-06-25 14:02:13', '2025-06-25 14:02:13'); +INSERT INTO `group_buy_discount` VALUES (2, 25120208, '满减优惠100-10元', '满减优惠100-10元', 0, 'MJ', '100,10', NULL, '2025-06-25 14:02:13', '2025-06-25 14:02:13'); +INSERT INTO `group_buy_discount` VALUES (4, 25120209, '折扣优惠8折', '折扣优惠8折', 0, 'ZK', '0.8', NULL, '2025-06-25 14:02:13', '2025-06-25 14:02:13'); +INSERT INTO `group_buy_discount` VALUES (5, 25120210, 'N元购买优惠', 'N元购买优惠', 0, 'N', '1.99', NULL, '2025-06-25 14:02:13', '2025-06-25 14:02:13'); + +-- ---------------------------- +-- Table structure for group_buy_order +-- ---------------------------- +DROP TABLE IF EXISTS `group_buy_order`; +CREATE TABLE `group_buy_order` ( + `id` int UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增ID', + `team_id` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '拼单组队ID', + `activity_id` bigint NOT NULL COMMENT '活动ID', + `source` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '渠道', + `channel` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '来源', + `original_price` decimal(8, 2) NOT NULL COMMENT '原始价格', + `deduction_price` decimal(8, 2) NOT NULL COMMENT '折扣金额', + `pay_price` decimal(8, 2) NOT NULL COMMENT '支付价格', + `target_count` int NOT NULL COMMENT '目标数量', + `complete_count` int NOT NULL COMMENT '完成数量', + `lock_count` int NOT NULL COMMENT '锁单数量', + `status` tinyint(1) NOT NULL DEFAULT 0 COMMENT '状态(0-拼单中、1-完成、2-失败)', + `valid_start_time` datetime NOT NULL COMMENT '拼团开始时间', + `valid_end_time` datetime NOT NULL COMMENT '拼团结束时间', + `notify_type` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT 'HTTP' COMMENT '回调类型(HTTP、MQ)', + `notify_url` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '回调地址(HTTP 回调不可为空)', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`id`) USING BTREE, + UNIQUE INDEX `uq_team_id`(`team_id` ASC) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 38 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '拼团订单表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of group_buy_order +-- ---------------------------- +INSERT INTO `group_buy_order` VALUES (39, '92219797', 100124, 's01', 'c01', 100.00, 20.00, 80.00, 1, 1, 1, 1, '2025-07-19 18:08:18', '2025-07-19 19:08:18', 'MQ', NULL, '2025-07-19 18:08:18', '2025-07-19 18:08:55'); + +-- ---------------------------- +-- Table structure for group_buy_order_list +-- ---------------------------- +DROP TABLE IF EXISTS `group_buy_order_list`; +CREATE TABLE `group_buy_order_list` ( + `id` int UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增ID', + `user_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户ID', + `team_id` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '拼单组队ID', + `order_id` varchar(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '订单ID', + `activity_id` bigint NOT NULL COMMENT '活动ID', + `start_time` datetime NOT NULL COMMENT '活动开始时间', + `end_time` datetime NOT NULL COMMENT '活动结束时间', + `goods_id` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '商品ID', + `source` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '渠道', + `channel` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '来源', + `original_price` decimal(8, 2) NOT NULL COMMENT '原始价格', + `deduction_price` decimal(8, 2) NOT NULL COMMENT '折扣金额', + `pay_price` decimal(8, 2) NOT NULL COMMENT '支付金额', + `status` tinyint(1) NOT NULL DEFAULT 0 COMMENT '状态;0初始锁定、1消费完成', + `out_trade_no` varchar(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '外部交易单号-确保外部调用唯一幂等', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `biz_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '业务唯一ID', + `out_trade_time` datetime NULL DEFAULT NULL COMMENT '外部交易时间', + PRIMARY KEY (`id`) USING BTREE, + UNIQUE INDEX `uq_order_id`(`order_id` ASC) USING BTREE, + INDEX `idx_user_id_activity_id`(`user_id` ASC, `activity_id` ASC) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 35 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '拼团订单明细表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of group_buy_order_list +-- ---------------------------- +INSERT INTO `group_buy_order_list` VALUES (37, 'smile02', '92219797', '527461199182', 100124, '2025-07-05 13:39:52', '2025-09-28 13:39:34', '9890001', 's01', 'c01', 100.00, 20.00, 80.00, 1, '334152190173', '2025-07-19 18:08:18', '2025-07-19 18:08:55', '100124_smile02_1', '2025-07-19 18:08:55'); + +-- ---------------------------- +-- Table structure for notify_task +-- ---------------------------- +DROP TABLE IF EXISTS `notify_task`; +CREATE TABLE `notify_task` ( + `id` int UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增ID', + `activity_id` bigint NOT NULL COMMENT '活动ID', + `team_id` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '拼单组队ID', + `notify_type` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT 'HTTP' COMMENT '回调类型(HTTP、MQ)', + `notify_mq` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '回调消息', + `notify_url` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '回调接口', + `notify_count` int NOT NULL COMMENT '回调次数', + `notify_status` tinyint(1) NOT NULL COMMENT '回调状态【0初始、1完成、2重试、3失败】', + `parameter_json` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '参数对象', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`id`) USING BTREE, + UNIQUE INDEX `uq_team_id`(`team_id` ASC) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of notify_task +-- ---------------------------- +INSERT INTO `notify_task` VALUES (7, 100124, '92219797', 'MQ', 'topic.team_success', NULL, 1, 1, '{\"teamId\":\"92219797\",\"outTradeNoList\":[\"334152190173\"]}', '2025-07-19 18:08:55', '2025-07-19 18:08:55'); + +-- ---------------------------- +-- Table structure for sc_sku_activity +-- ---------------------------- +DROP TABLE IF EXISTS `sc_sku_activity`; +CREATE TABLE `sc_sku_activity` ( + `id` int UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增ID', + `source` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '渠道', + `channel` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '来源', + `activity_id` bigint NOT NULL COMMENT '活动ID', + `goods_id` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '商品ID', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`id`) USING BTREE, + UNIQUE INDEX `uq_sc_goodsid`(`source` ASC, `channel` ASC, `goods_id` ASC) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '渠道商品活动配置关联表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sc_sku_activity +-- ---------------------------- +INSERT INTO `sc_sku_activity` VALUES (1, 's01', 'c01', 100123, '9890001', '2025-06-26 17:15:54', '2025-06-26 17:15:54'); + +-- ---------------------------- +-- Table structure for sku +-- ---------------------------- +DROP TABLE IF EXISTS `sku`; +CREATE TABLE `sku` ( + `id` int UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增ID', + `source` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '渠道', + `channel` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '来源', + `goods_id` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '商品ID', + `goods_name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '商品名称', + `original_price` decimal(10, 2) NOT NULL COMMENT '商品价格', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`id`) USING BTREE, + UNIQUE INDEX `uq_goods_id`(`goods_id` ASC) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '商品信息' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of sku +-- ---------------------------- +INSERT INTO `sku` VALUES (1, 's01', 'c01', '9890001', '《手写MyBatis:渐进式源码实践》', 100.00, '2025-06-22 11:10:06', '2025-06-22 11:10:06'); + +SET FOREIGN_KEY_CHECKS = 1; diff --git a/docs/dev-ops/mysql/sql/0716group_buying_sys.sql b/docs/dev-ops/sql-back/0716group_buying_sys.sql similarity index 98% rename from docs/dev-ops/mysql/sql/0716group_buying_sys.sql rename to docs/dev-ops/sql-back/0716group_buying_sys.sql index 525211a..121f677 100644 --- a/docs/dev-ops/mysql/sql/0716group_buying_sys.sql +++ b/docs/dev-ops/sql-back/0716group_buying_sys.sql @@ -13,6 +13,16 @@ Date: 16/07/2025 17:09:09 */ +-- 如果存在就删除 +DROP DATABASE IF EXISTS `group_buying_sys`; + +-- 创建(如需指定字符集与排序规则,可自行调整) +CREATE DATABASE IF NOT EXISTS `group_buying_sys` + DEFAULT CHARACTER SET utf8mb4 + COLLATE utf8mb4_unicode_ci; + +-- 切换到该库 +USE `group_buying_sys`; SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; diff --git a/group-buying-sys-api/src/main/java/edu/whut/api/dto/LockMarketPayOrderRequestDTO.java b/group-buying-sys-api/src/main/java/edu/whut/api/dto/LockMarketPayOrderRequestDTO.java index 8ccb62e..f471099 100644 --- a/group-buying-sys-api/src/main/java/edu/whut/api/dto/LockMarketPayOrderRequestDTO.java +++ b/group-buying-sys-api/src/main/java/edu/whut/api/dto/LockMarketPayOrderRequestDTO.java @@ -22,7 +22,39 @@ public class LockMarketPayOrderRequestDTO { private String channel; // 外部交易单号 private String outTradeNo; - // 回调地址 - private String notifyUrl; + // 回调配置,调用方自己配置回调类型 + private NotifyConfigVO notifyConfigVO; + + // 兼容旧配置,用户仍可继续使用setNotifyUrl方法 + public void setNotifyUrl(String url) { + NotifyConfigVO notifyConfigVO = new NotifyConfigVO(); + notifyConfigVO.setNotifyType("HTTP"); + notifyConfigVO.setNotifyUrl(url); + this.notifyConfigVO = notifyConfigVO; + } + + // 兼容配置 - MQ不需要指定,系统会发统一MQ消息 + public void setNotifyMQ() { + NotifyConfigVO notifyConfigVO = new NotifyConfigVO(); + notifyConfigVO.setNotifyType("MQ"); + this.notifyConfigVO = notifyConfigVO; + } + + // 回调配置 + @Data + public static class NotifyConfigVO { + /** + * 回调方式;MQ、HTTP + */ + private String notifyType; + /** + * 回调消息 + */ + private String notifyMQ; + /** + * 回调地址 + */ + private String notifyUrl; + } } diff --git a/group-buying-sys-app/src/main/java/edu/whut/config/RabbitMQConfig.java b/group-buying-sys-app/src/main/java/edu/whut/config/RabbitMQConfig.java index b376e38..8eab1a8 100644 --- a/group-buying-sys-app/src/main/java/edu/whut/config/RabbitMQConfig.java +++ b/group-buying-sys-app/src/main/java/edu/whut/config/RabbitMQConfig.java @@ -3,8 +3,9 @@ package edu.whut.config; import org.springframework.amqp.core.*; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; -//@Configuration +@Configuration public class RabbitMQConfig { @Value("${spring.rabbitmq.config.producer.exchange}") diff --git a/group-buying-sys-app/src/main/resources/mybatis/mapper/group_buy_order_mapper.xml b/group-buying-sys-app/src/main/resources/mybatis/mapper/group_buy_order_mapper.xml index 75ee72c..47eec1b 100644 --- a/group-buying-sys-app/src/main/resources/mybatis/mapper/group_buy_order_mapper.xml +++ b/group-buying-sys-app/src/main/resources/mybatis/mapper/group_buy_order_mapper.xml @@ -17,6 +17,7 @@ + @@ -26,10 +27,10 @@ insert into group_buy_order( team_id, activity_id, source, channel, original_price, deduction_price, pay_price, target_count, complete_count, - lock_count, status, valid_start_time, valid_end_time, notify_url, create_time, update_time + lock_count, status, valid_start_time, valid_end_time, notify_type, notify_url, create_time, update_time ) values( #{teamId}, #{activityId}, #{source}, #{channel}, #{originalPrice}, - #{deductionPrice}, #{payPrice}, #{targetCount}, #{completeCount}, #{lockCount}, 0, #{validStartTime}, #{validEndTime} ,#{notifyUrl},now(), now() + #{deductionPrice}, #{payPrice}, #{targetCount}, #{completeCount}, #{lockCount}, 0, #{validStartTime}, #{validEndTime},#{notifyType}, #{notifyUrl},now(), now() ) @@ -67,13 +68,14 @@ - select activity_id, team_id, notify_url, notify_count, notify_status, parameter_json + select activity_id, team_id, notify_type, notify_mq, notify_url, notify_count, notify_status, parameter_json from notify_task where notify_status in (0, 2) limit 50 diff --git a/group-buying-sys-app/src/test/java/edu/whut/test/domain/trade/TradeSettlementOrderServiceTest.java b/group-buying-sys-app/src/test/java/edu/whut/test/domain/trade/TradeSettlementOrderServiceTest.java index 5d46297..fe4265a 100644 --- a/group-buying-sys-app/src/test/java/edu/whut/test/domain/trade/TradeSettlementOrderServiceTest.java +++ b/group-buying-sys-app/src/test/java/edu/whut/test/domain/trade/TradeSettlementOrderServiceTest.java @@ -12,6 +12,7 @@ import org.springframework.test.context.junit4.SpringRunner; import javax.annotation.Resource; import java.util.Date; +import java.util.concurrent.CountDownLatch; /** * 拼团交易结算服务测试 @@ -34,12 +35,15 @@ public class TradeSettlementOrderServiceTest { TradePaySuccessEntity tradePaySuccessEntity = new TradePaySuccessEntity(); tradePaySuccessEntity.setSource("s01"); tradePaySuccessEntity.setChannel("c01"); - tradePaySuccessEntity.setUserId("zy01"); - tradePaySuccessEntity.setOutTradeNo("451247062978"); + tradePaySuccessEntity.setUserId("smile02"); + tradePaySuccessEntity.setOutTradeNo("334152190173"); tradePaySuccessEntity.setOutTradeTime(new Date()); //交易时间 TradePaySettlementEntity tradePaySettlementEntity = tradeSettlementOrderService.settlementMarketPayOrder(tradePaySuccessEntity); log.info("请求参数:{}", JSON.toJSONString(tradePaySuccessEntity)); log.info("测试结果:{}", JSON.toJSONString(tradePaySettlementEntity)); + + // 暂停,等待MQ消息。处理完后,手动关闭程序 + new CountDownLatch(1).await(); } } diff --git a/group-buying-sys-app/src/test/java/edu/whut/test/trigger/MarketTradeControllerTest.java b/group-buying-sys-app/src/test/java/edu/whut/test/trigger/MarketTradeControllerTest.java index b28fc9a..22f4a92 100644 --- a/group-buying-sys-app/src/test/java/edu/whut/test/trigger/MarketTradeControllerTest.java +++ b/group-buying-sys-app/src/test/java/edu/whut/test/trigger/MarketTradeControllerTest.java @@ -24,6 +24,22 @@ public class MarketTradeControllerTest { @Resource private IMarketTradeService marketTradeService; + @Test + public void test_lockMarketPayOrder_mq() throws InterruptedException { + LockMarketPayOrderRequestDTO lockMarketPayOrderRequestDTO = new LockMarketPayOrderRequestDTO(); + lockMarketPayOrderRequestDTO.setUserId("smile02"); + lockMarketPayOrderRequestDTO.setTeamId(null); + lockMarketPayOrderRequestDTO.setActivityId(100124L); + lockMarketPayOrderRequestDTO.setGoodsId("9890001"); + lockMarketPayOrderRequestDTO.setSource("s01"); + lockMarketPayOrderRequestDTO.setChannel("c01"); + lockMarketPayOrderRequestDTO.setNotifyMQ(); + lockMarketPayOrderRequestDTO.setOutTradeNo(RandomStringUtils.randomNumeric(12)); + + Response lockMarketPayOrderResponseDTOResponse = marketTradeService.lockMarketPayOrder(lockMarketPayOrderRequestDTO); + + log.info("测试结果 req:{} res:{}", JSON.toJSONString(lockMarketPayOrderRequestDTO), JSON.toJSONString(lockMarketPayOrderResponseDTOResponse)); + } /** * 模拟第一个用户创建拼团 diff --git a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/adapter/repository/ITradeRepository.java b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/adapter/repository/ITradeRepository.java index 1c63ed6..4517da7 100644 --- a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/adapter/repository/ITradeRepository.java +++ b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/adapter/repository/ITradeRepository.java @@ -27,7 +27,7 @@ public interface ITradeRepository { GroupBuyTeamEntity queryGroupBuyTeamByTeamId(String teamId); - boolean settlementMarketPayOrder(GroupBuyTeamSettlementAggregate groupBuyTeamSettlementAggregate); + NotifyTaskEntity settlementMarketPayOrder(GroupBuyTeamSettlementAggregate groupBuyTeamSettlementAggregate); boolean isSCBlackIntercept(String source, String channel); diff --git a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/model/entity/GroupBuyTeamEntity.java b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/model/entity/GroupBuyTeamEntity.java index 074ba5b..7673d72 100644 --- a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/model/entity/GroupBuyTeamEntity.java +++ b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/model/entity/GroupBuyTeamEntity.java @@ -1,4 +1,5 @@ package edu.whut.domain.trade.model.entity; +import edu.whut.domain.trade.model.valobj.NotifyConfigVO; import edu.whut.types.enums.GroupBuyOrderStatusEnumVO; import lombok.AllArgsConstructor; import lombok.Builder; @@ -32,7 +33,7 @@ public class GroupBuyTeamEntity { private Date validStartTime; /** 拼团结束时间 - 拼团有效时长 */ private Date validEndTime; - /** 回调地址 */ - private String notifyUrl; + /** 回调配置 */ + private NotifyConfigVO notifyConfigVO; } diff --git a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/model/entity/NotifyTaskEntity.java b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/model/entity/NotifyTaskEntity.java index 0802d70..3037663 100644 --- a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/model/entity/NotifyTaskEntity.java +++ b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/model/entity/NotifyTaskEntity.java @@ -18,6 +18,14 @@ public class NotifyTaskEntity { * 拼单组队ID */ private String teamId; + /** + * 回调类型 + */ + private String notifyType; + /** + * 回调消息 + */ + private String notifyMQ; /** * 回调接口 */ diff --git a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/model/entity/PayDiscountEntity.java b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/model/entity/PayDiscountEntity.java index e8647bf..26e6664 100644 --- a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/model/entity/PayDiscountEntity.java +++ b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/model/entity/PayDiscountEntity.java @@ -1,5 +1,6 @@ package edu.whut.domain.trade.model.entity; +import edu.whut.domain.trade.model.valobj.NotifyConfigVO; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -32,6 +33,7 @@ public class PayDiscountEntity { private BigDecimal payPrice; /** 外部交易单号-确保外部调用唯一幂等 */ private String outTradeNo; - /** 回调地址 */ - private String notifyUrl; + /** 回调配置 */ + private NotifyConfigVO notifyConfigVO; + } diff --git a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/model/entity/TradeSettlementRuleFilterBackEntity.java b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/model/entity/TradeSettlementRuleFilterBackEntity.java index fb82604..d48a82e 100644 --- a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/model/entity/TradeSettlementRuleFilterBackEntity.java +++ b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/model/entity/TradeSettlementRuleFilterBackEntity.java @@ -1,4 +1,5 @@ package edu.whut.domain.trade.model.entity; +import edu.whut.domain.trade.model.valobj.NotifyConfigVO; import edu.whut.types.enums.GroupBuyOrderStatusEnumVO; import lombok.AllArgsConstructor; import lombok.Builder; @@ -32,7 +33,7 @@ public class TradeSettlementRuleFilterBackEntity { private Date validStartTime; /** 拼团结束时间 - 拼团有效时长 */ private Date validEndTime; - /** 回调地址 */ - private String notifyUrl; + /** 回调配置 */ + private NotifyConfigVO notifyConfigVO; } diff --git a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/model/valobj/NotifyConfigVO.java b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/model/valobj/NotifyConfigVO.java new file mode 100644 index 0000000..d794bed --- /dev/null +++ b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/model/valobj/NotifyConfigVO.java @@ -0,0 +1,30 @@ +package edu.whut.domain.trade.model.valobj; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +/** + * 回调配置值对象 + */ +@Getter +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class NotifyConfigVO { + + /** + * 回调方式;MQ、HTTP + */ + private NotifyTypeEnumVO notifyType; + /** + * 回调消息 + */ + private String notifyMQ; + /** + * 回调地址 + */ + private String notifyUrl; + +} diff --git a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/model/valobj/NotifyTypeEnumVO.java b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/model/valobj/NotifyTypeEnumVO.java new file mode 100644 index 0000000..e45fef0 --- /dev/null +++ b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/model/valobj/NotifyTypeEnumVO.java @@ -0,0 +1,22 @@ +package edu.whut.domain.trade.model.valobj; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +/** + * 回调方式枚举 + */ +@Getter +@AllArgsConstructor +@NoArgsConstructor +public enum NotifyTypeEnumVO { + + HTTP("HTTP", "HTTP 回调"), + MQ("MQ", "MQ 消息通知"), + ; + + private String code; + private String info; + +} diff --git a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/ITradeSettlementOrderService.java b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/ITradeSettlementOrderService.java index 7a61d0e..3275b48 100644 --- a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/ITradeSettlementOrderService.java +++ b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/ITradeSettlementOrderService.java @@ -1,5 +1,6 @@ package edu.whut.domain.trade.service; +import edu.whut.domain.trade.model.entity.NotifyTaskEntity; import edu.whut.domain.trade.model.entity.TradePaySettlementEntity; import edu.whut.domain.trade.model.entity.TradePaySuccessEntity; @@ -34,5 +35,15 @@ public interface ITradeSettlementOrderService { */ Map execSettlementNotifyJob(String teamId) throws Exception; + /** + * 执行结算通知任务 + * + * @param notifyTaskEntity 通知任务对象 + * @return 结算数量 + * @throws Exception 异常 + */ + Map execSettlementNotifyJob(NotifyTaskEntity notifyTaskEntity) throws Exception; + + } diff --git a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/settlement/TradeSettlementOrderService.java b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/settlement/TradeSettlementOrderService.java index ef7e152..7bd8ae8 100644 --- a/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/settlement/TradeSettlementOrderService.java +++ b/group-buying-sys-domain/src/main/java/edu/whut/domain/trade/service/settlement/TradeSettlementOrderService.java @@ -8,14 +8,17 @@ import edu.whut.domain.trade.service.ITradeSettlementOrderService; import edu.whut.domain.trade.service.settlement.factory.TradeSettlementRuleFilterFactory; import edu.whut.types.design.framework.link.model2.chain.BusinessLinkedList; import edu.whut.types.enums.NotifyTaskHTTPEnumVO; +import edu.whut.types.exception.AppException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Service; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.ThreadPoolExecutor; /** * 拼团交易结算服务 @@ -28,6 +31,8 @@ public class TradeSettlementOrderService implements ITradeSettlementOrderService private final ITradePort port; + private final ThreadPoolExecutor threadPoolExecutor; + private final BusinessLinkedList tradeSettlementRuleFilter; @@ -56,14 +61,21 @@ public class TradeSettlementOrderService implements ITradeSettlementOrderService .tradePaySuccessEntity(tradePaySuccessEntity) .build(); - // 4. 更新数据库,拼团交易结算 - boolean isNotify =repository.settlementMarketPayOrder(groupBuyTeamSettlementAggregate); + // 4. 更新数据库,拼团交易结算,若达到拼团人数,返回notifyTaskEntity发送回调通知,否则返回null不做处理 + NotifyTaskEntity notifyTaskEntity =repository.settlementMarketPayOrder(groupBuyTeamSettlementAggregate); - // 5. isNotify为true-> 付款人数达到target,即拼团成功,执行回调任务 - // 处理失败也会有定时任务补偿,通过这样的方式,可以减轻任务调度,提高时效性 - if (isNotify) { - Map notifyResultMap = execSettlementNotifyJob(teamId); - log.info("回调通知 拼团成功 result:{}", JSON.toJSONString(notifyResultMap)); + // 5. 组队回调处理 - 处理失败也会有定时任务补偿,通过这样的方式,可以减轻任务调度,提高时效性 + if (null != notifyTaskEntity) { + threadPoolExecutor.execute(() -> { + Map notifyResultMap = null; + try { + notifyResultMap = execSettlementNotifyJob(notifyTaskEntity); + log.info("回调通知拼团完结 result:{}", JSON.toJSONString(notifyResultMap)); + } catch (Exception e) { + log.error("回调通知拼团完结失败 result:{}", JSON.toJSONString(notifyResultMap), e); + throw new AppException(e.getMessage()); + } + }); } // 6. 返回结算信息 - 公司中开发这样的流程时候,会根据外部需要进行值的设置 @@ -100,6 +112,12 @@ public class TradeSettlementOrderService implements ITradeSettlementOrderService return execSettlementNotifyJob(notifyTaskEntityList); } + @Override + public Map execSettlementNotifyJob(NotifyTaskEntity notifyTaskEntity) throws Exception { + log.info("拼团交易-执行结算通知回调,指定 teamId:{} notifyTaskEntity:{}", notifyTaskEntity.getTeamId(), JSON.toJSONString(notifyTaskEntity)); + return execSettlementNotifyJob(Collections.singletonList(notifyTaskEntity)); + } + /** *公共逻辑抽取:遍历任务列表,调用外部服务,更新数据库并计数 * @param notifyTaskEntityList 待处理的通知任务列表 diff --git a/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/adapter/port/TradePort.java b/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/adapter/port/TradePort.java index d0b27ae..2be0421 100644 --- a/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/adapter/port/TradePort.java +++ b/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/adapter/port/TradePort.java @@ -1,6 +1,8 @@ package edu.whut.infrastructure.adapter.port; import edu.whut.domain.trade.adapter.port.ITradePort; import edu.whut.domain.trade.model.entity.NotifyTaskEntity; +import edu.whut.domain.trade.model.valobj.NotifyTypeEnumVO; +import edu.whut.infrastructure.event.EventPublisher; import edu.whut.infrastructure.gateway.GroupBuyNotifyService; import edu.whut.infrastructure.redis.IRedisService; import edu.whut.types.enums.NotifyTaskHTTPEnumVO; @@ -20,6 +22,8 @@ public class TradePort implements ITradePort { private final IRedisService redisService; + private final EventPublisher publisher; + @Override public String groupBuyNotify(NotifyTaskEntity notifyTask) throws Exception { RLock lock = redisService.getLock(notifyTask.lockKey()); @@ -28,11 +32,20 @@ public class TradePort implements ITradePort { // tryLock(long waitTime, long leaseTime, TimeUnit unit) 最大等待时间,锁自动释放时间(传0表示需手动释放) if (lock.tryLock(3, 0, TimeUnit.SECONDS)) { try { - // 无效的 notifyUrl 则直接返回成功 - if (StringUtils.isBlank(notifyTask.getNotifyUrl()) || "暂无".equals(notifyTask.getNotifyUrl())) { + // 回调方式 HTTP + if (NotifyTypeEnumVO.HTTP.getCode().equals(notifyTask.getNotifyType())) { + // 无效的 notifyUrl 则直接返回成功 + if (StringUtils.isBlank(notifyTask.getNotifyUrl()) || "暂无".equals(notifyTask.getNotifyUrl())) { + return NotifyTaskHTTPEnumVO.SUCCESS.getCode(); + } + return groupBuyNotifyService.groupBuyNotify(notifyTask.getNotifyUrl(), notifyTask.getParameterJson()); + } + + // 回调方式 MQ + if (NotifyTypeEnumVO.MQ.getCode().equals(notifyTask.getNotifyType())) { + publisher.publish(notifyTask.getNotifyMQ(), notifyTask.getParameterJson()); return NotifyTaskHTTPEnumVO.SUCCESS.getCode(); } - return groupBuyNotifyService.groupBuyNotify(notifyTask.getNotifyUrl(), notifyTask.getParameterJson()); } finally { //解锁 if (lock.isLocked() && lock.isHeldByCurrentThread()) { diff --git a/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/adapter/repository/TradeRepository.java b/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/adapter/repository/TradeRepository.java index a9bb56f..b609ba6 100644 --- a/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/adapter/repository/TradeRepository.java +++ b/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/adapter/repository/TradeRepository.java @@ -6,6 +6,8 @@ import edu.whut.domain.trade.model.aggregate.GroupBuyOrderAggregate; import edu.whut.domain.trade.model.aggregate.GroupBuyTeamSettlementAggregate; import edu.whut.domain.trade.model.entity.*; import edu.whut.domain.trade.model.valobj.GroupBuyProgressVO; +import edu.whut.domain.trade.model.valobj.NotifyConfigVO; +import edu.whut.domain.trade.model.valobj.NotifyTypeEnumVO; import edu.whut.domain.trade.model.valobj.TradeOrderStatusEnumVO; import edu.whut.infrastructure.dao.IGroupBuyActivityDao; import edu.whut.infrastructure.dao.IGroupBuyOrderDao; @@ -26,6 +28,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Value; import org.springframework.dao.DuplicateKeyException; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; @@ -53,6 +56,9 @@ public class TradeRepository implements ITradeRepository { private final DCCService dccService; + @Value("${spring.rabbitmq.config.producer.topic_team_success.routing_key}") + private String topic_team_success; + /** * 根据外部交易号 & 用户id 查询未支付的锁单记录(用于幂等) */ @@ -93,6 +99,7 @@ public class TradeRepository implements ITradeRepository { UserEntity user = agg.getUserEntity(); PayActivityEntity activity = agg.getPayActivityEntity(); PayDiscountEntity discount = agg.getPayDiscountEntity(); + NotifyConfigVO notifyConfigVO = discount.getNotifyConfigVO(); Integer userTakeOrderCount = agg.getUserTakeOrderCount(); @@ -122,7 +129,8 @@ public class TradeRepository implements ITradeRepository { .lockCount(1) // 首单已锁定 .validStartTime(currentDate) .validEndTime(calendar.getTime()) - .notifyUrl(discount.getNotifyUrl()) + .notifyType(notifyConfigVO.getNotifyType().getCode()) + .notifyUrl(notifyConfigVO.getNotifyUrl()) .build(); groupBuyOrderDao.insert(orderPo); @@ -222,10 +230,22 @@ public class TradeRepository implements ITradeRepository { @Override public GroupBuyTeamEntity queryGroupBuyTeamByTeamId(String teamId) { GroupBuyOrder groupBuyOrder = groupBuyOrderDao.queryGroupBuyTeamByTeamId(teamId); - GroupBuyTeamEntity groupBuyTeamEntity = new GroupBuyTeamEntity(); - BeanUtils.copyProperties(groupBuyOrder, groupBuyTeamEntity, "status"); - groupBuyTeamEntity.setStatus(GroupBuyOrderStatusEnumVO.valueOf(groupBuyOrder.getStatus())); - return groupBuyTeamEntity; + return GroupBuyTeamEntity.builder() + .teamId(groupBuyOrder.getTeamId()) + .activityId(groupBuyOrder.getActivityId()) + .targetCount(groupBuyOrder.getTargetCount()) + .completeCount(groupBuyOrder.getCompleteCount()) + .lockCount(groupBuyOrder.getLockCount()) + .status(GroupBuyOrderStatusEnumVO.valueOf(groupBuyOrder.getStatus())) + .validStartTime(groupBuyOrder.getValidStartTime()) + .validEndTime(groupBuyOrder.getValidEndTime()) + .notifyConfigVO(NotifyConfigVO.builder() + .notifyType(NotifyTypeEnumVO.valueOf(groupBuyOrder.getNotifyType())) + .notifyUrl(groupBuyOrder.getNotifyUrl()) + // MQ 是固定的 + .notifyMQ(topic_team_success) + .build()) + .build(); } @@ -239,11 +259,12 @@ public class TradeRepository implements ITradeRepository { */ @Transactional(timeout = 500) @Override - public boolean settlementMarketPayOrder(GroupBuyTeamSettlementAggregate agg) { + public NotifyTaskEntity settlementMarketPayOrder(GroupBuyTeamSettlementAggregate agg) { // ========= 1. 聚合拆分 ========= UserEntity user = agg.getUserEntity(); GroupBuyTeamEntity team = agg.getGroupBuyTeamEntity(); + NotifyConfigVO notifyConfigVO = team.getNotifyConfigVO(); TradePaySuccessEntity payOK = agg.getTradePaySuccessEntity(); // ========= 2. 更新拼团订单明细状态 ========= @@ -278,7 +299,9 @@ public class TradeRepository implements ITradeRepository { NotifyTask task = new NotifyTask(); task.setActivityId(team.getActivityId()); task.setTeamId(team.getTeamId()); - task.setNotifyUrl(team.getNotifyUrl()); + task.setNotifyType(notifyConfigVO.getNotifyType().getCode()); + task.setNotifyMQ(NotifyTypeEnumVO.MQ.equals(notifyConfigVO.getNotifyType()) ? notifyConfigVO.getNotifyMQ() : null); + task.setNotifyUrl(NotifyTypeEnumVO.HTTP.equals(notifyConfigVO.getNotifyType()) ? notifyConfigVO.getNotifyUrl() : null); task.setNotifyCount(0); task.setNotifyStatus(0); task.setParameterJson(JSON.toJSONString(new HashMap() {{ @@ -287,9 +310,16 @@ public class TradeRepository implements ITradeRepository { }})); notifyTaskDao.insert(task); - return true; + return NotifyTaskEntity.builder() + .teamId(task.getTeamId()) + .notifyType(task.getNotifyType()) + .notifyMQ(task.getNotifyMQ()) + .notifyUrl(task.getNotifyUrl()) + .notifyCount(task.getNotifyCount()) + .parameterJson(task.getParameterJson()) + .build(); } - return false; + return null; } /** @@ -337,6 +367,8 @@ public class TradeRepository implements ITradeRepository { if (null == notifyTask) return new ArrayList<>(); return Collections.singletonList(NotifyTaskEntity.builder() .teamId(notifyTask.getTeamId()) + .notifyType(notifyTask.getNotifyType()) + .notifyMQ(notifyTask.getNotifyMQ()) .notifyUrl(notifyTask.getNotifyUrl()) .notifyCount(notifyTask.getNotifyCount()) .parameterJson(notifyTask.getParameterJson()) diff --git a/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/dao/po/GroupBuyOrder.java b/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/dao/po/GroupBuyOrder.java index a54ec2b..097a245 100644 --- a/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/dao/po/GroupBuyOrder.java +++ b/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/dao/po/GroupBuyOrder.java @@ -45,7 +45,9 @@ public class GroupBuyOrder { private Date validStartTime; /** 拼团结束时间 - 拼团有效时长 */ private Date validEndTime; - /** 回调通知地址 */ + /** 回调类型 HTTP、MQ */ + private String notifyType; + /** 回调通知(HTTP 方式回调,地址不可为空) */ private String notifyUrl; /** 创建时间 */ private Date createTime; diff --git a/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/dao/po/NotifyTask.java b/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/dao/po/NotifyTask.java index 8568d3e..33c3acb 100644 --- a/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/dao/po/NotifyTask.java +++ b/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/dao/po/NotifyTask.java @@ -21,6 +21,10 @@ public class NotifyTask { private Long activityId; /** 拼单组队ID */ private String teamId; + /** 回调类型 */ + private String notifyType; + /** 回调消息 */ + private String notifyMQ; /** 回调接口 */ private String notifyUrl; /** 回调次数 */ diff --git a/group-buying-sys-trigger/src/main/java/edu/whut/trigger/http/MarketTradeController.java b/group-buying-sys-trigger/src/main/java/edu/whut/trigger/http/MarketTradeController.java index 01d9ad3..c4be67c 100644 --- a/group-buying-sys-trigger/src/main/java/edu/whut/trigger/http/MarketTradeController.java +++ b/group-buying-sys-trigger/src/main/java/edu/whut/trigger/http/MarketTradeController.java @@ -13,6 +13,8 @@ import edu.whut.domain.activity.model.valobj.GroupBuyActivityDiscountVO; import edu.whut.domain.activity.service.IIndexGroupBuyMarketService; import edu.whut.domain.trade.model.entity.*; import edu.whut.domain.trade.model.valobj.GroupBuyProgressVO; +import edu.whut.domain.trade.model.valobj.NotifyConfigVO; +import edu.whut.domain.trade.model.valobj.NotifyTypeEnumVO; import edu.whut.domain.trade.service.ITradeLockOrderService; import edu.whut.domain.trade.service.ITradeSettlementOrderService; import edu.whut.types.enums.ResponseCode; @@ -69,18 +71,25 @@ public class MarketTradeController implements IMarketTradeService { Long activityId = lockMarketPayOrderRequestDTO.getActivityId(); String outTradeNo = lockMarketPayOrderRequestDTO.getOutTradeNo(); String teamId = lockMarketPayOrderRequestDTO.getTeamId(); //可为空,对应参与拼团or创建拼团 - String notifyUrl = lockMarketPayOrderRequestDTO.getNotifyUrl(); + LockMarketPayOrderRequestDTO.NotifyConfigVO notifyConfigVO = lockMarketPayOrderRequestDTO.getNotifyConfigVO(); log.info("营销锁单开始执行:拼团交易锁单入参 userId={} req={}", userId, JSON.toJSONString(lockMarketPayOrderRequestDTO)); // 空值校验(任何一个关键字段为空则直接返回错误) - if (StringUtils.isAnyBlank(userId, source, channel, goodsId, notifyUrl) || activityId == null) { + boolean httpWithoutUrl = + "HTTP".equals(notifyConfigVO.getNotifyType()) + && StringUtils.isBlank(notifyConfigVO.getNotifyUrl()); + + if (StringUtils.isAnyBlank(userId, source, channel, goodsId) + || activityId == null + || httpWithoutUrl) { return Response.builder() .code(ResponseCode.ILLEGAL_PARAMETER.getCode()) .info(ResponseCode.ILLEGAL_PARAMETER.getInfo()) .build(); } + /* ---------- 2. 查询是否已存在未支付锁单 ---------- */ MarketPayOrderEntity marketPayOrderEntity = tradeOrderService.queryNoPayMarketPayOrderByOutTradeNo(userId, outTradeNo); @@ -147,7 +156,13 @@ public class MarketTradeController implements IMarketTradeService { .deductionPrice(trialBalance.getDeductionPrice()) .payPrice(trialBalance.getPayPrice()) .outTradeNo(outTradeNo) - .notifyUrl(notifyUrl) + .notifyConfigVO( + // 构建回调通知对象 + NotifyConfigVO.builder() + .notifyType(NotifyTypeEnumVO.valueOf(notifyConfigVO.getNotifyType())) + .notifyMQ(notifyConfigVO.getNotifyMQ()) + .notifyUrl(notifyConfigVO.getNotifyUrl()) + .build()) .build()); log.info("交易锁单成功 userId={} order={}", userId, JSON.toJSONString(marketPayOrderEntity));