mirror of
				https://github.com/YunaiV/ruoyi-vue-pro.git
				synced 2025-10-31 18:49:06 +08:00 
			
		
		
		
	pay 缓存,使用 guava 替代 job 扫描,目的:提升启动速度,加快缓存失效
This commit is contained in:
		| @ -48,7 +48,7 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen | |||||||
|      */ |      */ | ||||||
|     public final void init() { |     public final void init() { | ||||||
|         doInit(); |         doInit(); | ||||||
|         log.info("[init][客户端({}) 初始化完成]", getId()); |         log.debug("[init][客户端({}) 初始化完成]", getId()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|  | |||||||
| @ -233,14 +233,38 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest { | |||||||
|  |  | ||||||
|     @Test |     @Test | ||||||
|     public void testGetFileClient() { |     public void testGetFileClient() { | ||||||
|  |         // mock 数据 | ||||||
|  |         FileConfigDO fileConfig = randomFileConfigDO().setMaster(false); | ||||||
|  |         fileConfigMapper.insert(fileConfig); | ||||||
|         // 准备参数 |         // 准备参数 | ||||||
|         Long id = randomLongId(); |         Long id = fileConfig.getId(); | ||||||
|         // mock 获得 Client |         // mock 获得 Client | ||||||
|         FileClient fileClient = new LocalFileClient(id, new LocalFileClientConfig()); |         FileClient fileClient = new LocalFileClient(id, new LocalFileClientConfig()); | ||||||
|         when(fileClientFactory.getFileClient(eq(id))).thenReturn(fileClient); |         when(fileClientFactory.getFileClient(eq(id))).thenReturn(fileClient); | ||||||
|  |  | ||||||
|         // 调用,并断言 |         // 调用,并断言 | ||||||
|         assertSame(fileClient, fileConfigService.getFileClient(id)); |         assertSame(fileClient, fileConfigService.getFileClient(id)); | ||||||
|  |         // 断言缓存 | ||||||
|  |         verify(fileClientFactory).createOrUpdateFileClient(eq(id), eq(fileConfig.getStorage()), | ||||||
|  |                 eq(fileConfig.getConfig())); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Test | ||||||
|  |     public void testGetMasterFileClient() { | ||||||
|  |         // mock 数据 | ||||||
|  |         FileConfigDO fileConfig = randomFileConfigDO().setMaster(true); | ||||||
|  |         fileConfigMapper.insert(fileConfig); | ||||||
|  |         // 准备参数 | ||||||
|  |         Long id = fileConfig.getId(); | ||||||
|  |         // mock 获得 Client | ||||||
|  |         FileClient fileClient = new LocalFileClient(id, new LocalFileClientConfig()); | ||||||
|  |         when(fileClientFactory.getFileClient(eq(0L))).thenReturn(fileClient); | ||||||
|  |  | ||||||
|  |         // 调用,并断言 | ||||||
|  |         assertSame(fileClient, fileConfigService.getMasterFileClient()); | ||||||
|  |         // 断言缓存 | ||||||
|  |         verify(fileClientFactory).createOrUpdateFileClient(eq(0L), eq(fileConfig.getStorage()), | ||||||
|  |                 eq(fileConfig.getConfig())); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private FileConfigDO randomFileConfigDO() { |     private FileConfigDO randomFileConfigDO() { | ||||||
|  | |||||||
| @ -5,7 +5,6 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult; | |||||||
| import cn.iocoder.yudao.framework.common.pojo.PageResult; | import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||||||
| import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; | import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; | ||||||
| import cn.iocoder.yudao.framework.pay.core.client.PayClient; | import cn.iocoder.yudao.framework.pay.core.client.PayClient; | ||||||
| import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; |  | ||||||
| import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; | ||||||
| import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; | import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; | ||||||
| import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskDetailRespVO; | import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskDetailRespVO; | ||||||
| @ -16,6 +15,7 @@ import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; | |||||||
| import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyLogDO; | import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyLogDO; | ||||||
| import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyTaskDO; | import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyTaskDO; | ||||||
| import cn.iocoder.yudao.module.pay.service.app.PayAppService; | import cn.iocoder.yudao.module.pay.service.app.PayAppService; | ||||||
|  | import cn.iocoder.yudao.module.pay.service.channel.PayChannelService; | ||||||
| import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService; | import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService; | ||||||
| import cn.iocoder.yudao.module.pay.service.order.PayOrderService; | import cn.iocoder.yudao.module.pay.service.order.PayOrderService; | ||||||
| import cn.iocoder.yudao.module.pay.service.refund.PayRefundService; | import cn.iocoder.yudao.module.pay.service.refund.PayRefundService; | ||||||
| @ -53,9 +53,8 @@ public class PayNotifyController { | |||||||
|     private PayNotifyService notifyService; |     private PayNotifyService notifyService; | ||||||
|     @Resource |     @Resource | ||||||
|     private PayAppService appService; |     private PayAppService appService; | ||||||
|  |  | ||||||
|     @Resource |     @Resource | ||||||
|     private PayClientFactory payClientFactory; |     private PayChannelService channelService; | ||||||
|  |  | ||||||
|     @PostMapping(value = "/order/{channelId}") |     @PostMapping(value = "/order/{channelId}") | ||||||
|     @Operation(summary = "支付渠道的统一【支付】回调") |     @Operation(summary = "支付渠道的统一【支付】回调") | ||||||
| @ -66,7 +65,7 @@ public class PayNotifyController { | |||||||
|                               @RequestBody(required = false) String body) { |                               @RequestBody(required = false) String body) { | ||||||
|         log.info("[notifyOrder][channelId({}) 回调数据({}/{})]", channelId, params, body); |         log.info("[notifyOrder][channelId({}) 回调数据({}/{})]", channelId, params, body); | ||||||
|         // 1. 校验支付渠道是否存在 |         // 1. 校验支付渠道是否存在 | ||||||
|         PayClient payClient = payClientFactory.getPayClient(channelId); |         PayClient payClient = channelService.getPayClient(channelId); | ||||||
|         if (payClient == null) { |         if (payClient == null) { | ||||||
|             log.error("[notifyCallback][渠道编号({}) 找不到对应的支付客户端]", channelId); |             log.error("[notifyCallback][渠道编号({}) 找不到对应的支付客户端]", channelId); | ||||||
|             throw exception(CHANNEL_NOT_FOUND); |             throw exception(CHANNEL_NOT_FOUND); | ||||||
| @ -87,7 +86,7 @@ public class PayNotifyController { | |||||||
|                               @RequestBody(required = false) String body) { |                               @RequestBody(required = false) String body) { | ||||||
|         log.info("[notifyRefund][channelId({}) 回调数据({}/{})]", channelId, params, body); |         log.info("[notifyRefund][channelId({}) 回调数据({}/{})]", channelId, params, body); | ||||||
|         // 1. 校验支付渠道是否存在 |         // 1. 校验支付渠道是否存在 | ||||||
|         PayClient payClient = payClientFactory.getPayClient(channelId); |         PayClient payClient = channelService.getPayClient(channelId); | ||||||
|         if (payClient == null) { |         if (payClient == null) { | ||||||
|             log.error("[notifyCallback][渠道编号({}) 找不到对应的支付客户端]", channelId); |             log.error("[notifyCallback][渠道编号({}) 找不到对应的支付客户端]", channelId); | ||||||
|             throw exception(CHANNEL_NOT_FOUND); |             throw exception(CHANNEL_NOT_FOUND); | ||||||
|  | |||||||
| @ -28,7 +28,4 @@ public interface PayChannelMapper extends BaseMapperX<PayChannelDO> { | |||||||
|                 .eq(PayChannelDO::getStatus, status)); |                 .eq(PayChannelDO::getStatus, status)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Select("SELECT COUNT(*) FROM pay_channel WHERE update_time > #{maxUpdateTime}") |  | ||||||
|     Long selectCountByUpdateTimeGt(LocalDateTime maxUpdateTime); |  | ||||||
|  |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -15,7 +15,6 @@ import javax.annotation.Resource; | |||||||
|  * @author 芋道源码 |  * @author 芋道源码 | ||||||
|  */ |  */ | ||||||
| @Component | @Component | ||||||
| @TenantJob // 多租户 |  | ||||||
| @Slf4j | @Slf4j | ||||||
| public class PayNotifyJob implements JobHandler { | public class PayNotifyJob implements JobHandler { | ||||||
|  |  | ||||||
| @ -23,6 +22,7 @@ public class PayNotifyJob implements JobHandler { | |||||||
|     private PayNotifyService payNotifyService; |     private PayNotifyService payNotifyService; | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|  |     @TenantJob | ||||||
|     public String execute(String param) throws Exception { |     public String execute(String param) throws Exception { | ||||||
|         int notifyCount = payNotifyService.executeNotify(); |         int notifyCount = payNotifyService.executeNotify(); | ||||||
|         return String.format("执行支付通知 %s 个", notifyCount); |         return String.format("执行支付通知 %s 个", notifyCount); | ||||||
|  | |||||||
| @ -16,13 +16,13 @@ import javax.annotation.Resource; | |||||||
|  * @author 芋道源码 |  * @author 芋道源码 | ||||||
|  */ |  */ | ||||||
| @Component | @Component | ||||||
| @TenantJob |  | ||||||
| public class PayOrderExpireJob implements JobHandler { | public class PayOrderExpireJob implements JobHandler { | ||||||
|  |  | ||||||
|     @Resource |     @Resource | ||||||
|     private PayOrderService orderService; |     private PayOrderService orderService; | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|  |     @TenantJob | ||||||
|     public String execute(String param) { |     public String execute(String param) { | ||||||
|         int count = orderService.expireOrder(); |         int count = orderService.expireOrder(); | ||||||
|         return StrUtil.format("支付过期 {} 个", count); |         return StrUtil.format("支付过期 {} 个", count); | ||||||
|  | |||||||
| @ -18,7 +18,6 @@ import java.time.LocalDateTime; | |||||||
|  * @author 芋道源码 |  * @author 芋道源码 | ||||||
|  */ |  */ | ||||||
| @Component | @Component | ||||||
| @TenantJob |  | ||||||
| public class PayOrderSyncJob implements JobHandler { | public class PayOrderSyncJob implements JobHandler { | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @ -34,6 +33,7 @@ public class PayOrderSyncJob implements JobHandler { | |||||||
|     private PayOrderService orderService; |     private PayOrderService orderService; | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|  |     @TenantJob | ||||||
|     public String execute(String param) { |     public String execute(String param) { | ||||||
|         LocalDateTime minCreateTime = LocalDateTime.now().minus(CREATE_TIME_DURATION_BEFORE); |         LocalDateTime minCreateTime = LocalDateTime.now().minus(CREATE_TIME_DURATION_BEFORE); | ||||||
|         int count = orderService.syncOrder(minCreateTime); |         int count = orderService.syncOrder(minCreateTime); | ||||||
|  | |||||||
| @ -16,13 +16,13 @@ import javax.annotation.Resource; | |||||||
|  * @author 芋道源码 |  * @author 芋道源码 | ||||||
|  */ |  */ | ||||||
| @Component | @Component | ||||||
| @TenantJob |  | ||||||
| public class PayRefundSyncJob implements JobHandler { | public class PayRefundSyncJob implements JobHandler { | ||||||
|  |  | ||||||
|     @Resource |     @Resource | ||||||
|     private PayRefundService refundService; |     private PayRefundService refundService; | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|  |     @TenantJob | ||||||
|     public String execute(String param) { |     public String execute(String param) { | ||||||
|         int count = refundService.syncRefund(); |         int count = refundService.syncRefund(); | ||||||
|         return StrUtil.format("同步退款订单 {} 个", count); |         return StrUtil.format("同步退款订单 {} 个", count); | ||||||
|  | |||||||
| @ -1,6 +1,7 @@ | |||||||
| package cn.iocoder.yudao.module.pay.service.channel; | package cn.iocoder.yudao.module.pay.service.channel; | ||||||
|  |  | ||||||
| import cn.iocoder.yudao.framework.common.exception.ServiceException; | import cn.iocoder.yudao.framework.common.exception.ServiceException; | ||||||
|  | import cn.iocoder.yudao.framework.pay.core.client.PayClient; | ||||||
| import cn.iocoder.yudao.module.pay.controller.admin.channel.vo.PayChannelCreateReqVO; | import cn.iocoder.yudao.module.pay.controller.admin.channel.vo.PayChannelCreateReqVO; | ||||||
| import cn.iocoder.yudao.module.pay.controller.admin.channel.vo.PayChannelUpdateReqVO; | import cn.iocoder.yudao.module.pay.controller.admin.channel.vo.PayChannelUpdateReqVO; | ||||||
| import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO; | import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO; | ||||||
| @ -92,4 +93,12 @@ public interface PayChannelService { | |||||||
|      */ |      */ | ||||||
|     List<PayChannelDO> getEnableChannelList(Long appId); |     List<PayChannelDO> getEnableChannelList(Long appId); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 获得指定编号的支付客户端 | ||||||
|  |      * | ||||||
|  |      * @param id 编号 | ||||||
|  |      * @return 支付客户端 | ||||||
|  |      */ | ||||||
|  |     PayClient getPayClient(Long id); | ||||||
|  |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,38 +1,33 @@ | |||||||
| package cn.iocoder.yudao.module.pay.service.channel; | package cn.iocoder.yudao.module.pay.service.channel; | ||||||
|  |  | ||||||
| import cn.hutool.core.collection.CollUtil; |  | ||||||
| import cn.hutool.core.lang.Assert; | import cn.hutool.core.lang.Assert; | ||||||
| import cn.hutool.core.util.ObjectUtil; | import cn.hutool.core.util.ObjectUtil; | ||||||
| import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | ||||||
| import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; |  | ||||||
| import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | ||||||
|  | import cn.iocoder.yudao.framework.pay.core.client.PayClient; | ||||||
| import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig; | import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig; | ||||||
| import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; | import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; | ||||||
| import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; | import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; | ||||||
| import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; |  | ||||||
| import cn.iocoder.yudao.module.pay.controller.admin.channel.vo.PayChannelCreateReqVO; | import cn.iocoder.yudao.module.pay.controller.admin.channel.vo.PayChannelCreateReqVO; | ||||||
| import cn.iocoder.yudao.module.pay.controller.admin.channel.vo.PayChannelUpdateReqVO; | import cn.iocoder.yudao.module.pay.controller.admin.channel.vo.PayChannelUpdateReqVO; | ||||||
| import cn.iocoder.yudao.module.pay.convert.channel.PayChannelConvert; | import cn.iocoder.yudao.module.pay.convert.channel.PayChannelConvert; | ||||||
| import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO; | import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO; | ||||||
| import cn.iocoder.yudao.module.pay.dal.mysql.channel.PayChannelMapper; | import cn.iocoder.yudao.module.pay.dal.mysql.channel.PayChannelMapper; | ||||||
| import cn.iocoder.yudao.module.pay.framework.pay.wallet.WalletPayClient; | import com.google.common.cache.CacheLoader; | ||||||
|  | import com.google.common.cache.LoadingCache; | ||||||
| import lombok.Getter; | import lombok.Getter; | ||||||
| import lombok.Setter; |  | ||||||
| import lombok.extern.slf4j.Slf4j; | import lombok.extern.slf4j.Slf4j; | ||||||
| import org.springframework.scheduling.annotation.Scheduled; |  | ||||||
| import org.springframework.stereotype.Service; | import org.springframework.stereotype.Service; | ||||||
| import org.springframework.validation.annotation.Validated; | import org.springframework.validation.annotation.Validated; | ||||||
|  |  | ||||||
| import javax.annotation.PostConstruct; |  | ||||||
| import javax.annotation.Resource; | import javax.annotation.Resource; | ||||||
| import javax.validation.Validator; | import javax.validation.Validator; | ||||||
| import java.time.LocalDateTime; | import java.time.Duration; | ||||||
| import java.util.Collection; | import java.util.Collection; | ||||||
| import java.util.Collections; |  | ||||||
| import java.util.List; | import java.util.List; | ||||||
| import java.util.concurrent.TimeUnit; |  | ||||||
|  |  | ||||||
| import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | ||||||
|  | import static cn.iocoder.yudao.framework.common.util.cache.CacheUtils.buildAsyncReloadingCache; | ||||||
| import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*; | import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*; | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @ -45,71 +40,34 @@ import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*; | |||||||
| @Validated | @Validated | ||||||
| public class PayChannelServiceImpl implements PayChannelService { | public class PayChannelServiceImpl implements PayChannelService { | ||||||
|  |  | ||||||
|     @Getter // 为了方便测试,这里提供 getter 方法 |     /** | ||||||
|     @Setter |      * {@link PayClient} 缓存,通过它异步清空 smsClientFactory | ||||||
|     private volatile List<PayChannelDO> channelCache; |      */ | ||||||
|  |     @Getter | ||||||
|  |     private final LoadingCache<Long, PayClient> clientCache = buildAsyncReloadingCache(Duration.ofSeconds(10L), | ||||||
|  |             new CacheLoader<Long, PayClient>() { | ||||||
|  |  | ||||||
|  |                 @Override | ||||||
|  |                 public PayClient load(Long id) { | ||||||
|  |                     // 查询,然后尝试清空 | ||||||
|  |                     PayChannelDO channel = payChannelMapper.selectById(id); | ||||||
|  |                     if (channel != null) { | ||||||
|  |                         payClientFactory.createOrUpdatePayClient(channel.getId(), channel.getCode(), channel.getConfig()); | ||||||
|  |                     } | ||||||
|  |                     return payClientFactory.getPayClient(id); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |             }); | ||||||
|  |  | ||||||
|     @Resource |     @Resource | ||||||
|     private PayClientFactory payClientFactory; |     private PayClientFactory payClientFactory; | ||||||
|  |  | ||||||
|     @Resource |     @Resource | ||||||
|     private PayChannelMapper channelMapper; |     private PayChannelMapper payChannelMapper; | ||||||
|  |  | ||||||
|     @Resource |     @Resource | ||||||
|     private Validator validator; |     private Validator validator; | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 初始化 {@link #payClientFactory} 缓存 |  | ||||||
|      */ |  | ||||||
|     @PostConstruct |  | ||||||
|     public void initLocalCache() { |  | ||||||
|         // 注册钱包支付 Class |  | ||||||
|         payClientFactory.registerPayClientClass(PayChannelEnum.WALLET, WalletPayClient.class); |  | ||||||
|  |  | ||||||
|         // 注意:忽略自动多租户,因为要全局初始化缓存 |  | ||||||
|         TenantUtils.executeIgnore(() -> { |  | ||||||
|             // 第一步:查询数据 |  | ||||||
|             List<PayChannelDO> channels = Collections.emptyList(); |  | ||||||
|             try { |  | ||||||
|                 channels = channelMapper.selectList(); |  | ||||||
|             } catch (Throwable ex) { |  | ||||||
|                 if (!ex.getMessage().contains("doesn't exist")) { |  | ||||||
|                     throw ex; |  | ||||||
|                 } |  | ||||||
|                 log.error("[支付模块 yudao-module-pay - 表结构未导入][参考 https://doc.iocoder.cn/pay/build/ 开启]"); |  | ||||||
|             } |  | ||||||
|             log.info("[initLocalCache][缓存支付渠道,数量为:{}]", channels.size()); |  | ||||||
|  |  | ||||||
|             // 第二步:构建缓存:创建或更新支付 Client |  | ||||||
|             channels.forEach(payChannel -> payClientFactory.createOrUpdatePayClient(payChannel.getId(), |  | ||||||
|                     payChannel.getCode(), payChannel.getConfig())); |  | ||||||
|             this.channelCache = channels; |  | ||||||
|         }); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 通过定时任务轮询,刷新缓存 |  | ||||||
|      * |  | ||||||
|      * 目的:多节点部署时,通过轮询”通知“所有节点,进行刷新 |  | ||||||
|      */ |  | ||||||
|     @Scheduled(initialDelay = 60, fixedRate = 60, timeUnit = TimeUnit.SECONDS) |  | ||||||
|     public void refreshLocalCache() { |  | ||||||
|         // 注意:忽略自动多租户,因为要全局初始化缓存 |  | ||||||
|         TenantUtils.executeIgnore(() -> { |  | ||||||
|             // 情况一:如果缓存里没有数据,则直接刷新缓存 |  | ||||||
|             if (CollUtil.isEmpty(channelCache)) { |  | ||||||
|                 initLocalCache(); |  | ||||||
|                 return; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             // 情况二,如果缓存里数据,则通过 updateTime 判断是否有数据变更,有变更则刷新缓存 |  | ||||||
|             LocalDateTime maxTime = CollectionUtils.getMaxValue(channelCache, PayChannelDO::getUpdateTime); |  | ||||||
|             if (channelMapper.selectCountByUpdateTimeGt(maxTime) > 0) { |  | ||||||
|                 initLocalCache(); |  | ||||||
|             } |  | ||||||
|         }); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public Long createChannel(PayChannelCreateReqVO reqVO) { |     public Long createChannel(PayChannelCreateReqVO reqVO) { | ||||||
|         // 断言是否有重复的 |         // 断言是否有重复的 | ||||||
| @ -121,10 +79,7 @@ public class PayChannelServiceImpl implements PayChannelService { | |||||||
|         // 新增渠道 |         // 新增渠道 | ||||||
|         PayChannelDO channel = PayChannelConvert.INSTANCE.convert(reqVO) |         PayChannelDO channel = PayChannelConvert.INSTANCE.convert(reqVO) | ||||||
|                 .setConfig(parseConfig(reqVO.getCode(), reqVO.getConfig())); |                 .setConfig(parseConfig(reqVO.getCode(), reqVO.getConfig())); | ||||||
|         channelMapper.insert(channel); |         payChannelMapper.insert(channel); | ||||||
|  |  | ||||||
|         // 刷新缓存 |  | ||||||
|         initLocalCache(); |  | ||||||
|         return channel.getId(); |         return channel.getId(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @ -136,10 +91,10 @@ public class PayChannelServiceImpl implements PayChannelService { | |||||||
|         // 更新 |         // 更新 | ||||||
|         PayChannelDO channel = PayChannelConvert.INSTANCE.convert(updateReqVO) |         PayChannelDO channel = PayChannelConvert.INSTANCE.convert(updateReqVO) | ||||||
|                 .setConfig(parseConfig(dbChannel.getCode(), updateReqVO.getConfig())); |                 .setConfig(parseConfig(dbChannel.getCode(), updateReqVO.getConfig())); | ||||||
|         channelMapper.updateById(channel); |         payChannelMapper.updateById(channel); | ||||||
|  |  | ||||||
|         // 刷新缓存 |         // 清空缓存 | ||||||
|         initLocalCache(); |         clearCache(channel.getId()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @ -169,14 +124,23 @@ public class PayChannelServiceImpl implements PayChannelService { | |||||||
|         validateChannelExists(id); |         validateChannelExists(id); | ||||||
|  |  | ||||||
|         // 删除 |         // 删除 | ||||||
|         channelMapper.deleteById(id); |         payChannelMapper.deleteById(id); | ||||||
|  |  | ||||||
|         // 刷新缓存 |         // 清空缓存 | ||||||
|         initLocalCache(); |         clearCache(id); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 删除缓存 | ||||||
|  |      * | ||||||
|  |      * @param id 渠道编号 | ||||||
|  |      */ | ||||||
|  |     private void clearCache(Long id) { | ||||||
|  |         clientCache.invalidate(id); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private PayChannelDO validateChannelExists(Long id) { |     private PayChannelDO validateChannelExists(Long id) { | ||||||
|         PayChannelDO channel = channelMapper.selectById(id); |         PayChannelDO channel = payChannelMapper.selectById(id); | ||||||
|         if (channel == null) { |         if (channel == null) { | ||||||
|             throw exception(CHANNEL_NOT_FOUND); |             throw exception(CHANNEL_NOT_FOUND); | ||||||
|         } |         } | ||||||
| @ -185,29 +149,29 @@ public class PayChannelServiceImpl implements PayChannelService { | |||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public PayChannelDO getChannel(Long id) { |     public PayChannelDO getChannel(Long id) { | ||||||
|         return channelMapper.selectById(id); |         return payChannelMapper.selectById(id); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public List<PayChannelDO> getChannelListByAppIds(Collection<Long> appIds) { |     public List<PayChannelDO> getChannelListByAppIds(Collection<Long> appIds) { | ||||||
|         return channelMapper.selectListByAppIds(appIds); |         return payChannelMapper.selectListByAppIds(appIds); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public PayChannelDO getChannelByAppIdAndCode(Long appId, String code) { |     public PayChannelDO getChannelByAppIdAndCode(Long appId, String code) { | ||||||
|         return channelMapper.selectByAppIdAndCode(appId, code); |         return payChannelMapper.selectByAppIdAndCode(appId, code); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public PayChannelDO validPayChannel(Long id) { |     public PayChannelDO validPayChannel(Long id) { | ||||||
|         PayChannelDO channel = channelMapper.selectById(id); |         PayChannelDO channel = payChannelMapper.selectById(id); | ||||||
|         validPayChannel(channel); |         validPayChannel(channel); | ||||||
|         return channel; |         return channel; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public PayChannelDO validPayChannel(Long appId, String code) { |     public PayChannelDO validPayChannel(Long appId, String code) { | ||||||
|         PayChannelDO channel = channelMapper.selectByAppIdAndCode(appId, code); |         PayChannelDO channel = payChannelMapper.selectByAppIdAndCode(appId, code); | ||||||
|         validPayChannel(channel); |         validPayChannel(channel); | ||||||
|         return channel; |         return channel; | ||||||
|     } |     } | ||||||
| @ -223,7 +187,12 @@ public class PayChannelServiceImpl implements PayChannelService { | |||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public List<PayChannelDO> getEnableChannelList(Long appId) { |     public List<PayChannelDO> getEnableChannelList(Long appId) { | ||||||
|         return channelMapper.selectListByAppId(appId, CommonStatusEnum.ENABLE.getStatus()); |         return payChannelMapper.selectListByAppId(appId, CommonStatusEnum.ENABLE.getStatus()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public PayClient getPayClient(Long id) { | ||||||
|  |         return clientCache.getUnchecked(id); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -8,7 +8,6 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; | |||||||
| import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; | import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; | ||||||
| import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; | import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; | ||||||
| import cn.iocoder.yudao.framework.pay.core.client.PayClient; | import cn.iocoder.yudao.framework.pay.core.client.PayClient; | ||||||
| import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; |  | ||||||
| import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; | ||||||
| import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; | ||||||
| import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum; | import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum; | ||||||
| @ -60,9 +59,6 @@ public class PayOrderServiceImpl implements PayOrderService { | |||||||
|     @Resource |     @Resource | ||||||
|     private PayProperties payProperties; |     private PayProperties payProperties; | ||||||
|  |  | ||||||
|     @Resource |  | ||||||
|     private PayClientFactory payClientFactory; |  | ||||||
|  |  | ||||||
|     @Resource |     @Resource | ||||||
|     private PayOrderMapper orderMapper; |     private PayOrderMapper orderMapper; | ||||||
|     @Resource |     @Resource | ||||||
| @ -134,7 +130,7 @@ public class PayOrderServiceImpl implements PayOrderService { | |||||||
|         PayOrderDO order = validateOrderCanSubmit(reqVO.getId()); |         PayOrderDO order = validateOrderCanSubmit(reqVO.getId()); | ||||||
|         // 1.32 校验支付渠道是否有效 |         // 1.32 校验支付渠道是否有效 | ||||||
|         PayChannelDO channel = validateChannelCanSubmit(order.getAppId(), reqVO.getChannelCode()); |         PayChannelDO channel = validateChannelCanSubmit(order.getAppId(), reqVO.getChannelCode()); | ||||||
|         PayClient client = payClientFactory.getPayClient(channel.getId()); |         PayClient client = channelService.getPayClient(channel.getId()); | ||||||
|  |  | ||||||
|         // 2. 插入 PayOrderExtensionDO |         // 2. 插入 PayOrderExtensionDO | ||||||
|         String no = noRedisDAO.generate(payProperties.getOrderNoPrefix()); |         String no = noRedisDAO.generate(payProperties.getOrderNoPrefix()); | ||||||
| @ -205,7 +201,7 @@ public class PayOrderServiceImpl implements PayOrderService { | |||||||
|                 throw exception(ORDER_EXTENSION_IS_PAID); |                 throw exception(ORDER_EXTENSION_IS_PAID); | ||||||
|             } |             } | ||||||
|             // 情况二:调用三方接口,查询支付单状态,是不是已支付 |             // 情况二:调用三方接口,查询支付单状态,是不是已支付 | ||||||
|             PayClient payClient = payClientFactory.getPayClient(orderExtension.getChannelId()); |             PayClient payClient = channelService.getPayClient(orderExtension.getChannelId()); | ||||||
|             if (payClient == null) { |             if (payClient == null) { | ||||||
|                 log.error("[validateOrderCanSubmit][渠道编号({}) 找不到对应的支付客户端]", orderExtension.getChannelId()); |                 log.error("[validateOrderCanSubmit][渠道编号({}) 找不到对应的支付客户端]", orderExtension.getChannelId()); | ||||||
|                 return; |                 return; | ||||||
| @ -224,7 +220,7 @@ public class PayOrderServiceImpl implements PayOrderService { | |||||||
|         appService.validPayApp(appId); |         appService.validPayApp(appId); | ||||||
|         // 校验支付渠道是否有效 |         // 校验支付渠道是否有效 | ||||||
|         PayChannelDO channel = channelService.validPayChannel(appId, channelCode); |         PayChannelDO channel = channelService.validPayChannel(appId, channelCode); | ||||||
|         PayClient client = payClientFactory.getPayClient(channel.getId()); |         PayClient client = channelService.getPayClient(channel.getId()); | ||||||
|         if (client == null) { |         if (client == null) { | ||||||
|             log.error("[validatePayChannelCanSubmit][渠道编号({}) 找不到对应的支付客户端]", channel.getId()); |             log.error("[validatePayChannelCanSubmit][渠道编号({}) 找不到对应的支付客户端]", channel.getId()); | ||||||
|             throw exception(CHANNEL_NOT_FOUND); |             throw exception(CHANNEL_NOT_FOUND); | ||||||
| @ -458,7 +454,7 @@ public class PayOrderServiceImpl implements PayOrderService { | |||||||
|     private boolean syncOrder(PayOrderExtensionDO orderExtension) { |     private boolean syncOrder(PayOrderExtensionDO orderExtension) { | ||||||
|         try { |         try { | ||||||
|             // 1.1 查询支付订单信息 |             // 1.1 查询支付订单信息 | ||||||
|             PayClient payClient = payClientFactory.getPayClient(orderExtension.getChannelId()); |             PayClient payClient = channelService.getPayClient(orderExtension.getChannelId()); | ||||||
|             if (payClient == null) { |             if (payClient == null) { | ||||||
|                 log.error("[syncOrder][渠道编号({}) 找不到对应的支付客户端]", orderExtension.getChannelId()); |                 log.error("[syncOrder][渠道编号({}) 找不到对应的支付客户端]", orderExtension.getChannelId()); | ||||||
|                 return false; |                 return false; | ||||||
| @ -513,7 +509,7 @@ public class PayOrderServiceImpl implements PayOrderService { | |||||||
|                     return false; |                     return false; | ||||||
|                 } |                 } | ||||||
|                 // 情况二:调用三方接口,查询支付单状态,是不是已支付/已退款 |                 // 情况二:调用三方接口,查询支付单状态,是不是已支付/已退款 | ||||||
|                 PayClient payClient = payClientFactory.getPayClient(orderExtension.getChannelId()); |                 PayClient payClient = channelService.getPayClient(orderExtension.getChannelId()); | ||||||
|                 if (payClient == null) { |                 if (payClient == null) { | ||||||
|                     log.error("[expireOrder][渠道编号({}) 找不到对应的支付客户端]", orderExtension.getChannelId()); |                     log.error("[expireOrder][渠道编号({}) 找不到对应的支付客户端]", orderExtension.getChannelId()); | ||||||
|                     return false; |                     return false; | ||||||
|  | |||||||
| @ -4,7 +4,6 @@ import cn.hutool.core.collection.CollUtil; | |||||||
| import cn.hutool.extra.spring.SpringUtil; | import cn.hutool.extra.spring.SpringUtil; | ||||||
| import cn.iocoder.yudao.framework.common.pojo.PageResult; | import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||||||
| import cn.iocoder.yudao.framework.pay.core.client.PayClient; | import cn.iocoder.yudao.framework.pay.core.client.PayClient; | ||||||
| import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; |  | ||||||
| import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; | import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; | ||||||
| import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; | import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; | ||||||
| import cn.iocoder.yudao.framework.pay.core.enums.refund.PayRefundStatusRespEnum; | import cn.iocoder.yudao.framework.pay.core.enums.refund.PayRefundStatusRespEnum; | ||||||
| @ -52,9 +51,6 @@ public class PayRefundServiceImpl implements PayRefundService { | |||||||
|     @Resource |     @Resource | ||||||
|     private PayProperties payProperties; |     private PayProperties payProperties; | ||||||
|  |  | ||||||
|     @Resource |  | ||||||
|     private PayClientFactory payClientFactory; |  | ||||||
|  |  | ||||||
|     @Resource |     @Resource | ||||||
|     private PayRefundMapper refundMapper; |     private PayRefundMapper refundMapper; | ||||||
|     @Resource |     @Resource | ||||||
| @ -102,7 +98,7 @@ public class PayRefundServiceImpl implements PayRefundService { | |||||||
|         PayOrderDO order = validatePayOrderCanRefund(reqDTO); |         PayOrderDO order = validatePayOrderCanRefund(reqDTO); | ||||||
|         // 1.3 校验支付渠道是否有效 |         // 1.3 校验支付渠道是否有效 | ||||||
|         PayChannelDO channel = channelService.validPayChannel(order.getChannelId()); |         PayChannelDO channel = channelService.validPayChannel(order.getChannelId()); | ||||||
|         PayClient client = payClientFactory.getPayClient(channel.getId()); |         PayClient client = channelService.getPayClient(channel.getId()); | ||||||
|         if (client == null) { |         if (client == null) { | ||||||
|             log.error("[refund][渠道编号({}) 找不到对应的支付客户端]", channel.getId()); |             log.error("[refund][渠道编号({}) 找不到对应的支付客户端]", channel.getId()); | ||||||
|             throw exception(CHANNEL_NOT_FOUND); |             throw exception(CHANNEL_NOT_FOUND); | ||||||
| @ -305,7 +301,7 @@ public class PayRefundServiceImpl implements PayRefundService { | |||||||
|     private boolean syncRefund(PayRefundDO refund) { |     private boolean syncRefund(PayRefundDO refund) { | ||||||
|         try { |         try { | ||||||
|             // 1.1 查询退款订单信息 |             // 1.1 查询退款订单信息 | ||||||
|             PayClient payClient = payClientFactory.getPayClient(refund.getChannelId()); |             PayClient payClient = channelService.getPayClient(refund.getChannelId()); | ||||||
|             if (payClient == null) { |             if (payClient == null) { | ||||||
|                 log.error("[syncRefund][渠道编号({}) 找不到对应的支付客户端]", refund.getChannelId()); |                 log.error("[syncRefund][渠道编号({}) 找不到对应的支付客户端]", refund.getChannelId()); | ||||||
|                 return false; |                 return false; | ||||||
|  | |||||||
| @ -2,6 +2,7 @@ package cn.iocoder.yudao.module.pay.service.channel; | |||||||
|  |  | ||||||
| import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | ||||||
| import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | ||||||
|  | import cn.iocoder.yudao.framework.pay.core.client.PayClient; | ||||||
| import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; | import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; | ||||||
| import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayPayClientConfig; | import cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayPayClientConfig; | ||||||
| import cn.iocoder.yudao.framework.pay.core.client.impl.weixin.WxPayClientConfig; | import cn.iocoder.yudao.framework.pay.core.client.impl.weixin.WxPayClientConfig; | ||||||
| @ -12,30 +13,26 @@ import cn.iocoder.yudao.module.pay.controller.admin.channel.vo.PayChannelUpdateR | |||||||
| import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO; | import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO; | ||||||
| import cn.iocoder.yudao.module.pay.dal.mysql.channel.PayChannelMapper; | import cn.iocoder.yudao.module.pay.dal.mysql.channel.PayChannelMapper; | ||||||
| import com.alibaba.fastjson.JSON; | import com.alibaba.fastjson.JSON; | ||||||
| import org.junit.jupiter.api.BeforeEach; |  | ||||||
| import org.junit.jupiter.api.Test; | import org.junit.jupiter.api.Test; | ||||||
| import org.springframework.boot.test.mock.mockito.MockBean; | import org.springframework.boot.test.mock.mockito.MockBean; | ||||||
| import org.springframework.context.annotation.Import; | import org.springframework.context.annotation.Import; | ||||||
|  |  | ||||||
| import javax.annotation.Resource; | import javax.annotation.Resource; | ||||||
| import javax.validation.Validator; | import javax.validation.Validator; | ||||||
|  |  | ||||||
| import java.time.Duration; |  | ||||||
| import java.util.Collections; | import java.util.Collections; | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  |  | ||||||
| import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.addTime; |  | ||||||
| import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; | import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; | ||||||
| import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; | import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; | ||||||
| import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; | import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; | ||||||
| import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*; | import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*; | ||||||
| import static org.junit.jupiter.api.Assertions.*; | import static org.junit.jupiter.api.Assertions.*; | ||||||
|  | import static org.mockito.ArgumentMatchers.eq; | ||||||
|  | import static org.mockito.Mockito.*; | ||||||
|  |  | ||||||
| @Import({PayChannelServiceImpl.class}) | @Import({PayChannelServiceImpl.class}) | ||||||
| public class PayChannelServiceTest extends BaseDbUnitTest { | public class PayChannelServiceTest extends BaseDbUnitTest { | ||||||
|  |  | ||||||
|     private static final String ALIPAY_SERVER_URL = "https://openapi.alipay.com/gateway.do"; |  | ||||||
|  |  | ||||||
|     @Resource |     @Resource | ||||||
|     private PayChannelServiceImpl channelService; |     private PayChannelServiceImpl channelService; | ||||||
|  |  | ||||||
| @ -47,45 +44,6 @@ public class PayChannelServiceTest extends BaseDbUnitTest { | |||||||
|     @MockBean |     @MockBean | ||||||
|     private Validator validator; |     private Validator validator; | ||||||
|  |  | ||||||
|     @BeforeEach |  | ||||||
|     public void setUp() { |  | ||||||
|         channelService.setChannelCache(null); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Test |  | ||||||
|     public void testInitLocalCache() { |  | ||||||
|         // mock 数据 |  | ||||||
|         PayChannelDO dbChannel = randomPojo(PayChannelDO.class, |  | ||||||
|                 o -> o.setConfig(randomWxPayClientConfig())); |  | ||||||
|         channelMapper.insert(dbChannel);// @Sql: 先插入出一条存在的数据 |  | ||||||
|  |  | ||||||
|         // 调用 |  | ||||||
|         channelService.initLocalCache(); |  | ||||||
|         // 校验缓存 |  | ||||||
|         assertEquals(1, channelService.getChannelCache().size()); |  | ||||||
|         assertEquals(dbChannel, channelService.getChannelCache().get(0)); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Test |  | ||||||
|     public void testRefreshLocalCache() { |  | ||||||
|         // mock 数据 01 |  | ||||||
|         PayChannelDO dbChannel = randomPojo(PayChannelDO.class, |  | ||||||
|                 o -> o.setConfig(randomWxPayClientConfig()).setUpdateTime(addTime(Duration.ofMinutes(-2)))); |  | ||||||
|         channelMapper.insert(dbChannel);// @Sql: 先插入出一条存在的数据 |  | ||||||
|         channelService.initLocalCache(); |  | ||||||
|         // mock 数据 02 |  | ||||||
|         PayChannelDO dbChannel02 = randomPojo(PayChannelDO.class, |  | ||||||
|                 o -> o.setConfig(randomWxPayClientConfig())); |  | ||||||
|         channelMapper.insert(dbChannel02);// @Sql: 先插入出一条存在的数据 |  | ||||||
|  |  | ||||||
|         // 调用 |  | ||||||
|         channelService.refreshLocalCache(); |  | ||||||
|         // 校验缓存 |  | ||||||
|         assertEquals(2, channelService.getChannelCache().size()); |  | ||||||
|         assertEquals(dbChannel, channelService.getChannelCache().get(0)); |  | ||||||
|         assertEquals(dbChannel02, channelService.getChannelCache().get(1)); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Test |     @Test | ||||||
|     public void testCreateChannel_success() { |     public void testCreateChannel_success() { | ||||||
|         // 准备参数 |         // 准备参数 | ||||||
| @ -103,8 +61,7 @@ public class PayChannelServiceTest extends BaseDbUnitTest { | |||||||
|         assertPojoEquals(reqVO, channel, "config"); |         assertPojoEquals(reqVO, channel, "config"); | ||||||
|         assertPojoEquals(config, channel.getConfig()); |         assertPojoEquals(config, channel.getConfig()); | ||||||
|         // 校验缓存 |         // 校验缓存 | ||||||
|         assertEquals(1, channelService.getChannelCache().size()); |         assertNull(channelService.getClientCache().getIfPresent(channelId)); | ||||||
|         assertEquals(channel, channelService.getChannelCache().get(0)); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Test |     @Test | ||||||
| @ -146,8 +103,7 @@ public class PayChannelServiceTest extends BaseDbUnitTest { | |||||||
|         assertPojoEquals(reqVO, channel, "config"); |         assertPojoEquals(reqVO, channel, "config"); | ||||||
|         assertPojoEquals(config, channel.getConfig()); |         assertPojoEquals(config, channel.getConfig()); | ||||||
|         // 校验缓存 |         // 校验缓存 | ||||||
|         assertEquals(1, channelService.getChannelCache().size()); |         assertNull(channelService.getClientCache().getIfPresent(channel.getId())); | ||||||
|         assertEquals(channel, channelService.getChannelCache().get(0)); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Test |     @Test | ||||||
| @ -179,7 +135,7 @@ public class PayChannelServiceTest extends BaseDbUnitTest { | |||||||
|         // 校验数据不存在了 |         // 校验数据不存在了 | ||||||
|         assertNull(channelMapper.selectById(id)); |         assertNull(channelMapper.selectById(id)); | ||||||
|         // 校验缓存 |         // 校验缓存 | ||||||
|         assertEquals(0, channelService.getChannelCache().size()); |         assertNull(channelService.getClientCache().getIfPresent(id)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Test |     @Test | ||||||
| @ -344,6 +300,28 @@ public class PayChannelServiceTest extends BaseDbUnitTest { | |||||||
|         assertPojoEquals(channel, dbChannel03); |         assertPojoEquals(channel, dbChannel03); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     @Test | ||||||
|  |     public void testGetPayClient() { | ||||||
|  |         // mock 数据 | ||||||
|  |         PayChannelDO channel = randomPojo(PayChannelDO.class, o -> { | ||||||
|  |             o.setCode(PayChannelEnum.ALIPAY_APP.getCode()); | ||||||
|  |             o.setConfig(randomAlipayPayClientConfig()); | ||||||
|  |         }); | ||||||
|  |         channelMapper.insert(channel); | ||||||
|  |         // mock 参数 | ||||||
|  |         Long id = channel.getId(); | ||||||
|  |         // mock 方法 | ||||||
|  |         PayClient mockClient = mock(PayClient.class); | ||||||
|  |         when(payClientFactory.getPayClient(eq(id))).thenReturn(mockClient); | ||||||
|  |  | ||||||
|  |         // 调用 | ||||||
|  |         PayClient client = channelService.getPayClient(id); | ||||||
|  |         // 断言 | ||||||
|  |         assertSame(client, mockClient); | ||||||
|  |         verify(payClientFactory).createOrUpdatePayClient(eq(id), eq(channel.getCode()), | ||||||
|  |                 eq(channel.getConfig())); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     public WxPayClientConfig randomWxPayClientConfig() { |     public WxPayClientConfig randomWxPayClientConfig() { | ||||||
|         return new WxPayClientConfig() |         return new WxPayClientConfig() | ||||||
|                 .setAppId(randomString()) |                 .setAppId(randomString()) | ||||||
|  | |||||||
| @ -18,6 +18,7 @@ import lombok.Getter; | |||||||
| import lombok.extern.slf4j.Slf4j; | import lombok.extern.slf4j.Slf4j; | ||||||
| import org.springframework.scheduling.annotation.Scheduled; | import org.springframework.scheduling.annotation.Scheduled; | ||||||
| import org.springframework.stereotype.Service; | import org.springframework.stereotype.Service; | ||||||
|  | import org.springframework.util.Assert; | ||||||
| import org.springframework.validation.annotation.Validated; | import org.springframework.validation.annotation.Validated; | ||||||
|  |  | ||||||
| import javax.annotation.PostConstruct; | import javax.annotation.PostConstruct; | ||||||
| @ -42,6 +43,11 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SENSITIVE_ | |||||||
| @Validated | @Validated | ||||||
| public class SensitiveWordServiceImpl implements SensitiveWordService { | public class SensitiveWordServiceImpl implements SensitiveWordService { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 是否开启敏感词功能 | ||||||
|  |      */ | ||||||
|  |     private static final Boolean ENABLED = false; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 敏感词列表缓存 |      * 敏感词列表缓存 | ||||||
|      */ |      */ | ||||||
| @ -75,6 +81,10 @@ public class SensitiveWordServiceImpl implements SensitiveWordService { | |||||||
|      */ |      */ | ||||||
|     @PostConstruct |     @PostConstruct | ||||||
|     public void initLocalCache() { |     public void initLocalCache() { | ||||||
|  |         if (!ENABLED) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|         // 第一步:查询数据 |         // 第一步:查询数据 | ||||||
|         List<SensitiveWordDO> sensitiveWords = sensitiveWordMapper.selectList(); |         List<SensitiveWordDO> sensitiveWords = sensitiveWordMapper.selectList(); | ||||||
|         log.info("[initLocalCache][缓存敏感词,数量为:{}]", sensitiveWords.size()); |         log.info("[initLocalCache][缓存敏感词,数量为:{}]", sensitiveWords.size()); | ||||||
| @ -216,6 +226,9 @@ public class SensitiveWordServiceImpl implements SensitiveWordService { | |||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public List<String> validateText(String text, List<String> tags) { |     public List<String> validateText(String text, List<String> tags) { | ||||||
|  |         Assert.isTrue(ENABLED, "敏感词功能未开启,请将 ENABLED 设置为 true"); | ||||||
|  |  | ||||||
|  |         // 无标签时,默认所有 | ||||||
|         if (CollUtil.isEmpty(tags)) { |         if (CollUtil.isEmpty(tags)) { | ||||||
|             return defaultSensitiveWordTrie.validate(text); |             return defaultSensitiveWordTrie.validate(text); | ||||||
|         } |         } | ||||||
| @ -233,6 +246,9 @@ public class SensitiveWordServiceImpl implements SensitiveWordService { | |||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public boolean isTextValid(String text, List<String> tags) { |     public boolean isTextValid(String text, List<String> tags) { | ||||||
|  |         Assert.isTrue(ENABLED, "敏感词功能未开启,请将 ENABLED 设置为 true"); | ||||||
|  |  | ||||||
|  |         // 无标签时,默认所有 | ||||||
|         if (CollUtil.isEmpty(tags)) { |         if (CollUtil.isEmpty(tags)) { | ||||||
|             return defaultSensitiveWordTrie.isValid(text); |             return defaultSensitiveWordTrie.isValid(text); | ||||||
|         } |         } | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 YunaiV
					YunaiV