fix(docs): 修正 /// Markdown 本类成员链接写法为 [#member]

JEP 467 中 [name] 按类型解析,方法/字段/枚举常量应使用 [#name],
消除 IDEA 未解析引用报红;跨类 Type#member 保持不变。
This commit is contained in:
DaxPay Dev
2026-07-10 18:06:07 +08:00
parent 17fb60161d
commit 9a7fe7b2b3
43 changed files with 221 additions and 77 deletions

View File

@@ -15,7 +15,7 @@ import org.springframework.stereotype.Service;
/// # Adapay 直连支付策略
///
/// Adapay 支付(ProductEnum.ADA_PAY)下发起支付的具体执行策略。
/// 配置组装在 [doBeforePay] 阶段完成(委托 [AdapayDirectConfigAssembler]),
/// 配置组装在 [#doBeforePay] 阶段完成(委托 [AdapayDirectConfigAssembler]),
/// 支付执行委托给 [AdapayPayService]。
@Slf4j
@Service

View File

@@ -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);
}
}

View File

@@ -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(

View File

@@ -15,7 +15,7 @@ import org.springframework.stereotype.Service;
/// # 支付宝直连支付策略
///
/// 支付宝直连模式(ProductEnum.ALIPAY)下发起支付的具体执行策略。
/// 配置组装在 [doBeforePay] 阶段完成(委托 [AlipayDirectConfigAssembler]), 支付执行委托给 [AlipayPayService]。
/// 配置组装在 [#doBeforePay] 阶段完成(委托 [AlipayDirectConfigAssembler]), 支付执行委托给 [AlipayPayService]。
///
@Slf4j
@Service

View File

@@ -14,7 +14,7 @@ import org.springframework.stereotype.Service;
/// # 支付宝服务商支付策略
///
/// 支付宝服务商模式(ProductEnum.ALIPAY_ISV)下发起支付的具体执行策略。
/// 配置组装(含应用授权令牌)在 [doBeforePay] 阶段完成(委托 [AlipayIsvConfigAssembler]), 支付执行委托给 [AlipayPayService]。
/// 配置组装(含应用授权令牌)在 [#doBeforePay] 阶段完成(委托 [AlipayIsvConfigAssembler]), 支付执行委托给 [AlipayPayService]。
@Slf4j
@Service
@RequiredArgsConstructor

View File

@@ -14,7 +14,7 @@ import org.springframework.stereotype.Service;
/// # 斗拱服务商支付策略
///
/// 配置组装在 [doBeforePay] 阶段完成(委托 [DougongIsvConfigAssembler]),
/// 配置组装在 [#doBeforePay] 阶段完成(委托 [DougongIsvConfigAssembler]),
/// 支付执行委托给 [DougongPayService]。
///
/// 斗拱为聚合服务商模式, 仅有一个产品 DOUGONG_PAY(覆盖微信/支付宝/银联)。

View File

@@ -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);
}
}

View File

