mirror of
https://gitee.com/dromara/dax-pay
synced 2026-08-12 15:35:38 +08:00
feat(channel): 通道连通性 demo 链路, 含声明式通道客户端与 traceparent 透传
This commit is contained in:
@@ -12,7 +12,7 @@
|
||||
Target Server Version : 160009 (160009)
|
||||
File Encoding : 65001
|
||||
|
||||
Date: 17/06/2026 18:12:21
|
||||
Date: 23/06/2026 09:16:48
|
||||
*/
|
||||
|
||||
|
||||
@@ -103,7 +103,6 @@ INSERT INTO "public"."iam_perm_menu" VALUES (302, 3, NULL, 'admin', 'SystemLog',
|
||||
INSERT INTO "public"."iam_perm_menu" VALUES (30102, 301, 'iam:perm:menu', 'admin', 'SystemMenu', '菜单管理', 'Menu Management', 'menu.system.basic.menu', 'carbon:menu', 'f', 'f', '/iam/perm/menu/MenuList', '/system/basic/menu', NULL, 0, 'f', 't', 'f', 0, 1, 2, 'f', 'menu', NULL, NULL, NULL, NULL, '', '', '2026-03-20 03:11:13.134079+00', '2026-03-31 13:39:34.260955+00');
|
||||
INSERT INTO "public"."iam_perm_menu" VALUES (30201, 302, 'starter:log:login', 'admin', 'SystemLoginLog', '登录日志', 'Login Log', 'menu.system.log.login', 'lucide:log-in', 'f', 'f', '/system/log/login/LoginLogList', '/system/log/login', NULL, 1, 'f', 't', 'f', 0, 1, 1, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-03-20 03:11:13.134079+00', '2026-03-30 15:25:09.855555+00');
|
||||
INSERT INTO "public"."iam_perm_menu" VALUES (2, NULL, NULL, 'admin', 'Demos', '演示', 'Demos', 'menu.demos', 'ic:baseline-view-in-ar', 'f', 'f', NULL, '/demos', NULL, 1000, 'f', 't', 'f', 0, NULL, 0, 'f', 'catalog', NULL, NULL, NULL, NULL, NULL, NULL, '2026-03-20 03:11:13.134079+00', '2026-03-20 03:11:13.134079+00');
|
||||
INSERT INTO "public"."iam_perm_menu" VALUES (201, 2, NULL, 'admin', 'AntDesignDemos', 'Antd Next演示', 'Antd Next Demo', 'menu.demos.antd', 'lucide:box', 'f', 'f', '/demos/antd/AntdDemo', '/demos/ant-design-next', NULL, 1, 'f', 'f', 'f', 0, NULL, 0, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-03-20 03:11:13.134079+00', '2026-03-20 03:11:13.134079+00');
|
||||
INSERT INTO "public"."iam_perm_menu" VALUES (30202, 302, 'starter:log:operate', 'admin', 'SystemOperateLog', '操作日志', 'Operate Log', 'menu.system.log.operate', 'lucide:activity', 'f', 'f', '/system/log/operate/OperateLogList', '/system/log/operate', NULL, 2, 'f', 't', 'f', 0, 1, 1, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-03-20 03:11:13.134079+00', '2026-03-30 15:24:57.076166+00');
|
||||
INSERT INTO "public"."iam_perm_menu" VALUES (1, NULL, NULL, 'admin', 'Dashboard', '仪表板', 'Dashboard', 'menu.dashboard', 'lucide:layout-dashboard', 'f', 'f', NULL, '/dashboard', '/analytics', -1, 'f', 'f', 'f', 0, NULL, 0, 'f', 'catalog', NULL, NULL, NULL, NULL, NULL, NULL, '2026-03-20 03:11:13.134079+00', '2026-03-20 03:11:13.134079+00');
|
||||
INSERT INTO "public"."iam_perm_menu" VALUES (30402, 304, 'system:platform:config', 'admin', 'PlatformConfig', '平台配置', 'Platform Config', 'menu.system.config.platform', 'lucide:settings', 'f', 'f', '/system/config/platform/PlatformConfig', '/system/config/platform', NULL, 2, 'f', 't', 'f', 1, 1, 0, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-04-07 16:00:00+00', '2026-04-07 16:00:00+00');
|
||||
@@ -116,13 +115,10 @@ INSERT INTO "public"."iam_perm_menu" VALUES (40401, 404, 'payment:merchant:info'
|
||||
INSERT INTO "public"."iam_perm_menu" VALUES (401, 4, 'payment:platform', 'admin', 'PaymentPlatform', '支付主数据', 'Payment Master Data', 'menu.payment.platform', 'lucide:building', 'f', 'f', NULL, '/payment/platform', NULL, 1, 'f', 't', 'f', 0, 1, 3, 'f', 'catalog', NULL, NULL, NULL, NULL, NULL, NULL, '2026-04-05 16:00:00+00', '2026-05-28 06:25:42.880461+00');
|
||||
INSERT INTO "public"."iam_perm_menu" VALUES (203, 2, 'demos:region', 'admin', 'RegionCascaderDemo', '行政区划选择器', 'Region Cascader', 'menu.demos.region', 'lucide:map-pin', 'f', 'f', '/demos/region/RegionCascaderDemo', '/demos/region', NULL, 3, 'f', 't', 'f', 0, NULL, 0, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-04-24 16:00:00+00', '2026-04-24 16:00:00+00');
|
||||
INSERT INTO "public"."iam_perm_menu" VALUES (4040103, 40401, 'payment:merchant:manage:info', 'admin', 'MchInfoManage', '商户信息', 'Merchant Info', 'menu.payment.merchant.manage.info', NULL, 't', 'f', '/payment/merchant/manage/info/MchInfoManage', '/payment/merchant/manage/info', NULL, 3, 'f', 't', 'f', 1, 1, 0, 'f', 'subpage', NULL, NULL, NULL, NULL, NULL, NULL, '2026-05-01 16:00:00+00', '2026-05-01 16:00:00+00');
|
||||
INSERT INTO "public"."iam_perm_menu" VALUES (4040104, 40401, 'payment:merchant:manage:entity', 'admin', 'MchEntityManage', '主体信息', 'Entity Info', 'menu.payment.merchant.manage.entity', NULL, 't', 'f', '/payment/merchant/manage/entity/MchEntityManage', '/payment/merchant/manage/entity', NULL, 4, 'f', 't', 'f', 1, 1, 0, 'f', 'subpage', NULL, NULL, NULL, NULL, NULL, NULL, '2026-05-01 16:00:00+00', '2026-05-01 16:00:00+00');
|
||||
INSERT INTO "public"."iam_perm_menu" VALUES (4040105, 40401, 'payment:merchant:manage:settle', 'admin', 'MchSettleManage', '结算账户', 'Settle Account', 'menu.payment.merchant.manage.settle', NULL, 't', 'f', '/payment/merchant/manage/settle/MchSettleManage', '/payment/merchant/manage/settle', NULL, 5, 'f', 't', 'f', 1, 1, 0, 'f', 'subpage', NULL, NULL, NULL, NULL, NULL, NULL, '2026-05-01 16:00:00+00', '2026-05-01 16:00:00+00');
|
||||
INSERT INTO "public"."iam_perm_menu" VALUES (4, NULL, 'payment:system', 'admin', 'PaymentSystem', '平台管理', 'Platform Management', 'menu.platform', 'lucide:credit-card', 'f', 'f', NULL, '/payment', NULL, 3, 'f', 't', 'f', 0, 1, 1, 'f', 'catalog', NULL, NULL, NULL, NULL, NULL, NULL, '2026-04-05 16:00:00+00', '2026-06-13 00:00:00+00');
|
||||
INSERT INTO "public"."iam_perm_menu" VALUES (4040102, 40401, 'payment:merchant:manage:credentialConfig', 'admin', 'MerchantCredentialConfig', '对接配置', 'Credential Config', 'menu.payment.merchant.manage.credentialConfig', NULL, 't', 'f', '/payment/merchant/manage/credential/MerchantCredentialConfig', '/payment/merchant/manage/credential', NULL, 3, 'f', 't', 'f', 1, 1, 0, 'f', 'subpage', NULL, NULL, NULL, NULL, NULL, NULL, '2026-05-01 16:00:00+00', '2026-05-01 16:00:00+00');
|
||||
INSERT INTO "public"."iam_perm_menu" VALUES (4040101, 40401, 'payment:merchant:manage', 'admin', 'MerchantManage', '商户管理', 'Merchant Management', 'menu.payment.merchant.manage', '', 't', 'f', '/payment/merchant/manage/workbench/MerchantManage', '/payment/merchant/manage', NULL, 2, 'f', 't', 'f', 1, 1, 0, 'f', 'subpage', NULL, NULL, NULL, NULL, NULL, NULL, '2026-04-13 16:00:00+00', '2026-05-02 06:57:49.052168+00');
|
||||
INSERT INTO "public"."iam_perm_menu" VALUES (4040106, 40401, 'payment:merchant:channelMerchant', 'admin', 'ChannelMerchant', '通道商户', 'Channel Merchant', 'menu.payment.merchant.channelMerchant', NULL, 't', 'f', '/payment/merchant/channel-merchant/ChannelMerchantList', '/payment/merchant/channel-merchant', NULL, 6, 'f', 't', 'f', 1, 1, 0, 'f', 'subpage', NULL, NULL, NULL, NULL, NULL, NULL, '2026-05-03 16:00:00+00', '2026-05-03 16:00:00+00');
|
||||
INSERT INTO "public"."iam_perm_menu" VALUES (4040107, 40401, 'payment:merchant:product', 'admin', 'MchProductConfig', '支付产品', 'Payment Product', 'menu.payment.merchant.product', NULL, 't', 'f', '/payment/merchant/product/MchProductConfig', '/payment/merchant/product', NULL, 7, 'f', 't', 'f', 1, 1, 0, 'f', 'subpage', NULL, NULL, NULL, NULL, NULL, NULL, '2026-05-03 16:00:00+00', '2026-05-03 16:00:00+00');
|
||||
INSERT INTO "public"."iam_perm_menu" VALUES (4040108, 40401, 'payment:merchant:user', 'admin', 'MerchantUser', '商户用户', 'Merchant User', 'menu.payment.merchant.user', '', 't', 'f', '/payment/merchant/user/MerchantUserList', '/payment/merchant/user', NULL, 8, 'f', 't', 'f', 1, 1, 0, 'f', 'subpage', NULL, NULL, NULL, NULL, NULL, NULL, '2026-05-04 16:00:00+00', '2026-05-04 16:00:00+00');
|
||||
INSERT INTO "public"."iam_perm_menu" VALUES (4040109, 40401, 'payment:merchant:channelMerchant:create', 'admin', 'ChannelMerchantCreate', '创建通道商户', 'Create Channel Merchant', 'menu.payment.merchant.channelMerchant.create', NULL, 't', 'f', '/payment/merchant/channel-merchant/ChannelMerchantCreate', '/payment/merchant/channel-merchant/create', NULL, 9, 'f', 't', 'f', 1, 1, 0, 'f', 'subpage', NULL, NULL, NULL, NULL, NULL, NULL, '2026-05-05 16:00:00+00', '2026-05-05 16:00:00+00');
|
||||
INSERT INTO "public"."iam_perm_menu" VALUES (4040111, 4040110, 'payment:merchant:app:payRoute', 'admin', 'PayRouteConfig', '通道路由', 'Channel Routing', 'menu.payment.merchant.app.payRoute', NULL, 't', 'f', '/payment/merchant/route/PayRouteConfig', '/payment/merchant/route', NULL, 2, 'f', 't', 'f', 1, 1, 1, 'f', 'subpage', NULL, NULL, NULL, NULL, NULL, NULL, '2026-05-24 22:23:46.483985+00', '2026-05-26 20:03:06.445803+00');
|
||||
@@ -130,24 +126,24 @@ INSERT INTO "public"."iam_perm_menu" VALUES (4040110, 40401, 'payment:merchant:a
|
||||
INSERT INTO "public"."iam_perm_menu" VALUES (601, 6, NULL, 'admin', 'TransactionIndex', '功能开发中', 'Coming Soon', 'menu.trade.index', 'lucide:construction', 'f', 'f', '/_core/fallback/coming-soon', '/trade/index', NULL, 1, 'f', 'f', 'f', 1, 1, 0, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-05-24 16:00:00+00', '2026-05-24 16:00:00+00');
|
||||
INSERT INTO "public"."iam_perm_menu" VALUES (7, NULL, 'terminal:system', 'admin', 'TerminalManagement', '终端管理', 'Terminal Management', 'menu.terminal', 'lucide:smartphone', 'f', 'f', NULL, '/terminal', '/terminal/index', 4.5, 'f', 't', 'f', 1, 1, 0, 'f', 'catalog', NULL, NULL, NULL, NULL, NULL, NULL, '2026-05-24 16:00:00+00', '2026-05-24 16:00:00+00');
|
||||
INSERT INTO "public"."iam_perm_menu" VALUES (701, 7, NULL, 'admin', 'TerminalIndex', '功能开发中', 'Coming Soon', 'menu.terminal.index', 'lucide:construction', 'f', 'f', '/_core/fallback/coming-soon', '/terminal/index', NULL, 1, 'f', 'f', 'f', 1, 1, 0, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-05-24 16:00:00+00', '2026-05-24 16:00:00+00');
|
||||
INSERT INTO "public"."iam_perm_menu" VALUES (40103, 401, 'payment:platform:channel', 'admin', 'PayChannelList', '支付通道', 'Payment Channel', 'menu.payment.platform.channel', 'lucide:radio-tower', 'f', 'f', '/payment/masterdata/channel/PayChannelList', '/payment/platform/pay-channel', NULL, 0, 'f', 't', 'f', 1, 1, 0, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-05-28 16:00:00+00', '2026-05-28 16:00:00+00');
|
||||
INSERT INTO "public"."iam_perm_menu" VALUES (40104, 401, 'payment:platform:capability', 'admin', 'PayCapabilityList', '支付能力', 'Payment Capability', 'menu.payment.platform.capability', 'lucide:zap', 'f', 'f', '/payment/masterdata/capability/PayCapabilityList', '/payment/platform/pay-capability', NULL, 3, 'f', 't', 'f', 1, 1, 4, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-05-26 16:00:00+00', '2026-05-28 06:43:27.505831+00');
|
||||
INSERT INTO "public"."iam_perm_menu" VALUES (40101, 401, 'payment:platform:product', 'admin', 'ProductList', '支付产品', 'Payment Product', 'menu.payment.platform.product', 'lucide:package', 'f', 'f', '/payment/masterdata/product/PayProductList', '/payment/platform/product', NULL, 2, 'f', 't', 'f', 1, 1, 3, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-04-23 16:00:00+00', '2026-05-28 06:25:42.892396+00');
|
||||
INSERT INTO "public"."iam_perm_menu" VALUES (4040112, 40401, 'payment:merchant:channelMerchant:detail', 'admin', 'ChannelMerchantDetailDispatch', '通道商户详情', 'Channel Merchant Detail', 'menu.payment.merchant.channelMerchant.detail', NULL, 't', 'f', '/payment/merchant/channel-merchant/detail/ChannelMerchantDetailDispatch', '/payment/merchant/channel-merchant/detail', NULL, 10, 'f', 't', 'f', 1, 1, 0, 'f', 'subpage', NULL, NULL, NULL, NULL, NULL, NULL, '2026-06-07 19:48:34.936565+00', '2026-06-07 19:48:34.936565+00');
|
||||
INSERT INTO "public"."iam_perm_menu" VALUES (4040113, 40401, 'payment:merchant:channelMerchant:wechatApp', 'admin', 'WechatMchAppManage', '微信通道商户应用', 'WeChat Channel Merchant App', 'menu.payment.merchant.channelMerchant.wechatApp', NULL, 't', 'f', '/payment/channel/wechat/manage/mch/app/WechatMchAppManage', '/payment/merchant/channel-merchant/wechat-app-manage', NULL, 11, 'f', 't', 'f', 1, 1, 0, 'f', 'subpage', NULL, NULL, NULL, NULL, NULL, NULL, '2026-06-07 23:57:13.620205+00', '2026-06-07 23:57:13.620205+00');
|
||||
INSERT INTO "public"."iam_perm_menu" VALUES (4040114, 40401, 'payment:merchant:channelMerchant:alipayApp', 'admin', 'AlipayMchAppManage', '支付宝通道商户应用', 'Alipay Channel Merchant App', 'menu.payment.merchant.channelMerchant.alipayApp', NULL, 't', 'f', '/payment/channel/alipay/manage/mch/app/AlipayMchAppManage', '/payment/merchant/channel-merchant/alipay-app-manage', NULL, 12, 'f', 't', 'f', 1, 1, 0, 'f', 'subpage', NULL, NULL, NULL, NULL, NULL, NULL, '2026-06-11 22:28:11.274785+00', '2026-06-11 22:28:11.274785+00');
|
||||
INSERT INTO "public"."iam_perm_menu" VALUES (40104, 401, 'payment:platform:capability', 'admin', 'PayCapabilityList', '支付能力', 'Payment Capability', 'menu.payment.platform.capability', 'lucide:zap', 'f', 'f', '/payment/masterdata/capability/PayCapabilityList', '/payment/platform/pay-capability', NULL, 3, 'f', 't', 'f', 1, 1, 4, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-05-26 16:00:00+00', '2026-05-28 06:43:27.505831+00');
|
||||
INSERT INTO "public"."iam_perm_menu" VALUES (404, NULL, 'payment:merchant', 'admin', 'PaymentMerchant', '商户管理', 'Merchant Management', 'menu.payment.merchant', 'lucide:store', 'f', 'f', NULL, '/payment/merchant', NULL, 4, 't', 't', 'f', 0, NULL, 0, 'f', 'catalog', NULL, NULL, NULL, NULL, NULL, NULL, '2026-04-05 16:00:00+00', '2026-06-13 00:00:00+00');
|
||||
INSERT INTO "public"."iam_perm_menu" VALUES (40102, 401, 'payment:platform:provider', 'admin', 'PayProviderList', '支付方式', 'Payment Method', 'menu.payment.platform.provider', 'lucide:list-tree', 'f', 'f', '/payment/masterdata/provider/PayProviderList', '/payment/platform/pay-method', NULL, 1, 'f', 't', 'f', 1, 1, 5, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-05-27 20:18:01.383008+00', '2026-05-30 08:21:19.464024+00');
|
||||
INSERT INTO "public"."iam_perm_menu" VALUES (30403, 304, 'system:credential:config', 'admin', 'PlatformCredentialConfig', '对接配置', 'Credential Config', 'menu.system.config.credential', 'lucide:key-round', 'f', 'f', '/system/config/credential/PlatformCredentialConfig', '/system/config/credential', NULL, 3, 'f', 't', 'f', 1, 1, 0, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-06-13 00:00:00+00', '2026-06-13 00:00:00+00');
|
||||
INSERT INTO "public"."iam_perm_menu" VALUES (40102, 401, 'payment:platform:provider', 'admin', 'PayProviderList', '支付方式', 'Payment Method', 'menu.payment.platform.provider', 'lucide:list-tree', 'f', 'f', '/payment/masterdata/provider/PayMethodList', '/payment/platform/pay-method', NULL, 1, 'f', 't', 'f', 1, 1, 5, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-05-27 20:18:01.383008+00', '2026-05-30 08:21:19.464024+00');
|
||||
INSERT INTO "public"."iam_perm_menu" VALUES (40103, 401, 'payment:platform:channel', 'admin', 'PayChannelList', '支付通道', 'Payment Channel', 'menu.payment.platform.channel', 'lucide:radio-tower', 'f', 'f', '/payment/masterdata/channel/PayChannelList', '/payment/platform/pay-channel', NULL, 0, 'f', 't', 'f', 1, 1, 0, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-05-28 16:00:00+00', '2026-05-28 16:00:00+00');
|
||||
INSERT INTO "public"."iam_perm_menu" VALUES (40101, 401, 'payment:platform:product', 'admin', 'ProductList', '支付产品', 'Payment Product', 'menu.payment.platform.product', 'lucide:package', 'f', 'f', '/payment/masterdata/product/PayProductList', '/payment/platform/product', NULL, 2, 'f', 't', 'f', 1, 1, 3, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-04-23 16:00:00+00', '2026-05-28 06:25:42.892396+00');
|
||||
INSERT INTO "public"."iam_perm_menu" VALUES (405, 4, 'payment:config', 'admin', 'PaymentConfig', '支付配置', 'Payment Config', 'menu.payment.config', 'lucide:settings-2', 'f', 'f', NULL, '/payment/config', NULL, 2, 'f', 't', 'f', 1, 1, 0, 'f', 'catalog', NULL, NULL, NULL, NULL, NULL, NULL, '2026-06-14 00:00:00+00', '2026-06-14 00:00:00+00');
|
||||
INSERT INTO "public"."iam_perm_menu" VALUES (40105, 405, 'payment:config:productConfig', 'admin', 'ProductConfig', '支付产品管理', 'Payment Product Management', 'menu.payment.config.productConfig', 'lucide:layout-grid', 'f', 'f', '/payment/config/product/ProductConfig', '/payment/config/product', NULL, 1, 'f', 't', 'f', 1, 1, 0, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-06-13 00:00:00+00', '2026-06-13 09:14:10.179605+00');
|
||||
INSERT INTO "public"."iam_perm_menu" VALUES (40501, 405, 'payment:config:productDetail', 'admin', 'ProductDetailDispatch', '支付产品详情', 'Payment Product Detail', 'menu.payment.config.productDetail', NULL, 't', 'f', '/payment/config/product/detail/ProductDetailDispatch', '/payment/product-detail', NULL, 2, 'f', 't', 'f', 1, 1, 0, 'f', 'subpage', NULL, NULL, NULL, NULL, NULL, NULL, '2026-06-14 00:00:00+00', '2026-06-14 00:00:00+00');
|
||||
INSERT INTO "public"."iam_perm_menu" VALUES (40502, 405, 'payment:alipay:isvApp', 'admin', 'AlipayIsvAppManage', '支付宝服务商应用', 'Alipay ISV Application', 'menu.payment.alipay.isvApp', NULL, 't', 'f', '/payment/channel/alipay/manage/app/AlipayIsvAppManage', '/payment/config/product/app-manage', NULL, 3, 'f', 't', 'f', 1, 1, 0, 'f', 'subpage', NULL, NULL, NULL, NULL, NULL, NULL, '2026-06-14 00:00:00+00', '2026-06-14 00:00:00+00');
|
||||
INSERT INTO "public"."iam_perm_menu" VALUES (40503, 405, 'payment:wechat:isvApp', 'admin', 'WechatIsvAppManage', '微信服务商应用', 'WeChat ISV Application', 'menu.payment.wechat.isvApp', NULL, 't', 'f', '/payment/channel/wechat/manage/app/WechatIsvAppManage', '/payment/config/product/wechat-app-manage', NULL, 4, 'f', 't', 'f', 1, 1, 0, 'f', 'subpage', NULL, NULL, NULL, NULL, NULL, NULL, '2026-06-14 00:00:00+00', '2026-06-14 00:00:00+00');
|
||||
INSERT INTO "public"."iam_perm_menu" VALUES (4040115, 40401, 'payment:merchant:channelMerchant:douyinApp', 'admin', 'DouyinMchAppManage', '抖音通道商户应用', 'Douyin Channel Merchant App', 'menu.payment.merchant.channelMerchant.douyinApp', NULL, 't', 'f', '/payment/channel/douyin/manage/app/DouyinMchAppManage', '/payment/merchant/channel-merchant/douyin-app-manage', NULL, 13, 'f', 't', 'f', 1, 1, 0, 'f', 'subpage', NULL, NULL, NULL, NULL, NULL, NULL, '2026-06-15 16:00:00+00', '2026-06-15 16:00:00+00');
|
||||
INSERT INTO "public"."iam_perm_menu" VALUES (4040116, 401, 'payment:platform:provider', 'admin', 'PayProviderManage', '支付渠道', 'Payment Provider', 'menu.payment.platform.provider.manage', 'lucide:wallet', 'f', 'f', '/payment/masterdata/provider/PayProviderManage', '/payment/platform/pay-provider/manage', NULL, 0.5, 'f', 't', 'f', 1, 1, 0, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-06-17 10:00:31.640482+00', '2026-06-17 10:00:31.640482+00');
|
||||
INSERT INTO "public"."iam_perm_menu" VALUES (4040117, 401, 'payment:platform:provider', 'admin', 'PayProviderManage', '支付渠道', 'Payment Provider', 'menu.payment.platform.provider.manage', 'lucide:wallet', 'f', 'f', '/payment/masterdata/provider/PayProviderManage', '/payment/platform/pay-provider', NULL, 0.5, 'f', 't', 'f', 1, 1, 0, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-06-17 10:10:32.614861+00', '2026-06-17 10:10:32.614861+00');
|
||||
INSERT INTO "public"."iam_perm_menu" VALUES (4040116, 401, 'payment:platform:provider', 'admin', 'PayProviderManage', '支付渠道', 'Payment Provider', 'menu.payment.platform.provider.manage', 'lucide:wallet', 'f', 'f', '/payment/masterdata/provider/PayProviderList', '/payment/platform/pay-provider', NULL, 0.5, 'f', 't', 'f', 1, 1, 0, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-06-17 10:00:31.640482+00', '2026-06-17 10:00:31.640482+00');
|
||||
INSERT INTO "public"."iam_perm_menu" VALUES (204, 2, 'demos:artemis', 'admin', 'ArtemisDemo', '消息队列演示', 'Message Queue Demo', 'menu.demos.artemis', 'lucide:send', 'f', 'f', '/demos/artemis/ArtemisDemo', '/demos/artemis', NULL, 4, 'f', 't', 'f', 0, NULL, 0, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-06-18 00:00:00+00', '2026-06-18 00:00:00+00');
|
||||
INSERT INTO "public"."iam_perm_menu" VALUES (900001, 304, 'iam:social:config', 'admin', 'SocialConfig', '三方平台登录', 'Third-party Platform Login', 'menu.system.config.social', 'lucide:share-2', 'f', 'f', 'views/iam/social/social-config', '/system/config/social', NULL, 5, 'f', 't', 'f', 1, 1, 0, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
INSERT INTO "public"."iam_perm_menu" VALUES (205, 2, 'demos:channel', 'admin', 'ChannelDemo', '通道连通性演示', 'Channel Connectivity Demo', 'menu.demos.channel', 'lucide:radio-tower', 'f', 'f', '/demos/channel/ChannelDemo', '/demos/channel', NULL, 5, 'f', 't', 'f', 0, NULL, 0, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-06-23 00:00:00+00', '2026-06-23 00:00:00+00');
|
||||
|
||||
-- ----------------------------
|
||||
-- Primary Key structure for table iam_perm_menu
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package cn.daxpay.open.channel.alipay.client;
|
||||
|
||||
import cn.daxpay.open.channel.alipay.dto.AlipayPayReq;
|
||||
import cn.daxpay.open.channel.alipay.dto.AlipayPayResp;
|
||||
import cn.daxpay.open.payment.common.result.DaxResult;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.service.annotation.HttpExchange;
|
||||
import org.springframework.web.service.annotation.PostExchange;
|
||||
|
||||
/// # 支付宝通道客户端
|
||||
///
|
||||
/// 声明式 HTTP 接口, 调用子应用 dax-pay-channel-one 的支付宝通道接口。
|
||||
@HttpExchange(accept = MediaType.APPLICATION_JSON_VALUE, contentType = MediaType.APPLICATION_JSON_VALUE)
|
||||
public interface AlipayChannelClient {
|
||||
|
||||
/// 支付下单
|
||||
@PostExchange("/channel/pay")
|
||||
DaxResult<AlipayPayResp> pay(@RequestBody AlipayPayReq req);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package cn.daxpay.open.channel.alipay.config;
|
||||
|
||||
import cn.daxpay.open.channel.alipay.client.AlipayChannelClient;
|
||||
import cn.daxpay.open.platform.common.config.properties.DaxpayChannelProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.client.RestClient;
|
||||
import org.springframework.web.client.support.RestClientAdapter;
|
||||
import org.springframework.web.service.invoker.HttpServiceProxyFactory;
|
||||
|
||||
///
|
||||
/// 复用全局 [RestClient](由 common-spring 的 RestClientConfiguration 提供, 已预装:
|
||||
/// OTel traceparent 透传 / BusinessContextInterceptor 业务上下文透传 / Apache HttpClient5 连接池),
|
||||
/// 经 `mutate()` 派生出绑定 channel-one baseUrl 的实例。
|
||||
///
|
||||
/// baseUrl 从 [DaxpayChannelProperties] 统一读取。
|
||||
@Configuration
|
||||
public class AlipayClientConfig {
|
||||
|
||||
@Bean
|
||||
public AlipayChannelClient alipayChannelClient(
|
||||
RestClient restClient,
|
||||
DaxpayChannelProperties channelProperties) {
|
||||
// mutate 派生: 继承全局 RestClient 的拦截器 / observation / requestFactory, 仅覆盖 baseUrl
|
||||
RestClient channelClient = restClient
|
||||
.mutate()
|
||||
.baseUrl(channelProperties.getOne().getBaseUrl())
|
||||
.build();
|
||||
return HttpServiceProxyFactory
|
||||
.builderFor(RestClientAdapter.create(channelClient))
|
||||
.build()
|
||||
.createClient(AlipayChannelClient.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package cn.daxpay.open.channel.alipay.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/// # 支付宝通道支付请求
|
||||
///
|
||||
/// 与子应用 ChannelPayReq 字段一致, 通过 Jackson 序列化传输
|
||||
@Data
|
||||
public class AlipayPayReq {
|
||||
private String channel;
|
||||
private String bizOrderNo;
|
||||
private Long amount;
|
||||
private String subject;
|
||||
private String description;
|
||||
private String method;
|
||||
private String expireTime;
|
||||
private String otherMethod;
|
||||
private Map<String, Object> config;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package cn.daxpay.open.channel.alipay.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/// # 支付宝通道支付响应
|
||||
///
|
||||
/// 与子应用 ChannelPayResp 字段一致
|
||||
@Data
|
||||
public class AlipayPayResp {
|
||||
private String bizOrderNo;
|
||||
private String outOrderNo;
|
||||
private String transOrderNo;
|
||||
private String payBody;
|
||||
private String payBodyType;
|
||||
private Boolean complete;
|
||||
private String finishTime;
|
||||
}
|
||||
@@ -1,24 +1,35 @@
|
||||
package cn.daxpay.open.channel.alipay.service.pay;
|
||||
|
||||
import cn.daxpay.open.channel.alipay.client.AlipayChannelClient;
|
||||
import cn.daxpay.open.channel.alipay.dto.AlipayPayReq;
|
||||
import cn.daxpay.open.channel.alipay.dto.AlipayPayResp;
|
||||
import cn.daxpay.open.payment.common.result.DaxResult;
|
||||
import cn.daxpay.open.payment.pay.bo.PayTradeResultBo;
|
||||
import cn.daxpay.open.payment.pay.order.entity.PayTrade;
|
||||
import cn.daxpay.open.payment.unipay.param.trade.pay.PayParam;
|
||||
import cn.daxpay.open.platform.core.enums.unipay.PayBodyTypeEnum;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Map;
|
||||
|
||||
/// # 支付宝支付执行业务服务
|
||||
///
|
||||
/// 支付方式映射、通道请求组装、通道适配服务调用、支付结果转换。
|
||||
/// TODO Service 当前为占空实现, 后续补全支付执行流程逻辑。
|
||||
///
|
||||
/// 通过 [AlipayChannelClient] 调用子应用 dax-pay-channel-one 完成支付宝支付下单。
|
||||
/// 请求构建、响应解析全部在本类中完成。
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class AlipayPayService {
|
||||
|
||||
private static final BigDecimal HUNDRED = new BigDecimal("100");
|
||||
|
||||
private final AlipayChannelClient alipayChannelClient;
|
||||
|
||||
/// 执行支付宝支付
|
||||
///
|
||||
/// @param order 支付订单
|
||||
@@ -26,7 +37,50 @@ public class AlipayPayService {
|
||||
/// @param config 通道调用配置(密钥/证书/授权令牌等)
|
||||
/// @return 支付结果
|
||||
public PayTradeResultBo pay(PayTrade order, PayParam payParam, Map<String, Object> config) {
|
||||
// TODO 后续实现: method映射 → 组装ChannelPayReq → channelPayClient.pay → 结果转换
|
||||
throw new UnsupportedOperationException("AlipayPayService.pay 尚未实现");
|
||||
// 构建请求
|
||||
AlipayPayReq req = new AlipayPayReq();
|
||||
req.setChannel("alipay");
|
||||
req.setBizOrderNo(payParam.getBizOrderNo());
|
||||
req.setAmount(payParam.getAmount().multiply(HUNDRED).longValue());
|
||||
req.setSubject(payParam.getTitle());
|
||||
req.setDescription(payParam.getDescription());
|
||||
req.setMethod(payParam.getMethod());
|
||||
req.setConfig(config);
|
||||
|
||||
// 调用子应用
|
||||
DaxResult<AlipayPayResp> result = alipayChannelClient.pay(req);
|
||||
if (result.getCode() != 0) {
|
||||
throw new IllegalStateException("支付宝通道支付失败: " + result.getMsg());
|
||||
}
|
||||
|
||||
return toPayResult(result.getData());
|
||||
}
|
||||
|
||||
/// 解析子应用响应为支付结果 BO
|
||||
private PayTradeResultBo toPayResult(AlipayPayResp resp) {
|
||||
PayTradeResultBo bo = new PayTradeResultBo()
|
||||
.setOutOrderNo(resp.getOutOrderNo())
|
||||
.setComplete(Boolean.TRUE.equals(resp.getComplete()))
|
||||
.setPayBody(resp.getPayBody())
|
||||
.setTransOrderNo(resp.getTransOrderNo());
|
||||
|
||||
// 支付参数体类型
|
||||
String payBodyType = resp.getPayBodyType();
|
||||
if (payBodyType != null) {
|
||||
for (PayBodyTypeEnum type : PayBodyTypeEnum.values()) {
|
||||
if (type.getCode().equals(payBodyType)) {
|
||||
bo.setPayBodyType(type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 完成时间
|
||||
String finishTime = resp.getFinishTime();
|
||||
if (finishTime != null && !finishTime.isBlank()) {
|
||||
bo.setFinishTime(OffsetDateTime.parse(finishTime, DateTimeFormatter.ISO_DATE_TIME));
|
||||
}
|
||||
|
||||
return bo;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package cn.daxpay.open.channel.douyin.client;
|
||||
|
||||
import cn.daxpay.open.channel.douyin.dto.DouyinPayReq;
|
||||
import cn.daxpay.open.channel.douyin.dto.DouyinPayResp;
|
||||
import cn.daxpay.open.payment.common.result.DaxResult;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.service.annotation.HttpExchange;
|
||||
import org.springframework.web.service.annotation.PostExchange;
|
||||
|
||||
/// # 抖音通道客户端
|
||||
///
|
||||
/// 声明式 HTTP 接口, 调用子应用 dax-pay-channel-one 的抖音通道接口。
|
||||
@HttpExchange(accept = MediaType.APPLICATION_JSON_VALUE, contentType = MediaType.APPLICATION_JSON_VALUE)
|
||||
public interface DouyinChannelClient {
|
||||
|
||||
/// 支付下单
|
||||
@PostExchange("/channel/pay")
|
||||
DaxResult<DouyinPayResp> pay(@RequestBody DouyinPayReq req);
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package cn.daxpay.open.channel.douyin.config;
|
||||
|
||||
import cn.daxpay.open.channel.douyin.client.DouyinChannelClient;
|
||||
import cn.daxpay.open.platform.common.config.properties.DaxpayChannelProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.client.RestClient;
|
||||
import org.springframework.web.client.support.RestClientAdapter;
|
||||
import org.springframework.web.service.invoker.HttpServiceProxyFactory;
|
||||
|
||||
/// # 抖音通道客户端配置
|
||||
///
|
||||
/// 复用全局 [RestClient](由 common-spring 的 RestClientConfiguration 提供, 已预装:
|
||||
/// OTel traceparent 透传 / BusinessContextInterceptor 业务上下文透传 / Apache HttpClient5 连接池),
|
||||
/// 经 `mutate()` 派生出绑定 channel-one baseUrl 的实例。
|
||||
///
|
||||
/// baseUrl 从 [DaxpayChannelProperties] 统一读取。
|
||||
@Configuration
|
||||
public class DouyinClientConfig {
|
||||
|
||||
@Bean
|
||||
public DouyinChannelClient douyinChannelClient(
|
||||
RestClient restClient,
|
||||
DaxpayChannelProperties channelProperties) {
|
||||
// mutate 派生: 继承全局 RestClient 的拦截器 / observation / requestFactory, 仅覆盖 baseUrl
|
||||
RestClient channelClient = restClient
|
||||
.mutate()
|
||||
.baseUrl(channelProperties.getOne().getBaseUrl())
|
||||
.build();
|
||||
return HttpServiceProxyFactory
|
||||
.builderFor(RestClientAdapter.create(channelClient))
|
||||
.build()
|
||||
.createClient(DouyinChannelClient.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package cn.daxpay.open.channel.douyin.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/// # 抖音通道支付请求
|
||||
///
|
||||
/// 与子应用 ChannelPayReq 字段一致, 通过 Jackson 序列化传输
|
||||
@Data
|
||||
public class DouyinPayReq {
|
||||
private String channel;
|
||||
private String bizOrderNo;
|
||||
private Long amount;
|
||||
private String subject;
|
||||
private String description;
|
||||
private String method;
|
||||
private String expireTime;
|
||||
private String otherMethod;
|
||||
private Map<String, Object> config;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package cn.daxpay.open.channel.douyin.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/// # 抖音通道支付响应
|
||||
///
|
||||
/// 与子应用 ChannelPayResp 字段一致
|
||||
@Data
|
||||
public class DouyinPayResp {
|
||||
private String bizOrderNo;
|
||||
private String outOrderNo;
|
||||
private String transOrderNo;
|
||||
private String payBody;
|
||||
private String payBodyType;
|
||||
private Boolean complete;
|
||||
private String finishTime;
|
||||
}
|
||||
@@ -1,21 +1,32 @@
|
||||
package cn.daxpay.open.channel.douyin.strategy;
|
||||
|
||||
import cn.daxpay.open.platform.core.enums.pay.channel.ProductEnum;
|
||||
import cn.daxpay.open.channel.douyin.client.DouyinChannelClient;
|
||||
import cn.daxpay.open.channel.douyin.dto.DouyinPayReq;
|
||||
import cn.daxpay.open.channel.douyin.dto.DouyinPayResp;
|
||||
import cn.daxpay.open.payment.common.result.DaxResult;
|
||||
import cn.daxpay.open.payment.pay.bo.PayTradeResultBo;
|
||||
import cn.daxpay.open.payment.strategy.pay.AbsPayStrategy;
|
||||
import cn.daxpay.open.platform.core.enums.pay.channel.ProductEnum;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Map;
|
||||
|
||||
/// # 抖音支付直连支付策略
|
||||
///
|
||||
/// 抖音支付直连模式的支付策略(虚类,暂未实现具体支付逻辑)。
|
||||
///
|
||||
/// 通过 [DouyinChannelClient] 调用子应用 dax-pay-channel-one 完成抖音支付下单。
|
||||
/// TODO 通道配置获取逻辑待补充(需抖音通道配置管理实体)
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class DouyinDirectPayStrategy extends AbsPayStrategy {
|
||||
|
||||
private static final BigDecimal HUNDRED = new BigDecimal("100");
|
||||
|
||||
private final DouyinChannelClient douyinChannelClient;
|
||||
|
||||
@Override
|
||||
public ProductEnum getProduct() {
|
||||
return ProductEnum.DOUYIN_PAY;
|
||||
@@ -23,6 +34,28 @@ public class DouyinDirectPayStrategy extends AbsPayStrategy {
|
||||
|
||||
@Override
|
||||
public PayTradeResultBo doPayHandler() {
|
||||
throw new UnsupportedOperationException("抖音支付直连暂未实现");
|
||||
// 构建请求
|
||||
DouyinPayReq req = new DouyinPayReq();
|
||||
req.setChannel(ProductEnum.DOUYIN_PAY.getChannel());
|
||||
req.setBizOrderNo(getPayParam().getBizOrderNo());
|
||||
req.setAmount(getPayParam().getAmount().multiply(HUNDRED).longValue());
|
||||
req.setSubject(getPayParam().getTitle());
|
||||
req.setMethod(getPayParam().getMethod());
|
||||
// TODO 从数据库获取抖音通道配置
|
||||
req.setConfig(Map.of());
|
||||
|
||||
// 调用子应用
|
||||
DaxResult<DouyinPayResp> result = douyinChannelClient.pay(req);
|
||||
if (result.getCode() != 0) {
|
||||
throw new IllegalStateException("抖音通道支付失败: " + result.getMsg());
|
||||
}
|
||||
|
||||
// 解析响应
|
||||
DouyinPayResp data = result.getData();
|
||||
return new PayTradeResultBo()
|
||||
.setOutOrderNo(data.getOutOrderNo())
|
||||
.setComplete(Boolean.TRUE.equals(data.getComplete()))
|
||||
.setPayBody(data.getPayBody())
|
||||
.setTransOrderNo(data.getTransOrderNo());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,14 @@
|
||||
<artifactId>common-artemis</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 支付宝通道模块 -->
|
||||
<!-- 提供 AlipayChannelClient (@HttpExchange) 及 AlipayPayReq/AlipayPayResp DTO, 供 Demo 控制器直接调用子应用 -->
|
||||
<dependency>
|
||||
<groupId>cn.daxpay.open</groupId>
|
||||
<artifactId>daxpay-channel-alipay</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
package cn.daxpay.open.demo.channel.controller;
|
||||
|
||||
import cn.daxpay.open.channel.alipay.client.AlipayChannelClient;
|
||||
import cn.daxpay.open.channel.alipay.dto.AlipayPayReq;
|
||||
import cn.daxpay.open.channel.alipay.dto.AlipayPayResp;
|
||||
import cn.daxpay.open.demo.channel.param.ChannelDemoPayParam;
|
||||
import cn.daxpay.open.demo.channel.result.ChannelDemoPayResult;
|
||||
import cn.daxpay.open.platform.core.annotation.IgnoreAuth;
|
||||
import cn.daxpay.open.platform.core.rest.Res;
|
||||
import cn.daxpay.open.platform.core.rest.result.Result;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.MDC;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Map;
|
||||
|
||||
/// # 通道连通性 Demo 接口
|
||||
///
|
||||
/// 演示主应用通过 @HttpExchange 客户端调用子应用 dax-pay-channel-one 的完整链路。
|
||||
/// 前端发起请求 → 主应用构建 AlipayPayReq → AlipayChannelClient 发送 HTTP → 子应用接收并处理 → 响应返回。
|
||||
///
|
||||
/// 鉴权: URL 前缀 `/demo/**` 已在白名单, 类上叠加 `@IgnoreAuth` 双保险。
|
||||
@Slf4j
|
||||
@IgnoreAuth
|
||||
@Validated
|
||||
@Tag(name = "通道连通性演示")
|
||||
@RestController
|
||||
@RequestMapping("/demo/channel")
|
||||
@RequiredArgsConstructor
|
||||
public class ChannelDemoController {
|
||||
|
||||
private static final BigDecimal HUNDRED = new BigDecimal("100");
|
||||
|
||||
private final AlipayChannelClient alipayChannelClient;
|
||||
|
||||
/// 发起 Demo 支付请求到子应用
|
||||
///
|
||||
/// 通过 @HttpExchange 声明式客户端将请求转发到 dax-pay-channel-one 的 `/channel/pay` 端点。
|
||||
/// config 传空 Map, 子应用进入 Demo 模式返回模拟响应。
|
||||
@Operation(summary = "发起通道 Demo 支付")
|
||||
@PostMapping("/pay")
|
||||
public Result<ChannelDemoPayResult> pay(@Validated @RequestBody ChannelDemoPayParam param) {
|
||||
log.info("🚀 Demo: 主应用发起通道支付请求, bizOrderNo={}", param.getBizOrderNo());
|
||||
|
||||
// 构建通道请求
|
||||
AlipayPayReq req = new AlipayPayReq();
|
||||
req.setChannel("alipay");
|
||||
req.setBizOrderNo(param.getBizOrderNo());
|
||||
req.setAmount(param.getAmount().multiply(HUNDRED).longValue());
|
||||
req.setSubject(param.getSubject());
|
||||
req.setMethod(param.getMethod());
|
||||
// 空配置 → 子应用进入 Demo 模式
|
||||
req.setConfig(Map.of());
|
||||
|
||||
// 调用子应用 (通过 @HttpExchange, OTel 自动透传 traceId)
|
||||
var channelResult = alipayChannelClient.pay(req);
|
||||
if (channelResult.getCode() != 0) {
|
||||
throw new RuntimeException("通道支付失败: " + channelResult.getMsg());
|
||||
}
|
||||
|
||||
AlipayPayResp resp = channelResult.getData();
|
||||
|
||||
// 构建返回结果 (包含双端 traceId 用于链路对照)
|
||||
ChannelDemoPayResult result = new ChannelDemoPayResult();
|
||||
result.setBizOrderNo(resp.getBizOrderNo());
|
||||
result.setOutOrderNo(resp.getOutOrderNo());
|
||||
result.setPayBody(resp.getPayBody());
|
||||
result.setPayBodyType(resp.getPayBodyType());
|
||||
result.setMainAppTraceId(MDC.get("traceId"));
|
||||
result.setSubAppTraceId(channelResult.getTraceId());
|
||||
|
||||
log.info("✅ Demo: 收到子应用响应, outOrderNo={}, subAppTraceId={}",
|
||||
result.getOutOrderNo(), result.getSubAppTraceId());
|
||||
|
||||
return Res.ok(result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package cn.daxpay.open.demo.channel.param;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.DecimalMin;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/// # 通道连通性 Demo 支付参数
|
||||
///
|
||||
/// 前端表单提交的简化参数, 不涉及真实支付订单实体。
|
||||
@Data
|
||||
@Schema(description = "通道 Demo 支付参数")
|
||||
public class ChannelDemoPayParam {
|
||||
|
||||
/// 商户订单号
|
||||
@Schema(description = "商户订单号")
|
||||
@NotBlank(message = "{validation.field.bizOrderNo.notBlank}")
|
||||
private String bizOrderNo;
|
||||
|
||||
/// 支付金额(元)
|
||||
@Schema(description = "支付金额(元)")
|
||||
@NotNull(message = "{validation.field.amount.notNull}")
|
||||
@DecimalMin(value = "0.01", message = "{validation.field.amount.min}")
|
||||
private BigDecimal amount;
|
||||
|
||||
/// 支付标题
|
||||
@Schema(description = "支付标题")
|
||||
@NotBlank(message = "{validation.field.subject.notBlank}")
|
||||
private String subject;
|
||||
|
||||
/// 支付方式(alipay_wap / alipay_app / alipay_page / alipay_qr)
|
||||
@Schema(description = "支付方式", example = "alipay_qr")
|
||||
@NotBlank(message = "{validation.field.method.notBlank}")
|
||||
private String method;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package cn.daxpay.open.demo.channel.result;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
/// # 通道连通性 Demo 支付结果
|
||||
///
|
||||
/// 展示主应用 → 子应用往返的完整信息, 包含双端 traceId 用于链路对照。
|
||||
@Data
|
||||
@Schema(description = "通道 Demo 支付结果")
|
||||
public class ChannelDemoPayResult {
|
||||
|
||||
/// 商户订单号
|
||||
@Schema(description = "商户订单号")
|
||||
private String bizOrderNo;
|
||||
|
||||
/// 通道侧订单号
|
||||
@Schema(description = "通道侧订单号")
|
||||
private String outOrderNo;
|
||||
|
||||
/// 支付内容(支付链接 / 二维码 / 表单等)
|
||||
@Schema(description = "支付内容")
|
||||
private String payBody;
|
||||
|
||||
/// 支付内容类型(qr_code / form / order_id)
|
||||
@Schema(description = "支付内容类型")
|
||||
private String payBodyType;
|
||||
|
||||
/// 主应用 traceId
|
||||
@Schema(description = "主应用 traceId")
|
||||
private String mainAppTraceId;
|
||||
|
||||
/// 子应用 traceId
|
||||
@Schema(description = "子应用 traceId")
|
||||
private String subAppTraceId;
|
||||
}
|
||||
@@ -3,7 +3,7 @@ package cn.daxpay.open.payment.old.pay.channel;
|
||||
import cn.daxpay.open.payment.old.pay.channel.dto.ChannelPayReq;
|
||||
import cn.daxpay.open.payment.old.pay.channel.dto.ChannelPayResp;
|
||||
import cn.daxpay.open.payment.old.pay.channel.dto.ChannelResult;
|
||||
import cn.daxpay.open.platform.common.config.properties.PlatformCommonProperties;
|
||||
import cn.daxpay.open.platform.common.config.properties.DaxpayChannelProperties;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
@@ -13,7 +13,7 @@ import org.springframework.web.client.RestClient;
|
||||
/// # 通道服务 HTTP 客户端
|
||||
///
|
||||
/// 封装对通道适配服务(daxpay-channel-one)的 HTTP 调用,统一处理地址拼接、结果解析与异常转换。
|
||||
/// baseUrl 来自 [PlatformCommonProperties.ChannelOne] 配置。
|
||||
/// baseUrl 来自 [DaxpayChannelProperties] 配置。
|
||||
///
|
||||
@Slf4j
|
||||
@Component
|
||||
@@ -21,14 +21,14 @@ import org.springframework.web.client.RestClient;
|
||||
public class ChannelPayClient {
|
||||
|
||||
private final RestClient restClient;
|
||||
private final PlatformCommonProperties properties;
|
||||
private final DaxpayChannelProperties channelProperties;
|
||||
|
||||
/// 发起支付下单调用
|
||||
///
|
||||
/// @param req 通道支付请求
|
||||
/// @return 通道支付响应
|
||||
public ChannelPayResp pay(ChannelPayReq req) {
|
||||
String url = properties.getChannelOne().getBaseUrl() + "/channel/pay";
|
||||
String url = channelProperties.getOne().getBaseUrl() + "/channel/pay";
|
||||
ChannelResult<ChannelPayResp> result = restClient.post()
|
||||
.uri(url)
|
||||
.body(req)
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package cn.daxpay.open.platform.common.config.properties;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/// # 通道适配子应用配置
|
||||
///
|
||||
/// 统一管理各通道适配子应用(dax-pay-channel-one/two/...)的连接地址。
|
||||
/// 各通道模块通过注入本类获取对应子应用的 baseUrl。
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@ConfigurationProperties(prefix = "daxpay.channel")
|
||||
public class DaxpayChannelProperties {
|
||||
|
||||
/// 子应用1(支付宝/微信)
|
||||
private ChannelApp one = new ChannelApp();
|
||||
|
||||
/// 子应用2(银联/拉卡拉) — 未来扩展
|
||||
private ChannelApp two = new ChannelApp();
|
||||
|
||||
/// 子应用3(抖音/其他) — 未来扩展
|
||||
private ChannelApp three = new ChannelApp();
|
||||
|
||||
/// # 子应用连接配置
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public static class ChannelApp {
|
||||
|
||||
/// 基础地址
|
||||
private String baseUrl = "http://127.0.0.1:20100";
|
||||
}
|
||||
}
|
||||
@@ -19,8 +19,6 @@ public class PlatformCommonProperties {
|
||||
private Spring spring = new Spring();
|
||||
/// Swagger 配置
|
||||
private Swagger swagger = new Swagger();
|
||||
/// 通道适配服务配置
|
||||
private ChannelOne channelOne = new ChannelOne();
|
||||
|
||||
/// # 缓存配置
|
||||
///
|
||||
@@ -100,14 +98,6 @@ public class PlatformCommonProperties {
|
||||
private Integer connectionRequestTimeout = 3;
|
||||
}
|
||||
}
|
||||
/// # 通道适配服务配置
|
||||
///
|
||||
@Data
|
||||
public static class ChannelOne {
|
||||
/// 通道服务基础地址
|
||||
private String baseUrl = "http://127.0.0.1:20100";
|
||||
}
|
||||
|
||||
/// # Swagger 配置
|
||||
///
|
||||
@Data
|
||||
|
||||
@@ -18,6 +18,11 @@
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<!-- RestClient 声明式 HTTP 客户端(Spring Boot 4 拆为独立 starter, 提供 RestClient.Builder 自动配置 + W3C traceparent 透传) -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-restclient</artifactId>
|
||||
</dependency>
|
||||
<!-- 切面 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
|
||||
@@ -9,6 +9,7 @@ import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
|
||||
import org.apache.hc.client5.http.impl.classic.HttpClients;
|
||||
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
|
||||
import org.apache.hc.core5.util.Timeout;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
@@ -80,12 +81,13 @@ public class RestClientConfiguration {
|
||||
|
||||
/// 创建 RestClient Bean
|
||||
///
|
||||
/// 使用自动配置的 RestClient.Builder 而非静态 [RestClient.builder],
|
||||
/// 以便 OTel 拦截器自动注入(W3C traceparent 头自动透传)。
|
||||
/// 优先使用 Spring Boot 自动配置的 RestClient.Builder(携带 OTel 拦截器,
|
||||
/// 自动透传 W3C traceparent); 若 autoconfiguration 未注册则 fallback 到 [RestClient.builder]。
|
||||
@Bean
|
||||
public RestClient restClient(RestClient.Builder restClientBuilder,
|
||||
public RestClient restClient(ObjectProvider<RestClient.Builder> builderProvider,
|
||||
HttpComponentsClientHttpRequestFactory httpRequestFactory) {
|
||||
return restClientBuilder
|
||||
RestClient.Builder builder = builderProvider.getIfAvailable(RestClient::builder);
|
||||
return builder
|
||||
.requestFactory(httpRequestFactory)
|
||||
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
|
||||
.requestInterceptor(new BusinessContextInterceptor())
|
||||
|
||||
Reference in New Issue
Block a user