mirror of
https://gitee.com/dromara/dax-pay
synced 2026-08-09 22:45:58 +08:00
fix(docs): 修正 /// Markdown 本类成员链接写法为 [#member]
JEP 467 中 [name] 按类型解析,方法/字段/枚举常量应使用 [#name], 消除 IDEA 未解析引用报红;跨类 Type#member 保持不变。
This commit is contained in:
@@ -15,7 +15,7 @@ import org.springframework.stereotype.Service;
|
||||
/// # Adapay 直连支付策略
|
||||
///
|
||||
/// Adapay 支付(ProductEnum.ADA_PAY)下发起支付的具体执行策略。
|
||||
/// 配置组装在 [doBeforePay] 阶段完成(委托 [AdapayDirectConfigAssembler]),
|
||||
/// 配置组装在 [#doBeforePay] 阶段完成(委托 [AdapayDirectConfigAssembler]),
|
||||
/// 支付执行委托给 [AdapayPayService]。
|
||||
@Slf4j
|
||||
@Service
|
||||
|
||||
@@ -2,6 +2,7 @@ package cn.daxpay.open.channel.alipay.dao.direct;
|
||||
|
||||
import cn.daxpay.open.platform.common.mybatisplus.impl.BaseManager;
|
||||
import cn.daxpay.open.channel.alipay.entity.direct.AlipayDirectApp;
|
||||
import cn.daxpay.open.platform.core.annotation.IgnoreTenant;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -11,7 +12,9 @@ import java.util.Optional;
|
||||
|
||||
/// # 支付宝直连商户应用
|
||||
///
|
||||
/// 直连商户应用数据访问管理器,提供按商户号和通道商户号查询列表、同一通道下应用ID唯一性校验等方法。
|
||||
/// - 配置态 CRUD: [#listByMchNoAndChannelMchNo]、[#existsByChannelMchNoAndAliAppId]、[#findFirstByMchNo]
|
||||
/// - 支付/回调(已装载 mchNo): 租户内 [#findFirstByChannelMchNo]、[#findFirstByChannelMchNoAndAppType]
|
||||
/// - 认证引导: 方法名带 NotTenant
|
||||
///
|
||||
@Slf4j
|
||||
@Service
|
||||
@@ -46,7 +49,7 @@ public class AlipayDirectAppManager extends BaseManager<AlipayDirectAppMapper, A
|
||||
.orderByAsc(AlipayDirectApp::getId));
|
||||
}
|
||||
|
||||
/// 根据通道商户号与应用类型查询首个应用(appType自动推导时使用, 按创建时间升序取第一条)
|
||||
/// 根据通道商户号与应用类型查询首个应用(支付/回调,租户内)
|
||||
public Optional<AlipayDirectApp> findFirstByChannelMchNoAndAppType(String channelMchNo, String appType) {
|
||||
return firstOpt(q -> q
|
||||
.eq(AlipayDirectApp::getChannelMchNo, channelMchNo)
|
||||
@@ -55,11 +58,24 @@ public class AlipayDirectAppManager extends BaseManager<AlipayDirectAppMapper, A
|
||||
.orderByAsc(AlipayDirectApp::getId));
|
||||
}
|
||||
|
||||
/// 根据通道商户号查询首个应用(兜底回退使用, 按创建时间升序取第一条)
|
||||
/// 根据通道商户号查询首个应用(支付/回调,租户内)
|
||||
public Optional<AlipayDirectApp> findFirstByChannelMchNo(String channelMchNo) {
|
||||
return firstOpt(q -> q
|
||||
.eq(AlipayDirectApp::getChannelMchNo, channelMchNo)
|
||||
.orderByAsc(AlipayDirectApp::getCreateTime)
|
||||
.orderByAsc(AlipayDirectApp::getId));
|
||||
}
|
||||
|
||||
/// 根据通道商户号与应用类型查询首个应用(认证引导,忽略租户)
|
||||
@IgnoreTenant
|
||||
public Optional<AlipayDirectApp> findFirstByChannelMchNoAndAppTypeNotTenant(String channelMchNo, String appType) {
|
||||
return findFirstByChannelMchNoAndAppType(channelMchNo, appType);
|
||||
}
|
||||
|
||||
/// 根据通道商户号查询首个应用(认证引导,忽略租户)
|
||||
@IgnoreTenant
|
||||
public Optional<AlipayDirectApp> findFirstByChannelMchNoNotTenant(String channelMchNo) {
|
||||
return findFirstByChannelMchNo(channelMchNo);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import cn.daxpay.open.platform.core.code.CommonErrorCode;
|
||||
import cn.daxpay.open.platform.core.enums.pay.channel.PayCapabilityEnum;
|
||||
import cn.daxpay.open.platform.core.enums.pay.channel.ProductEnum;
|
||||
import cn.daxpay.open.platform.core.exception.BizInfoException;
|
||||
import cn.daxpay.open.platform.core.annotation.IgnoreTenant;
|
||||
import cn.daxpay.open.payment.core.strategy.PaymentStrategyFactory;
|
||||
import cn.daxpay.open.payment.core.strategy.product.AbsProductStrategy;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
@@ -34,7 +35,7 @@ import java.util.stream.Collectors;
|
||||
/// # 支付宝直连商户应用支付能力关联
|
||||
///
|
||||
/// 管理通道商户维度下「支付能力 → 应用」的绑定关系。
|
||||
/// 支付时通过 [resolveApp] 解析当前能力对应的应用:显式配置 > appType自动推导。
|
||||
/// 支付时通过 [#resolveApp] 解析当前能力对应的应用:显式配置 > appType自动推导。
|
||||
///
|
||||
@Slf4j
|
||||
@Service
|
||||
@@ -102,7 +103,9 @@ public class AlipayDirectAppCapabilityService {
|
||||
capabilityManager.deleteByAlipayDirectAppId(alipayDirectAppId);
|
||||
}
|
||||
|
||||
/// 支付时解析当前支付能力对应的应用:显式配置 > appType自动推导
|
||||
/// 支付/回调解析应用:显式配置 > appType 自动推导(须已装载 mchNo,租户内)
|
||||
///
|
||||
/// 认证无上下文请用 [#resolveAppNotTenant]。
|
||||
///
|
||||
/// @param channelMchNo 通道商户号
|
||||
/// @param capability 支付能力编码
|
||||
@@ -124,6 +127,12 @@ public class AlipayDirectAppCapabilityService {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
/// 认证等无租户上下文时解析应用(忽略租户)
|
||||
@IgnoreTenant
|
||||
public Optional<AlipayDirectApp> resolveAppNotTenant(String channelMchNo, String capability) {
|
||||
return resolveApp(channelMchNo, capability);
|
||||
}
|
||||
|
||||
/// 查询支付宝直连产品支持的支付能力候选列表(含国际化名称)
|
||||
public List<AlipayDirectCapabilityOption> listSupportedCapabilities() {
|
||||
AbsProductStrategy strategy = PaymentStrategyFactory.createByProduct(
|
||||
|
||||
@@ -15,7 +15,7 @@ import org.springframework.stereotype.Service;
|
||||
/// # 支付宝直连支付策略
|
||||
///
|
||||
/// 支付宝直连模式(ProductEnum.ALIPAY)下发起支付的具体执行策略。
|
||||
/// 配置组装在 [doBeforePay] 阶段完成(委托 [AlipayDirectConfigAssembler]), 支付执行委托给 [AlipayPayService]。
|
||||
/// 配置组装在 [#doBeforePay] 阶段完成(委托 [AlipayDirectConfigAssembler]), 支付执行委托给 [AlipayPayService]。
|
||||
///
|
||||
@Slf4j
|
||||
@Service
|
||||
|
||||
@@ -14,7 +14,7 @@ import org.springframework.stereotype.Service;
|
||||
/// # 支付宝服务商支付策略
|
||||
///
|
||||
/// 支付宝服务商模式(ProductEnum.ALIPAY_ISV)下发起支付的具体执行策略。
|
||||
/// 配置组装(含应用授权令牌)在 [doBeforePay] 阶段完成(委托 [AlipayIsvConfigAssembler]), 支付执行委托给 [AlipayPayService]。
|
||||
/// 配置组装(含应用授权令牌)在 [#doBeforePay] 阶段完成(委托 [AlipayIsvConfigAssembler]), 支付执行委托给 [AlipayPayService]。
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
|
||||
@@ -14,7 +14,7 @@ import org.springframework.stereotype.Service;
|
||||
|
||||
/// # 斗拱服务商支付策略
|
||||
///
|
||||
/// 配置组装在 [doBeforePay] 阶段完成(委托 [DougongIsvConfigAssembler]),
|
||||
/// 配置组装在 [#doBeforePay] 阶段完成(委托 [DougongIsvConfigAssembler]),
|
||||
/// 支付执行委托给 [DougongPayService]。
|
||||
///
|
||||
/// 斗拱为聚合服务商模式, 仅有一个产品 DOUGONG_PAY(覆盖微信/支付宝/银联)。
|
||||
|
||||
@@ -2,6 +2,7 @@ package cn.daxpay.open.channel.douyin.dao.direct;
|
||||
|
||||
import cn.daxpay.open.channel.douyin.entity.direct.DouyinDirectApp;
|
||||
import cn.daxpay.open.platform.common.mybatisplus.impl.BaseManager;
|
||||
import cn.daxpay.open.platform.core.annotation.IgnoreTenant;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
@@ -9,7 +10,9 @@ import java.util.Optional;
|
||||
|
||||
/// # 抖音直连商户应用
|
||||
///
|
||||
/// 直连商户应用数据访问管理器,提供按商户号和通道商户号查询列表、同一通道下应用ID唯一性校验等方法。
|
||||
/// - 配置态 CRUD: [#listByMchNoAndChannelMchNo]、[#existsByChannelMchNoAndDouyinAppId]
|
||||
/// - 支付/回调(已装载 mchNo): 租户内 [#findFirstByChannelMchNo]、[#findFirstByChannelMchNoAndAppType]
|
||||
/// - 认证引导: 方法名带 NotTenant
|
||||
///
|
||||
@Repository
|
||||
public class DouyinDirectAppManager extends BaseManager<DouyinDirectAppMapper, DouyinDirectApp> {
|
||||
@@ -34,20 +37,37 @@ public class DouyinDirectAppManager extends BaseManager<DouyinDirectAppMapper, D
|
||||
.exists();
|
||||
}
|
||||
|
||||
/// 按通道商户号查询首个应用(能力解析兜底时使用)
|
||||
/// 根据通道商户号取首个应用(支付/回调,租户内)
|
||||
public Optional<DouyinDirectApp> findFirstByChannelMchNo(String channelMchNo) {
|
||||
return firstOpt(q -> q
|
||||
return lambdaQuery()
|
||||
.eq(DouyinDirectApp::getChannelMchNo, channelMchNo)
|
||||
.orderByAsc(DouyinDirectApp::getCreateTime)
|
||||
.orderByAsc(DouyinDirectApp::getId));
|
||||
.orderByAsc(DouyinDirectApp::getId)
|
||||
.last("limit 1")
|
||||
.oneOpt();
|
||||
}
|
||||
|
||||
/// 按通道商户号与应用类型查询首个应用(appType自动推导时使用)
|
||||
/// 根据通道商户号与应用类型取首个应用(支付/回调,租户内)
|
||||
public Optional<DouyinDirectApp> findFirstByChannelMchNoAndAppType(String channelMchNo, String appType) {
|
||||
return firstOpt(q -> q
|
||||
return lambdaQuery()
|
||||
.eq(DouyinDirectApp::getChannelMchNo, channelMchNo)
|
||||
.eq(DouyinDirectApp::getAppType, appType)
|
||||
.orderByAsc(DouyinDirectApp::getCreateTime)
|
||||
.orderByAsc(DouyinDirectApp::getId));
|
||||
.orderByAsc(DouyinDirectApp::getId)
|
||||
.last("limit 1")
|
||||
.oneOpt();
|
||||
}
|
||||
|
||||
/// 根据通道商户号取首个应用(认证引导,忽略租户)
|
||||
@IgnoreTenant
|
||||
public Optional<DouyinDirectApp> findFirstByChannelMchNoNotTenant(String channelMchNo) {
|
||||
return findFirstByChannelMchNo(channelMchNo);
|
||||
}
|
||||
|
||||
/// 根据通道商户号与应用类型取首个应用(认证引导,忽略租户)
|
||||
@IgnoreTenant
|
||||
public Optional<DouyinDirectApp> findFirstByChannelMchNoAndAppTypeNotTenant(String channelMchNo, String appType) {
|
||||
return findFirstByChannelMchNoAndAppType(channelMchNo, appType);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import cn.daxpay.open.platform.common.i18n.util.I18nUtil;
|
||||
import cn.daxpay.open.platform.core.code.CommonErrorCode;
|
||||
import cn.daxpay.open.platform.core.enums.pay.channel.ProductEnum;
|
||||
import cn.daxpay.open.platform.core.exception.BizInfoException;
|
||||
import cn.daxpay.open.platform.core.annotation.IgnoreTenant;
|
||||
import cn.daxpay.open.payment.core.strategy.PaymentStrategyFactory;
|
||||
import cn.daxpay.open.payment.core.strategy.product.AbsProductStrategy;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
@@ -33,7 +34,7 @@ import java.util.stream.Collectors;
|
||||
/// # 抖音直连商户应用支付能力关联
|
||||
///
|
||||
/// 管理通道商户维度下「支付能力 → 直连应用」的绑定关系。
|
||||
/// 支付时通过 [resolveApp] 解析当前能力对应的应用:显式配置 > appType自动推导 > 通道商户首个兜底。
|
||||
/// 支付时通过 [#resolveApp] 解析当前能力对应的应用:显式配置 > appType自动推导 > 通道商户首个兜底。
|
||||
///
|
||||
@Slf4j
|
||||
@Service
|
||||
@@ -101,7 +102,9 @@ public class DouyinDirectAppCapabilityService {
|
||||
capabilityManager.deleteByDouyinDirectAppId(douyinDirectAppId);
|
||||
}
|
||||
|
||||
/// 支付时解析当前支付能力对应的应用:显式配置 > appType自动推导 > 通道商户首个兜底
|
||||
/// 支付/回调解析应用:显式配置 > appType 自动推导 > 通道商户首个兜底(须已装载 mchNo,租户内)
|
||||
///
|
||||
/// 认证无上下文请用 [#resolveAppNotTenant]。
|
||||
///
|
||||
/// @param channelMchNo 通道商户号
|
||||
/// @param capability 支付能力编码
|
||||
@@ -127,6 +130,12 @@ public class DouyinDirectAppCapabilityService {
|
||||
return douyinDirectAppManager.findFirstByChannelMchNo(channelMchNo);
|
||||
}
|
||||
|
||||
/// 认证等无租户上下文时解析应用(忽略租户)
|
||||
@IgnoreTenant
|
||||
public Optional<DouyinDirectApp> resolveAppNotTenant(String channelMchNo, String capability) {
|
||||
return resolveApp(channelMchNo, capability);
|
||||
}
|
||||
|
||||
/// 查询抖音直连产品支持的支付能力候选列表(含国际化名称)
|
||||
public List<DouyinCapabilityOption> listSupportedCapabilities() {
|
||||
AbsProductStrategy strategy = PaymentStrategyFactory.createByProduct(
|
||||
|
||||
@@ -15,7 +15,7 @@ import org.springframework.stereotype.Service;
|
||||
/// # 抖音支付直连支付策略
|
||||
///
|
||||
/// 抖音直连模式(ProductEnum.DOUYIN_PAY)下发起支付的具体执行策略。
|
||||
/// 配置组装在 [doBeforePay] 阶段完成(委托 [DouyinDirectConfigAssembler]), 支付执行委托给 [DouyinPayService]。
|
||||
/// 配置组装在 [#doBeforePay] 阶段完成(委托 [DouyinDirectConfigAssembler]), 支付执行委托给 [DouyinPayService]。
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
|
||||
@@ -15,7 +15,7 @@ import org.springframework.stereotype.Service;
|
||||
/// # 富友服务商支付策略
|
||||
///
|
||||
/// 富友支付(ProductEnum.FUYOU_PAY)下发起支付的具体执行策略。
|
||||
/// 配置组装在 [doBeforePay] 阶段完成(委托 [FuyouIsvConfigAssembler]), 支付执行委托给 [FuyouPayService]。
|
||||
/// 配置组装在 [#doBeforePay] 阶段完成(委托 [FuyouIsvConfigAssembler]), 支付执行委托给 [FuyouPayService]。
|
||||
///
|
||||
/// 富友为聚合服务商模式, 不区分直连/服务商, 仅有一个产品 FUYOU_PAY。
|
||||
@Slf4j
|
||||
|
||||
@@ -38,7 +38,7 @@ public class HkrtIsvKeyConfigService {
|
||||
|
||||
/// 支付场景查询服务商密钥(必填校验, 不创建记录)
|
||||
///
|
||||
/// 与 [findByProduct] 的 upsert 语义不同, 此方法只读不写:
|
||||
/// 与 [#findByProduct] 的 upsert 语义不同, 此方法只读不写:
|
||||
/// 记录不存在或关键字段(agentNo/accessId/accessKey)任一为空时 fail-fast,
|
||||
/// 避免空凭证下发到子应用后子应用才发现问题。
|
||||
public HkrtIsvKeyConfig getByProductForPay(String product, boolean sandbox) {
|
||||
|
||||
@@ -15,7 +15,7 @@ import org.springframework.stereotype.Service;
|
||||
/// # 海科融通服务商支付策略
|
||||
///
|
||||
/// 海科融通支付(ProductEnum.HKRT_PAY)下发起支付的具体执行策略。
|
||||
/// 配置组装在 [doBeforePay] 阶段完成(委托 [HkrtIsvConfigAssembler]), 支付执行委托给 [HkrtPayService]。
|
||||
/// 配置组装在 [#doBeforePay] 阶段完成(委托 [HkrtIsvConfigAssembler]), 支付执行委托给 [HkrtPayService]。
|
||||
///
|
||||
/// 海科融通为聚合服务商模式, 仅有一个产品 HKRT_PAY。
|
||||
@Slf4j
|
||||
|
||||
@@ -14,7 +14,7 @@ import org.springframework.stereotype.Service;
|
||||
|
||||
/// # 河马付服务商支付策略
|
||||
///
|
||||
/// 配置组装在 [doBeforePay] 阶段完成(委托 [HmpayIsvConfigAssembler]),
|
||||
/// 配置组装在 [#doBeforePay] 阶段完成(委托 [HmpayIsvConfigAssembler]),
|
||||
/// 支付执行委托给 [HmpayPayService]。
|
||||
@Slf4j
|
||||
@Service
|
||||
|
||||
@@ -38,7 +38,7 @@ public class LakalaIsvKeyConfigService {
|
||||
|
||||
/// 支付场景查询服务商密钥(必填校验, 不创建记录)
|
||||
///
|
||||
/// 与 [findByProduct] 的 upsert 语义不同, 此方法只读不写:
|
||||
/// 与 [#findByProduct] 的 upsert 语义不同, 此方法只读不写:
|
||||
/// 记录不存在或关键字段(lklAppId/privateKey/publicKey)任一为空时 fail-fast,
|
||||
/// 避免空凭证下发到子应用后子应用才发现问题。
|
||||
public LakalaIsvKeyConfig getByProductForPay(String product, boolean sandbox) {
|
||||
|
||||
@@ -15,7 +15,7 @@ import org.springframework.stereotype.Service;
|
||||
/// # 拉卡拉服务商支付策略
|
||||
///
|
||||
/// 拉卡拉支付(ProductEnum.LAKALA_PAY)下发起支付的具体执行策略。
|
||||
/// 配置组装在 [doBeforePay] 阶段完成(委托 [LakalaIsvConfigAssembler]), 支付执行委托给 [LakalaPayService]。
|
||||
/// 配置组装在 [#doBeforePay] 阶段完成(委托 [LakalaIsvConfigAssembler]), 支付执行委托给 [LakalaPayService]。
|
||||
///
|
||||
/// 拉卡拉为聚合服务商模式, 不区分直连/服务商, 仅有一个产品 LAKALA_PAY。
|
||||
@Slf4j
|
||||
|
||||
@@ -37,7 +37,7 @@ public class LeshuaIsvKeyConfigService {
|
||||
|
||||
/// 支付场景查询服务商密钥(必填校验, 不创建记录)
|
||||
///
|
||||
/// 与 [findByProduct] 的 upsert 语义不同, 此方法只读不写:
|
||||
/// 与 [#findByProduct] 的 upsert 语义不同, 此方法只读不写:
|
||||
/// 记录不存在或关键字段(lsMchNo/tradeKey/signType)任一为空时 fail-fast。
|
||||
public LeshuaIsvKeyConfig getByProductForPay(String product, boolean sandbox) {
|
||||
LeshuaIsvKeyConfig config = leshuaIsvKeyConfigManager.findByProductAndSandbox(product, sandbox)
|
||||
|
||||
@@ -15,7 +15,7 @@ import org.springframework.stereotype.Service;
|
||||
/// # 乐刷服务商支付策略
|
||||
///
|
||||
/// 乐刷支付(ProductEnum.LESHUA_PAY)下发起支付的具体执行策略。
|
||||
/// 配置组装在 [doBeforePay] 阶段完成(委托 [LeshuaIsvConfigAssembler]), 支付执行委托给 [LeshuaPayService]。
|
||||
/// 配置组装在 [#doBeforePay] 阶段完成(委托 [LeshuaIsvConfigAssembler]), 支付执行委托给 [LeshuaPayService]。
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
|
||||
@@ -15,7 +15,7 @@ import org.springframework.stereotype.Service;
|
||||
/// # 银联商务直连支付策略
|
||||
///
|
||||
/// 银联商务直连模式(ProductEnum.UMS_QRCODE)下发起支付的具体执行策略。
|
||||
/// 配置组装在 [doBeforePay] 阶段完成(委托 [UmsDirectConfigAssembler]),
|
||||
/// 配置组装在 [#doBeforePay] 阶段完成(委托 [UmsDirectConfigAssembler]),
|
||||
/// 支付执行委托给 [UmsPayService]。
|
||||
@Slf4j
|
||||
@Service
|
||||
|
||||
@@ -15,7 +15,7 @@ import org.springframework.stereotype.Service;
|
||||
/// # 随行付服务商支付策略
|
||||
///
|
||||
/// 随行付支付(ProductEnum.VBILL_PAY)下发起支付的具体执行策略。
|
||||
/// 配置组装在 [doBeforePay] 阶段完成(委托 [VbillIsvConfigAssembler]), 支付执行委托给 [VbillPayService]。
|
||||
/// 配置组装在 [#doBeforePay] 阶段完成(委托 [VbillIsvConfigAssembler]), 支付执行委托给 [VbillPayService]。
|
||||
///
|
||||
/// 随行付为聚合服务商模式, 不区分直连/服务商, 仅有一个产品 VBILL_PAY。
|
||||
@Slf4j
|
||||
|
||||
@@ -2,6 +2,7 @@ package cn.daxpay.open.channel.wechat.dao.direct;
|
||||
|
||||
import cn.daxpay.open.channel.wechat.entity.direct.WechatDirectApp;
|
||||
import cn.daxpay.open.platform.common.mybatisplus.impl.BaseManager;
|
||||
import cn.daxpay.open.platform.core.annotation.IgnoreTenant;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
@@ -9,7 +10,10 @@ import java.util.Optional;
|
||||
|
||||
/// # 微信直连商户应用
|
||||
///
|
||||
/// 直连商户应用数据访问管理器,提供按商户号和通道商户号查询列表、同一通道下应用ID唯一性校验等方法。
|
||||
/// 方法按租户隔离边界分三类:
|
||||
/// - 配置态 CRUD: [#listByMchNoAndChannelMchNo]、[#existsByChannelMchNoAndWxAppId]
|
||||
/// - 支付/回调(已装载 mchNo): [#findFirstByChannelMchNo]、[#findFirstByChannelMchNoAndAppType] 等租户内方法
|
||||
/// - 认证引导(无上下文): 方法名带 NotTenant
|
||||
///
|
||||
@Repository
|
||||
public class WechatDirectAppManager extends BaseManager<WechatDirectAppMapper, WechatDirectApp> {
|
||||
@@ -24,7 +28,7 @@ public class WechatDirectAppManager extends BaseManager<WechatDirectAppMapper, W
|
||||
.list();
|
||||
}
|
||||
|
||||
/// 按通道商户号查询首个应用(能力解析兜底时使用)
|
||||
/// 按通道商户号查询首个应用(支付/回调,租户内)
|
||||
public Optional<WechatDirectApp> findFirstByChannelMchNo(String channelMchNo) {
|
||||
return firstOpt(q -> q
|
||||
.eq(WechatDirectApp::getChannelMchNo, channelMchNo)
|
||||
@@ -32,7 +36,7 @@ public class WechatDirectAppManager extends BaseManager<WechatDirectAppMapper, W
|
||||
.orderByAsc(WechatDirectApp::getId));
|
||||
}
|
||||
|
||||
/// 按通道商户号与应用类型查询首个应用(能力→应用类型推导时使用)
|
||||
/// 按通道商户号与应用类型查询首个应用(支付/回调,租户内)
|
||||
public Optional<WechatDirectApp> findFirstByChannelMchNoAndAppType(String channelMchNo, String appType) {
|
||||
return firstOpt(q -> q
|
||||
.eq(WechatDirectApp::getChannelMchNo, channelMchNo)
|
||||
@@ -41,13 +45,31 @@ public class WechatDirectAppManager extends BaseManager<WechatDirectAppMapper, W
|
||||
.orderByAsc(WechatDirectApp::getId));
|
||||
}
|
||||
|
||||
/// 按通道商户号与wxAppId查询应用(opAppId显式指定认证应用时使用, 校验该appId在系统中预配过)
|
||||
/// 按通道商户号与wxAppId查询应用(支付/回调,租户内)
|
||||
public Optional<WechatDirectApp> findByChannelMchNoAndWxAppId(String channelMchNo, String wxAppId) {
|
||||
return firstOpt(q -> q
|
||||
.eq(WechatDirectApp::getChannelMchNo, channelMchNo)
|
||||
.eq(WechatDirectApp::getWxAppId, wxAppId));
|
||||
}
|
||||
|
||||
/// 按通道商户号查询首个应用(认证引导,忽略租户)
|
||||
@IgnoreTenant
|
||||
public Optional<WechatDirectApp> findFirstByChannelMchNoNotTenant(String channelMchNo) {
|
||||
return findFirstByChannelMchNo(channelMchNo);
|
||||
}
|
||||
|
||||
/// 按通道商户号与应用类型查询首个应用(认证引导,忽略租户)
|
||||
@IgnoreTenant
|
||||
public Optional<WechatDirectApp> findFirstByChannelMchNoAndAppTypeNotTenant(String channelMchNo, String appType) {
|
||||
return findFirstByChannelMchNoAndAppType(channelMchNo, appType);
|
||||
}
|
||||
|
||||
/// 按通道商户号与wxAppId查询应用(认证引导,忽略租户)
|
||||
@IgnoreTenant
|
||||
public Optional<WechatDirectApp> findByChannelMchNoAndWxAppIdNotTenant(String channelMchNo, String wxAppId) {
|
||||
return findByChannelMchNoAndWxAppId(channelMchNo, wxAppId);
|
||||
}
|
||||
|
||||
/// 校验同一通道商户下wxAppId是否已存在(排除自身)
|
||||
public boolean existsByChannelMchNoAndWxAppId(String mchNo, String channelMchNo, String wxAppId, Long excludeId) {
|
||||
return lambdaQuery()
|
||||
|
||||
@@ -2,6 +2,7 @@ package cn.daxpay.open.channel.wechat.dao.isv;
|
||||
|
||||
import cn.daxpay.open.channel.wechat.entity.isv.WechatIsvMchApp;
|
||||
import cn.daxpay.open.platform.common.mybatisplus.impl.BaseManager;
|
||||
import cn.daxpay.open.platform.core.annotation.IgnoreTenant;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
@@ -9,8 +10,11 @@ import java.util.Optional;
|
||||
|
||||
/// # 微信服务商通道商户应用 Manager
|
||||
///
|
||||
/// 服务商通道商户应用(子商户应用)数据访问管理器,提供按商户号和通道商户号查询列表、
|
||||
/// 首个应用查询、应用类型推导查询及同一通道下应用AppId唯一性校验等方法。
|
||||
/// 服务商通道商户应用(子商户应用)数据访问管理器。方法按租户隔离边界分两类:
|
||||
/// - 配置态(管理端 CRUD, 带租户隔离): [#listByMchNoAndChannelMchNo]、[#existsByChannelMchNoAndWxAppId]
|
||||
/// - 运行态(认证/支付解析, 忽略租户, 方法名带 NotTenant): [#findFirstByChannelMchNoNotTenant]、
|
||||
/// [#findFirstByChannelMchNoAndAppTypeNotTenant]、[#findByChannelMchNoAndWxAppIdNotTenant];
|
||||
/// 按主键见基类 [BaseManager.findByIdNotTenant]
|
||||
///
|
||||
@Repository
|
||||
public class WechatIsvMchAppManager extends BaseManager<WechatIsvMchAppMapper, WechatIsvMchApp> {
|
||||
@@ -25,16 +29,18 @@ public class WechatIsvMchAppManager extends BaseManager<WechatIsvMchAppMapper, W
|
||||
.list();
|
||||
}
|
||||
|
||||
/// 按通道商户号查询首个应用(能力解析兜底时使用)
|
||||
public Optional<WechatIsvMchApp> findFirstByChannelMchNo(String channelMchNo) {
|
||||
/// 按通道商户号查询首个应用(能力解析兜底时使用, 忽略租户隔离)
|
||||
@IgnoreTenant
|
||||
public Optional<WechatIsvMchApp> findFirstByChannelMchNoNotTenant(String channelMchNo) {
|
||||
return firstOpt(q -> q
|
||||
.eq(WechatIsvMchApp::getChannelMchNo, channelMchNo)
|
||||
.orderByAsc(WechatIsvMchApp::getCreateTime)
|
||||
.orderByAsc(WechatIsvMchApp::getId));
|
||||
}
|
||||
|
||||
/// 按通道商户号与应用类型查询首个应用(能力→应用类型推导时使用)
|
||||
public Optional<WechatIsvMchApp> findFirstByChannelMchNoAndAppType(String channelMchNo, String appType) {
|
||||
/// 按通道商户号与应用类型查询首个应用(能力→应用类型推导时使用, 忽略租户隔离)
|
||||
@IgnoreTenant
|
||||
public Optional<WechatIsvMchApp> findFirstByChannelMchNoAndAppTypeNotTenant(String channelMchNo, String appType) {
|
||||
return firstOpt(q -> q
|
||||
.eq(WechatIsvMchApp::getChannelMchNo, channelMchNo)
|
||||
.eq(WechatIsvMchApp::getAppType, appType)
|
||||
@@ -42,8 +48,9 @@ public class WechatIsvMchAppManager extends BaseManager<WechatIsvMchAppMapper, W
|
||||
.orderByAsc(WechatIsvMchApp::getId));
|
||||
}
|
||||
|
||||
/// 按通道商户号与wxAppId查询应用(opAppId显式指定认证应用时使用, 校验该appId在系统中预配过)
|
||||
public Optional<WechatIsvMchApp> findByChannelMchNoAndWxAppId(String channelMchNo, String wxAppId) {
|
||||
/// 按通道商户号与wxAppId查询应用(opAppId显式指定认证应用时使用, 校验该appId在系统中预配过, 忽略租户隔离)
|
||||
@IgnoreTenant
|
||||
public Optional<WechatIsvMchApp> findByChannelMchNoAndWxAppIdNotTenant(String channelMchNo, String wxAppId) {
|
||||
return firstOpt(q -> q
|
||||
.eq(WechatIsvMchApp::getChannelMchNo, channelMchNo)
|
||||
.eq(WechatIsvMchApp::getWxAppId, wxAppId));
|
||||
|
||||
@@ -9,6 +9,7 @@ import cn.daxpay.open.channel.wechat.param.direct.WechatDirectAppAuthConfigParam
|
||||
import cn.daxpay.open.platform.core.code.CommonErrorCode;
|
||||
import cn.daxpay.open.platform.core.exception.BizInfoException;
|
||||
import cn.daxpay.open.platform.core.exception.DataNotExistException;
|
||||
import cn.daxpay.open.platform.core.annotation.IgnoreTenant;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -44,6 +45,28 @@ public class WechatDirectAppAuthConfigService {
|
||||
return config;
|
||||
}
|
||||
|
||||
/// 根据应用ID查询授权认证配置(运行态认证使用, 忽略租户隔离)
|
||||
///
|
||||
/// 与 [#findByWechatDirectAppId] 的区别: 走 NotTenant 查询路径, 供认证策略(网关端无登录态)调用;
|
||||
/// [#save] 等配置态仍调原方法(保留租户隔离)。
|
||||
@IgnoreTenant
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public WechatDirectAppAuthConfig findByWechatDirectAppIdForAuth(Long wechatDirectAppId) {
|
||||
var existing = wechatDirectAppAuthConfigManager.findByWechatDirectAppIdNotTenant(wechatDirectAppId);
|
||||
if (existing.isPresent()) {
|
||||
return existing.get();
|
||||
}
|
||||
var app = wechatDirectAppManager.findByIdNotTenant(wechatDirectAppId)
|
||||
// 微信: 直连商户应用不存在
|
||||
.orElseThrow(() -> new DataNotExistException("error.channel.wechat.mchAppNotFound"));
|
||||
var config = new WechatDirectAppAuthConfig()
|
||||
.setChannelMchNo(app.getChannelMchNo())
|
||||
.setWechatDirectAppId(wechatDirectAppId);
|
||||
config.setMchNo(app.getMchNo());
|
||||
wechatDirectAppAuthConfigManager.save(config);
|
||||
return config;
|
||||
}
|
||||
|
||||
/// 保存应用授权认证配置(更新)
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void save(WechatDirectAppAuthConfigParam param) {
|
||||
|
||||
@@ -14,6 +14,7 @@ import cn.daxpay.open.platform.common.i18n.util.I18nUtil;
|
||||
import cn.daxpay.open.platform.core.code.CommonErrorCode;
|
||||
import cn.daxpay.open.platform.core.enums.pay.channel.ProductEnum;
|
||||
import cn.daxpay.open.platform.core.exception.BizInfoException;
|
||||
import cn.daxpay.open.platform.core.annotation.IgnoreTenant;
|
||||
import cn.daxpay.open.payment.core.strategy.PaymentStrategyFactory;
|
||||
import cn.daxpay.open.payment.core.strategy.product.AbsProductStrategy;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
@@ -33,7 +34,7 @@ import java.util.stream.Collectors;
|
||||
/// # 微信直连商户应用支付能力关联
|
||||
///
|
||||
/// 管理通道商户维度下「支付能力 → 直连应用」的绑定关系。
|
||||
/// 支付时通过 [resolveApp] 解析当前能力对应的应用:显式配置 > appType自动推导 > 通道商户首个兜底。
|
||||
/// 支付时通过 [#resolveApp] 解析当前能力对应的应用:显式配置 > appType自动推导 > 通道商户首个兜底。
|
||||
///
|
||||
@Slf4j
|
||||
@Service
|
||||
@@ -101,7 +102,10 @@ public class WechatDirectAppCapabilityService {
|
||||
capabilityManager.deleteByWechatDirectAppId(wechatDirectAppId);
|
||||
}
|
||||
|
||||
/// 支付时解析当前支付能力对应的应用:显式配置 > appType自动推导 > 通道商户首个兜底
|
||||
/// 支付/回调解析应用:显式配置 > appType 自动推导 > 通道商户首个兜底
|
||||
///
|
||||
/// **须已装载 mchNo**([PaymentVerify] 的 initMch / 回调 Filter),走租户过滤。
|
||||
/// 认证无上下文请用 [#resolveAppNotTenant]。
|
||||
///
|
||||
/// @param channelMchNo 通道商户号
|
||||
/// @param capability 支付能力编码
|
||||
@@ -127,6 +131,12 @@ public class WechatDirectAppCapabilityService {
|
||||
return wechatDirectAppManager.findFirstByChannelMchNo(channelMchNo);
|
||||
}
|
||||
|
||||
/// 认证等无租户上下文时解析应用(忽略租户,内部复用 [#resolveApp] 逻辑)
|
||||
@IgnoreTenant
|
||||
public Optional<WechatDirectApp> resolveAppNotTenant(String channelMchNo, String capability) {
|
||||
return resolveApp(channelMchNo, capability);
|
||||
}
|
||||
|
||||
/// 查询微信直连产品支持的支付能力候选列表(含国际化名称)
|
||||
public List<WechatCapabilityOption> listSupportedCapabilities() {
|
||||
AbsProductStrategy strategy = PaymentStrategyFactory.createByProduct(
|
||||
|
||||
@@ -33,7 +33,7 @@ import java.util.stream.Collectors;
|
||||
/// # 微信服务商应用支付能力关联
|
||||
///
|
||||
/// 管理全局维度下「支付能力 → 服务商应用」的绑定关系(微信服务商应用全局共享)。
|
||||
/// 支付时通过 [resolveApp] 解析当前能力对应的应用:显式配置 > appType自动推导 > 取首个兜底。
|
||||
/// 支付时通过 [#resolveApp] 解析当前能力对应的应用:显式配置 > appType自动推导 > 取首个兜底。
|
||||
///
|
||||
@Slf4j
|
||||
@Service
|
||||
|
||||
@@ -38,7 +38,7 @@ public class WechatIsvKeyConfigService {
|
||||
|
||||
/// 支付场景查询服务商密钥(必填校验, 不创建记录)
|
||||
///
|
||||
/// 与 [findByProduct] 的 upsert 语义不同, 此方法只读不写:
|
||||
/// 与 [#findByProduct] 的 upsert 语义不同, 此方法只读不写:
|
||||
/// 记录不存在或关键字段(wxMchId/apiKeyV3/privateKey/certSerialNo)任一为空时 fail-fast,
|
||||
/// 避免空凭证下发到子应用后子应用才发现问题。
|
||||
public WechatIsvKeyConfig getByProductForPay(String product) {
|
||||
|
||||
@@ -9,6 +9,7 @@ import cn.daxpay.open.channel.wechat.param.isv.WechatIsvMchAppAuthConfigParam;
|
||||
import cn.daxpay.open.platform.core.code.CommonErrorCode;
|
||||
import cn.daxpay.open.platform.core.exception.BizInfoException;
|
||||
import cn.daxpay.open.platform.core.exception.DataNotExistException;
|
||||
import cn.daxpay.open.platform.core.annotation.IgnoreTenant;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -44,6 +45,28 @@ public class WechatIsvMchAppAuthConfigService {
|
||||
return config;
|
||||
}
|
||||
|
||||
/// 根据应用ID查询授权认证配置(运行态认证使用, 忽略租户隔离)
|
||||
///
|
||||
/// 与 [#findByWechatIsvMchAppId] 的区别: 走 NotTenant 查询路径, 供认证策略(网关端无登录态)调用;
|
||||
/// [#save] 等配置态仍调原方法(保留租户隔离)。
|
||||
@IgnoreTenant
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public WechatIsvMchAppAuthConfig findByWechatIsvMchAppIdForAuth(Long wechatIsvMchAppId) {
|
||||
var existing = wechatIsvMchAppAuthConfigManager.findByWechatIsvMchAppIdNotTenant(wechatIsvMchAppId);
|
||||
if (existing.isPresent()) {
|
||||
return existing.get();
|
||||
}
|
||||
var app = wechatIsvMchAppManager.findByIdNotTenant(wechatIsvMchAppId)
|
||||
// 微信: 服务商通道商户应用不存在
|
||||
.orElseThrow(() -> new DataNotExistException("error.channel.wechat.mchAppNotFound"));
|
||||
var config = new WechatIsvMchAppAuthConfig()
|
||||
.setChannelMchNo(app.getChannelMchNo())
|
||||
.setWechatIsvMchAppId(wechatIsvMchAppId);
|
||||
config.setMchNo(app.getMchNo());
|
||||
wechatIsvMchAppAuthConfigManager.save(config);
|
||||
return config;
|
||||
}
|
||||
|
||||
/// 保存应用授权认证配置(更新)
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void save(WechatIsvMchAppAuthConfigParam param) {
|
||||
|
||||
@@ -13,6 +13,7 @@ import cn.daxpay.open.platform.common.i18n.util.I18nUtil;
|
||||
import cn.daxpay.open.platform.core.code.CommonErrorCode;
|
||||
import cn.daxpay.open.platform.core.enums.pay.channel.ProductEnum;
|
||||
import cn.daxpay.open.platform.core.exception.BizInfoException;
|
||||
import cn.daxpay.open.platform.core.annotation.IgnoreTenant;
|
||||
import cn.daxpay.open.payment.core.strategy.PaymentStrategyFactory;
|
||||
import cn.daxpay.open.payment.core.strategy.product.AbsProductStrategy;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
@@ -36,7 +37,7 @@ import java.util.stream.Collectors;
|
||||
/// 由调用方(未来的微信服务商支付策略/配置组装器)回退到全局服务商应用配置
|
||||
/// ([cn.daxpay.open.channel.wechat.service.isv.WechatIsvAppCapabilityService])。
|
||||
///
|
||||
/// 支付时通过 [resolveApp] 解析当前能力对应的应用:仅读取显式配置, 未配置返回 empty
|
||||
/// 支付时通过 [#resolveApp] 解析当前能力对应的应用:仅读取显式配置, 未配置返回 empty
|
||||
/// (语义为"该能力未在子商户维度配置, sub_appid 留空, 走纯服务商应用模式")。
|
||||
///
|
||||
@Slf4j
|
||||
@@ -108,10 +109,10 @@ public class WechatIsvMchAppCapabilityService {
|
||||
capabilityManager.deleteByWechatIsvMchAppId(wechatIsvMchAppId);
|
||||
}
|
||||
|
||||
/// 支付时解析当前支付能力对应的子商户应用(仅读取显式配置)
|
||||
/// 支付/回调解析子商户应用(仅读取显式配置,须已装载 mchNo,租户内)
|
||||
///
|
||||
/// 子商户应用(sub_appid)为可选项, 不做 appType 推导与首个兜底, 避免取到不相关的子应用
|
||||
/// 导致 openid 体系不匹配。未配置返回 empty, 由调用方留空 sub_appid, 走纯服务商应用模式。
|
||||
/// 子商户应用(sub_appid)为可选项, 不做 appType 推导与首个兜底。
|
||||
/// 未配置返回 empty, 由调用方留空 sub_appid。认证无上下文请用 [#resolveAppNotTenant]。
|
||||
///
|
||||
/// @param channelMchNo 通道商户号(服务商特约商户)
|
||||
/// @param capability 支付能力编码
|
||||
@@ -120,12 +121,16 @@ public class WechatIsvMchAppCapabilityService {
|
||||
if (StrUtil.hasBlank(channelMchNo, capability)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
// 子商户应用(sub_appid)为可选项, 仅读取显式配置, 未配置则返回 empty
|
||||
// (sub_appid 留空时走纯服务商应用 sp_appid + sub_mchid 模式)
|
||||
return capabilityManager.findOne(channelMchNo, capability)
|
||||
.flatMap(rel -> wechatIsvMchAppManager.findById(rel.getWechatIsvMchAppId()));
|
||||
}
|
||||
|
||||
/// 认证等无租户上下文时解析子商户应用(忽略租户)
|
||||
@IgnoreTenant
|
||||
public Optional<WechatIsvMchApp> resolveAppNotTenant(String channelMchNo, String capability) {
|
||||
return resolveApp(channelMchNo, capability);
|
||||
}
|
||||
|
||||
/// 查询微信服务商产品支持的支付能力候选列表(含国际化名称)
|
||||
public List<WechatCapabilityOption> listSupportedCapabilities() {
|
||||
AbsProductStrategy strategy = PaymentStrategyFactory.createByProduct(
|
||||
|
||||
@@ -15,7 +15,7 @@ import org.springframework.stereotype.Service;
|
||||
/// # 微信直连支付策略
|
||||
///
|
||||
/// 微信直连模式(ProductEnum.WECHAT_PAY)下发起支付的具体执行策略。
|
||||
/// 配置组装在 [doBeforePay] 阶段完成(委托 [WechatDirectConfigAssembler]), 支付执行委托给 [WechatPayService]。
|
||||
/// 配置组装在 [#doBeforePay] 阶段完成(委托 [WechatDirectConfigAssembler]), 支付执行委托给 [WechatPayService]。
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
|
||||
@@ -15,7 +15,7 @@ import org.springframework.stereotype.Service;
|
||||
/// # 微信服务商支付策略
|
||||
///
|
||||
/// 微信服务商模式(ProductEnum.WECHAT_ISV)下发起支付的具体执行策略。
|
||||
/// 配置组装在 [doBeforePay] 阶段完成(委托 [WechatIsvConfigAssembler]), 支付执行委托给 [WechatPayService]。
|
||||
/// 配置组装在 [#doBeforePay] 阶段完成(委托 [WechatIsvConfigAssembler]), 支付执行委托给 [WechatPayService]。
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
|
||||
@@ -15,7 +15,7 @@ import org.springframework.stereotype.Service;
|
||||
/// # 易宝直连支付策略
|
||||
///
|
||||
/// 易宝支付(ProductEnum.YEE_PAY)下发起支付的具体执行策略。
|
||||
/// 配置组装在 [doBeforePay] 阶段完成(委托 [YeepayDirectConfigAssembler]),
|
||||
/// 配置组装在 [#doBeforePay] 阶段完成(委托 [YeepayDirectConfigAssembler]),
|
||||
/// 支付执行委托给 [YeepayPayService]。
|
||||
@Slf4j
|
||||
@Service
|
||||
|
||||
@@ -54,7 +54,7 @@ public final class PaymentContext {
|
||||
}
|
||||
}
|
||||
|
||||
/// 在作用域内执行(无返回值),语义同 [runAs]
|
||||
/// 在作用域内执行(无返回值),语义同 [#runAs]
|
||||
public void runAs(Runnable action) {
|
||||
if (isOpen()) {
|
||||
action.run();
|
||||
|
||||
@@ -36,9 +36,9 @@ public class AuthSession {
|
||||
/// 认证来源
|
||||
///
|
||||
/// 标识本次认证的配置来源:
|
||||
/// - [SOURCE_PLATFORM_ALIPAY]: 平台级支付宝配置(调试场景)
|
||||
/// - [SOURCE_PLATFORM_MP]: 平台级微信公众号配置(调试场景)
|
||||
/// - [SOURCE_PLATFORM_DOUYIN]: 平台级抖音 H5 应用配置(调试场景)
|
||||
/// - [#SOURCE_PLATFORM_ALIPAY]: 平台级支付宝配置(调试场景)
|
||||
/// - [#SOURCE_PLATFORM_MP]: 平台级微信公众号配置(调试场景)
|
||||
/// - [#SOURCE_PLATFORM_DOUYIN]: 平台级抖音 H5 应用配置(调试场景)
|
||||
/// - null/空: 走商户级支付产品策略(直连/服务商)
|
||||
private String source;
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ public class PlatformAuthService {
|
||||
///
|
||||
/// 读取平台级 [PlatformAlipayAuthConfig], 调用 capability-alipay 生成支付宝 OAuth 授权链接,
|
||||
/// 回调指向固定的 `/auth/alipay`。会话标识 authToken 通过 OAuth state 参数透传, 回调后从 state 恢复会话。
|
||||
/// session 标记 `source=platform_alipay`, 认证分发层据此走平台级支付宝换票分支([authAlipay])。
|
||||
/// session 标记 `source=platform_alipay`, 认证分发层据此走平台级支付宝换票分支([#authAlipay])。
|
||||
public AuthUrlResult generateAlipayAuthUrl() {
|
||||
AlipayAuthConfig config = platformAlipayAuthConfigService.toCapabilityConfig();
|
||||
if (!alipayAuthCapability.isConfigured(config)) {
|
||||
@@ -108,7 +108,7 @@ public class PlatformAuthService {
|
||||
///
|
||||
/// 读取平台级 [PlatformWechatMpAuthConfig], 调用 capability-wechat 生成微信公众号 OAuth 授权链接,
|
||||
/// 回调指向固定的 `/auth/wechat`。会话标识 authToken 通过 OAuth state 参数透传, 回调后从 state 恢复会话。
|
||||
/// session 标记 `source=platform_mp`, 认证分发层据此走平台级微信换票分支([authWechatMp])。
|
||||
/// session 标记 `source=platform_mp`, 认证分发层据此走平台级微信换票分支([#authWechatMp])。
|
||||
public AuthUrlResult generateWechatMpAuthUrl() {
|
||||
PlatformWechatMpAuthConfig config = platformWechatMpAuthConfigService.getWechatMpAuthConfig();
|
||||
if (!isWechatMpConfigured(config)) {
|
||||
@@ -138,7 +138,7 @@ public class PlatformAuthService {
|
||||
/// 读取平台级 [PlatformDouyinH5AuthConfig], 调用 capability-douyin [DouyinH5AuthService] 构造 silent_auth 链接,
|
||||
/// 回调指向固定的 `/auth/douyin`(抖音要求 redirect_uri 与平台配置完全一致, 不支持 path 段或 query 参数)。
|
||||
/// 会话标识 authToken 通过 state 参数透传, 回调后从 state 恢复会话。
|
||||
/// session 标记 `source=platform_douyin`, 认证分发层据此走平台级抖音换票分支([authDouyin])。
|
||||
/// session 标记 `source=platform_douyin`, 认证分发层据此走平台级抖音换票分支([#authDouyin])。
|
||||
public AuthUrlResult generateDouyinAuthUrl() {
|
||||
PlatformDouyinH5AuthConfig config = platformDouyinH5AuthConfigService.getDouyinH5AuthConfig();
|
||||
if (!isDouyinH5Configured(config)) {
|
||||
|
||||
@@ -111,7 +111,7 @@ public class PayCloseService {
|
||||
/// 供 MQ 延时消息消费者 [cn.daxpay.open.payment.core.trade.mq.NormalPayTimeoutConsumer]
|
||||
/// 与兜底定时任务 [cn.daxpay.open.payment.core.trade.job.NormalPayTimeoutJob] 调用。
|
||||
///
|
||||
/// 与 [closeOrder] 的区别:
|
||||
/// 与 [#closeOrder] 的区别:
|
||||
/// - 仅接受 tradeNo 定位, 非 PROCESSING 状态静默返回(幂等, 不抛异常)
|
||||
/// - closeType 固定 TIMEOUT, 容器态置 EXPIRED(见 [PayUniHandleService#payTimeout])
|
||||
/// - 不接受 useCancel, 超时统一走 close
|
||||
|
||||
@@ -6,8 +6,8 @@ import lombok.Getter;
|
||||
/// # 支付宝鉴权方式
|
||||
///
|
||||
/// 区分公钥模式与证书模式, 决定 OpenAPI 请求参数与响应验签公钥来源:
|
||||
/// - [KEY] 公钥模式: 使用 alipayPublicKey 验签
|
||||
/// - [CERT] 证书模式: 请求附加 app_cert_sn / alipay_root_cert_sn, 从支付宝公钥证书取验签公钥
|
||||
/// - [#KEY] 公钥模式: 使用 alipayPublicKey 验签
|
||||
/// - [#CERT] 证书模式: 请求附加 app_cert_sn / alipay_root_cert_sn, 从支付宝公钥证书取验签公钥
|
||||
///
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
|
||||
@@ -6,7 +6,7 @@ import cn.daxpay.open.platform.capability.auth.entity.LoginAuthContext;
|
||||
/// # 认证后挑战 SPI
|
||||
///
|
||||
/// 认证(凭证校验 + 用户状态校验)通过后、建立会话前, 判断是否需要额外挑战(如双因素认证 / 设备验证 / 风控)。
|
||||
/// 需要挑战时由 [createChallenge] 颁发挑战凭证并返回挑战异常, 由全局处理器返回前端。
|
||||
/// 需要挑战时由 [#createChallenge] 颁发挑战凭证并返回挑战异常, 由全局处理器返回前端。
|
||||
/// 挑战不属于登录失败, 不触发失败计数与失败日志。
|
||||
///
|
||||
public interface PostAuthenticationChallenge {
|
||||
|
||||
@@ -8,7 +8,7 @@ import java.util.List;
|
||||
|
||||
/// # 单条数据读取安全
|
||||
///
|
||||
/// 重写 [one]:查询结果不唯一时记录告警(查全部,方言无关),适用于期望唯一的场景。
|
||||
/// 重写 [#one]:查询结果不唯一时记录告警(查全部,方言无关),适用于期望唯一的场景。
|
||||
/// 取"排序后第一条"的方言无关写法(只查 1 条、不校验唯一)见 [cn.daxpay.open.platform.common.mybatisplus.impl.BaseManager.firstOpt]。
|
||||
///
|
||||
@Slf4j
|
||||
|
||||
@@ -110,7 +110,7 @@ public class BaseManager<M extends MPJBaseMapper<T>, T> {
|
||||
|
||||
/// 取排序后第一条(方言无关,由分页插件按当前数据库方言生成 limit,只查 1 条)
|
||||
///
|
||||
/// 适用于 findFirst* 场景(明确取首条,不校验唯一),区别于期望唯一的 [lambdaQuery]...one()。
|
||||
/// 适用于 findFirst* 场景(明确取首条,不校验唯一),区别于期望唯一的 [#lambdaQuery]...one()。
|
||||
///
|
||||
/// @param customizer 查询条件定制(eq/orderBy 等)
|
||||
/// @return 第一条的 Optional 包装,无数据返回 empty
|
||||
@@ -271,7 +271,7 @@ public class BaseManager<M extends MPJBaseMapper<T>, T> {
|
||||
|
||||
/// 按主键查询(忽略租户隔离)
|
||||
///
|
||||
/// 运行态认证/支付解析/网关引导等无租户上下文时使用;配置态 CRUD 请用 [findById]。
|
||||
/// 运行态认证/支付解析/网关引导等无租户上下文时使用;配置态 CRUD 请用 [#findById]。
|
||||
/// 须经 Spring 注入的 Manager Bean 外部调用(同类 this 自调用不走 AOP)。
|
||||
@IgnoreTenant
|
||||
public Optional<T> findByIdNotTenant(Serializable id) {
|
||||
|
||||
@@ -183,7 +183,7 @@ public class MpUtil {
|
||||
return tableInfo.getPropertyValue(object, keyProperty);
|
||||
}
|
||||
|
||||
/// 进入忽略租户作用域(可重入,与 [clearIgnoreTenant] 成对使用)
|
||||
/// 进入忽略租户作用域(可重入,与 [#clearIgnoreTenant] 成对使用)
|
||||
///
|
||||
/// 基于线程内引用计数:仅 depth 从 0→1 时真正打开 MP 忽略策略;
|
||||
/// 嵌套调用不会互相 clear,直到最外层 exit 才恢复租户过滤。
|
||||
|
||||
@@ -27,7 +27,7 @@ import java.util.Objects;
|
||||
/// # 账号密码登录基类
|
||||
///
|
||||
/// 承载密码登录的通用流程(用户定位、验证码校验、密码比对、登录重试状态注入)。
|
||||
/// 子类只需声明终端编码 [getClientCode], 由认证框架按"终端 + 登录方式"双键路由,
|
||||
/// 子类只需声明终端编码 [#getClientCode], 由认证框架按"终端 + 登录方式"双键路由,
|
||||
/// 从而消除多终端同登录方式(如平台端/商户端均为 password)的 findFirst 歧义与重复代码。
|
||||
///
|
||||
@Slf4j
|
||||
|
||||
@@ -25,9 +25,9 @@ import org.springframework.stereotype.Service;
|
||||
/// # 第三方平台登录配置服务
|
||||
///
|
||||
/// 配置页采用"枚举驱动 + 惰性初始化"模式: 平台清单来源于 [SocialSourceEnum] 枚举.
|
||||
/// [findAll] 仅内存合并展示(不落库), 未配置平台返回无 id 的瞬态展示项;
|
||||
/// [findBySource] 在平台记录不存在时按需初始化占位记录(`configured=false`), 用户保存配置后置 `configured=true`.
|
||||
/// 数据访问全部委托 [SocialLoginConfigManager], 本层不直接使用 lambdaQuery.
|
||||
/// [#findAll] 仅内存合并展示(不落库), 未配置平台返回无 id 的瞬态展示项;
|
||||
/// [#findBySource] 在平台记录不存在时按需初始化占位记录(`configured=false`), 用户保存配置后置 `configured=true`.
|
||||
/// 数据访问全部委托 [SocialLoginConfigManager#listAll], 本层不直接使用 lambdaQuery.
|
||||
/// 配置表 source 全局唯一, 占位记录仅插入一次.
|
||||
///
|
||||
/// **平台级跳转型**(如支付宝): 凭据在独立平台配置中维护, 本表仅存 enabled 占位;
|
||||
@@ -42,7 +42,7 @@ public class SocialLoginConfigService {
|
||||
|
||||
/// 全量查询平台配置(枚举驱动, 内存合并, 不落库)
|
||||
/// 已配置平台返回库表记录, 未配置平台返回 `configured=false` 的瞬态展示项(无 id).
|
||||
/// 真正的初始化落库延迟到 [findBySource] 按需触发, 避免读操作产生写副作用.
|
||||
/// 真正的初始化落库延迟到 [#findBySource] 按需触发, 避免读操作产生写副作用.
|
||||
/// **平台级跳转型平台**(如支付宝)不在本表存凭据, `configured`/`enabled` 均取本表占位行。
|
||||
public List<SocialLoginConfigResult> findAll() {
|
||||
// 库表已有配置按 source 索引
|
||||
|
||||
@@ -69,13 +69,13 @@ public class AlipaySocialAuthRequest implements SocialAuthRequest {
|
||||
.setToken(token);
|
||||
}
|
||||
|
||||
/// 支付宝换用户在 [login] 内一次完成, 不单独暴露 accessToken 步骤
|
||||
/// 支付宝换用户在 [#login] 内一次完成, 不单独暴露 accessToken 步骤
|
||||
@Override
|
||||
public AuthToken getAccessToken(AuthCallback callback) {
|
||||
throw new SocialException("error.social.unsupportedSource");
|
||||
}
|
||||
|
||||
/// 支付宝换用户在 [login] 内一次完成, 不单独暴露 userInfo 步骤
|
||||
/// 支付宝换用户在 [#login] 内一次完成, 不单独暴露 userInfo 步骤
|
||||
@Override
|
||||
public AuthUser getUserInfo(AuthToken token) {
|
||||
throw new SocialException("error.social.unsupportedSource");
|
||||
|
||||
@@ -21,7 +21,7 @@ import java.util.Map;
|
||||
|
||||
/// # 微信公众号模板通知发送门面(编排层)
|
||||
///
|
||||
/// 业务方通过 [sendToUser] 发送模板通知, 内部完成:
|
||||
/// 业务方通过 [#sendToUser] 发送模板通知, 内部完成:
|
||||
/// "读三方平台凭据 -> 读消息通知配置 -> 反查 openId -> 选模板 -> 调能力层发送 -> 写记录"全链路.
|
||||
///
|
||||
/// 降级策略(不抛异常, 不阻塞主业务, 每个降级点都写一条 failed 记录留痕):
|
||||
|
||||
Reference in New Issue
Block a user