@@ -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(

View File

@@ -15,7 +15,7 @@ import org.springframework.stereotype.Service;
/// # 抖音支付直连支付策略
///
/// 抖音直连模式(ProductEnum.DOUYIN_PAY)下发起支付的具体执行策略。
/// 配置组装在 [doBeforePay] 阶段完成(委托 [DouyinDirectConfigAssembler]), 支付执行委托给 [DouyinPayService]。
/// 配置组装在 [#doBeforePay] 阶段完成(委托 [DouyinDirectConfigAssembler]), 支付执行委托给 [DouyinPayService]。
@Slf4j
@Service
@RequiredArgsConstructor

View File

@@ -15,7 +15,7 @@ import org.springframework.stereotype.Service;
/// # 富友服务商支付策略
///
/// 富友支付(ProductEnum.FUYOU_PAY)下发起支付的具体执行策略。
/// 配置组装在 [doBeforePay] 阶段完成(委托 [FuyouIsvConfigAssembler]), 支付执行委托给 [FuyouPayService]。
/// 配置组装在 [#doBeforePay] 阶段完成(委托 [FuyouIsvConfigAssembler]), 支付执行委托给 [FuyouPayService]。
///
/// 富友为聚合服务商模式, 不区分直连/服务商, 仅有一个产品 FUYOU_PAY。
@Slf4j

View File

@@ -38,7 +38,7 @@ public class HkrtIsvKeyConfigService {
/// 支付场景查询服务商密钥(必填校验, 不创建记录)
///
/// 与 [findByProduct] 的 upsert 语义不同, 此方法只读不写:
/// 与 [#findByProduct] 的 upsert 语义不同, 此方法只读不写:
/// 记录不存在或关键字段(agentNo/accessId/accessKey)任一为空时 fail-fast,
/// 避免空凭证下发到子应用后子应用才发现问题。
public HkrtIsvKeyConfig getByProductForPay(String product, boolean sandbox) {

View File

@@ -15,7 +15,7 @@ import org.springframework.stereotype.Service;
/// # 海科融通服务商支付策略
///
/// 海科融通支付(ProductEnum.HKRT_PAY)下发起支付的具体执行策略。
/// 配置组装在 [doBeforePay] 阶段完成(委托 [HkrtIsvConfigAssembler]), 支付执行委托给 [HkrtPayService]。
/// 配置组装在 [#doBeforePay] 阶段完成(委托 [HkrtIsvConfigAssembler]), 支付执行委托给 [HkrtPayService]。
///
/// 海科融通为聚合服务商模式, 仅有一个产品 HKRT_PAY。
@Slf4j

View File

@@ -14,7 +14,7 @@ import org.springframework.stereotype.Service;
/// # 河马付服务商支付策略
///
/// 配置组装在 [doBeforePay] 阶段完成(委托 [HmpayIsvConfigAssembler]),
/// 配置组装在 [#doBeforePay] 阶段完成(委托 [HmpayIsvConfigAssembler]),
/// 支付执行委托给 [HmpayPayService]。
@Slf4j
@Service

View File

@@ -38,7 +38,7 @@ public class LakalaIsvKeyConfigService {
/// 支付场景查询服务商密钥(必填校验, 不创建记录)
///
/// 与 [findByProduct] 的 upsert 语义不同, 此方法只读不写:
/// 与 [#findByProduct] 的 upsert 语义不同, 此方法只读不写:
/// 记录不存在或关键字段(lklAppId/privateKey/publicKey)任一为空时 fail-fast,
/// 避免空凭证下发到子应用后子应用才发现问题。
public LakalaIsvKeyConfig getByProductForPay(String product, boolean sandbox) {

View File

@@ -15,7 +15,7 @@ import org.springframework.stereotype.Service;
/// # 拉卡拉服务商支付策略
///
/// 拉卡拉支付(ProductEnum.LAKALA_PAY)下发起支付的具体执行策略。
/// 配置组装在 [doBeforePay] 阶段完成(委托 [LakalaIsvConfigAssembler]), 支付执行委托给 [LakalaPayService]。
/// 配置组装在 [#doBeforePay] 阶段完成(委托 [LakalaIsvConfigAssembler]), 支付执行委托给 [LakalaPayService]。
///
/// 拉卡拉为聚合服务商模式, 不区分直连/服务商, 仅有一个产品 LAKALA_PAY。
@Slf4j

View File

@@ -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)

View File

@@ -15,7 +15,7 @@ import org.springframework.stereotype.Service;
/// # 乐刷服务商支付策略
///
/// 乐刷支付(ProductEnum.LESHUA_PAY)下发起支付的具体执行策略。
/// 配置组装在 [doBeforePay] 阶段完成(委托 [LeshuaIsvConfigAssembler]), 支付执行委托给 [LeshuaPayService]。
/// 配置组装在 [#doBeforePay] 阶段完成(委托 [LeshuaIsvConfigAssembler]), 支付执行委托给 [LeshuaPayService]。
@Slf4j
@Service
@RequiredArgsConstructor

View File

@@ -15,7 +15,7 @@ import org.springframework.stereotype.Service;
/// # 银联商务直连支付策略
///
/// 银联商务直连模式(ProductEnum.UMS_QRCODE)下发起支付的具体执行策略。
/// 配置组装在 [doBeforePay] 阶段完成(委托 [UmsDirectConfigAssembler]),
/// 配置组装在 [#doBeforePay] 阶段完成(委托 [UmsDirectConfigAssembler]),
/// 支付执行委托给 [UmsPayService]。
@Slf4j
@Service

View File

@@ -15,7 +15,7 @@ import org.springframework.stereotype.Service;
/// # 随行付服务商支付策略
///
/// 随行付支付(ProductEnum.VBILL_PAY)下发起支付的具体执行策略。
/// 配置组装在 [doBeforePay] 阶段完成(委托 [VbillIsvConfigAssembler]), 支付执行委托给 [VbillPayService]。
/// 配置组装在 [#doBeforePay] 阶段完成(委托 [VbillIsvConfigAssembler]), 支付执行委托给 [VbillPayService]。
///
/// 随行付为聚合服务商模式, 不区分直连/服务商, 仅有一个产品 VBILL_PAY。
@Slf4j

View File

@@ -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()

View File

@@ -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));

View File

@@ -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) {

View File

@@ -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(

View File

@@ -33,7 +33,7 @@ import java.util.stream.Collectors;
/// # 微信服务商应用支付能力关联
///
/// 管理全局维度下「支付能力 → 服务商应用」的绑定关系(微信服务商应用全局共享)。
/// 支付时通过 [resolveApp] 解析当前能力对应的应用:显式配置 > appType自动推导 > 取首个兜底。
/// 支付时通过 [#resolveApp] 解析当前能力对应的应用:显式配置 > appType自动推导 > 取首个兜底。
///
@Slf4j
@Service

View File

@@ -38,7 +38,7 @@ public class WechatIsvKeyConfigService {
/// 支付场景查询服务商密钥(必填校验, 不创建记录)
///
/// 与 [findByProduct] 的 upsert 语义不同, 此方法只读不写:
/// 与 [#findByProduct] 的 upsert 语义不同, 此方法只读不写:
/// 记录不存在或关键字段(wxMchId/apiKeyV3/privateKey/certSerialNo)任一为空时 fail-fast,
/// 避免空凭证下发到子应用后子应用才发现问题。
public WechatIsvKeyConfig getByProductForPay(String product) {

View File

@@ -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) {

View File

@@ -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(

View File

@@ -15,7 +15,7 @@ import org.springframework.stereotype.Service;
/// # 微信直连支付策略
///
/// 微信直连模式(ProductEnum.WECHAT_PAY)下发起支付的具体执行策略。
/// 配置组装在 [doBeforePay] 阶段完成(委托 [WechatDirectConfigAssembler]), 支付执行委托给 [WechatPayService]。
/// 配置组装在 [#doBeforePay] 阶段完成(委托 [WechatDirectConfigAssembler]), 支付执行委托给 [WechatPayService]。
@Slf4j
@Service
@RequiredArgsConstructor

View File

@@ -15,7 +15,7 @@ import org.springframework.stereotype.Service;
/// # 微信服务商支付策略
///
/// 微信服务商模式(ProductEnum.WECHAT_ISV)下发起支付的具体执行策略。
/// 配置组装在 [doBeforePay] 阶段完成(委托 [WechatIsvConfigAssembler]), 支付执行委托给 [WechatPayService]。
/// 配置组装在 [#doBeforePay] 阶段完成(委托 [WechatIsvConfigAssembler]), 支付执行委托给 [WechatPayService]。
@Slf4j
@Service
@RequiredArgsConstructor

View File

@@ -15,7 +15,7 @@ import org.springframework.stereotype.Service;
/// # 易宝直连支付策略
///
/// 易宝支付(ProductEnum.YEE_PAY)下发起支付的具体执行策略。
/// 配置组装在 [doBeforePay] 阶段完成(委托 [YeepayDirectConfigAssembler]),
/// 配置组装在 [#doBeforePay] 阶段完成(委托 [YeepayDirectConfigAssembler]),
/// 支付执行委托给 [YeepayPayService]。
@Slf4j
@Service

View File

@@ -54,7 +54,7 @@ public final class PaymentContext {
}
}
/// 在作用域内执行(无返回值),语义同 [runAs]
/// 在作用域内执行(无返回值),语义同 [#runAs]
public void runAs(Runnable action) {
if (isOpen()) {
action.run();

View File

@@ -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;

View File

@@ -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)) {

View File

@@ -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

View File

@@ -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

View File

@@ -6,7 +6,7 @@ import cn.daxpay.open.platform.capability.auth.entity.LoginAuthContext;
/// # 认证后挑战 SPI
///
/// 认证(凭证校验 + 用户状态校验)通过后、建立会话前, 判断是否需要额外挑战(如双因素认证 / 设备验证 / 风控)。
/// 需要挑战时由 [createChallenge] 颁发挑战凭证并返回挑战异常, 由全局处理器返回前端。
/// 需要挑战时由 [#createChallenge] 颁发挑战凭证并返回挑战异常, 由全局处理器返回前端。
/// 挑战不属于登录失败, 不触发失败计数与失败日志。
///
public interface PostAuthenticationChallenge {

View File

@@ -8,7 +8,7 @@ import java.util.List;
/// # 单条数据读取安全
///
/// 重写 [one]:查询结果不唯一时记录告警(查全部,方言无关),适用于期望唯一的场景。
/// 重写 [#one]:查询结果不唯一时记录告警(查全部,方言无关),适用于期望唯一的场景。
/// 取"排序后第一条"的方言无关写法(只查 1 条、不校验唯一)见 [cn.daxpay.open.platform.common.mybatisplus.impl.BaseManager.firstOpt]。
///
@Slf4j

View File

@@ -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) {

View File

@@ -183,7 +183,7 @@ public class MpUtil {
return tableInfo.getPropertyValue(object, keyProperty);
}
/// 进入忽略租户作用域(可重入,与 [clearIgnoreTenant] 成对使用)
/// 进入忽略租户作用域(可重入,与 [#clearIgnoreTenant] 成对使用)
///
/// 基于线程内引用计数:仅 depth 从 0→1 时真正打开 MP 忽略策略;
/// 嵌套调用不会互相 clear直到最外层 exit 才恢复租户过滤。

View File

@@ -27,7 +27,7 @@ import java.util.Objects;
/// # 账号密码登录基类
///
/// 承载密码登录的通用流程(用户定位、验证码校验、密码比对、登录重试状态注入)。
/// 子类只需声明终端编码 [getClientCode], 由认证框架按"终端 + 登录方式"双键路由,
/// 子类只需声明终端编码 [#getClientCode], 由认证框架按"终端 + 登录方式"双键路由,
/// 从而消除多终端同登录方式(如平台端/商户端均为 password)的 findFirst 歧义与重复代码。
///
@Slf4j

View File

@@ -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 索引

View File

@@ -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");

View File

@@ -21,7 +21,7 @@ import java.util.Map;
/// # 微信公众号模板通知发送门面(编排层)
///
/// 业务方通过 [sendToUser] 发送模板通知, 内部完成:
/// 业务方通过 [#sendToUser] 发送模板通知, 内部完成:
/// "读三方平台凭据 -> 读消息通知配置 -> 反查 openId -> 选模板 -> 调能力层发送 -> 写记录"全链路.
///
/// 降级策略(不抛异常, 不阻塞主业务, 每个降级点都写一条 failed 记录留痕):