mirror of
https://gitee.com/dromara/dax-pay
synced 2026-08-13 07:45:41 +08:00
refactor(backend): 清理死方法与 @Deprecated 代码
删除无引用工具类/方法及废弃字段,收缩 PayUtil/DateTimeUtil/MpUtil 等实现,并移除 Service/Manager 中未使用的查询脚手架。
This commit is contained in:
@@ -2,7 +2,6 @@ package cn.daxpay.open.channel.alipay.dao.direct;
|
||||
|
||||
import cn.daxpay.open.channel.alipay.entity.direct.AlipayDirectAppCapability;
|
||||
import cn.daxpay.open.platform.common.mybatisplus.impl.BaseManager;
|
||||
import cn.daxpay.open.platform.core.annotation.IgnoreTenant;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -36,12 +35,6 @@ public class AlipayDirectAppCapabilityManager extends BaseManager<AlipayDirectAp
|
||||
.oneOpt();
|
||||
}
|
||||
|
||||
/// 根据通道商户号与支付能力查询单条关联(认证引导,忽略租户)
|
||||
@IgnoreTenant
|
||||
public Optional<AlipayDirectAppCapability> findOneNotTenant(String channelMchNo, String capability) {
|
||||
return findOne(channelMchNo, capability);
|
||||
}
|
||||
|
||||
/// 根据通道商户号删除全部关联(批量保存时先清后插)
|
||||
public void deleteByChannelMchNo(String channelMchNo) {
|
||||
lambdaUpdate()
|
||||
|
||||
@@ -2,7 +2,6 @@ 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;
|
||||
@@ -14,7 +13,6 @@ import java.util.Optional;
|
||||
///
|
||||
/// - 配置态 CRUD: [#listByMchNoAndChannelMchNo]、[#existsByChannelMchNoAndAliAppId]、[#findFirstByMchNo]
|
||||
/// - 支付/回调(已装载 mchNo): 租户内 [#findFirstByChannelMchNo]、[#findFirstByChannelMchNoAndAppType]
|
||||
/// - 认证引导: 方法名带 NotTenant
|
||||
///
|
||||
@Slf4j
|
||||
@Service
|
||||
@@ -66,16 +64,4 @@ public class AlipayDirectAppManager extends BaseManager<AlipayDirectAppMapper, A
|
||||
.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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package cn.daxpay.open.channel.douyin.dao.direct;
|
||||
|
||||
import cn.daxpay.open.channel.douyin.entity.direct.DouyinDirectAppCapability;
|
||||
import cn.daxpay.open.platform.common.mybatisplus.impl.BaseManager;
|
||||
import cn.daxpay.open.platform.core.annotation.IgnoreTenant;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -36,11 +35,6 @@ public class DouyinDirectAppCapabilityManager extends BaseManager<DouyinDirectAp
|
||||
.oneOpt();
|
||||
}
|
||||
|
||||
/// 根据通道商户号与支付能力查询单条关联(认证引导,忽略租户)
|
||||
@IgnoreTenant
|
||||
public Optional<DouyinDirectAppCapability> findOneNotTenant(String channelMchNo, String capability) {
|
||||
return findOne(channelMchNo, capability);
|
||||
}
|
||||
|
||||
/// 根据通道商户号删除全部关联(批量保存时先清后插)
|
||||
public void deleteByChannelMchNo(String channelMchNo) {
|
||||
|
||||
@@ -2,7 +2,6 @@ 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;
|
||||
@@ -12,7 +11,6 @@ import java.util.Optional;
|
||||
///
|
||||
/// - 配置态 CRUD: [#listByMchNoAndChannelMchNo]、[#existsByChannelMchNoAndDouyinAppId]
|
||||
/// - 支付/回调(已装载 mchNo): 租户内 [#findFirstByChannelMchNo]、[#findFirstByChannelMchNoAndAppType]
|
||||
/// - 认证引导: 方法名带 NotTenant
|
||||
///
|
||||
@Repository
|
||||
public class DouyinDirectAppManager extends BaseManager<DouyinDirectAppMapper, DouyinDirectApp> {
|
||||
@@ -58,16 +56,4 @@ public class DouyinDirectAppManager extends BaseManager<DouyinDirectAppMapper, D
|
||||
.oneOpt();
|
||||
}
|
||||
|
||||
/// 根据通道商户号取首个应用(认证引导,忽略租户)
|
||||
@IgnoreTenant
|
||||
public Optional<DouyinDirectApp> findFirstByChannelMchNoNotTenant(String channelMchNo) {
|
||||
return findFirstByChannelMchNo(channelMchNo);
|
||||
}
|
||||
|
||||
/// 根据通道商户号与应用类型取首个应用(认证引导,忽略租户)
|
||||
@IgnoreTenant
|
||||
public Optional<DouyinDirectApp> findFirstByChannelMchNoAndAppTypeNotTenant(String channelMchNo, String appType) {
|
||||
return findFirstByChannelMchNoAndAppType(channelMchNo, appType);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package cn.daxpay.open.channel.wechat.dao.direct;
|
||||
|
||||
import cn.daxpay.open.channel.wechat.entity.direct.WechatDirectAppCapability;
|
||||
import cn.daxpay.open.platform.common.mybatisplus.impl.BaseManager;
|
||||
import cn.daxpay.open.platform.core.annotation.IgnoreTenant;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -36,12 +35,6 @@ public class WechatDirectAppCapabilityManager extends BaseManager<WechatDirectAp
|
||||
.oneOpt();
|
||||
}
|
||||
|
||||
/// 根据通道商户号与支付能力查询单条关联(认证等无租户上下文时使用,忽略租户)
|
||||
@IgnoreTenant
|
||||
public Optional<WechatDirectAppCapability> findOneNotTenant(String channelMchNo, String capability) {
|
||||
return findOne(channelMchNo, capability);
|
||||
}
|
||||
|
||||
/// 根据通道商户号删除全部关联(批量保存时先清后插)
|
||||
public void deleteByChannelMchNo(String channelMchNo) {
|
||||
lambdaUpdate()
|
||||
|
||||
@@ -52,18 +52,6 @@ public class WechatDirectAppManager extends BaseManager<WechatDirectAppMapper, W
|
||||
.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) {
|
||||
|
||||
@@ -2,7 +2,6 @@ package cn.daxpay.open.channel.wechat.dao.isv;
|
||||
|
||||
import cn.daxpay.open.channel.wechat.entity.isv.WechatIsvMchAppCapability;
|
||||
import cn.daxpay.open.platform.common.mybatisplus.impl.BaseManager;
|
||||
import cn.daxpay.open.platform.core.annotation.IgnoreTenant;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -36,12 +35,6 @@ public class WechatIsvMchAppCapabilityManager extends BaseManager<WechatIsvMchAp
|
||||
.oneOpt();
|
||||
}
|
||||
|
||||
/// 根据通道商户号与支付能力查询单条关联(认证引导,忽略租户)
|
||||
@IgnoreTenant
|
||||
public Optional<WechatIsvMchAppCapability> findOneNotTenant(String channelMchNo, String capability) {
|
||||
return findOne(channelMchNo, capability);
|
||||
}
|
||||
|
||||
/// 根据通道商户号删除全部关联(批量保存时先清后插)
|
||||
public void deleteByChannelMchNo(String channelMchNo) {
|
||||
lambdaUpdate()
|
||||
|
||||
@@ -12,8 +12,7 @@ import java.util.Optional;
|
||||
///
|
||||
/// 服务商通道商户应用(子商户应用)数据访问管理器。方法按租户隔离边界分两类:
|
||||
/// - 配置态(管理端 CRUD, 带租户隔离): [#listByMchNoAndChannelMchNo]、[#existsByChannelMchNoAndWxAppId]
|
||||
/// - 运行态(认证/支付解析, 忽略租户, 方法名带 NotTenant): [#findFirstByChannelMchNoNotTenant]、
|
||||
/// [#findFirstByChannelMchNoAndAppTypeNotTenant]、[#findByChannelMchNoAndWxAppIdNotTenant];
|
||||
/// - 运行态(认证/支付解析, 忽略租户, 方法名带 NotTenant): [#findByChannelMchNoAndWxAppIdNotTenant];
|
||||
/// 按主键见基类 [BaseManager.findByIdNotTenant]
|
||||
///
|
||||
@Repository
|
||||
@@ -29,25 +28,6 @@ public class WechatIsvMchAppManager extends BaseManager<WechatIsvMchAppMapper, W
|
||||
.list();
|
||||
}
|
||||
|
||||
/// 按通道商户号查询首个应用(能力解析兜底时使用, 忽略租户隔离)
|
||||
@IgnoreTenant
|
||||
public Optional<WechatIsvMchApp> findFirstByChannelMchNoNotTenant(String channelMchNo) {
|
||||
return firstOpt(q -> q
|
||||
.eq(WechatIsvMchApp::getChannelMchNo, channelMchNo)
|
||||
.orderByAsc(WechatIsvMchApp::getCreateTime)
|
||||
.orderByAsc(WechatIsvMchApp::getId));
|
||||
}
|
||||
|
||||
/// 按通道商户号与应用类型查询首个应用(能力→应用类型推导时使用, 忽略租户隔离)
|
||||
@IgnoreTenant
|
||||
public Optional<WechatIsvMchApp> findFirstByChannelMchNoAndAppTypeNotTenant(String channelMchNo, String appType) {
|
||||
return firstOpt(q -> q
|
||||
.eq(WechatIsvMchApp::getChannelMchNo, channelMchNo)
|
||||
.eq(WechatIsvMchApp::getAppType, appType)
|
||||
.orderByAsc(WechatIsvMchApp::getCreateTime)
|
||||
.orderByAsc(WechatIsvMchApp::getId));
|
||||
}
|
||||
|
||||
/// 按通道商户号与wxAppId查询应用(opAppId显式指定认证应用时使用, 校验该appId在系统中预配过, 忽略租户隔离)
|
||||
@IgnoreTenant
|
||||
public Optional<WechatIsvMchApp> findByChannelMchNoAndWxAppIdNotTenant(String channelMchNo, String wxAppId) {
|
||||
|
||||
@@ -1,24 +1,10 @@
|
||||
package cn.daxpay.open.payment.common.util;
|
||||
|
||||
import cn.daxpay.open.platform.core.exception.operation.OperationFailException;
|
||||
import cn.daxpay.open.platform.core.enums.pay.channel.PayMethodEnum;
|
||||
import cn.daxpay.open.platform.core.enums.pay.channel.PayProviderEnum;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.Charset;
|
||||
import java.time.Duration;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import cn.daxpay.open.platform.core.code.CommonCode;
|
||||
|
||||
/// # 支付工具类
|
||||
///
|
||||
@@ -30,84 +16,4 @@ public class PayUtil {
|
||||
return OffsetDateTime.now(ZoneOffset.UTC).plus(minute, ChronoUnit.MINUTES);
|
||||
}
|
||||
|
||||
/// 获取支付单的超时分钟数, 舍去秒数, 所以会有大约一分钟的误差
|
||||
public int getPaymentExpiredTime(OffsetDateTime date) {
|
||||
Duration duration = Duration.between(OffsetDateTime.now(ZoneOffset.UTC), date);
|
||||
return Math.toIntExact(duration.getSeconds() / 60);
|
||||
}
|
||||
|
||||
/// 保留两位小数
|
||||
public BigDecimal toDecimal(BigDecimal amount) {
|
||||
return amount.setScale(2, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
/// 获取请求参数
|
||||
public Map<String, String> toMap(HttpServletRequest request) {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
Map<String, String[]> requestParams = request.getParameterMap();
|
||||
|
||||
for (String name : requestParams.keySet()) {
|
||||
String[] values = requestParams.get(name);
|
||||
String valueStr = "";
|
||||
|
||||
for (int i = 0; i < values.length; ++i) {
|
||||
valueStr = i == values.length - 1 ? valueStr + values[i] : valueStr + values[i] + ",";
|
||||
}
|
||||
|
||||
params.put(name, valueStr);
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
/// 是否为付款码类支付方式
|
||||
public boolean isBarcodePayMethod(String methodCode) {
|
||||
if (StrUtil.isBlank(methodCode)) {
|
||||
return false;
|
||||
}
|
||||
PayMethodEnum method = PayMethodEnum.findByCode(methodCode);
|
||||
return method == PayMethodEnum.AGGREGATE_PAY_BARCODE
|
||||
|| method == PayMethodEnum.WECHAT_BARCODE
|
||||
|| method == PayMethodEnum.ALIPAY_BARCODE
|
||||
|| method == PayMethodEnum.UNION_PAY_BARCODE;
|
||||
}
|
||||
|
||||
/// 获取付款码类型
|
||||
public PayProviderEnum getBarCodeType(String barCode) {
|
||||
// 支付宝
|
||||
String[] ali = {"25", "26", "27", "28", "29", "30"};
|
||||
if (StrUtil.startWithAny(barCode.substring(0, 2), ali)) {
|
||||
return PayProviderEnum.ALIPAY;
|
||||
}
|
||||
// 微信
|
||||
String[] wx = {"10", "11", "12", "13", "14", "15"};
|
||||
if (StrUtil.startWithAny(barCode.substring(0, 2), wx)) {
|
||||
return PayProviderEnum.WECHAT;
|
||||
}
|
||||
// 银联
|
||||
if (StrUtil.startWith(barCode.substring(0, 2), "62")) {
|
||||
return PayProviderEnum.UNION_PAY;
|
||||
}
|
||||
// 订单: 不支持的条码类型
|
||||
throw new OperationFailException(CommonCode.FAIL_CODE, "error.payment.order.unsupportedBarcodeType");
|
||||
}
|
||||
|
||||
/// 转换为RestClient使用的form表单参数
|
||||
public LinkedMultiValueMap<String, String> toFormData(Map<String, ?> param) {
|
||||
// 转换为 MultiValueMap<String, String>
|
||||
var formData = new LinkedMultiValueMap<String, String>();
|
||||
// 注意:Object 要转 String
|
||||
param.forEach((key, value) -> formData.add(key, String.valueOf(value)));
|
||||
return formData;
|
||||
}
|
||||
|
||||
/// 转换为Get请求使用的QueryParam参数,不进行编码
|
||||
public String toQueryParam(Map<String, String> param) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
param.forEach((key, value) -> sb.append(key).append("=").append(URLEncoder.encode(value, Charset.defaultCharset())).append("&"));
|
||||
if (!sb.isEmpty()) {
|
||||
sb.deleteCharAt(sb.length() - 1);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -30,11 +30,6 @@ public class PayCapabilityManager extends BaseManager<PayCapabilityMapper, PayCa
|
||||
return lambdaQuery().eq(PayCapability::getCode, code).oneOpt();
|
||||
}
|
||||
|
||||
/// 是否存在任意主数据行(预留:后续若能力参与运行时收窄可据此分支)
|
||||
public boolean hasAny() {
|
||||
return lambdaQuery().count() > 0;
|
||||
}
|
||||
|
||||
/// 分页(默认 sort_no、id 升序)
|
||||
public Page<PayCapability> page(PageParam pageParam, PayCapabilityQuery query) {
|
||||
Page<PayCapability> mpPage = MpUtil.getMpPage(pageParam);
|
||||
|
||||
@@ -37,15 +37,6 @@ public class PayProviderMethodManager extends BaseManager<PayProviderMethodMappe
|
||||
return provider + "|" + method;
|
||||
}
|
||||
|
||||
/// 某支付方式下的全部关联(未删除)
|
||||
public List<PayProviderMethod> listByMethod(String methodCode) {
|
||||
return lambdaQuery()
|
||||
.eq(PayProviderMethod::getMethod, methodCode)
|
||||
.orderByAsc(PayProviderMethod::getSortNo)
|
||||
.orderByAsc(PayProviderMethod::getId)
|
||||
.list();
|
||||
}
|
||||
|
||||
/// 某支付渠道下的全部关联(未删除)
|
||||
public List<PayProviderMethod> listByProvider(String providerCode) {
|
||||
return lambdaQuery()
|
||||
|
||||
@@ -73,11 +73,6 @@ public class PayChannelService {
|
||||
return buildChannels();
|
||||
}
|
||||
|
||||
/// 按通道编码取展示名称
|
||||
public String findNameByCode(String code) {
|
||||
return resolveChannelName(code);
|
||||
}
|
||||
|
||||
/// 枚举与库表合并为通道列表
|
||||
private List<PayChannelResult> buildChannels() {
|
||||
Map<String, PayChannel> dbMap = payChannelManager.listAllOrdered().stream()
|
||||
|
||||
@@ -90,11 +90,6 @@ public class PayProviderMethodService {
|
||||
.toList();
|
||||
}
|
||||
|
||||
/// 同 {@link #listMethodsForProvider(PayProviderEnum)}
|
||||
public List<PayMethodEnum> listMethodsForBrand(PayProviderEnum brand) {
|
||||
return listMethodsForProvider(brand);
|
||||
}
|
||||
|
||||
/// 平铺返回目录中的渠道与支付方式(不按渠道分组,不含支持的产品)
|
||||
public List<PayProviderMethodResult> listDirectoryFlat() {
|
||||
DirectoryLoadContext context = loadDirectoryContext();
|
||||
|
||||
@@ -7,7 +7,6 @@ import cn.daxpay.open.platform.core.annotation.IgnoreTenant;
|
||||
import cn.daxpay.open.platform.core.exception.config.ConfigNotExistException;
|
||||
import cn.daxpay.open.platform.core.rest.param.PageParam;
|
||||
import cn.daxpay.open.payment.merchant.entity.appinfo.MchAppInfo;
|
||||
import cn.daxpay.open.platform.core.enums.merchant.MchAppStatusEnum;
|
||||
import cn.daxpay.open.payment.merchant.param.appinfo.MchAppInfoQuery;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
@@ -48,20 +47,6 @@ public class MchAppInfoManager extends BaseManager<MchAppInfoMapper, MchAppInfo>
|
||||
return this.findByField(MchAppInfo::getAppId, appId);
|
||||
}
|
||||
|
||||
/// 按应用号加载商户应用(运行态引导,忽略租户)
|
||||
@IgnoreTenant
|
||||
public MchAppInfo requireByAppIdNotTenant(String appId) {
|
||||
return findByAppIdNotTenant(appId)
|
||||
// 商户: 未找到指定应用的配置
|
||||
.orElseThrow(() -> new ConfigNotExistException("error.payment.merchant.specifiedAppConfigNotFound"));
|
||||
}
|
||||
|
||||
/// 按应用号解析商户号(运行态引导,忽略租户)
|
||||
@IgnoreTenant
|
||||
public String requireMchNoByAppIdNotTenant(String appId) {
|
||||
return requireByAppIdNotTenant(appId).getMchNo();
|
||||
}
|
||||
|
||||
/// 分页
|
||||
public Page<MchAppInfo> page(PageParam pageParam, MchAppInfoQuery query) {
|
||||
Page<MchAppInfo> mpPage = MpUtil.getMpPage(pageParam);
|
||||
@@ -86,14 +71,6 @@ public class MchAppInfoManager extends BaseManager<MchAppInfoMapper, MchAppInfo>
|
||||
.oneOpt();
|
||||
}
|
||||
|
||||
/// 根据商户号查询启用的应用
|
||||
public List<MchAppInfo> findAllByMchNoAndEnable(String mchNo) {
|
||||
return lambdaQuery()
|
||||
.eq(MchAppInfo::getMchNo, mchNo)
|
||||
.eq(MchAppInfo::getStatus, MchAppStatusEnum.ENABLE.getCode())
|
||||
.list();
|
||||
}
|
||||
|
||||
/// 根据商户号查询应用
|
||||
public List<MchAppInfo> findAllByMchNo(String mchNo) {
|
||||
return lambdaQuery()
|
||||
|
||||
@@ -49,9 +49,4 @@ public class MerchantInfoManager extends BaseManager<MerchantInfoMapper, Merchan
|
||||
.list();
|
||||
}
|
||||
|
||||
/// 查询商户号是否存在
|
||||
public boolean existedByMchNo(String mchNo) {
|
||||
return existedByField(MerchantInfo::getMchNo, mchNo);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ import cn.daxpay.open.platform.core.rest.param.PageParam;
|
||||
import cn.daxpay.open.platform.core.rest.result.PageResult;
|
||||
import cn.daxpay.open.platform.iam.service.client.ClientCodeService;
|
||||
import cn.daxpay.open.platform.core.exception.config.ConfigErrorException;
|
||||
import cn.daxpay.open.platform.core.exception.config.ConfigNotEnableException;
|
||||
import cn.daxpay.open.platform.core.exception.config.ConfigNotExistException;
|
||||
import cn.daxpay.open.payment.common.context.PaymentContext;
|
||||
import cn.daxpay.open.payment.merchant.convert.appinfo.MchAppInfoConvert;
|
||||
@@ -19,7 +18,6 @@ import cn.daxpay.open.payment.merchant.dao.appinfo.MchAppInfoManager;
|
||||
import cn.daxpay.open.payment.merchant.dao.info.MerchantInfoManager;
|
||||
import cn.daxpay.open.payment.merchant.entity.appinfo.MchAppInfo;
|
||||
import cn.daxpay.open.payment.merchant.entity.info.MerchantInfo;
|
||||
import cn.daxpay.open.platform.core.enums.merchant.MerchantStatusEnum;
|
||||
import cn.daxpay.open.payment.merchant.param.appinfo.MchAppInfoParam;
|
||||
import cn.daxpay.open.payment.merchant.param.appinfo.MchAppInfoQuery;
|
||||
import cn.daxpay.open.payment.merchant.result.appinfo.MchAppInfoResult;
|
||||
@@ -149,31 +147,6 @@ public class MchAppInfoService {
|
||||
return mchApp.toResult();
|
||||
}
|
||||
|
||||
/// 启用下拉列表, 需要应用和商户都是启用状态
|
||||
public List<LabelValue> dropdownByEnable(String mchNo) {
|
||||
if (clientCodeService.getClientCode().equals(ClientEnum.MERCHANT.getCode())) {
|
||||
mchNo = paymentContext.getMchNo();
|
||||
}
|
||||
// 判断商户状态
|
||||
MerchantInfo merchantInfo = merchantInfoManager.findByMchNo(mchNo)
|
||||
// 商户: 商户不存在
|
||||
.orElseThrow(() -> new DataNotExistException("error.payment.merchant.mchNotExist"));
|
||||
if (!Objects.equals(merchantInfo.getStatus(), MerchantStatusEnum.ENABLE.getCode())) {
|
||||
throw new ConfigNotEnableException(CommonCode.FAIL_CODE, "pay.error.assist.mchNotEnabled");
|
||||
}
|
||||
// 查询启用的应用
|
||||
return mchAppInfoManager.findAllByMchNoAndEnable(mchNo).stream()
|
||||
.map(o -> new LabelValue(o.getAppName(), o.getAppId()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/// 查询商户默认应用号
|
||||
public String findDefaultAppId(String mchNo) {
|
||||
return mchAppInfoManager.findDefaultByMchNo(mchNo)
|
||||
.map(MchAppInfo::getAppId)
|
||||
.orElseThrow(() -> new DataNotExistException("error.payment.merchant.defaultAppNotConfigured"));
|
||||
}
|
||||
|
||||
/// 下拉列表, 不判断应用和商户的状态
|
||||
public List<LabelValue> dropdown(String mchNo) {
|
||||
if (clientCodeService.getClientCode().equals(ClientEnum.MERCHANT.getCode())) {
|
||||
|
||||
@@ -16,20 +16,6 @@ import java.util.List;
|
||||
@UtilityClass
|
||||
public class PaymentStrategyFactory {
|
||||
|
||||
/// 根据通道编码获取策略
|
||||
/// @param channel 通道编码
|
||||
/// @param clazz 策略类型
|
||||
/// @return 策略类
|
||||
/// @param <T> 需要为 PaymentStrategy 的子类
|
||||
public <T extends PaymentStrategy> T create(String channel, Class<T> clazz) {
|
||||
var beansOfType = SpringUtil.getBeansOfType(clazz);
|
||||
return beansOfType.values().stream()
|
||||
.filter(strategy -> strategy.getProduct().getChannel().equals(channel))
|
||||
.findFirst()
|
||||
// 不支持的能力: {0}
|
||||
.orElseThrow(() -> new UnsupportedAbilityException("pay.error.unsupportedAbilityWithDetail", channel));
|
||||
}
|
||||
|
||||
/// 根据产品编码获取策略
|
||||
/// @param product 产品编码
|
||||
/// @param clazz 策略类型
|
||||
@@ -44,12 +30,6 @@ public class PaymentStrategyFactory {
|
||||
.orElseThrow(() -> new UnsupportedAbilityException("pay.error.unsupportedAbilityWithDetail", product));
|
||||
}
|
||||
|
||||
/// 判断传入通道的策略是否存在
|
||||
public <T extends PaymentStrategy> boolean existsByChannel(String channel, Class<T> clazz) {
|
||||
var beansOfType = SpringUtil.getBeansOfType(clazz);
|
||||
return beansOfType.values().stream().anyMatch(strategy -> strategy.getProduct().getChannel().equals(channel));
|
||||
}
|
||||
|
||||
/// 判断传入产品的策略是否存在
|
||||
public <T extends PaymentStrategy> boolean existsByProduct(String product, Class<T> clazz) {
|
||||
var beansOfType = SpringUtil.getBeansOfType(clazz);
|
||||
|
||||
@@ -27,13 +27,6 @@ public class PayRefundOrderManager extends BaseManager<PayRefundOrderMapper, Pay
|
||||
return findByField(PayRefundOrder::getOutRefundNo, outRefundNo);
|
||||
}
|
||||
|
||||
/// 根据原支付订单号查询退款订单数量(用于判断是否已退款)
|
||||
public long countByOrderNo(String orderNo) {
|
||||
return lambdaQuery()
|
||||
.eq(PayRefundOrder::getOrderNo, orderNo)
|
||||
.count();
|
||||
}
|
||||
|
||||
/// 分页查询(管理端), 默认按创建时间倒序
|
||||
public Page<PayRefundOrder> page(PageParam pageParam, PayRefundOrderQuery query) {
|
||||
Page<PayRefundOrder> mpPage = MpUtil.getMpPage(pageParam);
|
||||
|
||||
@@ -29,14 +29,6 @@ public class GenerateAuthUrlParam extends MerchantPaymentCommonParam {
|
||||
@Schema(description = "认证类型")
|
||||
private String authType = ChannelAuthTypeEnum.WECHAT.getCode();
|
||||
|
||||
/// 自定义授权认证路径(暂未实现)
|
||||
///
|
||||
/// 当前三通道统一使用固定路径(`/auth/wechat` / `/auth/alipay` / `/auth/douyin`) + state 透传 authToken,
|
||||
/// 本字段传入会被忽略。保留字段仅为兼容旧调用方, 后续若支持自定义路径再启用。
|
||||
@Deprecated
|
||||
@Schema(description = "授权认证路径(暂未实现, 忽略)")
|
||||
private String authPath;
|
||||
|
||||
/// 支付产品编码, 决定走哪个通道产品的认证策略
|
||||
/// 可选: 缺失时由 [cn.daxpay.open.payment.auth.ChannelAuthService] 从通道商户号(channelMchNo)反查
|
||||
/// @see cn.daxpay.open.platform.core.enums.pay.channel.ProductEnum
|
||||
|
||||
@@ -61,12 +61,4 @@ public class MerchantInfoService {
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/// 商户下拉框
|
||||
public List<LabelValue> dropdownByEnable() {
|
||||
List<MerchantInfo> list = merchantInfoManager.findAllByEnable();
|
||||
return list.stream()
|
||||
.map(mch -> new LabelValue(mch.getMchName(),mch.getMchNo()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
package cn.daxpay.open.platform.capability.wechat.auth.result;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/// # 微信用户信息结果
|
||||
///
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class WechatUserInfoResult {
|
||||
|
||||
/// 用户OpenId
|
||||
private String openId;
|
||||
|
||||
/// 用户昵称
|
||||
private String nickname;
|
||||
|
||||
/// 用户头像
|
||||
private String headImgUrl;
|
||||
|
||||
/// 性别:0-未知,1-男,2-女
|
||||
private Integer sex;
|
||||
|
||||
/// 国家
|
||||
private String country;
|
||||
|
||||
/// 省份
|
||||
private String province;
|
||||
|
||||
/// 城市
|
||||
private String city;
|
||||
|
||||
/// 语言
|
||||
private String language;
|
||||
|
||||
/// 是否关注公众号
|
||||
private Boolean subscribe;
|
||||
|
||||
/// 关注时间
|
||||
private Long subscribeTime;
|
||||
|
||||
/// UnionId
|
||||
private String unionId;
|
||||
}
|
||||
@@ -3,13 +3,10 @@ package cn.daxpay.open.platform.capability.wechat.auth.service;
|
||||
import cn.daxpay.open.platform.core.exception.operation.OperationFailException;
|
||||
import cn.daxpay.open.platform.capability.wechat.auth.result.WechatAuthResult;
|
||||
import cn.daxpay.open.platform.capability.wechat.auth.result.WechatAuthUrlResult;
|
||||
import cn.daxpay.open.platform.capability.wechat.auth.result.WechatUserInfoResult;
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.chanjar.weixin.common.api.WxConsts;
|
||||
import me.chanjar.weixin.common.bean.WxOAuth2UserInfo;
|
||||
import me.chanjar.weixin.common.bean.oauth2.WxOAuth2AccessToken;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import me.chanjar.weixin.mp.api.WxMpService;
|
||||
@@ -36,20 +33,6 @@ public class WechatMpAuthService {
|
||||
return new WechatAuthUrlResult().setAuthUrl(authUrl).setQueryCode(queryCode);
|
||||
}
|
||||
|
||||
/// 生成用户信息授权链接
|
||||
/// @param redirectUrl 回调地址(固定路径, 不含动态段)
|
||||
/// @param appId 公众号AppId
|
||||
/// @param appSecret 公众号AppSecret
|
||||
/// @param state OAuth state 参数(透传会话标识 authToken)
|
||||
/// @return 授权链接结果
|
||||
public WechatAuthUrlResult generateUserInfoAuthUrl(String redirectUrl, String appId, String appSecret, String state) {
|
||||
WxMpService wxMpService = this.getWxMpService(appId, appSecret);
|
||||
String queryCode = RandomUtil.randomString(10);
|
||||
// 使用SNSAPI_USERINFO获取用户信息
|
||||
String authUrl = wxMpService.getOAuth2Service().buildAuthorizationUrl(redirectUrl, WxConsts.OAuth2Scope.SNSAPI_USERINFO, state);
|
||||
return new WechatAuthUrlResult().setAuthUrl(authUrl).setQueryCode(queryCode);
|
||||
}
|
||||
|
||||
/// 获取微信AccessToken和OpenId
|
||||
/// @param authCode 授权码
|
||||
/// @param appId 微信公众号AppId
|
||||
@@ -68,43 +51,6 @@ public class WechatMpAuthService {
|
||||
.setOpenId(accessToken.getOpenId());
|
||||
}
|
||||
|
||||
/// 获取用户信息(包含OpenId和用户详情)
|
||||
/// @param authCode 授权码
|
||||
/// @param appId 公众号AppId
|
||||
/// @param appSecret 公众号AppSecret
|
||||
/// @return 用户信息结果
|
||||
public WechatUserInfoResult getUserInfoByAuthCode(String authCode, String appId, String appSecret) {
|
||||
WxMpService wxMpService = this.getWxMpService(appId, appSecret);
|
||||
|
||||
try {
|
||||
// 获取AccessToken
|
||||
WxOAuth2AccessToken accessToken = wxMpService.getOAuth2Service().getAccessToken(authCode);
|
||||
|
||||
// 获取用户信息
|
||||
WxOAuth2UserInfo userInfo = wxMpService.getOAuth2Service().getUserInfo(accessToken, null);
|
||||
|
||||
// 转换结果
|
||||
var result = new WechatUserInfoResult();
|
||||
result.setOpenId(userInfo.getOpenid());
|
||||
result.setNickname(userInfo.getNickname());
|
||||
result.setHeadImgUrl(userInfo.getHeadImgUrl());
|
||||
result.setSex(userInfo.getSex());
|
||||
result.setCountry(userInfo.getCountry());
|
||||
result.setProvince(userInfo.getProvince());
|
||||
result.setCity(userInfo.getCity());
|
||||
// 注意:weixin-java-common 4.8.1.B版本的WxOAuth2UserInfo不再提供getLanguage()方法
|
||||
result.setUnionId(userInfo.getUnionId());
|
||||
|
||||
log.info("获取用户信息成功,openId: {}", userInfo.getOpenid());
|
||||
return result;
|
||||
|
||||
} catch (WxErrorException e) {
|
||||
log.error("获取用户信息失败,错误: {}", e.getMessage());
|
||||
// 微信: 获取用户信息失败: {0}
|
||||
throw new OperationFailException("error.channel.wechat.userInfoFetchFailed", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/// 获取微信公众号API的Service
|
||||
public WxMpService getWxMpService(String appId, String appSecret) {
|
||||
WxMpService wxMpService = new WxMpServiceImpl();
|
||||
|
||||
@@ -1,15 +1,8 @@
|
||||
package cn.daxpay.open.platform.common.mybatisplus.util;
|
||||
|
||||
import cn.daxpay.open.platform.common.mybatisplus.function.ToResult;
|
||||
import cn.daxpay.open.platform.core.annotation.BigField;
|
||||
import cn.daxpay.open.platform.core.exception.BizException;
|
||||
import cn.daxpay.open.platform.core.rest.param.PageParam;
|
||||
import cn.daxpay.open.platform.core.rest.result.PageResult;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
|
||||
import com.baomidou.mybatisplus.core.metadata.TableInfo;
|
||||
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
|
||||
import com.baomidou.mybatisplus.core.plugins.IgnoreStrategy;
|
||||
@@ -19,23 +12,16 @@ import com.baomidou.mybatisplus.core.toolkit.LambdaUtils;
|
||||
import com.baomidou.mybatisplus.core.toolkit.support.ColumnCache;
|
||||
import com.baomidou.mybatisplus.core.toolkit.support.LambdaMeta;
|
||||
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
|
||||
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import org.apache.ibatis.reflection.property.PropertyNamer;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.lang.reflect.Method;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
import cn.daxpay.open.platform.core.code.CommonCode;
|
||||
|
||||
/// # MP工具类
|
||||
///
|
||||
@@ -72,27 +58,6 @@ public class MpUtil {
|
||||
return columnCache.getColumn();
|
||||
}
|
||||
|
||||
/// 获取行名称
|
||||
/// @param readMethod 对象字段对应的读取方法对象
|
||||
/// @param clazz 实体类类型. 辅助进行判断, 传多个只有第一个生效,可以为空, 为空时使用读取方法对应的Class类,
|
||||
/// @return 字段名
|
||||
@SafeVarargs
|
||||
public <T> String getColumnName(Method readMethod, Class<T>... clazz) {
|
||||
Class<?> beanClass;
|
||||
if (ArrayUtil.isNotEmpty(clazz)) {
|
||||
beanClass = clazz[0];
|
||||
}
|
||||
else {
|
||||
beanClass = readMethod.getDeclaringClass();
|
||||
}
|
||||
|
||||
Map<String, ColumnCache> columnMap = LambdaUtils.getColumnMap(beanClass);
|
||||
Assert.notEmpty(columnMap, "错误:无法执行.因为无法获取到实体类的表对应缓存!");
|
||||
String fieldName = PropertyNamer.methodToProperty(readMethod.getName());
|
||||
ColumnCache columnCache = columnMap.get(LambdaUtils.formatKey(fieldName));
|
||||
return columnCache.getColumn();
|
||||
}
|
||||
|
||||
/// mp page转换为 PageResult 同时进行dto转换
|
||||
public <T> PageResult<T> toPageResult(Page<? extends ToResult<T>> page) {
|
||||
if (Objects.isNull(page)) {
|
||||
@@ -111,38 +76,6 @@ public class MpUtil {
|
||||
return list.stream().map(ToResult::toResult).toList();
|
||||
}
|
||||
|
||||
/// 批量执行语句, 通常用于for循环方式的批量插入
|
||||
public <T> void executeBatch(List<T> saveList, Consumer<List<T>> consumer, int batchSize) {
|
||||
// 开始游标
|
||||
int start = 0;
|
||||
// 结束游标
|
||||
int end = Math.min(batchSize, saveList.size());
|
||||
while (start < end) {
|
||||
List<T> list = ListUtil.sub(saveList, start, end);
|
||||
start = end;
|
||||
end = Math.min(end + batchSize, saveList.size());
|
||||
consumer.accept(list);
|
||||
}
|
||||
}
|
||||
|
||||
/// 字段是否存在长文本注解
|
||||
public static boolean excludeBigField(TableFieldInfo tableFieldInfo) {
|
||||
BigField annotation = tableFieldInfo.getField().getAnnotation(BigField.class);
|
||||
return Objects.isNull(annotation);
|
||||
}
|
||||
|
||||
/// 获取的一条数据, 有多条取第一条
|
||||
public <T> Optional<T> findOne(LambdaQueryChainWrapper<T> lambdaQuery) {
|
||||
Page<T> mpPage = new Page<>(0, 1);
|
||||
Page<T> page = lambdaQuery.page(mpPage);
|
||||
// 关闭 count 查询
|
||||
page.setSearchCount(false);
|
||||
if (CollUtil.isNotEmpty(page.getRecords())) {
|
||||
return Optional.of(page.getRecords().getFirst());
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
/// 获取关联的 TableInfo
|
||||
public TableInfo getTableInfo(String tableName) {
|
||||
for (TableInfo tableInfo : TableInfoHelper.getTableInfos()) {
|
||||
@@ -153,17 +86,6 @@ public class MpUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
/// 获取当前数据库类型, 别忘了关闭, 不然会连接池泄露
|
||||
public String getDbType(){
|
||||
try {
|
||||
try (Connection connection = SpringUtil.getBean(DataSource.class).getConnection()) {
|
||||
return connection.getMetaData().getDatabaseProductName();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
throw new BizException(CommonCode.FAIL_CODE, "error.common.dbTypeNotFound");
|
||||
}
|
||||
}
|
||||
|
||||
/// 获取主键名称
|
||||
public String getKeyProperty(Class<?> clazz) {
|
||||
TableInfo tableInfo = TableInfoHelper.getTableInfo(clazz);
|
||||
@@ -173,16 +95,6 @@ public class MpUtil {
|
||||
return keyProperty;
|
||||
}
|
||||
|
||||
/// 获取主键值
|
||||
public Object getKeyPropertyValue(Object object) {
|
||||
TableInfo tableInfo = TableInfoHelper.getTableInfo(object.getClass());
|
||||
Assert.notNull(tableInfo, "错误:无法执行.因为找不到实体的 TableInfo 缓存!");
|
||||
String keyProperty = tableInfo.getKeyProperty();
|
||||
Assert.notEmpty(keyProperty, "错误:无法执行.因为无法从实体中找到主键的列!");
|
||||
// 反射获取值
|
||||
return tableInfo.getPropertyValue(object, keyProperty);
|
||||
}
|
||||
|
||||
/// 进入忽略租户作用域(可重入,与 [#clearIgnoreTenant] 成对使用)
|
||||
///
|
||||
/// 基于线程内引用计数:仅 depth 从 0→1 时真正打开 MP 忽略策略;
|
||||
|
||||
@@ -4,12 +4,7 @@ import java.lang.annotation.*;
|
||||
|
||||
/// # 大字段注解
|
||||
///
|
||||
/// 配合 {@linkplain cn.hutool.core.map.MapUtil} 中 excludeBigField 方法使用使用
|
||||
///
|
||||
/// 使用Mp条件构造器器分页查询时样例
|
||||
/// ```java
|
||||
/// wrapper.select(this.getEntityClass (), MpUtil::excludeBigField);
|
||||
/// ```
|
||||
/// 标记实体中体积较大的字段(如文本/二进制),供查询构造时选择性排除。
|
||||
@Target({ ElementType.PARAMETER, ElementType.FIELD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
package cn.daxpay.open.platform.core.util;
|
||||
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/// # BigDecimal相关的工具类
|
||||
///
|
||||
@UtilityClass
|
||||
public class BigDecimalUtil {
|
||||
|
||||
/// 比较大小
|
||||
/// @param first 数字1
|
||||
/// @param last 数字2
|
||||
/// @return first > last =1 / first == last = 0 / first < last = -1
|
||||
public int compareTo(BigDecimal first, BigDecimal last) {
|
||||
BigDecimal newFirst = first != null ? first : BigDecimal.ZERO;
|
||||
BigDecimal newLast = last != null ? last : BigDecimal.ZERO;
|
||||
return newFirst.compareTo(newLast);
|
||||
}
|
||||
|
||||
/// 是否大于
|
||||
public boolean isGreaterThan(BigDecimal first, BigDecimal last) {
|
||||
return compareTo(first, last) > 0;
|
||||
}
|
||||
|
||||
/// 是否大于或等于
|
||||
public boolean isGreaterAndEqualThan(BigDecimal first, BigDecimal last) {
|
||||
return compareTo(first, last) >= 0;
|
||||
}
|
||||
|
||||
/// 是否小于
|
||||
public boolean isLessThan(BigDecimal first, BigDecimal last) {
|
||||
return compareTo(first, last) < 0;
|
||||
}
|
||||
|
||||
/// 是否等于
|
||||
public boolean isEqual(BigDecimal first, BigDecimal last) {
|
||||
return compareTo(first, last) == 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
package cn.daxpay.open.platform.core.util;
|
||||
|
||||
import cn.hutool.core.codec.Base64Encoder;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.PublicKey;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateFactory;
|
||||
|
||||
/// # 证书工具类
|
||||
///
|
||||
@UtilityClass
|
||||
public class CertUtil {
|
||||
|
||||
/// 根据证书文本获取证书
|
||||
/// @param certContent 证书字符串
|
||||
@SneakyThrows
|
||||
public String getCertByContent(String certContent) {
|
||||
CertificateFactory cf = CertificateFactory.getInstance("X.509");
|
||||
Certificate cert = cf.generateCertificate(new ByteArrayInputStream(certContent.getBytes(StandardCharsets.UTF_8)));
|
||||
PublicKey publicKey = cert.getPublicKey();
|
||||
return Base64Encoder.encode(publicKey.getEncoded());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,8 +4,6 @@ import cn.hutool.core.util.ClassUtil;
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/// # 类工具类
|
||||
@@ -29,32 +27,4 @@ public class ClassUtils {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// 递归扫描父类的fields
|
||||
/// @param clas 类
|
||||
/// @param fields 属性
|
||||
public Field[] recursionParents(Class<?> clas, Field[] fields) {
|
||||
if (Objects.nonNull(clas.getSuperclass())) {
|
||||
Class<?> clsSup = clas.getSuperclass();
|
||||
List<Field> fieldList = new ArrayList<>(List.of(fields));
|
||||
// 获取当前class的所有fields的name列表
|
||||
List<String> fdNames = fieldList.stream().map(Field::getName).toList();
|
||||
for (Field pfd : clsSup.getDeclaredFields()) {
|
||||
// 避免重载属性
|
||||
if (fdNames.contains(pfd.getName())) {
|
||||
continue;
|
||||
}
|
||||
fieldList.add(pfd);
|
||||
}
|
||||
fields = new Field[fieldList.size()];
|
||||
int i = 0;
|
||||
for (Object field : fieldList.toArray()) {
|
||||
fields[i] = (Field) field;
|
||||
i++;
|
||||
}
|
||||
fields = recursionParents(clsSup, fields);
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ package cn.daxpay.open.platform.core.util;
|
||||
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
import java.time.*;
|
||||
import java.time.OffsetDateTime;
|
||||
|
||||
/// # java8 时间工具类
|
||||
///
|
||||
@@ -11,11 +11,6 @@ import java.time.*;
|
||||
@UtilityClass
|
||||
public class DateTimeUtil {
|
||||
|
||||
/// 大于
|
||||
public boolean gt(OffsetDateTime now, OffsetDateTime next) {
|
||||
return now.toEpochSecond() > next.toEpochSecond();
|
||||
}
|
||||
|
||||
/// 小于
|
||||
public boolean lt(OffsetDateTime now, OffsetDateTime next) {
|
||||
return now.toEpochSecond() < next.toEpochSecond();
|
||||
@@ -31,49 +26,4 @@ public class DateTimeUtil {
|
||||
return now.toEpochSecond() <= next.toEpochSecond();
|
||||
}
|
||||
|
||||
/// 获取当前 UTC 时间
|
||||
public OffsetDateTime nowUtc() {
|
||||
return OffsetDateTime.now(ZoneOffset.UTC);
|
||||
}
|
||||
|
||||
/// 将 long 类型的 timestamp 转为 OffsetDateTime (UTC)
|
||||
public OffsetDateTime fromEpochMilli(long timestamp) {
|
||||
return Instant.ofEpochMilli(timestamp).atOffset(ZoneOffset.UTC);
|
||||
}
|
||||
|
||||
/// OffsetDateTime 转为 long 类型的 timestamp
|
||||
public long toEpochMilli(OffsetDateTime dateTime) {
|
||||
return dateTime.toInstant().toEpochMilli();
|
||||
}
|
||||
|
||||
/// 将 localDate 转换成当天开始时间的 OffsetDateTime (UTC)
|
||||
/// 用于日期范围查询等场景
|
||||
public OffsetDateTime dateStartUtc(LocalDate localDate) {
|
||||
return localDate.atStartOfDay(ZoneOffset.UTC).toOffsetDateTime();
|
||||
}
|
||||
|
||||
/// 将 localDate 转换成当天结束时间的 OffsetDateTime (UTC)
|
||||
public OffsetDateTime dateEndUtc(LocalDate localDate) {
|
||||
return localDate.atTime(LocalTime.MAX).atZone(ZoneOffset.UTC).toOffsetDateTime();
|
||||
}
|
||||
|
||||
/// 旧版兼容: 将 Asia/Shanghai 时区的 LocalDateTime 转为 UTC OffsetDateTime
|
||||
public OffsetDateTime shanghaiToUtc(LocalDateTime shanghaiTime) {
|
||||
if (shanghaiTime == null) return null;
|
||||
return shanghaiTime.atOffset(ZoneOffset.ofHours(8)).withOffsetSameInstant(ZoneOffset.UTC);
|
||||
}
|
||||
|
||||
/// 旧版兼容: 将 UTC OffsetDateTime 转为 Asia/Shanghai 时区的 LocalDateTime
|
||||
public LocalDateTime utcToShanghai(OffsetDateTime utcTime) {
|
||||
if (utcTime == null) return null;
|
||||
return utcTime.withOffsetSameInstant(ZoneOffset.ofHours(8)).toLocalDateTime();
|
||||
}
|
||||
|
||||
/// 格式化为 ISO 8601 标准时间字符串 (UTC)
|
||||
public String formatIso(OffsetDateTime dateTime) {
|
||||
if (dateTime == null) return null;
|
||||
return dateTime.withOffsetSameInstant(ZoneOffset.UTC).toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,128 +0,0 @@
|
||||
package cn.daxpay.open.platform.core.util;
|
||||
|
||||
import cn.daxpay.open.platform.core.enums.pay.channel.PayMethodEnum;
|
||||
import cn.daxpay.open.platform.core.enums.pay.channel.PayProviderEnum;
|
||||
import cn.daxpay.open.platform.core.model.PayProviderMethodEntry;
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import static cn.daxpay.open.platform.core.enums.pay.channel.PayMethodEnum.*;
|
||||
|
||||
/// # 支付渠道支付方式目录(平台 V1)
|
||||
///
|
||||
/// 全平台固定的「支付渠道 × 支付方式」组合,供路由配置、下单校验、管理端展示复用。
|
||||
/// 与 PayMethodEnum、PayProviderEnum 等枚举类区分,本类为静态目录定义,不放在 enums 包下。
|
||||
@Deprecated
|
||||
@UtilityClass
|
||||
public class PayProviderMethodUtil {
|
||||
|
||||
/// 各支付渠道下固定、有序的支付方式列表
|
||||
private static final Map<PayProviderEnum, List<PayMethodEnum>> PROVIDER_METHODS;
|
||||
|
||||
/// 扁平化目录项,顺序与渠道内列表一致
|
||||
private static final List<PayProviderMethodEntry> ALL_ENTRIES;
|
||||
|
||||
static {
|
||||
Map<PayProviderEnum, List<PayMethodEnum>> providerMethods = new EnumMap<>(PayProviderEnum.class);
|
||||
// 聚合支付:扫码 / 付款码
|
||||
providerMethods.put(PayProviderEnum.AGGREGATE_PAY, List.of(
|
||||
AGGREGATE_PAY_QRCODE,
|
||||
AGGREGATE_PAY_BARCODE
|
||||
));
|
||||
// 微信:JSAPI / APP / H5 / Native / 小程序 / 付款码 / 小程序收银台
|
||||
providerMethods.put(PayProviderEnum.WECHAT, List.of(
|
||||
WECHAT_JSAPI,
|
||||
WECHAT_APP,
|
||||
WECHAT_H5,
|
||||
WECHAT_QR,
|
||||
WECHAT_MINI,
|
||||
WECHAT_BARCODE,
|
||||
WECHAT_CASHIER
|
||||
));
|
||||
// 支付宝:付款码 / 扫码 / APP / 手机网站 / 电脑网站 / JSAPI
|
||||
providerMethods.put(PayProviderEnum.ALIPAY, List.of(
|
||||
ALIPAY_BARCODE,
|
||||
ALIPAY_QR,
|
||||
ALIPAY_APP,
|
||||
ALIPAY_H5,
|
||||
ALIPAY_PC,
|
||||
ALIPAY_JSAPI
|
||||
));
|
||||
// 银联:扫码 / 付款码 / H5 / JSAPI
|
||||
providerMethods.put(PayProviderEnum.UNION_PAY, List.of(
|
||||
UNION_QR,
|
||||
UNION_PAY_BARCODE,
|
||||
UNION_H5,
|
||||
UNION_JSAPI
|
||||
));
|
||||
// Visa:网关 / 刷卡
|
||||
providerMethods.put(PayProviderEnum.VISA, List.of(
|
||||
VISA_CARD_GATEWAY,
|
||||
VISA_CARD_PRESENT
|
||||
));
|
||||
// 万事达:网关 / 刷卡
|
||||
providerMethods.put(PayProviderEnum.MASTERCARD, List.of(
|
||||
MASTERCARD_CARD_GATEWAY,
|
||||
MASTERCARD_CARD_PRESENT
|
||||
));
|
||||
PROVIDER_METHODS = Collections.unmodifiableMap(copyProviderMethods(providerMethods));
|
||||
|
||||
List<PayProviderMethodEntry> entries = new ArrayList<>();
|
||||
for (Map.Entry<PayProviderEnum, List<PayMethodEnum>> entry : PROVIDER_METHODS.entrySet()) {
|
||||
for (PayMethodEnum method : entry.getValue()) {
|
||||
entries.add(new PayProviderMethodEntry(entry.getKey(), method));
|
||||
}
|
||||
}
|
||||
ALL_ENTRIES = List.copyOf(entries);
|
||||
}
|
||||
|
||||
/// 深拷贝渠道-支付方式映射,用于保护静态常量的不可变性
|
||||
private static Map<PayProviderEnum, List<PayMethodEnum>> copyProviderMethods(
|
||||
Map<PayProviderEnum, List<PayMethodEnum>> source) {
|
||||
Map<PayProviderEnum, List<PayMethodEnum>> copy = new EnumMap<>(PayProviderEnum.class);
|
||||
source.forEach((provider, methods) -> copy.put(provider, List.copyOf(methods)));
|
||||
return copy;
|
||||
}
|
||||
|
||||
/// 指定支付渠道下的固定支付方式(有序)
|
||||
public List<PayMethodEnum> methodsOf(PayProviderEnum provider) {
|
||||
if (provider == null) {
|
||||
return List.of();
|
||||
}
|
||||
return PROVIDER_METHODS.getOrDefault(provider, List.of());
|
||||
}
|
||||
|
||||
/// 指定支付渠道编码下的固定支付方式(有序)
|
||||
public List<PayMethodEnum> methodsOf(String providerCode) {
|
||||
return methodsOf(PayProviderEnum.findByCode(providerCode));
|
||||
}
|
||||
|
||||
/// 是否属于渠道支付方式目录中的 (provider, method) 组合
|
||||
public boolean contains(PayProviderEnum provider, String methodCode) {
|
||||
if (provider == null || methodCode == null || methodCode.isBlank()) {
|
||||
return false;
|
||||
}
|
||||
return methodsOf(provider).stream().anyMatch(method -> Objects.equals(method.getCode(), methodCode));
|
||||
}
|
||||
|
||||
/// 是否属于渠道支付方式目录中的 (provider, method) 组合
|
||||
public boolean contains(String providerCode, String methodCode) {
|
||||
return contains(PayProviderEnum.findByCode(providerCode), methodCode);
|
||||
}
|
||||
|
||||
/// 渠道支付方式目录全量项(以本类静态定义为准,运行时启用态见 `PayProviderService`)
|
||||
public List<PayProviderMethodEntry> allEntries() {
|
||||
return ALL_ENTRIES;
|
||||
}
|
||||
|
||||
/// 是否必须显式传入支付渠道(仅 other 无法推导)
|
||||
public boolean requiresProviderForMethod(String methodCode) {
|
||||
return Objects.equals(PayMethodEnum.OTHER.getCode(), methodCode);
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,7 @@ public final class PermCodeUtil {
|
||||
}
|
||||
|
||||
/// 解析操作码(未拼接 menuCode)。
|
||||
public static String resolveActionCode(PermCode classPermCode, PermCode methodPermCode) {
|
||||
private static String resolveActionCode(PermCode classPermCode, PermCode methodPermCode) {
|
||||
if (Objects.nonNull(methodPermCode) && StrUtil.isNotBlank(methodPermCode.code())) {
|
||||
return methodPermCode.code();
|
||||
}
|
||||
@@ -49,26 +49,4 @@ public final class PermCodeUtil {
|
||||
return "";
|
||||
}
|
||||
|
||||
/// 解析中文名称。
|
||||
public static String resolveNameCn(PermCode classPermCode, PermCode methodPermCode) {
|
||||
if (Objects.nonNull(methodPermCode) && StrUtil.isNotBlank(methodPermCode.nameCn())) {
|
||||
return methodPermCode.nameCn();
|
||||
}
|
||||
if (Objects.nonNull(classPermCode) && StrUtil.isNotBlank(classPermCode.nameCn())) {
|
||||
return classPermCode.nameCn();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/// 解析英文名称。
|
||||
public static String resolveNameEn(PermCode classPermCode, PermCode methodPermCode) {
|
||||
if (Objects.nonNull(methodPermCode) && StrUtil.isNotBlank(methodPermCode.nameEn())) {
|
||||
return methodPermCode.nameEn();
|
||||
}
|
||||
if (Objects.nonNull(classPermCode) && StrUtil.isNotBlank(classPermCode.nameEn())) {
|
||||
return classPermCode.nameEn();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,127 +0,0 @@
|
||||
package cn.daxpay.open.platform.core.util;
|
||||
|
||||
import cn.daxpay.open.platform.core.exception.DangerSqlException;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/// # sql注入处理工具类 参考自 Jeecg Boot
|
||||
///
|
||||
@Slf4j
|
||||
@UtilityClass
|
||||
public class SqlInjectionUtil {
|
||||
|
||||
private final String XSS_STR = "and |extractvalue|updatexml|geohash|gtid_subset|gtid_subtract|exec |insert |select |delete |update |drop |count |chr |mid |master |truncate |char |declare |;|or |+|user()";
|
||||
|
||||
/// 正则 user() 匹配更严谨
|
||||
private final String REGULAR_EXPRE_USER = "user[\\s]*\\([\\s]*\\)";
|
||||
|
||||
/// 正则 show tables
|
||||
private final String SHOW_TABLES = "show\\s+tables";
|
||||
|
||||
/// sql注释的正则
|
||||
private final Pattern SQL_ANNOTATION = Pattern.compile("/\\*[\\s\\S]*\\*/");
|
||||
|
||||
/// sql注入过滤处理,遇到注入关键字抛异常
|
||||
public void filterContent(String value) {
|
||||
filterContent(value, null);
|
||||
}
|
||||
|
||||
/// sql注入过滤处理,遇到注入关键字抛异常
|
||||
public void filterContent(String value, String customXssString) {
|
||||
if (StrUtil.isEmpty(value)) {
|
||||
return;
|
||||
}
|
||||
// 校验sql注释 不允许有sql注释
|
||||
checkSqlAnnotation(value);
|
||||
// 统一转为小写
|
||||
value = value.toLowerCase();
|
||||
// SQL注入检测存在绕过风险
|
||||
String[] xssArr = XSS_STR.split("\\|");
|
||||
for (String s : xssArr) {
|
||||
if (value.contains(s)) {
|
||||
log.error("请注意,存在SQL注入关键词---> {}", s);
|
||||
log.error("请注意,值可能存在SQL注入风险!---> {}", value);
|
||||
// 通用: 检测到SQL注入关键词
|
||||
throw new DangerSqlException("error.common.dangerSqlWithValue", value);
|
||||
}
|
||||
}
|
||||
// 除了XSS_STR这些提前设置好的,还需要额外的校验比如 单引号
|
||||
if (customXssString != null) {
|
||||
String[] xssArr2 = customXssString.split("\\|");
|
||||
for (String s : xssArr2) {
|
||||
if (value.contains(s)) {
|
||||
log.error("请注意,存在SQL注入关键词---> {}", s);
|
||||
log.error("请注意,值可能存在SQL注入风险!---> {}", value);
|
||||
// 通用: 检测到SQL注入关键词
|
||||
throw new DangerSqlException("error.common.dangerSqlWithValue", value);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 除了XSS_STR这些提前设置好的,还需要额外的校验比如 单引号
|
||||
if (Pattern.matches(SHOW_TABLES, value) || Pattern.matches(REGULAR_EXPRE_USER, value)) {
|
||||
// 通用: 检测到SQL注入关键词
|
||||
throw new DangerSqlException("error.common.dangerSqlWithValue", value);
|
||||
}
|
||||
}
|
||||
|
||||
/// sql注入过滤处理,遇到注入关键字抛异常
|
||||
public void filterContent(String[] values) {
|
||||
filterContent(values, null);
|
||||
}
|
||||
|
||||
/// sql注入过滤处理,遇到注入关键字抛异常
|
||||
public void filterContent(String[] values, String customXssString) {
|
||||
String[] xssArr = XSS_STR.split("\\|");
|
||||
for (String value : values) {
|
||||
if (StrUtil.isEmpty(value)) {
|
||||
return;
|
||||
}
|
||||
// 校验sql注释 不允许有sql注释
|
||||
checkSqlAnnotation(value);
|
||||
// 统一转为小写
|
||||
value = value.toLowerCase();
|
||||
|
||||
for (String s : xssArr) {
|
||||
if (value.contains(s)) {
|
||||
log.error("请注意,存在SQL注入关键词---> {}", s);
|
||||
log.error("请注意,值可能存在SQL注入风险!---> {}", value);
|
||||
// 通用: 检测到SQL注入关键词
|
||||
throw new DangerSqlException("error.common.dangerSqlWithValue", value);
|
||||
}
|
||||
}
|
||||
// 除了XSS_STR这些提前设置好的,还需要额外的校验比如 单引号
|
||||
if (customXssString != null) {
|
||||
String[] xssArr2 = customXssString.split("\\|");
|
||||
for (String s : xssArr2) {
|
||||
if (value.contains(s)) {
|
||||
log.error("请注意,存在SQL注入关键词---> {}", s);
|
||||
log.error("请注意,值可能存在SQL注入风险!---> {}", value);
|
||||
// 通用: 检测到SQL注入关键词
|
||||
throw new DangerSqlException("error.common.dangerSqlWithValue", value);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 除了XSS_STR这些提前设置好的,还需要额外的校验比如 单引号
|
||||
if (Pattern.matches(SHOW_TABLES, value) || Pattern.matches(REGULAR_EXPRE_USER, value)) {
|
||||
// 通用: 检测到SQL注入关键词
|
||||
throw new DangerSqlException("error.common.dangerSqlWithValue", value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 校验是否有sql注释
|
||||
public void checkSqlAnnotation(String str) {
|
||||
Matcher matcher = SQL_ANNOTATION.matcher(str);
|
||||
if (matcher.find()) {
|
||||
String error = "请注意,值可能存在SQL注入风险---> \\*.*\\";
|
||||
log.error(error);
|
||||
// 请注意,值可能存在SQL注入风险
|
||||
throw new DangerSqlException("error.common.dangerSqlWithValue", "\\*.*\\");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import lombok.Setter;
|
||||
/// # 各类型订单号生成工具类
|
||||
///
|
||||
/// 格式: {环境前缀}{3字母类型}{雪花ID}, 例如 PRODPAY1872635419283456
|
||||
/// 类型使用3字母缩写: PAY(支付) ALL(分账) REP(修复)
|
||||
/// 类型使用3字母缩写: PAY(支付) REF(退款)
|
||||
@Setter
|
||||
public final class TradeNoGenerateUtil {
|
||||
|
||||
@@ -23,11 +23,6 @@ public final class TradeNoGenerateUtil {
|
||||
return prefix() + "REF" + IdUtil.getSnowflakeNextId();
|
||||
}
|
||||
|
||||
/// 生成修复单号
|
||||
public static String repair() {
|
||||
return prefix() + "REP" + IdUtil.getSnowflakeNextId();
|
||||
}
|
||||
|
||||
/// 拼接环境前缀, 不添加分隔符, 部分通道不允许特殊符号
|
||||
private static String prefix() {
|
||||
return env == null ? "" : env;
|
||||
|
||||
@@ -63,32 +63,6 @@ public class TreeBuildUtil {
|
||||
}
|
||||
return children;
|
||||
}
|
||||
|
||||
/// 展开树为list列表
|
||||
///
|
||||
/// @param list 要进行展开的列表
|
||||
/// @param getChildren 获取子节点列表的方法引用
|
||||
/// @return 展开后的结果列表
|
||||
public <T> List<T> unfold(List<T> list, Function<T, List<T>> getChildren){
|
||||
return unfold(list,getChildren, new ArrayList<>());
|
||||
}
|
||||
|
||||
/// 展开树为list列表
|
||||
///
|
||||
/// @param list 要进行展开的列表
|
||||
/// @param getChildren 获取子节点列表的方法引用
|
||||
/// @param result 用于存储展开后的列表对象
|
||||
/// @return 展开后的结果列表
|
||||
private <T> List<T> unfold(List<T> list, Function<T, List<T>> getChildren, List<T> result){
|
||||
if (CollectionUtil.isEmpty(list)) {
|
||||
return new ArrayList<>(0);
|
||||
}
|
||||
for (T region : list) {
|
||||
unfold(getChildren.apply(region), getChildren, result);
|
||||
result.add(region);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -30,15 +30,4 @@ public class RoleMenuManager extends BaseManager<RoleMenuMapper, RoleMenu> {
|
||||
public List<RoleMenu> findAllByRole(Long roleId) {
|
||||
return findAllByField(RoleMenu::getRoleId, roleId);
|
||||
}
|
||||
|
||||
/// 根据角色id、菜单ID进行删除
|
||||
public void deleteByMenuIds(Long roleId, List<Long> menuIds) {
|
||||
if (menuIds.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
lambdaUpdate()
|
||||
.eq(RoleMenu::getRoleId, roleId)
|
||||
.in(RoleMenu::getMenuId, menuIds)
|
||||
.remove();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,11 +80,6 @@ public class DictItemService {
|
||||
.orElseThrow(() -> new DataNotExistException("error.system.dict.itemNotExist"));
|
||||
}
|
||||
|
||||
/// 根据字典编码和字典项编码查询启用的菜单项
|
||||
public Optional<DictItem> findEnableByCode(String dictCode, String code) {
|
||||
return dictItemManager.findByCodeAndEnable(dictCode, code, true);
|
||||
}
|
||||
|
||||
/// 查询指定目录下的所有内容
|
||||
public List<DictItemResult> findByDictionaryId(Long dictionaryId) {
|
||||
return dictItemManager.findByDictId(dictionaryId)
|
||||
@@ -94,20 +89,8 @@ public class DictItemService {
|
||||
.toList();
|
||||
}
|
||||
|
||||
/// 查询指定字典编码下的所有启用的字典项
|
||||
/// @return code -> nameCn 的映射
|
||||
@Cacheable(value = "system:dict", key = "#dictCode")
|
||||
public Map<String, String> findEnableByDictCode(String dictCode) {
|
||||
return dictItemManager.findByDictCodeAndEnable(dictCode, true)
|
||||
.stream()
|
||||
.collect(HashMap::new,
|
||||
(map, item) -> map.put(item.getCode(), item.getNameCn()),
|
||||
HashMap::putAll);
|
||||
|
||||
}
|
||||
|
||||
/// 查询指定字典编码下所有启用的字典项完整列表(含多语言字段)
|
||||
/// 供 DictTranslatorImpl 使用,缓存键与 findEnableByDictCode 区分以避免类型冲突
|
||||
/// 供 DictTranslatorImpl 使用
|
||||
/// @return 字典项完整实体列表
|
||||
@Cacheable(value = "system:dict", key = "#dictCode + ':list'")
|
||||
public List<DictItem> findAllEnableByDictCode(String dictCode) {
|
||||
|
||||
@@ -92,40 +92,6 @@ public class MobileAppService {
|
||||
.map(this::toMaskedResult);
|
||||
}
|
||||
|
||||
/// 运行时读取实体(不脱敏, appConfig 为解密后 JSON 明文)
|
||||
public MobileApp getEntity(String appType, String platform) {
|
||||
return manager.findByAppTypeAndPlatform(appType, platform)
|
||||
.orElseThrow(() -> new DataNotExistException("error.mobile_app.notExist"));
|
||||
}
|
||||
|
||||
/// 运行时读取已启用的配置实体
|
||||
public MobileApp getEnabledEntity(String appType, String platform) {
|
||||
MobileApp entity = getEntity(appType, platform);
|
||||
if (!Boolean.TRUE.equals(entity.getEnabled())) {
|
||||
throw new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR,
|
||||
"error.mobile_app.notEnabled", appType, platform);
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
|
||||
/// 运行时: 解析微信小程序配置(明文密钥)
|
||||
public WxMiniAppConfig getWxMiniConfig(String appType) {
|
||||
return parseConfig(getEnabledEntity(appType, MobilePlatformEnum.WX_MINI.getCode()).getAppConfig(),
|
||||
WxMiniAppConfig.class);
|
||||
}
|
||||
|
||||
/// 运行时: 解析支付宝小程序配置(明文密钥)
|
||||
public AlipayMiniAppConfig getAlipayMiniConfig(String appType) {
|
||||
return parseConfig(getEnabledEntity(appType, MobilePlatformEnum.ALIPAY_MINI.getCode()).getAppConfig(),
|
||||
AlipayMiniAppConfig.class);
|
||||
}
|
||||
|
||||
/// 运行时: 解析抖音小程序配置(明文密钥)
|
||||
public DyMiniAppConfig getDyMiniConfig(String appType) {
|
||||
return parseConfig(getEnabledEntity(appType, MobilePlatformEnum.DY_MINI.getCode()).getAppConfig(),
|
||||
DyMiniAppConfig.class);
|
||||
}
|
||||
|
||||
/// 保存(按端类型+平台组合 upsert)
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public MobileAppResult save(MobileAppParam param) {
|
||||
|
||||
Reference in New Issue
Block a user