From a927dd059eb94c28316ac3cdde71359d8ab73e8d Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 2 May 2021 23:23:05 +0800 Subject: [PATCH] 项目结构调整 x 18 : 解决拆分后的报错 --- yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/infra/controller/job/InfJobController.java | 2 +- yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/infra/dal/dataobject/job/InfJobLogDO.java | 2 +- yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/infra/dal/mysql/config/InfConfigDAOImpl.java | 5 ++--- yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/infra/mq/consumer/config/InfConfigRefreshConsumer.java | 2 +- yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/infra/service/job/InfJobLogService.java | 2 +- yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/infra/service/job/impl/InfJobServiceImpl.java | 4 ++-- yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsCallbackController.java | 2 +- yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SysSmsChannelConvert.java | 2 +- yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsChannelDO.java | 2 +- yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsLogDO.java | 2 +- yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/system/job/auth/SysUserSessionTimeoutJob.java | 2 +- yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/system/service/auth/impl/SysAuthServiceImpl.java | 2 ++ yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsChannelServiceImpl.java | 4 ++-- yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java | 10 +++++----- yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsTemplateServiceImpl.java | 8 ++++---- yudao-admin-server/src/main/resources/1logback-spring.xml | 76 ---------------------------------------------------------------------------- yudao-admin-server/src/main/resources/META-INF/services/com.ctrip.framework.apollo.internals.Injector | 1 - yudao-admin-server/src/main/resources/META-INF/spring.factories | 2 -- yudao-admin-server/src/main/resources/application.yaml | 2 ++ yudao-admin-server/src/main/resources/logback-spring.xml | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-admin-server/src/test-integration/java/cn/iocoder/dashboard/BaseDbAndRedisIntegrationTest.java | 2 +- yudao-admin-server/src/test-integration/java/cn/iocoder/dashboard/BaseRedisIntegrationTest.java | 2 +- yudao-admin-server/src/test/java/cn/iocoder/dashboard/BaseDbAndRedisUnitTest.java | 4 ++-- yudao-admin-server/src/test/java/cn/iocoder/dashboard/BaseRedisUnitTest.java | 5 +++-- yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/infra/service/config/InfConfigServiceTest.java | 6 +++--- yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/infra/service/file/InfFileServiceTest.java | 8 ++++---- yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/infra/service/job/InfJobLogServiceTest.java | 8 ++++---- yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/infra/service/job/InfJobServiceTest.java | 10 +++++----- yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/infra/service/logger/InfApiAccessLogServiceImplTest.java | 4 ++-- yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/infra/service/logger/InfApiErrorLogServiceImplTest.java | 6 +++--- yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/auth/SysAuthServiceImplTest.java | 6 +++--- yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/auth/SysUserSessionServiceImplTest.java | 14 +++++++------- yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/common/SysCaptchaServiceTest.java | 2 +- yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/dept/SysDeptServiceTest.java | 6 +++--- yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/dept/SysPostServiceTest.java | 8 ++++---- yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/dict/SysDictDataServiceTest.java | 6 +++--- yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/dict/SysDictTypeServiceTest.java | 6 +++--- yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/errorcode/SysErrorCodeServiceTest.java | 6 +++--- yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/logger/SysLoginLogServiceImplTest.java | 4 ++-- yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/logger/SysOperateLogServiceImplTest.java | 6 +++--- yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/notice/SysNoticeServiceImplTest.java | 8 ++++---- yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/permission/SysMenuServiceTest.java | 14 +++++++------- yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/permission/SysPermissionServiceTest.java | 6 +++--- yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/permission/SysRoleServiceTest.java | 6 +++--- yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsChannelServiceTest.java | 6 +++--- yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsLogServiceTest.java | 4 ++-- yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsServiceTest.java | 14 +++++++------- yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsTemplateServiceTest.java | 14 +++++++------- yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/user/SysUserServiceImplTest.java | 6 +++--- yudao-framework/yudao-spring-boot-starter-biz-dict/src/main/java/cn/iocoder/yudao/framework/dict/config/DictConfiguration.java | 18 ------------------ yudao-framework/yudao-spring-boot-starter-biz-dict/src/main/java/cn/iocoder/yudao/framework/dict/config/YudaoDictAutoConfiguration.java | 18 ++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-biz-dict/src/main/java/cn/iocoder/yudao/framework/dict/core/util/DictFrameworkUtils.java | 28 ++++++++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-biz-dict/src/main/java/cn/iocoder/yudao/framework/dict/core/util/DictUtils.java | 28 ---------------------------- yudao-framework/yudao-spring-boot-starter-biz-dict/src/main/java/cn/iocoder/yudao/framework/dict/package-info.java | 2 +- yudao-framework/yudao-spring-boot-starter-biz-dict/src/main/resources/META-INF/spring.factories | 2 ++ yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelog/core/dto/OperateLogCreateReqDTO.java | 2 +- yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/resources/META-INF/spring.factories | 2 ++ yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/config/SmsConfiguration.java | 21 --------------------- yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClient.java | 54 ------------------------------------------------------ yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClientFactory.java | 36 ------------------------------------ yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsCodeMapping.java | 17 ----------------- yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsCommonResult.java | 68 -------------------------------------------------------------------- yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsReceiveRespDTO.java | 48 ------------------------------------------------ yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsSendRespDTO.java | 18 ------------------ yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsTemplateRespDTO.java | 33 --------------------------------- yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/AbstractSmsClient.java | 122 -------------------------------------------------------------------------------------------------------------------------- yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/SmsClientFactoryImpl.java | 90 ------------------------------------------------------------------------------------------ yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java | 212 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsCodeMapping.java | 43 ------------------------------------------- yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/debug/DebugDingTalkCodeMapping.java | 23 ----------------------- yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/debug/DebugDingTalkSmsClient.java | 96 ------------------------------------------------------------------------------------------------ yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java | 204 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsCodeMapping.java | 45 --------------------------------------------- yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsChannelEnum.java | 37 ------------------------------------- yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsFrameworkErrorCodeConstants.java | 47 ----------------------------------------------- yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsTemplateAuditStatusEnum.java | 21 --------------------- yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/property/SmsChannelProperties.java | 52 ---------------------------------------------------- yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/config/YudaoSmsAutoConfiguration.java | 21 +++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/SmsClient.java | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/SmsClientFactory.java | 36 ++++++++++++++++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/SmsCodeMapping.java | 17 +++++++++++++++++ yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/SmsCommonResult.java | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/dto/SmsReceiveRespDTO.java | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/dto/SmsSendRespDTO.java | 18 ++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/dto/SmsTemplateRespDTO.java | 33 +++++++++++++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/AbstractSmsClient.java | 122 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/SmsClientFactoryImpl.java | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java | 212 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/aliyun/AliyunSmsCodeMapping.java | 42 ++++++++++++++++++++++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/debug/DebugDingTalkCodeMapping.java | 22 ++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/debug/DebugDingTalkSmsClient.java | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java | 204 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/yunpian/YunpianSmsCodeMapping.java | 45 +++++++++++++++++++++++++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/enums/SmsChannelEnum.java | 37 +++++++++++++++++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/enums/SmsFrameworkErrorCodeConstants.java | 47 +++++++++++++++++++++++++++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/enums/SmsTemplateAuditStatusEnum.java | 21 +++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/property/SmsChannelProperties.java | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/resources/META-INF/spring.factories | 2 ++ yudao-framework/yudao-spring-boot-starter-biz-sms/src/test/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClientTest.java | 224 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- yudao-framework/yudao-spring-boot-starter-biz-sms/src/test/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsCodeMappingTest.java | 43 ------------------------------------------- yudao-framework/yudao-spring-boot-starter-biz-sms/src/test/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClientTest.java | 202 ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- yudao-framework/yudao-spring-boot-starter-biz-sms/src/test/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsCodeMappingTest.java | 43 ------------------------------------------- yudao-framework/yudao-spring-boot-starter-biz-sms/src/test/java/cn/iocoder/yudao/framework/sms/core/client/impl/aliyun/AliyunSmsClientTest.java | 225 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-biz-sms/src/test/java/cn/iocoder/yudao/framework/sms/core/client/impl/aliyun/AliyunSmsCodeMappingTest.java | 43 +++++++++++++++++++++++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-biz-sms/src/test/java/cn/iocoder/yudao/framework/sms/core/client/impl/yunpian/YunpianSmsClientTest.java | 202 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-biz-sms/src/test/java/cn/iocoder/yudao/framework/sms/core/client/impl/yunpian/YunpianSmsCodeMappingTest.java | 44 ++++++++++++++++++++++++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/dashboard/framework/apollo/core/ConfigConsts.java | 20 -------------------- yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/dashboard/framework/apollo/internals/ConfigFrameworkDAO.java | 32 -------------------------------- yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/dashboard/framework/apollo/internals/DBConfigRepository.java | 183 --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/dashboard/framework/apollo/internals/DefaultXInjector.java | 75 --------------------------------------------------------------------------- yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/dashboard/framework/apollo/internals/dto/ConfigRespDTO.java | 33 --------------------------------- yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/dashboard/framework/apollo/package-info.java | 13 ------------- yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/dashboard/framework/apollo/spi/DBConfigFactory.java | 32 -------------------------------- yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/dashboard/framework/apollo/spring/boot/ApolloApplicationContextInitializer.java | 63 --------------------------------------------------------------- yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/yudao/framework/apollo/core/ConfigConsts.java | 22 ++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/yudao/framework/apollo/internals/ConfigFrameworkDAO.java | 32 ++++++++++++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/yudao/framework/apollo/internals/DBConfigRepository.java | 183 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/yudao/framework/apollo/internals/DefaultXInjector.java | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/yudao/framework/apollo/internals/dto/ConfigRespDTO.java | 33 +++++++++++++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/yudao/framework/apollo/package-info.java | 13 +++++++++++++ yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/yudao/framework/apollo/spi/DBConfigFactory.java | 32 ++++++++++++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/yudao/framework/apollo/spring/boot/ApolloApplicationContextInitializer.java | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-config/src/main/resources/META-INF/services/com.ctrip.framework.apollo.internals.Injector | 1 + yudao-framework/yudao-spring-boot-starter-config/src/main/resources/META-INF/spring.factories | 2 ++ yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/convert/DictConvert.java | 6 +++--- yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/dashboard/framework/quartz/config/QuartzConfig.java | 18 ------------------ yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/dashboard/framework/quartz/core/enums/JobDataKeyEnum.java | 14 -------------- yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/dashboard/framework/quartz/core/handler/JobHandler.java | 19 ------------------- yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/dashboard/framework/quartz/core/handler/JobHandlerInvoker.java | 113 ----------------------------------------------------------------------------------------------------------------- yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/dashboard/framework/quartz/core/scheduler/SchedulerManager.java | 130 ---------------------------------------------------------------------------------------------------------------------------------- yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/dashboard/framework/quartz/core/service/JobLogFrameworkService.java | 44 -------------------------------------------- yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/dashboard/framework/quartz/core/util/CronUtils.java | 54 ------------------------------------------------------ yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/dashboard/framework/quartz/package-info.java | 5 ----- yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/config/YudaoQuartzAutoConfiguration.java | 18 ++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/enums/JobDataKeyEnum.java | 14 ++++++++++++++ yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/handler/JobHandler.java | 19 +++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/handler/JobHandlerInvoker.java | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/scheduler/SchedulerManager.java | 130 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/service/JobLogFrameworkService.java | 44 ++++++++++++++++++++++++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/util/CronUtils.java | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/package-info.java | 5 +++++ yudao-framework/yudao-spring-boot-starter-job/src/main/resources/META-INF/spring.factories | 2 ++ yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/config/TracerAutoConfiguration.java | 56 -------------------------------------------------------- yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/config/YudaoTracerAutoConfiguration.java | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/《芋道 Spring Boot 链路追踪 SkyWalking 入门》.md | 1 - yudao-framework/yudao-spring-boot-starter-monitor/src/main/resources/META-INF/spring.factories | 2 ++ yudao-framework/yudao-spring-boot-starter-monitor/《芋道 Spring Boot 监控工具 Admin 入门》.md | 1 + yudao-framework/yudao-spring-boot-starter-monitor/《芋道 Spring Boot 监控端点 Actuator 入门》.md | 1 + yudao-framework/yudao-spring-boot-starter-monitor/《芋道 Spring Boot 链路追踪 SkyWalking 入门》.md | 1 + yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml | 6 ------ yudao-framework/yudao-spring-boot-starter-protection/pom.xml | 1 - yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/config/IdempotentConfiguration.java | 42 ------------------------------------------ yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/config/YudaoIdempotentConfiguration.java | 42 ++++++++++++++++++++++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/lock4j/config/Lock4jConfiguration.java | 23 ----------------------- yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/lock4j/config/YudaoLock4jConfiguration.java | 23 +++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-protection/src/main/resources/resources/META-INF/spring.factories | 3 +++ yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/RedisConfig.java | 119 ----------------------------------------------------------------------------------------------------------------------- yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoRedisAutoConfiguration.java | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-redis/src/main/resources/META-INF/spring.factories | 2 ++ yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoSecurityAutoConfiguration.java | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoSecurityConfiguration.java | 167 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java | 165 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/filter/JwtAuthenticationTokenFilter.java | 14 +++++++------- yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/handler/AccessDeniedHandlerImpl.java | 3 +-- yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/handler/AuthenticationEntryPointImpl.java | 2 -- yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/handler/LogoutSuccessHandlerImpl.java | 9 ++++----- yudao-framework/yudao-spring-boot-starter-security/src/main/resources/META-INF/spring.factories | 3 +++ yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/dashboard/framework/test/core/ut/BaseMockitoUnitTest.java | 13 ------------- yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/dashboard/framework/test/core/ut/package-info.java | 4 ---- yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/dashboard/framework/test/core/util/AssertUtils.java | 97 ------------------------------------------------------------------------------------------------- yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/dashboard/framework/test/core/util/RandomUtils.java | 100 ---------------------------------------------------------------------------------------------------- yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/dashboard/framework/test/package-info.java | 4 ---- yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/ut/BaseMockitoUnitTest.java | 13 +++++++++++++ yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/ut/package-info.java | 4 ++++ yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/util/AssertUtils.java | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/util/RandomUtils.java | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/package-info.java | 4 ++++ yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/WebProperties.java | 2 +- yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/YudaoWebAutoConfiguration.java | 19 +++++++++++++++++++ yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java | 8 ++++---- yudao-framework/yudao-spring-boot-starter-web/src/main/resources/META-INF/spring.factories | 5 +++++ 181 files changed, 3670 insertions(+), 3554 deletions(-) delete mode 100644 yudao-admin-server/src/main/resources/1logback-spring.xml delete mode 100644 yudao-admin-server/src/main/resources/META-INF/services/com.ctrip.framework.apollo.internals.Injector delete mode 100644 yudao-admin-server/src/main/resources/META-INF/spring.factories create mode 100644 yudao-admin-server/src/main/resources/logback-spring.xml delete mode 100644 yudao-framework/yudao-spring-boot-starter-biz-dict/src/main/java/cn/iocoder/yudao/framework/dict/config/DictConfiguration.java create mode 100644 yudao-framework/yudao-spring-boot-starter-biz-dict/src/main/java/cn/iocoder/yudao/framework/dict/config/YudaoDictAutoConfiguration.java create mode 100644 yudao-framework/yudao-spring-boot-starter-biz-dict/src/main/java/cn/iocoder/yudao/framework/dict/core/util/DictFrameworkUtils.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-biz-dict/src/main/java/cn/iocoder/yudao/framework/dict/core/util/DictUtils.java create mode 100644 yudao-framework/yudao-spring-boot-starter-biz-dict/src/main/resources/META-INF/spring.factories create mode 100644 yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/resources/META-INF/spring.factories delete mode 100644 yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/config/SmsConfiguration.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClient.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClientFactory.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsCodeMapping.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsCommonResult.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsReceiveRespDTO.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsSendRespDTO.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsTemplateRespDTO.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/AbstractSmsClient.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/SmsClientFactoryImpl.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsCodeMapping.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/debug/DebugDingTalkCodeMapping.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/debug/DebugDingTalkSmsClient.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsCodeMapping.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsChannelEnum.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsFrameworkErrorCodeConstants.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsTemplateAuditStatusEnum.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/property/SmsChannelProperties.java create mode 100644 yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/config/YudaoSmsAutoConfiguration.java create mode 100644 yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/SmsClient.java create mode 100644 yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/SmsClientFactory.java create mode 100644 yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/SmsCodeMapping.java create mode 100644 yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/SmsCommonResult.java create mode 100644 yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/dto/SmsReceiveRespDTO.java create mode 100644 yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/dto/SmsSendRespDTO.java create mode 100644 yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/dto/SmsTemplateRespDTO.java create mode 100644 yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/AbstractSmsClient.java create mode 100644 yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/SmsClientFactoryImpl.java create mode 100644 yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java create mode 100644 yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/aliyun/AliyunSmsCodeMapping.java create mode 100644 yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/debug/DebugDingTalkCodeMapping.java create mode 100644 yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/debug/DebugDingTalkSmsClient.java create mode 100644 yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java create mode 100644 yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/yunpian/YunpianSmsCodeMapping.java create mode 100644 yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/enums/SmsChannelEnum.java create mode 100644 yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/enums/SmsFrameworkErrorCodeConstants.java create mode 100644 yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/enums/SmsTemplateAuditStatusEnum.java create mode 100644 yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/property/SmsChannelProperties.java create mode 100644 yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/resources/META-INF/spring.factories delete mode 100644 yudao-framework/yudao-spring-boot-starter-biz-sms/src/test/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClientTest.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-biz-sms/src/test/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsCodeMappingTest.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-biz-sms/src/test/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClientTest.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-biz-sms/src/test/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsCodeMappingTest.java create mode 100644 yudao-framework/yudao-spring-boot-starter-biz-sms/src/test/java/cn/iocoder/yudao/framework/sms/core/client/impl/aliyun/AliyunSmsClientTest.java create mode 100644 yudao-framework/yudao-spring-boot-starter-biz-sms/src/test/java/cn/iocoder/yudao/framework/sms/core/client/impl/aliyun/AliyunSmsCodeMappingTest.java create mode 100644 yudao-framework/yudao-spring-boot-starter-biz-sms/src/test/java/cn/iocoder/yudao/framework/sms/core/client/impl/yunpian/YunpianSmsClientTest.java create mode 100644 yudao-framework/yudao-spring-boot-starter-biz-sms/src/test/java/cn/iocoder/yudao/framework/sms/core/client/impl/yunpian/YunpianSmsCodeMappingTest.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/dashboard/framework/apollo/core/ConfigConsts.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/dashboard/framework/apollo/internals/ConfigFrameworkDAO.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/dashboard/framework/apollo/internals/DBConfigRepository.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/dashboard/framework/apollo/internals/DefaultXInjector.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/dashboard/framework/apollo/internals/dto/ConfigRespDTO.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/dashboard/framework/apollo/package-info.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/dashboard/framework/apollo/spi/DBConfigFactory.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/dashboard/framework/apollo/spring/boot/ApolloApplicationContextInitializer.java create mode 100644 yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/yudao/framework/apollo/core/ConfigConsts.java create mode 100644 yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/yudao/framework/apollo/internals/ConfigFrameworkDAO.java create mode 100644 yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/yudao/framework/apollo/internals/DBConfigRepository.java create mode 100644 yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/yudao/framework/apollo/internals/DefaultXInjector.java create mode 100644 yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/yudao/framework/apollo/internals/dto/ConfigRespDTO.java create mode 100644 yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/yudao/framework/apollo/package-info.java create mode 100644 yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/yudao/framework/apollo/spi/DBConfigFactory.java create mode 100644 yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/yudao/framework/apollo/spring/boot/ApolloApplicationContextInitializer.java create mode 100644 yudao-framework/yudao-spring-boot-starter-config/src/main/resources/META-INF/services/com.ctrip.framework.apollo.internals.Injector create mode 100644 yudao-framework/yudao-spring-boot-starter-config/src/main/resources/META-INF/spring.factories delete mode 100644 yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/dashboard/framework/quartz/config/QuartzConfig.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/dashboard/framework/quartz/core/enums/JobDataKeyEnum.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/dashboard/framework/quartz/core/handler/JobHandler.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/dashboard/framework/quartz/core/handler/JobHandlerInvoker.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/dashboard/framework/quartz/core/scheduler/SchedulerManager.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/dashboard/framework/quartz/core/service/JobLogFrameworkService.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/dashboard/framework/quartz/core/util/CronUtils.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/dashboard/framework/quartz/package-info.java create mode 100644 yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/config/YudaoQuartzAutoConfiguration.java create mode 100644 yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/enums/JobDataKeyEnum.java create mode 100644 yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/handler/JobHandler.java create mode 100644 yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/handler/JobHandlerInvoker.java create mode 100644 yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/scheduler/SchedulerManager.java create mode 100644 yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/service/JobLogFrameworkService.java create mode 100644 yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/util/CronUtils.java create mode 100644 yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/package-info.java create mode 100644 yudao-framework/yudao-spring-boot-starter-job/src/main/resources/META-INF/spring.factories delete mode 100644 yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/config/TracerAutoConfiguration.java create mode 100644 yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/config/YudaoTracerAutoConfiguration.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/《芋道 Spring Boot 链路追踪 SkyWalking 入门》.md create mode 100644 yudao-framework/yudao-spring-boot-starter-monitor/src/main/resources/META-INF/spring.factories create mode 100644 yudao-framework/yudao-spring-boot-starter-monitor/《芋道 Spring Boot 监控工具 Admin 入门》.md create mode 100644 yudao-framework/yudao-spring-boot-starter-monitor/《芋道 Spring Boot 监控端点 Actuator 入门》.md create mode 100644 yudao-framework/yudao-spring-boot-starter-monitor/《芋道 Spring Boot 链路追踪 SkyWalking 入门》.md delete mode 100644 yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/config/IdempotentConfiguration.java create mode 100644 yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/config/YudaoIdempotentConfiguration.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/lock4j/config/Lock4jConfiguration.java create mode 100644 yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/lock4j/config/YudaoLock4jConfiguration.java create mode 100644 yudao-framework/yudao-spring-boot-starter-protection/src/main/resources/resources/META-INF/spring.factories delete mode 100644 yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/RedisConfig.java create mode 100644 yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoRedisAutoConfiguration.java create mode 100644 yudao-framework/yudao-spring-boot-starter-redis/src/main/resources/META-INF/spring.factories create mode 100644 yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoSecurityAutoConfiguration.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoSecurityConfiguration.java create mode 100644 yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java create mode 100644 yudao-framework/yudao-spring-boot-starter-security/src/main/resources/META-INF/spring.factories delete mode 100644 yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/dashboard/framework/test/core/ut/BaseMockitoUnitTest.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/dashboard/framework/test/core/ut/package-info.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/dashboard/framework/test/core/util/AssertUtils.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/dashboard/framework/test/core/util/RandomUtils.java delete mode 100644 yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/dashboard/framework/test/package-info.java create mode 100644 yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/ut/BaseMockitoUnitTest.java create mode 100644 yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/ut/package-info.java create mode 100644 yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/util/AssertUtils.java create mode 100644 yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/util/RandomUtils.java create mode 100644 yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/package-info.java create mode 100644 yudao-framework/yudao-spring-boot-starter-web/src/main/resources/META-INF/spring.factories diff --git a/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/infra/controller/job/InfJobController.java b/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/infra/controller/job/InfJobController.java index c9df9a5..83af689 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/infra/controller/job/InfJobController.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/infra/controller/job/InfJobController.java @@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; -import cn.iocoder.dashboard.framework.quartz.core.util.CronUtils; +import cn.iocoder.yudao.framework.quartz.core.util.CronUtils; import cn.iocoder.dashboard.modules.infra.controller.job.vo.job.*; import cn.iocoder.dashboard.modules.infra.convert.job.InfJobConvert; import cn.iocoder.dashboard.modules.infra.dal.dataobject.job.InfJobDO; diff --git a/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/infra/dal/dataobject/job/InfJobLogDO.java b/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/infra/dal/dataobject/job/InfJobLogDO.java index 4674544..49d76e0 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/infra/dal/dataobject/job/InfJobLogDO.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/infra/dal/dataobject/job/InfJobLogDO.java @@ -1,7 +1,7 @@ package cn.iocoder.dashboard.modules.infra.dal.dataobject.job; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; -import cn.iocoder.dashboard.framework.quartz.core.handler.JobHandler; +import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; import cn.iocoder.dashboard.modules.infra.enums.job.InfJobLogStatusEnum; import com.baomidou.mybatisplus.annotation.TableName; import lombok.*; diff --git a/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/infra/dal/mysql/config/InfConfigDAOImpl.java b/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/infra/dal/mysql/config/InfConfigDAOImpl.java index 48f44bd..d6a5019 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/infra/dal/mysql/config/InfConfigDAOImpl.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/infra/dal/mysql/config/InfConfigDAOImpl.java @@ -1,8 +1,7 @@ package cn.iocoder.dashboard.modules.infra.dal.mysql.config; -import cn.iocoder.dashboard.framework.apollo.internals.ConfigFrameworkDAO; -import cn.iocoder.dashboard.framework.apollo.internals.dto.ConfigRespDTO; -import cn.iocoder.dashboard.modules.infra.dal.dataobject.config.InfConfigDO; +import cn.iocoder.yudao.framework.apollo.internals.ConfigFrameworkDAO; +import cn.iocoder.yudao.framework.apollo.internals.dto.ConfigRespDTO; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.datasource.DriverManagerDataSource; diff --git a/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/infra/mq/consumer/config/InfConfigRefreshConsumer.java b/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/infra/mq/consumer/config/InfConfigRefreshConsumer.java index 9ad5652..a47493c 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/infra/mq/consumer/config/InfConfigRefreshConsumer.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/infra/mq/consumer/config/InfConfigRefreshConsumer.java @@ -1,6 +1,6 @@ package cn.iocoder.dashboard.modules.infra.mq.consumer.config; -import cn.iocoder.dashboard.framework.apollo.internals.DBConfigRepository; +import cn.iocoder.yudao.framework.apollo.internals.DBConfigRepository; import cn.iocoder.yudao.framework.redis.core.pubsub.AbstractChannelMessageListener; import cn.iocoder.dashboard.modules.infra.mq.message.config.InfConfigRefreshMessage; import lombok.extern.slf4j.Slf4j; diff --git a/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/infra/service/job/InfJobLogService.java b/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/infra/service/job/InfJobLogService.java index 9ffefbe..97fb19a 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/infra/service/job/InfJobLogService.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/infra/service/job/InfJobLogService.java @@ -1,7 +1,7 @@ package cn.iocoder.dashboard.modules.infra.service.job; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.dashboard.framework.quartz.core.service.JobLogFrameworkService; +import cn.iocoder.yudao.framework.quartz.core.service.JobLogFrameworkService; import cn.iocoder.dashboard.modules.infra.controller.job.vo.log.InfJobLogExportReqVO; import cn.iocoder.dashboard.modules.infra.controller.job.vo.log.InfJobLogPageReqVO; import cn.iocoder.dashboard.modules.infra.dal.dataobject.job.InfJobLogDO; diff --git a/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/infra/service/job/impl/InfJobServiceImpl.java b/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/infra/service/job/impl/InfJobServiceImpl.java index cc534c9..055d7ef 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/infra/service/job/impl/InfJobServiceImpl.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/infra/service/job/impl/InfJobServiceImpl.java @@ -1,8 +1,8 @@ package cn.iocoder.dashboard.modules.infra.service.job.impl; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.dashboard.framework.quartz.core.scheduler.SchedulerManager; -import cn.iocoder.dashboard.framework.quartz.core.util.CronUtils; +import cn.iocoder.yudao.framework.quartz.core.scheduler.SchedulerManager; +import cn.iocoder.yudao.framework.quartz.core.util.CronUtils; import cn.iocoder.dashboard.modules.infra.controller.job.vo.job.InfJobCreateReqVO; import cn.iocoder.dashboard.modules.infra.controller.job.vo.job.InfJobExportReqVO; import cn.iocoder.dashboard.modules.infra.controller.job.vo.job.InfJobPageReqVO; diff --git a/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsCallbackController.java b/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsCallbackController.java index 3f70116..3562621 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsCallbackController.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsCallbackController.java @@ -4,7 +4,7 @@ import cn.hutool.core.util.URLUtil; import cn.hutool.extra.servlet.ServletUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; -import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum; +import cn.iocoder.yudao.framework.sms.core.enums.SmsChannelEnum; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; diff --git a/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SysSmsChannelConvert.java b/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SysSmsChannelConvert.java index 88541af..4236565 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SysSmsChannelConvert.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SysSmsChannelConvert.java @@ -1,7 +1,7 @@ package cn.iocoder.dashboard.modules.system.convert.sms; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; +import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties; import cn.iocoder.dashboard.modules.system.controller.sms.vo.channel.SysSmsChannelCreateReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.channel.SysSmsChannelRespVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.channel.SysSmsChannelSimpleRespVO; diff --git a/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsChannelDO.java b/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsChannelDO.java index dc36cc5..befc9b9 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsChannelDO.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsChannelDO.java @@ -2,7 +2,7 @@ package cn.iocoder.dashboard.modules.system.dal.dataobject.sms; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; -import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum; +import cn.iocoder.yudao.framework.sms.core.enums.SmsChannelEnum; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import lombok.EqualsAndHashCode; diff --git a/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsLogDO.java b/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsLogDO.java index 9506ad3..782d004 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsLogDO.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsLogDO.java @@ -2,7 +2,7 @@ package cn.iocoder.dashboard.modules.system.dal.dataobject.sms; import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; -import cn.iocoder.dashboard.framework.sms.core.enums.SmsFrameworkErrorCodeConstants; +import cn.iocoder.yudao.framework.sms.core.enums.SmsFrameworkErrorCodeConstants; import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsReceiveStatusEnum; import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum; import com.baomidou.mybatisplus.annotation.TableField; diff --git a/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/system/job/auth/SysUserSessionTimeoutJob.java b/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/system/job/auth/SysUserSessionTimeoutJob.java index 96ec74b..0d028ee 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/system/job/auth/SysUserSessionTimeoutJob.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/system/job/auth/SysUserSessionTimeoutJob.java @@ -1,6 +1,6 @@ package cn.iocoder.dashboard.modules.system.job.auth; -import cn.iocoder.dashboard.framework.quartz.core.handler.JobHandler; +import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; import cn.iocoder.dashboard.modules.system.service.auth.SysUserSessionService; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; diff --git a/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/system/service/auth/impl/SysAuthServiceImpl.java b/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/system/service/auth/impl/SysAuthServiceImpl.java index fddd14b..11d6f5f 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/system/service/auth/impl/SysAuthServiceImpl.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/system/service/auth/impl/SysAuthServiceImpl.java @@ -18,6 +18,7 @@ import cn.iocoder.dashboard.modules.system.service.permission.SysPermissionServi import cn.iocoder.dashboard.modules.system.service.user.SysUserService; import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Lazy; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.DisabledException; @@ -46,6 +47,7 @@ import static java.util.Collections.singleton; public class SysAuthServiceImpl implements SysAuthService { @Resource + @Lazy // 延迟加载,因为存在相互依赖的问题 private AuthenticationManager authenticationManager; @Resource private SysUserService userService; diff --git a/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsChannelServiceImpl.java b/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsChannelServiceImpl.java index 307ad16..f0fe411 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsChannelServiceImpl.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsChannelServiceImpl.java @@ -3,8 +3,8 @@ package cn.iocoder.dashboard.modules.system.service.sms.impl; import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; -import cn.iocoder.dashboard.framework.sms.core.client.SmsClientFactory; -import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; +import cn.iocoder.yudao.framework.sms.core.client.SmsClientFactory; +import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties; import cn.iocoder.dashboard.modules.system.controller.sms.vo.channel.SysSmsChannelCreateReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.channel.SysSmsChannelPageReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.channel.SysSmsChannelUpdateReqVO; diff --git a/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java b/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java index df0e9dc..7e2f350 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java @@ -5,11 +5,11 @@ import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.core.KeyValue; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; -import cn.iocoder.dashboard.framework.sms.core.client.SmsClient; -import cn.iocoder.dashboard.framework.sms.core.client.SmsClientFactory; -import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; -import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO; -import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; +import cn.iocoder.yudao.framework.sms.core.client.SmsClient; +import cn.iocoder.yudao.framework.sms.core.client.SmsClientFactory; +import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult; +import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO; +import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO; import cn.iocoder.dashboard.modules.system.dal.dataobject.user.SysUserDO; import cn.iocoder.dashboard.modules.system.mq.message.sms.SysSmsSendMessage; diff --git a/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsTemplateServiceImpl.java b/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsTemplateServiceImpl.java index 8a561da..2e04693 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsTemplateServiceImpl.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsTemplateServiceImpl.java @@ -6,10 +6,10 @@ import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; -import cn.iocoder.dashboard.framework.sms.core.client.SmsClient; -import cn.iocoder.dashboard.framework.sms.core.client.SmsClientFactory; -import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; -import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsTemplateRespDTO; +import cn.iocoder.yudao.framework.sms.core.client.SmsClient; +import cn.iocoder.yudao.framework.sms.core.client.SmsClientFactory; +import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult; +import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplateCreateReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplateExportReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplatePageReqVO; diff --git a/yudao-admin-server/src/main/resources/1logback-spring.xml b/yudao-admin-server/src/main/resources/1logback-spring.xml deleted file mode 100644 index 1d9bec6..0000000 --- a/yudao-admin-server/src/main/resources/1logback-spring.xml +++ /dev/null @@ -1,76 +0,0 @@ - - - - - - - - - -       - - - ${PATTERN_DEFAULT} - - - - - - - - - - ${PATTERN_DEFAULT} - - - - ${LOG_FILE} - - - ${LOGBACK_ROLLINGPOLICY_FILE_NAME_PATTERN:-${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz} - - ${LOGBACK_ROLLINGPOLICY_CLEAN_HISTORY_ON_START:-false} - - ${LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZE:-10MB} - - ${LOGBACK_ROLLINGPOLICY_TOTAL_SIZE_CAP:-0} - - ${LOGBACK_ROLLINGPOLICY_MAX_HISTORY:-30} - - - - - - 0 - - 256 - - - - - - - - ${PATTERN_DEFAULT} - - - - - - - - - - - - - - - - - - - - - - diff --git a/yudao-admin-server/src/main/resources/META-INF/services/com.ctrip.framework.apollo.internals.Injector b/yudao-admin-server/src/main/resources/META-INF/services/com.ctrip.framework.apollo.internals.Injector deleted file mode 100644 index a52f206..0000000 --- a/yudao-admin-server/src/main/resources/META-INF/services/com.ctrip.framework.apollo.internals.Injector +++ /dev/null @@ -1 +0,0 @@ -cn.iocoder.dashboard.framework.apollo.internals.DefaultXInjector diff --git a/yudao-admin-server/src/main/resources/META-INF/spring.factories b/yudao-admin-server/src/main/resources/META-INF/spring.factories deleted file mode 100644 index 8a5fa54..0000000 --- a/yudao-admin-server/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1,2 +0,0 @@ -org.springframework.boot.env.EnvironmentPostProcessor=\ - cn.iocoder.dashboard.framework.apollo.spring.boot.ApolloApplicationContextInitializer diff --git a/yudao-admin-server/src/main/resources/application.yaml b/yudao-admin-server/src/main/resources/application.yaml index 9e9f940..ff50a89 100644 --- a/yudao-admin-server/src/main/resources/application.yaml +++ b/yudao-admin-server/src/main/resources/application.yaml @@ -40,3 +40,5 @@ yudao: constants-class-list: - cn.iocoder.dashboard.modules.infra.enums.InfErrorCodeConstants - cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants + +debug: false diff --git a/yudao-admin-server/src/main/resources/logback-spring.xml b/yudao-admin-server/src/main/resources/logback-spring.xml new file mode 100644 index 0000000..1d9bec6 --- /dev/null +++ b/yudao-admin-server/src/main/resources/logback-spring.xml @@ -0,0 +1,76 @@ + + + + + + + + + +       + + + ${PATTERN_DEFAULT} + + + + + + + + + + ${PATTERN_DEFAULT} + + + + ${LOG_FILE} + + + ${LOGBACK_ROLLINGPOLICY_FILE_NAME_PATTERN:-${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz} + + ${LOGBACK_ROLLINGPOLICY_CLEAN_HISTORY_ON_START:-false} + + ${LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZE:-10MB} + + ${LOGBACK_ROLLINGPOLICY_TOTAL_SIZE_CAP:-0} + + ${LOGBACK_ROLLINGPOLICY_MAX_HISTORY:-30} + + + + + + 0 + + 256 + + + + + + + + ${PATTERN_DEFAULT} + + + + + + + + + + + + + + + + + + + + + + diff --git a/yudao-admin-server/src/test-integration/java/cn/iocoder/dashboard/BaseDbAndRedisIntegrationTest.java b/yudao-admin-server/src/test-integration/java/cn/iocoder/dashboard/BaseDbAndRedisIntegrationTest.java index 72216d2..6694db7 100644 --- a/yudao-admin-server/src/test-integration/java/cn/iocoder/dashboard/BaseDbAndRedisIntegrationTest.java +++ b/yudao-admin-server/src/test-integration/java/cn/iocoder/dashboard/BaseDbAndRedisIntegrationTest.java @@ -2,7 +2,7 @@ package cn.iocoder.dashboard; import cn.iocoder.yudao.framework.datasource.config.DataSourceConfiguration; import cn.iocoder.yudao.framework.mybatis.config.MybatisConfiguration; -import cn.iocoder.yudao.framework.redis.config.RedisConfig; +import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration; import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceAutoConfiguration; import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration; import org.redisson.spring.starter.RedissonAutoConfiguration; diff --git a/yudao-admin-server/src/test-integration/java/cn/iocoder/dashboard/BaseRedisIntegrationTest.java b/yudao-admin-server/src/test-integration/java/cn/iocoder/dashboard/BaseRedisIntegrationTest.java index 287a5f3..469efa5 100644 --- a/yudao-admin-server/src/test-integration/java/cn/iocoder/dashboard/BaseRedisIntegrationTest.java +++ b/yudao-admin-server/src/test-integration/java/cn/iocoder/dashboard/BaseRedisIntegrationTest.java @@ -1,6 +1,6 @@ package cn.iocoder.dashboard; -import cn.iocoder.yudao.framework.redis.config.RedisConfig; +import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration; import org.redisson.spring.starter.RedissonAutoConfiguration; import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; diff --git a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/BaseDbAndRedisUnitTest.java b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/BaseDbAndRedisUnitTest.java index 5a6493c..1a3b854 100644 --- a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/BaseDbAndRedisUnitTest.java +++ b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/BaseDbAndRedisUnitTest.java @@ -1,7 +1,7 @@ package cn.iocoder.dashboard; import cn.iocoder.dashboard.config.RedisTestConfiguration; -import cn.iocoder.yudao.framework.redis.config.RedisConfig; +import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration; import cn.iocoder.yudao.framework.datasource.config.YudaoDataSourceAutoConfiguration; import cn.iocoder.yudao.framework.mybatis.config.YudaoMybatisAutoConfiguration; import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure; @@ -39,7 +39,7 @@ public class BaseDbAndRedisUnitTest { // Redis 配置类 RedisTestConfiguration.class, // Redis 测试配置类,用于启动 RedisServer RedisAutoConfiguration.class, // Spring Redis 自动配置类 - RedisConfig.class, // 自己的 Redis 配置类 + YudaoRedisAutoConfiguration.class, // 自己的 Redis 配置类 RedissonAutoConfiguration.class, // Redisson 自动高配置类 }) public static class Application { diff --git a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/BaseRedisUnitTest.java b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/BaseRedisUnitTest.java index 93affa2..ce9ac1b 100644 --- a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/BaseRedisUnitTest.java +++ b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/BaseRedisUnitTest.java @@ -1,7 +1,8 @@ package cn.iocoder.dashboard; import cn.iocoder.dashboard.config.RedisTestConfiguration; -import cn.iocoder.yudao.framework.redis.config.RedisConfig; +import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration; +import cn.iocoder.yudao.framework.tracer.config.YudaoTracerAutoConfiguration; import org.redisson.spring.starter.RedissonAutoConfiguration; import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; @@ -23,7 +24,7 @@ public class BaseRedisUnitTest { // Redis 配置类 RedisTestConfiguration.class, // Redis 测试配置类,用于启动 RedisServer RedisAutoConfiguration.class, // Spring Redis 自动配置类 - RedisConfig.class, // 自己的 Redis 配置类 + YudaoTracerAutoConfiguration.class, // 自己的 Redis 配置类 RedissonAutoConfiguration.class, // Redisson 自动高配置类 }) public static class Application { diff --git a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/infra/service/config/InfConfigServiceTest.java b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/infra/service/config/InfConfigServiceTest.java index 1d60143..f6cc3d9 100644 --- a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/infra/service/config/InfConfigServiceTest.java +++ b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/infra/service/config/InfConfigServiceTest.java @@ -23,10 +23,10 @@ import java.util.function.Consumer; import static cn.hutool.core.util.RandomUtil.randomEle; import static cn.iocoder.dashboard.modules.infra.enums.InfErrorCodeConstants.*; -import static cn.iocoder.dashboard.framework.test.core.util.AssertUtils.assertPojoEquals; -import static cn.iocoder.dashboard.framework.test.core.util.AssertUtils.assertServiceException; -import static cn.iocoder.dashboard.framework.test.core.util.RandomUtils.*; +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.common.util.date.DateUtils.buildTime; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; diff --git a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/infra/service/file/InfFileServiceTest.java b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/infra/service/file/InfFileServiceTest.java index 348abc8..9a1b565 100644 --- a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/infra/service/file/InfFileServiceTest.java +++ b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/infra/service/file/InfFileServiceTest.java @@ -14,12 +14,12 @@ import org.springframework.context.annotation.Import; import javax.annotation.Resource; -import static cn.iocoder.dashboard.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; import static cn.iocoder.dashboard.modules.infra.enums.InfErrorCodeConstants.FILE_NOT_EXISTS; import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.FILE_PATH_EXISTS; -import static cn.iocoder.dashboard.framework.test.core.util.AssertUtils.assertServiceException; -import static cn.iocoder.dashboard.framework.test.core.util.RandomUtils.randomPojo; -import static cn.iocoder.dashboard.framework.test.core.util.RandomUtils.randomString; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString; import static cn.iocoder.yudao.framework.common.util.date.DateUtils.buildTime; import static org.junit.jupiter.api.Assertions.*; diff --git a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/infra/service/job/InfJobLogServiceTest.java b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/infra/service/job/InfJobLogServiceTest.java index a7e94dc..f028825 100644 --- a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/infra/service/job/InfJobLogServiceTest.java +++ b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/infra/service/job/InfJobLogServiceTest.java @@ -1,10 +1,10 @@ package cn.iocoder.dashboard.modules.infra.service.job; import static cn.hutool.core.util.RandomUtil.randomEle; -import static cn.iocoder.dashboard.framework.test.core.util.AssertUtils.assertPojoEquals; -import static cn.iocoder.dashboard.framework.test.core.util.RandomUtils.randomLongId; -import static cn.iocoder.dashboard.framework.test.core.util.RandomUtils.randomPojo; -import static cn.iocoder.dashboard.framework.test.core.util.RandomUtils.randomString; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString; import static cn.iocoder.yudao.framework.common.util.date.DateUtils.buildTime; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; diff --git a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/infra/service/job/InfJobServiceTest.java b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/infra/service/job/InfJobServiceTest.java index d426a1e..dde3600 100644 --- a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/infra/service/job/InfJobServiceTest.java +++ b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/infra/service/job/InfJobServiceTest.java @@ -7,10 +7,10 @@ import static cn.iocoder.dashboard.modules.infra.enums.InfErrorCodeConstants.JOB import static cn.iocoder.dashboard.modules.infra.enums.InfErrorCodeConstants.JOB_HANDLER_EXISTS; import static cn.iocoder.dashboard.modules.infra.enums.InfErrorCodeConstants.JOB_NOT_EXISTS; import static cn.iocoder.dashboard.modules.infra.enums.InfErrorCodeConstants.JOB_UPDATE_ONLY_NORMAL_STATUS; -import static cn.iocoder.dashboard.framework.test.core.util.AssertUtils.assertPojoEquals; -import static cn.iocoder.dashboard.framework.test.core.util.AssertUtils.assertServiceException; -import static cn.iocoder.dashboard.framework.test.core.util.RandomUtils.randomPojo; -import static cn.iocoder.dashboard.framework.test.core.util.RandomUtils.randomString; +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.RandomUtils.randomPojo; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; @@ -30,7 +30,7 @@ import org.springframework.context.annotation.Import; import cn.iocoder.dashboard.BaseDbUnitTest; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.dashboard.framework.quartz.core.scheduler.SchedulerManager; +import cn.iocoder.yudao.framework.quartz.core.scheduler.SchedulerManager; import cn.iocoder.dashboard.modules.infra.controller.job.vo.job.InfJobCreateReqVO; import cn.iocoder.dashboard.modules.infra.controller.job.vo.job.InfJobExportReqVO; import cn.iocoder.dashboard.modules.infra.controller.job.vo.job.InfJobPageReqVO; diff --git a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/infra/service/logger/InfApiAccessLogServiceImplTest.java b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/infra/service/logger/InfApiAccessLogServiceImplTest.java index 89bcef3..11a00cd 100644 --- a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/infra/service/logger/InfApiAccessLogServiceImplTest.java +++ b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/infra/service/logger/InfApiAccessLogServiceImplTest.java @@ -11,7 +11,7 @@ import cn.iocoder.dashboard.modules.infra.controller.logger.vo.apiaccesslog.InfA import cn.iocoder.dashboard.modules.infra.dal.dataobject.logger.InfApiAccessLogDO; import cn.iocoder.dashboard.modules.infra.dal.mysql.logger.InfApiAccessLogMapper; import cn.iocoder.dashboard.modules.infra.service.logger.impl.InfApiAccessLogServiceImpl; -import cn.iocoder.dashboard.framework.test.core.util.RandomUtils; +import cn.iocoder.yudao.framework.test.core.util.RandomUtils; import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; import org.junit.jupiter.api.Test; import org.springframework.context.annotation.Import; @@ -21,7 +21,7 @@ import java.util.Date; import java.util.List; import java.util.concurrent.Future; -import static cn.iocoder.dashboard.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; import static cn.iocoder.yudao.framework.common.util.date.DateUtils.buildTime; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; diff --git a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/infra/service/logger/InfApiErrorLogServiceImplTest.java b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/infra/service/logger/InfApiErrorLogServiceImplTest.java index 4427244..d82afad 100644 --- a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/infra/service/logger/InfApiErrorLogServiceImplTest.java +++ b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/infra/service/logger/InfApiErrorLogServiceImplTest.java @@ -11,7 +11,7 @@ import cn.iocoder.dashboard.modules.infra.dal.dataobject.logger.InfApiErrorLogDO import cn.iocoder.dashboard.modules.infra.dal.mysql.logger.InfApiErrorLogMapper; import cn.iocoder.dashboard.modules.infra.enums.logger.InfApiErrorLogProcessStatusEnum; import cn.iocoder.dashboard.modules.infra.service.logger.impl.InfApiErrorLogServiceImpl; -import cn.iocoder.dashboard.framework.test.core.util.RandomUtils; +import cn.iocoder.yudao.framework.test.core.util.RandomUtils; import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; import org.junit.jupiter.api.Test; import org.springframework.context.annotation.Import; @@ -23,8 +23,8 @@ import java.util.concurrent.Future; import static cn.iocoder.dashboard.modules.infra.enums.InfErrorCodeConstants.API_ERROR_LOG_NOT_FOUND; import static cn.iocoder.dashboard.modules.infra.enums.InfErrorCodeConstants.API_ERROR_LOG_PROCESSED; -import static cn.iocoder.dashboard.framework.test.core.util.AssertUtils.assertPojoEquals; -import static cn.iocoder.dashboard.framework.test.core.util.AssertUtils.assertServiceException; +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.common.util.date.DateUtils.buildTime; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; diff --git a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/auth/SysAuthServiceImplTest.java b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/auth/SysAuthServiceImplTest.java index 9be405a..5e621d0 100644 --- a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/auth/SysAuthServiceImplTest.java +++ b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/auth/SysAuthServiceImplTest.java @@ -12,7 +12,7 @@ import cn.iocoder.dashboard.modules.system.service.common.SysCaptchaService; import cn.iocoder.dashboard.modules.system.service.logger.SysLoginLogService; import cn.iocoder.dashboard.modules.system.service.permission.SysPermissionService; import cn.iocoder.dashboard.modules.system.service.user.SysUserService; -import cn.iocoder.dashboard.framework.test.core.util.AssertUtils; +import cn.iocoder.yudao.framework.test.core.util.AssertUtils; import org.junit.jupiter.api.Test; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.context.annotation.Import; @@ -28,8 +28,8 @@ import javax.annotation.Resource; import java.util.Set; import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*; -import static cn.iocoder.dashboard.framework.test.core.util.AssertUtils.assertServiceException; -import static cn.iocoder.dashboard.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; import static java.util.Collections.singleton; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.eq; diff --git a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/auth/SysUserSessionServiceImplTest.java b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/auth/SysUserSessionServiceImplTest.java index 8302cf0..aa782d9 100644 --- a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/auth/SysUserSessionServiceImplTest.java +++ b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/auth/SysUserSessionServiceImplTest.java @@ -1,11 +1,11 @@ package cn.iocoder.dashboard.modules.system.service.auth; import static cn.hutool.core.util.RandomUtil.randomEle; -import static cn.iocoder.dashboard.framework.test.core.util.AssertUtils.assertPojoEquals; -import static cn.iocoder.dashboard.framework.test.core.util.RandomUtils.randomDate; -import static cn.iocoder.dashboard.framework.test.core.util.RandomUtils.randomLongId; -import static cn.iocoder.dashboard.framework.test.core.util.RandomUtils.randomPojo; -import static cn.iocoder.dashboard.framework.test.core.util.RandomUtils.randomString; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomDate; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString; import static cn.iocoder.yudao.framework.common.util.date.DateUtils.addTime; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals; @@ -42,8 +42,8 @@ import cn.iocoder.dashboard.modules.system.service.auth.impl.SysUserSessionServi import cn.iocoder.dashboard.modules.system.service.dept.impl.SysDeptServiceImpl; import cn.iocoder.dashboard.modules.system.service.logger.impl.SysLoginLogServiceImpl; import cn.iocoder.dashboard.modules.system.service.user.SysUserServiceImpl; -import cn.iocoder.dashboard.framework.test.core.util.AssertUtils; -import cn.iocoder.dashboard.framework.test.core.util.RandomUtils; +import cn.iocoder.yudao.framework.test.core.util.AssertUtils; +import cn.iocoder.yudao.framework.test.core.util.RandomUtils; import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; /** diff --git a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/common/SysCaptchaServiceTest.java b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/common/SysCaptchaServiceTest.java index d397ef1..dadd68a 100644 --- a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/common/SysCaptchaServiceTest.java +++ b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/common/SysCaptchaServiceTest.java @@ -10,7 +10,7 @@ import org.springframework.context.annotation.Import; import javax.annotation.Resource; -import static cn.iocoder.dashboard.framework.test.core.util.RandomUtils.randomString; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString; import static org.junit.jupiter.api.Assertions.*; @Import({SysCaptchaServiceImpl.class, CaptchaProperties.class, SysCaptchaRedisDAO.class}) diff --git a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/dept/SysDeptServiceTest.java b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/dept/SysDeptServiceTest.java index 72300ec..4913f6a 100644 --- a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/dept/SysDeptServiceTest.java +++ b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/dept/SysDeptServiceTest.java @@ -26,9 +26,9 @@ import java.util.function.Consumer; import static cn.hutool.core.bean.BeanUtil.getFieldValue; import static cn.hutool.core.util.RandomUtil.randomEle; import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*; -import static cn.iocoder.dashboard.framework.test.core.util.AssertUtils.assertPojoEquals; -import static cn.iocoder.dashboard.framework.test.core.util.AssertUtils.assertServiceException; -import static cn.iocoder.dashboard.framework.test.core.util.RandomUtils.*; +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.RandomUtils.*; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; diff --git a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/dept/SysPostServiceTest.java b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/dept/SysPostServiceTest.java index 641ad2d..97fe199 100644 --- a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/dept/SysPostServiceTest.java +++ b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/dept/SysPostServiceTest.java @@ -21,10 +21,10 @@ import java.util.function.Consumer; import static cn.hutool.core.util.RandomUtil.randomEle; import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*; -import static cn.iocoder.dashboard.framework.test.core.util.AssertUtils.assertPojoEquals; -import static cn.iocoder.dashboard.framework.test.core.util.AssertUtils.assertServiceException; -import static cn.iocoder.dashboard.framework.test.core.util.RandomUtils.randomLongId; -import static cn.iocoder.dashboard.framework.test.core.util.RandomUtils.randomPojo; +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.RandomUtils.randomLongId; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; import static org.junit.jupiter.api.Assertions.*; /** diff --git a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/dict/SysDictDataServiceTest.java b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/dict/SysDictDataServiceTest.java index 60b0c87..1ed2bb2 100644 --- a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/dict/SysDictDataServiceTest.java +++ b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/dict/SysDictDataServiceTest.java @@ -26,9 +26,9 @@ import java.util.function.Consumer; import static cn.hutool.core.bean.BeanUtil.getFieldValue; import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*; -import static cn.iocoder.dashboard.framework.test.core.util.AssertUtils.assertPojoEquals; -import static cn.iocoder.dashboard.framework.test.core.util.AssertUtils.assertServiceException; -import static cn.iocoder.dashboard.framework.test.core.util.RandomUtils.*; +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.RandomUtils.*; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.*; diff --git a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/dict/SysDictTypeServiceTest.java b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/dict/SysDictTypeServiceTest.java index a0c116c..5e9de95 100644 --- a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/dict/SysDictTypeServiceTest.java +++ b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/dict/SysDictTypeServiceTest.java @@ -22,10 +22,10 @@ import java.util.function.Consumer; import static cn.hutool.core.util.RandomUtil.randomEle; import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*; -import static cn.iocoder.dashboard.framework.test.core.util.AssertUtils.assertPojoEquals; -import static cn.iocoder.dashboard.framework.test.core.util.AssertUtils.assertServiceException; -import static cn.iocoder.dashboard.framework.test.core.util.RandomUtils.*; +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.common.util.date.DateUtils.buildTime; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; diff --git a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/errorcode/SysErrorCodeServiceTest.java b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/errorcode/SysErrorCodeServiceTest.java index 3dd14ba..ee55185 100644 --- a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/errorcode/SysErrorCodeServiceTest.java +++ b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/errorcode/SysErrorCodeServiceTest.java @@ -27,10 +27,10 @@ import java.util.function.Consumer; import static cn.hutool.core.util.RandomUtil.randomEle; import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.ERROR_CODE_DUPLICATE; import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.ERROR_CODE_NOT_EXISTS; -import static cn.iocoder.dashboard.framework.test.core.util.AssertUtils.assertPojoEquals; -import static cn.iocoder.dashboard.framework.test.core.util.AssertUtils.assertServiceException; -import static cn.iocoder.dashboard.framework.test.core.util.RandomUtils.*; +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.common.util.date.DateUtils.buildTime; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; import static org.junit.jupiter.api.Assertions.*; /** diff --git a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/logger/SysLoginLogServiceImplTest.java b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/logger/SysLoginLogServiceImplTest.java index e3ad2fb..715e99e 100644 --- a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/logger/SysLoginLogServiceImplTest.java +++ b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/logger/SysLoginLogServiceImplTest.java @@ -12,7 +12,7 @@ import cn.iocoder.dashboard.modules.system.dal.mysql.logger.SysLoginLogMapper; import cn.iocoder.dashboard.modules.system.enums.logger.SysLoginLogTypeEnum; import cn.iocoder.dashboard.modules.system.enums.logger.SysLoginResultEnum; import cn.iocoder.dashboard.modules.system.service.logger.impl.SysLoginLogServiceImpl; -import cn.iocoder.dashboard.framework.test.core.util.RandomUtils; +import cn.iocoder.yudao.framework.test.core.util.RandomUtils; import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; import org.junit.jupiter.api.Test; import org.springframework.context.annotation.Import; @@ -20,7 +20,7 @@ import org.springframework.context.annotation.Import; import javax.annotation.Resource; import java.util.List; -import static cn.iocoder.dashboard.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; import static cn.iocoder.yudao.framework.common.util.date.DateUtils.buildTime; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/logger/SysOperateLogServiceImplTest.java b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/logger/SysOperateLogServiceImplTest.java index ac34034..3407caf 100644 --- a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/logger/SysOperateLogServiceImplTest.java +++ b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/logger/SysOperateLogServiceImplTest.java @@ -16,7 +16,7 @@ import cn.iocoder.dashboard.modules.system.dal.mysql.logger.SysOperateLogMapper; import cn.iocoder.dashboard.modules.system.enums.common.SysSexEnum; import cn.iocoder.dashboard.modules.system.service.logger.impl.SysOperateLogServiceImpl; import cn.iocoder.dashboard.modules.system.service.user.SysUserService; -import cn.iocoder.dashboard.framework.test.core.util.RandomUtils; +import cn.iocoder.yudao.framework.test.core.util.RandomUtils; import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; import org.junit.jupiter.api.Test; import org.springframework.boot.test.mock.mockito.MockBean; @@ -27,8 +27,8 @@ import java.util.*; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; -import static cn.iocoder.dashboard.framework.test.core.util.AssertUtils.assertPojoEquals; -import static cn.iocoder.dashboard.framework.test.core.util.RandomUtils.randomLongId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; import static cn.iocoder.yudao.framework.common.util.date.DateUtils.buildTime; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.when; diff --git a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/notice/SysNoticeServiceImplTest.java b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/notice/SysNoticeServiceImplTest.java index f3dab91..b680eca 100644 --- a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/notice/SysNoticeServiceImplTest.java +++ b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/notice/SysNoticeServiceImplTest.java @@ -20,10 +20,10 @@ import java.util.function.Consumer; import static cn.hutool.core.util.RandomUtil.randomEle; import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.NOTICE_NOT_FOUND; -import static cn.iocoder.dashboard.framework.test.core.util.AssertUtils.assertPojoEquals; -import static cn.iocoder.dashboard.framework.test.core.util.AssertUtils.assertServiceException; -import static cn.iocoder.dashboard.framework.test.core.util.RandomUtils.randomLongId; -import static cn.iocoder.dashboard.framework.test.core.util.RandomUtils.randomPojo; +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.RandomUtils.randomLongId; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; import static org.junit.jupiter.api.Assertions.*; @Import(SysNoticeServiceImpl.class) diff --git a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/permission/SysMenuServiceTest.java b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/permission/SysMenuServiceTest.java index a804d46..deda173 100644 --- a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/permission/SysMenuServiceTest.java +++ b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/permission/SysMenuServiceTest.java @@ -13,7 +13,7 @@ import cn.iocoder.dashboard.modules.system.enums.permission.MenuTypeEnum; import cn.iocoder.dashboard.modules.system.mq.producer.permission.SysMenuProducer; import cn.iocoder.dashboard.modules.system.service.permission.impl.SysMenuServiceImpl; import cn.iocoder.yudao.framework.common.util.sping.SpringAopUtils; -import cn.iocoder.dashboard.framework.test.core.util.RandomUtils; +import cn.iocoder.yudao.framework.test.core.util.RandomUtils; import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; import com.google.common.collect.Multimap; import org.junit.jupiter.api.Assertions; @@ -25,9 +25,9 @@ import javax.annotation.Resource; import java.util.*; import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*; -import static cn.iocoder.dashboard.framework.test.core.util.AssertUtils.assertPojoEquals; -import static cn.iocoder.dashboard.framework.test.core.util.AssertUtils.assertServiceException; -import static cn.iocoder.dashboard.framework.test.core.util.RandomUtils.*; +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.RandomUtils.*; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.verify; @@ -108,7 +108,7 @@ public class SysMenuServiceTest extends BaseDbUnitTest { Long parentId = sonMenuDO.getParentId(); //调用 - SysMenuUpdateReqVO vo = RandomUtils.randomPojo(SysMenuUpdateReqVO.class, o -> { + SysMenuUpdateReqVO vo = randomPojo(SysMenuUpdateReqVO.class, o -> { o.setId(sonId); o.setParentId(parentId); o.setType(MenuTypeEnum.MENU.getType()); @@ -131,7 +131,7 @@ public class SysMenuServiceTest extends BaseDbUnitTest { Long parentId = 10000L; //调用 - SysMenuUpdateReqVO vo = RandomUtils.randomPojo(SysMenuUpdateReqVO.class, o -> { + SysMenuUpdateReqVO vo = randomPojo(SysMenuUpdateReqVO.class, o -> { o.setId(sonId); o.setParentId(parentId); o.setType(MenuTypeEnum.MENU.getType()); @@ -354,7 +354,7 @@ public class SysMenuServiceTest extends BaseDbUnitTest { } private SysMenuDO createMenuDO(Long id, MenuTypeEnum typeEnum, String menuName, Long parentId, Integer status) { - return RandomUtils.randomPojo(SysMenuDO.class, o -> { + return randomPojo(SysMenuDO.class, o -> { o.setId(id); o.setParentId(parentId); o.setType(typeEnum.getType()); diff --git a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/permission/SysPermissionServiceTest.java b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/permission/SysPermissionServiceTest.java index 591e08b..1091d58 100644 --- a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/permission/SysPermissionServiceTest.java +++ b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/permission/SysPermissionServiceTest.java @@ -14,9 +14,9 @@ import org.springframework.context.annotation.Import; import javax.annotation.Resource; import java.util.List; -import static cn.iocoder.dashboard.framework.test.core.util.AssertUtils.assertPojoEquals; -import static cn.iocoder.dashboard.framework.test.core.util.RandomUtils.randomLongId; -import static cn.iocoder.dashboard.framework.test.core.util.RandomUtils.randomPojo; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.verify; diff --git a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/permission/SysRoleServiceTest.java b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/permission/SysRoleServiceTest.java index fd2936e..41696df 100644 --- a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/permission/SysRoleServiceTest.java +++ b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/permission/SysRoleServiceTest.java @@ -23,10 +23,10 @@ import java.util.*; import java.util.stream.Collectors; import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*; -import static cn.iocoder.dashboard.framework.test.core.util.AssertUtils.assertPojoEquals; -import static cn.iocoder.dashboard.framework.test.core.util.AssertUtils.assertServiceException; -import static cn.iocoder.dashboard.framework.test.core.util.RandomUtils.*; +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.common.util.object.ObjectUtils.max; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.verify; diff --git a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsChannelServiceTest.java b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsChannelServiceTest.java index f233d60..252c31d 100644 --- a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsChannelServiceTest.java +++ b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsChannelServiceTest.java @@ -4,7 +4,7 @@ import cn.hutool.core.bean.BeanUtil; import cn.iocoder.dashboard.BaseDbUnitTest; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.dashboard.framework.sms.core.client.SmsClientFactory; +import cn.iocoder.yudao.framework.sms.core.client.SmsClientFactory; import cn.iocoder.dashboard.modules.system.controller.sms.vo.channel.SysSmsChannelCreateReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.channel.SysSmsChannelPageReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.channel.SysSmsChannelUpdateReqVO; @@ -25,10 +25,10 @@ import java.util.function.Consumer; import static cn.hutool.core.util.RandomUtil.randomEle; import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.SMS_CHANNEL_HAS_CHILDREN; import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.SMS_CHANNEL_NOT_EXISTS; -import static cn.iocoder.dashboard.framework.test.core.util.AssertUtils.*; -import static cn.iocoder.dashboard.framework.test.core.util.RandomUtils.*; import static cn.iocoder.yudao.framework.common.util.date.DateUtils.buildTime; import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.max; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.*; diff --git a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsLogServiceTest.java b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsLogServiceTest.java index ec778b4..aa59bf5 100644 --- a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsLogServiceTest.java +++ b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsLogServiceTest.java @@ -27,9 +27,9 @@ import java.util.function.Consumer; import static cn.hutool.core.util.RandomUtil.randomBoolean; import static cn.hutool.core.util.RandomUtil.randomEle; -import static cn.iocoder.dashboard.framework.test.core.util.AssertUtils.assertPojoEquals; -import static cn.iocoder.dashboard.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; import static cn.iocoder.yudao.framework.common.util.date.DateUtils.buildTime; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; import static org.junit.jupiter.api.Assertions.*; /** diff --git a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsServiceTest.java b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsServiceTest.java index 39db4be..c07f08b 100644 --- a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsServiceTest.java +++ b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsServiceTest.java @@ -5,11 +5,11 @@ import cn.iocoder.dashboard.BaseMockitoUnitTest; import cn.iocoder.yudao.framework.common.core.KeyValue; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; -import cn.iocoder.dashboard.framework.sms.core.client.SmsClient; -import cn.iocoder.dashboard.framework.sms.core.client.SmsClientFactory; -import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; -import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO; -import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; +import cn.iocoder.yudao.framework.sms.core.client.SmsClient; +import cn.iocoder.yudao.framework.sms.core.client.SmsClientFactory; +import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult; +import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO; +import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO; import cn.iocoder.dashboard.modules.system.mq.message.sms.SysSmsSendMessage; import cn.iocoder.dashboard.modules.system.mq.producer.sms.SysSmsProducer; @@ -25,8 +25,8 @@ import java.util.Map; import static cn.hutool.core.util.RandomUtil.randomEle; import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*; -import static cn.iocoder.dashboard.framework.test.core.util.AssertUtils.assertServiceException; -import static cn.iocoder.dashboard.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.*; diff --git a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsTemplateServiceTest.java b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsTemplateServiceTest.java index fb5cbd5..295e9de 100644 --- a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsTemplateServiceTest.java +++ b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsTemplateServiceTest.java @@ -4,10 +4,10 @@ import cn.iocoder.dashboard.BaseDbUnitTest; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.dashboard.framework.sms.core.client.SmsClient; -import cn.iocoder.dashboard.framework.sms.core.client.SmsClientFactory; -import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; -import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsTemplateRespDTO; +import cn.iocoder.yudao.framework.sms.core.client.SmsClient; +import cn.iocoder.yudao.framework.sms.core.client.SmsClientFactory; +import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult; +import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplateCreateReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplateExportReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplatePageReqVO; @@ -34,11 +34,11 @@ import java.util.function.Consumer; import static cn.hutool.core.bean.BeanUtil.getFieldValue; import static cn.hutool.core.util.RandomUtil.randomEle; import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*; -import static cn.iocoder.dashboard.framework.test.core.util.AssertUtils.assertPojoEquals; -import static cn.iocoder.dashboard.framework.test.core.util.AssertUtils.assertServiceException; -import static cn.iocoder.dashboard.framework.test.core.util.RandomUtils.*; +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.common.util.date.DateUtils.buildTime; import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.max; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.*; diff --git a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/user/SysUserServiceImplTest.java b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/user/SysUserServiceImplTest.java index 88aaf51..9d55050 100644 --- a/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/user/SysUserServiceImplTest.java +++ b/yudao-admin-server/src/test/java/cn/iocoder/dashboard/modules/system/service/user/SysUserServiceImplTest.java @@ -35,10 +35,10 @@ import java.util.function.Consumer; import static cn.hutool.core.util.RandomUtil.randomBytes; import static cn.hutool.core.util.RandomUtil.randomEle; import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*; -import static cn.iocoder.dashboard.framework.test.core.util.AssertUtils.assertPojoEquals; -import static cn.iocoder.dashboard.framework.test.core.util.AssertUtils.assertServiceException; -import static cn.iocoder.dashboard.framework.test.core.util.RandomUtils.*; +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.common.util.date.DateUtils.buildTime; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; import static org.assertj.core.util.Lists.newArrayList; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; diff --git a/yudao-framework/yudao-spring-boot-starter-biz-dict/src/main/java/cn/iocoder/yudao/framework/dict/config/DictConfiguration.java b/yudao-framework/yudao-spring-boot-starter-biz-dict/src/main/java/cn/iocoder/yudao/framework/dict/config/DictConfiguration.java deleted file mode 100644 index 551872f..0000000 --- a/yudao-framework/yudao-spring-boot-starter-biz-dict/src/main/java/cn/iocoder/yudao/framework/dict/config/DictConfiguration.java +++ /dev/null @@ -1,18 +0,0 @@ -package cn.iocoder.yudao.framework.dict.config; - -import cn.iocoder.yudao.framework.dict.core.service.DictDataFrameworkService; -import cn.iocoder.yudao.framework.dict.core.util.DictUtils; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Configuration -public class DictConfiguration { - - @Bean - @SuppressWarnings("InstantiationOfUtilityClass") - public DictUtils dictUtils(DictDataFrameworkService service) { - DictUtils.init(service); - return new DictUtils(); - } - -} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-dict/src/main/java/cn/iocoder/yudao/framework/dict/config/YudaoDictAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-biz-dict/src/main/java/cn/iocoder/yudao/framework/dict/config/YudaoDictAutoConfiguration.java new file mode 100644 index 0000000..1828585 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-dict/src/main/java/cn/iocoder/yudao/framework/dict/config/YudaoDictAutoConfiguration.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.framework.dict.config; + +import cn.iocoder.yudao.framework.dict.core.service.DictDataFrameworkService; +import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class YudaoDictAutoConfiguration { + + @Bean + @SuppressWarnings("InstantiationOfUtilityClass") + public DictFrameworkUtils dictUtils(DictDataFrameworkService service) { + DictFrameworkUtils.init(service); + return new DictFrameworkUtils(); + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-dict/src/main/java/cn/iocoder/yudao/framework/dict/core/util/DictFrameworkUtils.java b/yudao-framework/yudao-spring-boot-starter-biz-dict/src/main/java/cn/iocoder/yudao/framework/dict/core/util/DictFrameworkUtils.java new file mode 100644 index 0000000..ee1de88 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-dict/src/main/java/cn/iocoder/yudao/framework/dict/core/util/DictFrameworkUtils.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.framework.dict.core.util; + +import cn.iocoder.yudao.framework.dict.core.dto.DictDataRespDTO; +import cn.iocoder.yudao.framework.dict.core.service.DictDataFrameworkService; +import lombok.extern.slf4j.Slf4j; + +/** + * 字典工具类 + */ +@Slf4j +public class DictFrameworkUtils { + + private static DictDataFrameworkService service; + + public static void init(DictDataFrameworkService service) { + DictFrameworkUtils.service = service; + log.info("[init][初始化 DictFrameworkUtils 成功]"); + } + + public static DictDataRespDTO getDictDataFromCache(String type, String value) { + return service.getDictDataFromCache(type, value); + } + + public static DictDataRespDTO parseDictDataFromCache(String type, String label) { + return service.getDictDataFromCache(type, label); + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-dict/src/main/java/cn/iocoder/yudao/framework/dict/core/util/DictUtils.java b/yudao-framework/yudao-spring-boot-starter-biz-dict/src/main/java/cn/iocoder/yudao/framework/dict/core/util/DictUtils.java deleted file mode 100644 index 1e2ce43..0000000 --- a/yudao-framework/yudao-spring-boot-starter-biz-dict/src/main/java/cn/iocoder/yudao/framework/dict/core/util/DictUtils.java +++ /dev/null @@ -1,28 +0,0 @@ -package cn.iocoder.yudao.framework.dict.core.util; - -import cn.iocoder.yudao.framework.dict.core.dto.DictDataRespDTO; -import cn.iocoder.yudao.framework.dict.core.service.DictDataFrameworkService; -import lombok.extern.slf4j.Slf4j; - -/** - * 字典工具类 - */ -@Slf4j -public class DictUtils { - - private static DictDataFrameworkService service; - - public static void init(DictDataFrameworkService service) { - DictUtils.service = service; - log.info("[init][初始化 DictUtils 成功]"); - } - - public static DictDataRespDTO getDictDataFromCache(String type, String value) { - return service.getDictDataFromCache(type, value); - } - - public static DictDataRespDTO parseDictDataFromCache(String type, String label) { - return service.getDictDataFromCache(type, label); - } - -} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-dict/src/main/java/cn/iocoder/yudao/framework/dict/package-info.java b/yudao-framework/yudao-spring-boot-starter-biz-dict/src/main/java/cn/iocoder/yudao/framework/dict/package-info.java index a3226af..94a787e 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-dict/src/main/java/cn/iocoder/yudao/framework/dict/package-info.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-dict/src/main/java/cn/iocoder/yudao/framework/dict/package-info.java @@ -1,5 +1,5 @@ /** - * 字典数据模块,提供 {@link cn.iocoder.yudao.framework.dict.core.util.DictUtils} 工具类 + * 字典数据模块,提供 {@link cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils} 工具类 * * 通过将字典缓存在内存中,保证性能 */ diff --git a/yudao-framework/yudao-spring-boot-starter-biz-dict/src/main/resources/META-INF/spring.factories b/yudao-framework/yudao-spring-boot-starter-biz-dict/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000..529a476 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-dict/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ + cn.iocoder.yudao.framework.operatelog.config.YudaoOperateLogAutoConfiguration diff --git a/yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelog/core/dto/OperateLogCreateReqDTO.java b/yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelog/core/dto/OperateLogCreateReqDTO.java index 8dd98d4..1c8f49a 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelog/core/dto/OperateLogCreateReqDTO.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelog/core/dto/OperateLogCreateReqDTO.java @@ -56,7 +56,7 @@ public class OperateLogCreateReqDTO { @NotEmpty(message = "浏览器 UserAgent 不能为空") private String userAgent; - @ApiModelProperty(value = "Java 方法名", required = true, example = "cn.iocoder.dashboard.UserController.save(...)") + @ApiModelProperty(value = "Java 方法名", required = true, example = "cn.iocoder.yudao.UserController.save(...)") @NotEmpty(message = "Java 方法名不能为空") private String javaMethod; diff --git a/yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/resources/META-INF/spring.factories b/yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000..529a476 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ + cn.iocoder.yudao.framework.operatelog.config.YudaoOperateLogAutoConfiguration diff --git a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/config/SmsConfiguration.java b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/config/SmsConfiguration.java deleted file mode 100644 index e5441c9..0000000 --- a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/config/SmsConfiguration.java +++ /dev/null @@ -1,21 +0,0 @@ -package cn.iocoder.dashboard.framework.sms.config; - -import cn.iocoder.dashboard.framework.sms.core.client.SmsClientFactory; -import cn.iocoder.dashboard.framework.sms.core.client.impl.SmsClientFactoryImpl; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -/** - * 短信配置类 - * - * @author 芋道源码 - */ -@Configuration -public class SmsConfiguration { - - @Bean - public SmsClientFactory smsClientFactory() { - return new SmsClientFactoryImpl(); - } - -} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClient.java b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClient.java deleted file mode 100644 index ee7bbc1..0000000 --- a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClient.java +++ /dev/null @@ -1,54 +0,0 @@ -package cn.iocoder.dashboard.framework.sms.core.client; - -import cn.iocoder.yudao.framework.common.core.KeyValue; -import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO; -import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; -import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsTemplateRespDTO; - -import java.util.List; - -/** - * 短信客户端接口 - * - * @author zzf - * @date 2021/1/25 14:14 - */ -public interface SmsClient { - - /** - * 获得渠道编号 - * - * @return 渠道编号 - */ - Long getId(); - - /** - * 发送消息 - * - * @param logId 日志编号 - * @param mobile 手机号 - * @param apiTemplateId 短信 API 的模板编号 - * @param templateParams 短信模板参数。通过 List 数组,保证参数的顺序 - * @return 短信发送结果 - */ - SmsCommonResult sendSms(Long logId, String mobile, String apiTemplateId, - List> templateParams); - - /** - * 解析接收短信的接收结果 - * - * @param text 结果 - * @return 结果内容 - * @throws Throwable 当解析 text 发生异常时,则会抛出异常 - */ - List parseSmsReceiveStatus(String text) throws Throwable; - - /** - * 查询指定的短信模板 - * - * @param apiTemplateId 短信 API 的模板编号 - * @return 短信模板 - */ - SmsCommonResult getSmsTemplate(String apiTemplateId); - -} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClientFactory.java b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClientFactory.java deleted file mode 100644 index 83fb88c..0000000 --- a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClientFactory.java +++ /dev/null @@ -1,36 +0,0 @@ -package cn.iocoder.dashboard.framework.sms.core.client; - -import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; - -/** - * 短信客户端工厂接口 - * - * @author zzf - * @date 2021/1/28 14:01 - */ -public interface SmsClientFactory { - - /** - * 获得短信 Client - * - * @param channelId 渠道编号 - * @return 短信 Client - */ - SmsClient getSmsClient(Long channelId); - - /** - * 获得短信 Client - * - * @param channelCode 渠道编码 - * @return 短信 Client - */ - SmsClient getSmsClient(String channelCode); - - /** - * 创建短信 Client - * - * @param properties 配置对象 - */ - void createOrUpdateSmsClient(SmsChannelProperties properties); - -} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsCodeMapping.java b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsCodeMapping.java deleted file mode 100644 index d2a726b..0000000 --- a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsCodeMapping.java +++ /dev/null @@ -1,17 +0,0 @@ -package cn.iocoder.dashboard.framework.sms.core.client; - -import cn.iocoder.yudao.framework.common.exception.ErrorCode; -import cn.iocoder.dashboard.framework.sms.core.enums.SmsFrameworkErrorCodeConstants; - -import java.util.function.Function; - -/** - * 将 API 的错误码,转换为通用的错误码 - * - * @see SmsCommonResult - * @see SmsFrameworkErrorCodeConstants - * - * @author 芋道源码 - */ -public interface SmsCodeMapping extends Function { -} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsCommonResult.java b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsCommonResult.java deleted file mode 100644 index 2780c8d..0000000 --- a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsCommonResult.java +++ /dev/null @@ -1,68 +0,0 @@ -package cn.iocoder.dashboard.framework.sms.core.client; - -import cn.hutool.core.exceptions.ExceptionUtil; -import cn.hutool.core.lang.Assert; -import cn.iocoder.yudao.framework.common.exception.ErrorCode; -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.dashboard.framework.sms.core.enums.SmsFrameworkErrorCodeConstants; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; - -/** - * 短信的 CommonResult 拓展类 - * - * 考虑到不同的平台,返回的 code 和 msg 是不同的,所以统一额外返回 {@link #apiCode} 和 {@link #apiMsg} 字段 - * - * 另外,一些短信平台(例如说阿里云、腾讯云)会返回一个请求编号,用于排查请求失败的问题,我们设置到 {@link #apiRequestId} 字段 - * - * @author 芋道源码 - */ -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -public class SmsCommonResult extends CommonResult { - - /** - * API 返回错误码 - * - * 由于第三方的错误码可能是字符串,所以使用 String 类型 - */ - private String apiCode; - /** - * API 返回提示 - */ - private String apiMsg; - - /** - * API 请求编号 - */ - private String apiRequestId; - - private SmsCommonResult() { - } - - public static SmsCommonResult build(String apiCode, String apiMsg, String apiRequestId, - T data, SmsCodeMapping codeMapping) { - Assert.notNull(codeMapping, "参数 codeMapping 不能为空"); - SmsCommonResult result = new SmsCommonResult().setApiCode(apiCode).setApiMsg(apiMsg).setApiRequestId(apiRequestId); - result.setData(data); - // 翻译错误码 - if (codeMapping != null) { - ErrorCode errorCode = codeMapping.apply(apiCode); - if (errorCode == null) { - errorCode = SmsFrameworkErrorCodeConstants.SMS_UNKNOWN; - } - result.setCode(errorCode.getCode()).setMsg(errorCode.getMsg()); - } - return result; - } - - public static SmsCommonResult error(Throwable ex) { - SmsCommonResult result = new SmsCommonResult<>(); - result.setCode(SmsFrameworkErrorCodeConstants.EXCEPTION.getCode()); - result.setMsg(ExceptionUtil.getRootCauseMessage(ex)); - return result; - } - -} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsReceiveRespDTO.java b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsReceiveRespDTO.java deleted file mode 100644 index ecfdb04..0000000 --- a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsReceiveRespDTO.java +++ /dev/null @@ -1,48 +0,0 @@ -package cn.iocoder.dashboard.framework.sms.core.client.dto; - -import lombok.Data; - -import java.util.Date; - -/** - * 消息接收 Response DTO - * - * @author 芋道源码 - */ -@Data -public class SmsReceiveRespDTO { - - /** - * 是否接收成功 - */ - private Boolean success; - /** - * API 接收结果的编码 - */ - private String errorCode; - /** - * API 接收结果的说明 - */ - private String errorMsg; - - /** - * 手机号 - */ - private String mobile; - /** - * 用户接收时间 - */ - private Date receiveTime; - - /** - * 短信 API 发送返回的序号 - */ - private String serialNo; - /** - * 短信日志编号 - * - * 对应 SysSmsLogDO 的编号 - */ - private Long logId; - -} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsSendRespDTO.java b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsSendRespDTO.java deleted file mode 100644 index c3f6b51..0000000 --- a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsSendRespDTO.java +++ /dev/null @@ -1,18 +0,0 @@ -package cn.iocoder.dashboard.framework.sms.core.client.dto; - -import lombok.Data; - -/** - * 短信发送 Response DTO - * - * @author 芋道源码 - */ -@Data -public class SmsSendRespDTO { - - /** - * 短信 API 发送返回的序号 - */ - private String serialNo; - -} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsTemplateRespDTO.java b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsTemplateRespDTO.java deleted file mode 100644 index 938310e..0000000 --- a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsTemplateRespDTO.java +++ /dev/null @@ -1,33 +0,0 @@ -package cn.iocoder.dashboard.framework.sms.core.client.dto; - -import cn.iocoder.dashboard.framework.sms.core.enums.SmsTemplateAuditStatusEnum; -import lombok.Data; - -/** - * 短信模板 Response DTO - * - * @author 芋道源码 - */ -@Data -public class SmsTemplateRespDTO { - - /** - * 模板编号 - */ - private String id; - /** - * 短信内容 - */ - private String content; - /** - * 审核状态 - * - * 枚举 {@link SmsTemplateAuditStatusEnum} - */ - private Integer auditStatus; - /** - * 审核未通过的理由 - */ - private String auditReason; - -} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/AbstractSmsClient.java b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/AbstractSmsClient.java deleted file mode 100644 index bad40fd..0000000 --- a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/AbstractSmsClient.java +++ /dev/null @@ -1,122 +0,0 @@ -package cn.iocoder.dashboard.framework.sms.core.client.impl; - -import cn.iocoder.yudao.framework.common.core.KeyValue; -import cn.iocoder.dashboard.framework.sms.core.client.SmsClient; -import cn.iocoder.dashboard.framework.sms.core.client.SmsCodeMapping; -import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; -import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO; -import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; -import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsTemplateRespDTO; -import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; -import lombok.extern.slf4j.Slf4j; - -import java.util.List; - -/** - * 短信客户端抽象类 - * - * @author zzf - * @date 2021/2/1 9:28 - */ -@Slf4j -public abstract class AbstractSmsClient implements SmsClient { - - /** - * 短信渠道配置 - */ - protected volatile SmsChannelProperties properties; - /** - * 错误码枚举类 - */ - protected final SmsCodeMapping codeMapping; - - /** - * 短信客户端有参构造函数 - * - * @param properties 短信配置 - */ - public AbstractSmsClient(SmsChannelProperties properties, SmsCodeMapping codeMapping) { - this.properties = properties; - this.codeMapping = codeMapping; - } - - /** - * 初始化 - */ - public final void init() { - doInit(); - log.info("[init][配置({}) 初始化完成]", properties); - } - - public final void refresh(SmsChannelProperties properties) { - // 判断是否更新 - if (properties.equals(this.properties)) { - return; - } - log.info("[refresh][配置({})发生变化,重新初始化]", properties); - this.properties = properties; - // 初始化 - this.init(); - } - - /** - * 自定义初始化 - */ - protected abstract void doInit(); - - @Override - public Long getId() { - return properties.getId(); - } - - @Override - public final SmsCommonResult sendSms(Long logId, String mobile, - String apiTemplateId, List> templateParams) { - // 执行短信发送 - SmsCommonResult result; - try { - result = doSendSms(logId, mobile, apiTemplateId, templateParams); - } catch (Throwable ex) { - // 打印异常日志 - log.error("[sendSms][发送短信异常,sendLogId({}) mobile({}) apiTemplateId({}) templateParams({})]", - logId, mobile, apiTemplateId, templateParams, ex); - // 封装返回 - return SmsCommonResult.error(ex); - } - return result; - } - - protected abstract SmsCommonResult doSendSms(Long sendLogId, String mobile, - String apiTemplateId, List> templateParams) - throws Throwable; - - @Override - public List parseSmsReceiveStatus(String text) throws Throwable { - try { - return doParseSmsReceiveStatus(text); - } catch (Throwable ex) { - log.error("[parseSmsReceiveStatus][text({}) 解析发生异常]", text, ex); - throw ex; - } - } - - protected abstract List doParseSmsReceiveStatus(String text) throws Throwable; - - @Override - public SmsCommonResult getSmsTemplate(String apiTemplateId) { - // 执行短信发送 - SmsCommonResult result; - try { - result = doGetSmsTemplate(apiTemplateId); - } catch (Throwable ex) { - // 打印异常日志 - log.error("[getSmsTemplate][获得短信模板({}) 发生异常]", apiTemplateId, ex); - // 封装返回 - return SmsCommonResult.error(ex); - } - return result; - } - - protected abstract SmsCommonResult doGetSmsTemplate(String apiTemplateId) throws Throwable; - -} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/SmsClientFactoryImpl.java b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/SmsClientFactoryImpl.java deleted file mode 100644 index 44f87d7..0000000 --- a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/SmsClientFactoryImpl.java +++ /dev/null @@ -1,90 +0,0 @@ -package cn.iocoder.dashboard.framework.sms.core.client.impl; - -import cn.iocoder.dashboard.framework.sms.core.client.SmsClient; -import cn.iocoder.dashboard.framework.sms.core.client.SmsClientFactory; -import cn.iocoder.dashboard.framework.sms.core.client.impl.aliyun.AliyunSmsClient; -import cn.iocoder.dashboard.framework.sms.core.client.impl.debug.DebugDingTalkSmsClient; -import cn.iocoder.dashboard.framework.sms.core.client.impl.yunpian.YunpianSmsClient; -import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum; -import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; -import lombok.extern.slf4j.Slf4j; -import org.springframework.util.Assert; -import org.springframework.validation.annotation.Validated; - -import java.util.Arrays; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -/** - * 短信客户端工厂接口 - * - * @author zzf - */ -@Validated -@Slf4j -public class SmsClientFactoryImpl implements SmsClientFactory { - - /** - * 短信客户端 Map - * key:渠道编号,使用 {@link SmsChannelProperties#getId()} - */ - private final ConcurrentMap channelIdClients = new ConcurrentHashMap<>(); - - /** - * 短信客户端 Map - * key:渠道编码,使用 {@link SmsChannelProperties#getCode()} ()} - * - * 注意,一些场景下,需要获得某个渠道类型的客户端,所以需要使用它。 - * 例如说,解析短信接收结果,是相对通用的,不需要使用某个渠道编号的 {@link #channelIdClients} - */ - private final ConcurrentMap channelCodeClients = new ConcurrentHashMap<>(); - - public SmsClientFactoryImpl() { - // 初始化 channelCodeClients 集合 - Arrays.stream(SmsChannelEnum.values()).forEach(channel -> { - // 创建一个空的 SmsChannelProperties 对象 - SmsChannelProperties properties = new SmsChannelProperties().setCode(channel.getCode()) - .setApiKey("default").setApiSecret("default"); - // 创建 Sms 客户端 - AbstractSmsClient smsClient = createSmsClient(properties); - channelCodeClients.put(channel.getCode(), smsClient); - }); - } - - @Override - public SmsClient getSmsClient(Long channelId) { - return channelIdClients.get(channelId); - } - - @Override - public SmsClient getSmsClient(String channelCode) { - return channelCodeClients.get(channelCode); - } - - @Override - public void createOrUpdateSmsClient(SmsChannelProperties properties) { - AbstractSmsClient client = channelIdClients.get(properties.getId()); - if (client == null) { - client = this.createSmsClient(properties); - client.init(); - channelIdClients.put(client.getId(), client); - } else { - client.refresh(properties); - } - } - - private AbstractSmsClient createSmsClient(SmsChannelProperties properties) { - SmsChannelEnum channelEnum = SmsChannelEnum.getByCode(properties.getCode()); - Assert.notNull(channelEnum, String.format("渠道类型(%s) 为空", channelEnum)); - // 创建客户端 - switch (channelEnum) { - case ALIYUN: return new AliyunSmsClient(properties); - case YUN_PIAN: return new YunpianSmsClient(properties); - case DEBUG_DING_TALK: return new DebugDingTalkSmsClient(properties); - } - // 创建失败,错误日志 + 抛出异常 - log.error("[createSmsClient][配置({}) 找不到合适的客户端实现]", properties); - throw new IllegalArgumentException(String.format("配置(%s) 找不到合适的客户端实现", properties)); - } - -} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java deleted file mode 100644 index b47406b..0000000 --- a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java +++ /dev/null @@ -1,212 +0,0 @@ -package cn.iocoder.dashboard.framework.sms.core.client.impl.aliyun; - -import cn.hutool.core.lang.Assert; -import cn.hutool.core.util.ReflectUtil; -import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.common.core.KeyValue; -import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; -import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO; -import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; -import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsTemplateRespDTO; -import cn.iocoder.dashboard.framework.sms.core.client.impl.AbstractSmsClient; -import cn.iocoder.dashboard.framework.sms.core.enums.SmsTemplateAuditStatusEnum; -import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; -import cn.iocoder.yudao.framework.common.util.collection.MapUtils; -import cn.iocoder.yudao.framework.common.util.json.JsonUtils; -import com.aliyuncs.AcsRequest; -import com.aliyuncs.AcsResponse; -import com.aliyuncs.DefaultAcsClient; -import com.aliyuncs.IAcsClient; -import com.aliyuncs.dysmsapi.model.v20170525.QuerySmsTemplateRequest; -import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest; -import com.aliyuncs.exceptions.ClientException; -import com.aliyuncs.profile.DefaultProfile; -import com.aliyuncs.profile.IClientProfile; -import com.fasterxml.jackson.annotation.JsonFormat; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.google.common.annotations.VisibleForTesting; -import lombok.Data; -import lombok.extern.slf4j.Slf4j; - -import java.util.Date; -import java.util.List; -import java.util.Objects; -import java.util.function.Function; -import java.util.stream.Collectors; - -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DEFAULT; - -/** - * 阿里短信客户端的实现类 - * - * @author zzf - * @date 2021/1/25 14:17 - */ -@Slf4j -public class AliyunSmsClient extends AbstractSmsClient { - - /** - * REGION, 使用杭州 - */ - private static final String ENDPOINT = "cn-hangzhou"; - - /** - * 阿里云客户端 - */ - private volatile IAcsClient client; - - public AliyunSmsClient(SmsChannelProperties properties) { - super(properties, new AliyunSmsCodeMapping()); - Assert.notEmpty(properties.getApiKey(), "apiKey 不能为空"); - Assert.notEmpty(properties.getApiSecret(), "apiSecret 不能为空"); - } - - @Override - protected void doInit() { - IClientProfile profile = DefaultProfile.getProfile(ENDPOINT, properties.getApiKey(), properties.getApiSecret()); - client = new DefaultAcsClient(profile); - } - - @Override - protected SmsCommonResult doSendSms(Long sendLogId, String mobile, - String apiTemplateId, List> templateParams) { - // 构建参数 - SendSmsRequest request = new SendSmsRequest(); - request.setPhoneNumbers(mobile); - request.setSignName(properties.getSignature()); - request.setTemplateCode(apiTemplateId); - request.setTemplateParam(JsonUtils.toJsonString(MapUtils.convertMap(templateParams))); - request.setOutId(String.valueOf(sendLogId)); - // 执行请求 - return invoke(request, response -> new SmsSendRespDTO().setSerialNo(response.getBizId())); - } - - @Override - protected List doParseSmsReceiveStatus(String text) throws Throwable { - List statuses = JsonUtils.parseArray(text, SmsReceiveStatus.class); - return statuses.stream().map(status -> { - SmsReceiveRespDTO resp = new SmsReceiveRespDTO(); - resp.setSuccess(status.getSuccess()); - resp.setErrorCode(status.getErrCode()).setErrorMsg(status.getErrMsg()); - resp.setMobile(status.getPhoneNumber()).setReceiveTime(status.getReportTime()); - resp.setSerialNo(status.getBizId()).setLogId(Long.valueOf(status.getOutId())); - return resp; - }).collect(Collectors.toList()); - } - - @Override - protected SmsCommonResult doGetSmsTemplate(String apiTemplateId) { - // 构建参数 - QuerySmsTemplateRequest request = new QuerySmsTemplateRequest(); - request.setTemplateCode(apiTemplateId); - // 执行请求 - return invoke(request, response -> { - SmsTemplateRespDTO data = new SmsTemplateRespDTO(); - data.setId(response.getTemplateCode()).setContent(response.getTemplateContent()); - data.setAuditStatus(convertSmsTemplateAuditStatus(response.getTemplateStatus())).setAuditReason(response.getReason()); - return data; - }); - } - - @VisibleForTesting - Integer convertSmsTemplateAuditStatus(Integer templateStatus) { - switch (templateStatus) { - case 0: return SmsTemplateAuditStatusEnum.CHECKING.getStatus(); - case 1: return SmsTemplateAuditStatusEnum.SUCCESS.getStatus(); - case 2: return SmsTemplateAuditStatusEnum.FAIL.getStatus(); - default: throw new IllegalArgumentException(String.format("未知审核状态(%d)", templateStatus)); - } - } - - @VisibleForTesting - SmsCommonResult invoke(AcsRequest request, Function responseConsumer) { - try { - // 执行发送. 由于阿里云 sms 短信没有统一的 Response,但是有统一的 code、message、requestId 属性,所以只好反射 - T sendResult = client.getAcsResponse(request); - String code = (String) ReflectUtil.getFieldValue(sendResult, "code"); - String message = (String) ReflectUtil.getFieldValue(sendResult, "message"); - String requestId = (String) ReflectUtil.getFieldValue(sendResult, "requestId"); - // 解析结果 - R data = null; - if (Objects.equals(code, "OK")) { // 请求成功的情况下 - data = responseConsumer.apply(sendResult); - } - // 拼接结果 - return SmsCommonResult.build(code, message, requestId, data, codeMapping); - } catch (ClientException ex) { - return SmsCommonResult.build(ex.getErrCode(), formatResultMsg(ex), ex.getRequestId(), null, codeMapping); - } - } - - private static String formatResultMsg(ClientException ex) { - if (StrUtil.isEmpty(ex.getErrorDescription())) { - return ex.getErrMsg(); - } - return ex.getErrMsg() + " => " + ex.getErrorDescription(); - } - - /** - * 短信接收状态 - * - * 参见 https://help.aliyun.com/document_detail/101867.html 文档 - * - * @author 芋道源码 - */ - @Data - public static class SmsReceiveStatus { - - /** - * 手机号 - */ - @JsonProperty("phone_number") - private String phoneNumber; - /** - * 发送时间 - */ - @JsonProperty("send_time") - @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT) - private Date sendTime; - /** - * 状态报告时间 - */ - @JsonProperty("report_time") - @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT) - private Date reportTime; - /** - * 是否接收成功 - */ - private Boolean success; - /** - * 状态报告说明 - */ - @JsonProperty("err_msg") - private String errMsg; - /** - * 状态报告编码 - */ - @JsonProperty("err_code") - private String errCode; - /** - * 发送序列号 - */ - @JsonProperty("biz_id") - private String bizId; - /** - * 用户序列号 - * - * 这里我们传递的是 SysSmsLogDO 的日志编号 - */ - @JsonProperty("out_id") - private String outId; - /** - * 短信长度,例如说 1、2、3 - * - * 140 字节算一条短信,短信长度超过 140 字节时会拆分成多条短信发送 - */ - @JsonProperty("sms_size") - private Integer smsSize; - - } - -} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsCodeMapping.java b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsCodeMapping.java deleted file mode 100644 index 18ab0e7..0000000 --- a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsCodeMapping.java +++ /dev/null @@ -1,43 +0,0 @@ -package cn.iocoder.dashboard.framework.sms.core.client.impl.aliyun; - -import cn.iocoder.yudao.framework.common.exception.ErrorCode; -import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; -import cn.iocoder.dashboard.framework.sms.core.client.SmsCodeMapping; - -import static cn.iocoder.dashboard.framework.sms.core.enums.SmsFrameworkErrorCodeConstants.*; - -/** - * 阿里云的 SmsCodeMapping 实现类 - * - * 参见 https://help.aliyun.com/document_detail/101346.htm 文档 - * - * @author 芋道源码 - */ -public class AliyunSmsCodeMapping implements SmsCodeMapping { - - @Override - public ErrorCode apply(String apiCode) { - switch (apiCode) { - case "OK": return GlobalErrorCodeConstants.SUCCESS; - case "isv.ACCOUNT_NOT_EXISTS": - case "isv.ACCOUNT_ABNORMAL": - case "MissingAccessKeyId": return SMS_ACCOUNT_INVALID; - case "isp.RAM_PERMISSION_DENY": return SMS_PERMISSION_DENY; - case "isv.INVALID_JSON_PARAM": - case "isv.INVALID_PARAMETERS": return SMS_API_PARAM_ERROR; - case "isv.BUSINESS_LIMIT_CONTROL": return SMS_SEND_BUSINESS_LIMIT_CONTROL; - case "isv.DAY_LIMIT_CONTROL": return SMS_SEND_DAY_LIMIT_CONTROL; - case "isv.SMS_CONTENT_ILLEGAL": return SMS_SEND_CONTENT_INVALID; - case "isv.SMS_TEMPLATE_ILLEGAL": return SMS_TEMPLATE_INVALID; - case "isv.SMS_SIGNATURE_ILLEGAL": - case "isv.SIGN_NAME_ILLEGAL": - case "isv.SMS_SIGN_ILLEGAL": return SMS_SIGN_INVALID; - case "isv.AMOUNT_NOT_ENOUGH": - case "isv.OUT_OF_SERVICE": return SMS_ACCOUNT_MONEY_NOT_ENOUGH; - case "isv.MOBILE_NUMBER_ILLEGAL": return SMS_MOBILE_INVALID; - case "isv.TEMPLATE_MISSING_PARAMETERS": return SMS_TEMPLATE_PARAM_ERROR; - } - return SMS_UNKNOWN; - } - -} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/debug/DebugDingTalkCodeMapping.java b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/debug/DebugDingTalkCodeMapping.java deleted file mode 100644 index efd50a4..0000000 --- a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/debug/DebugDingTalkCodeMapping.java +++ /dev/null @@ -1,23 +0,0 @@ -package cn.iocoder.dashboard.framework.sms.core.client.impl.debug; - -import cn.iocoder.yudao.framework.common.exception.ErrorCode; -import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; -import cn.iocoder.dashboard.framework.sms.core.client.SmsCodeMapping; - -import java.util.Objects; - -import static cn.iocoder.dashboard.framework.sms.core.enums.SmsFrameworkErrorCodeConstants.SMS_UNKNOWN; - -/** - * 钉钉的 SmsCodeMapping 实现类 - * - * @author 芋道源码 - */ -public class DebugDingTalkCodeMapping implements SmsCodeMapping { - - @Override - public ErrorCode apply(String apiCode) { - return Objects.equals(apiCode, "0") ? GlobalErrorCodeConstants.SUCCESS : SMS_UNKNOWN; - } - -} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/debug/DebugDingTalkSmsClient.java b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/debug/DebugDingTalkSmsClient.java deleted file mode 100644 index aff2e67..0000000 --- a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/debug/DebugDingTalkSmsClient.java +++ /dev/null @@ -1,96 +0,0 @@ -package cn.iocoder.dashboard.framework.sms.core.client.impl.debug; - -import cn.hutool.core.codec.Base64; -import cn.hutool.core.lang.Assert; -import cn.hutool.core.map.MapUtil; -import cn.hutool.core.util.StrUtil; -import cn.hutool.crypto.digest.DigestUtil; -import cn.hutool.crypto.digest.HmacAlgorithm; -import cn.hutool.http.HttpUtil; -import cn.iocoder.yudao.framework.common.core.KeyValue; -import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; -import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO; -import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; -import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsTemplateRespDTO; -import cn.iocoder.dashboard.framework.sms.core.client.impl.AbstractSmsClient; -import cn.iocoder.dashboard.framework.sms.core.enums.SmsTemplateAuditStatusEnum; -import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; -import cn.iocoder.yudao.framework.common.util.collection.MapUtils; -import cn.iocoder.yudao.framework.common.util.json.JsonUtils; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * 基于钉钉 WebHook 实现的调试的短信客户端实现类 - * - * 考虑到省钱,我们使用钉钉 WebHook 模拟发送短信,方便调试。 - * - * @author 芋道源码 - */ -public class DebugDingTalkSmsClient extends AbstractSmsClient { - - public DebugDingTalkSmsClient(SmsChannelProperties properties) { - super(properties, new DebugDingTalkCodeMapping()); - Assert.notEmpty(properties.getApiKey(), "apiKey 不能为空"); - Assert.notEmpty(properties.getApiSecret(), "apiSecret 不能为空"); - } - - @Override - protected void doInit() { - } - - @Override - protected SmsCommonResult doSendSms(Long sendLogId, String mobile, - String apiTemplateId, List> templateParams) throws Throwable { - // 构建请求 - String url = buildUrl("robot/send"); - Map params = new HashMap<>(); - params.put("msgtype", "text"); - String content = String.format("【模拟短信】\n手机号:%s\n短信日志编号:%d\n模板参数:%s", - mobile, sendLogId, MapUtils.convertMap(templateParams)); - params.put("text", MapUtil.builder().put("content", content).build()); - // 执行请求 - String responseText = HttpUtil.post(url, JsonUtils.toJsonString(params)); - // 解析结果 - Map responseObj = JsonUtils.parseObject(responseText, Map.class); - return SmsCommonResult.build(MapUtil.getStr(responseObj, "errcode"), MapUtil.getStr(responseObj, "errorMsg"), - null, new SmsSendRespDTO().setSerialNo(StrUtil.uuid()), codeMapping); - } - - /** - * 构建请求地址 - * - * 参见 https://developers.dingtalk.com/document/app/custom-robot-access/title-nfv-794-g71 文档 - * - * @param path 请求路径 - * @return 请求地址 - */ - @SuppressWarnings("SameParameterValue") - private String buildUrl(String path) { - // 生成 timestamp - long timestamp = System.currentTimeMillis(); - // 生成 sign - String secret = properties.getApiSecret(); - String stringToSign = timestamp + "\n" + secret; - byte[] signData = DigestUtil.hmac(HmacAlgorithm.HmacSHA256, StrUtil.bytes(secret)).digest(stringToSign); - String sign = Base64.encode(signData); - // 构建最终 URL - return String.format("https://oapi.dingtalk.com/%s?access_token=%s×tamp=%d&sign=%s", - path, properties.getApiKey(), timestamp, sign); - } - - @Override - protected List doParseSmsReceiveStatus(String text) throws Throwable { - throw new UnsupportedOperationException("模拟短信客户端,暂时无需解析回调"); - } - - @Override - protected SmsCommonResult doGetSmsTemplate(String apiTemplateId) { - SmsTemplateRespDTO data = new SmsTemplateRespDTO().setId(apiTemplateId).setContent("") - .setAuditStatus(SmsTemplateAuditStatusEnum.SUCCESS.getStatus()).setAuditReason(""); - return SmsCommonResult.build("0", "success", null, data, codeMapping); - } - -} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java deleted file mode 100644 index 7ed31c2..0000000 --- a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java +++ /dev/null @@ -1,204 +0,0 @@ -package cn.iocoder.dashboard.framework.sms.core.client.impl.yunpian; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.lang.Assert; -import cn.hutool.core.util.StrUtil; -import cn.hutool.core.util.URLUtil; -import cn.iocoder.yudao.framework.common.core.KeyValue; -import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; -import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO; -import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; -import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsTemplateRespDTO; -import cn.iocoder.dashboard.framework.sms.core.client.impl.AbstractSmsClient; -import cn.iocoder.dashboard.framework.sms.core.enums.SmsTemplateAuditStatusEnum; -import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; -import cn.iocoder.yudao.framework.common.util.json.JsonUtils; -import com.fasterxml.jackson.annotation.JsonFormat; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.google.common.annotations.VisibleForTesting; -import com.yunpian.sdk.YunpianClient; -import com.yunpian.sdk.constant.YunpianConstant; -import com.yunpian.sdk.model.Result; -import com.yunpian.sdk.model.Template; -import lombok.Data; -import lombok.extern.slf4j.Slf4j; - -import java.util.*; -import java.util.function.Function; -import java.util.function.Supplier; -import java.util.stream.Collectors; - -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DEFAULT; - -/** - * 云片短信客户端的实现类 - * - * @author zzf - * @date 9:48 2021/3/5 - */ -@Slf4j -public class YunpianSmsClient extends AbstractSmsClient { - - /** - * 云信短信客户端 - */ - private volatile YunpianClient client; - - public YunpianSmsClient(SmsChannelProperties properties) { - super(properties, new YunpianSmsCodeMapping()); - Assert.notEmpty(properties.getApiKey(), "apiKey 不能为空"); - } - - @Override - public void doInit() { - YunpianClient oldClient = client; - // 初始化新的客户端 - YunpianClient newClient = new YunpianClient(properties.getApiKey()); - newClient.init(); - this.client = newClient; - // 销毁老的客户端 - if (oldClient != null) { - oldClient.close(); - } - } - - @Override - protected SmsCommonResult doSendSms(Long sendLogId, String mobile, - String apiTemplateId, List> templateParams) throws Throwable { - return invoke(() -> { - Map request = new HashMap<>(); - request.put(YunpianConstant.MOBILE, mobile); - request.put(YunpianConstant.TPL_ID, apiTemplateId); - request.put(YunpianConstant.TPL_VALUE, formatTplValue(templateParams)); - request.put(YunpianConstant.UID, String.valueOf(sendLogId)); - request.put(YunpianConstant.CALLBACK_URL, properties.getCallbackUrl()); - return client.sms().tpl_single_send(request); - }, response -> new SmsSendRespDTO().setSerialNo(String.valueOf(response.getSid()))); - } - - private static String formatTplValue(List> templateParams) { - if (CollUtil.isEmpty(templateParams)) { - return ""; - } - // 参考 https://www.yunpian.com/official/document/sms/zh_cn/introduction_demos_encode_sample 格式化 - StringJoiner joiner = new StringJoiner("&"); - templateParams.forEach(param -> joiner.add(String.format("#%s#=%s", param.getKey(), URLUtil.encode(String.valueOf(param.getValue()))))); - return joiner.toString(); - } - - @Override - protected List doParseSmsReceiveStatus(String text) throws Throwable { - List statuses = JsonUtils.parseArray(text, SmsReceiveStatus.class); - return statuses.stream().map(status -> { - SmsReceiveRespDTO resp = new SmsReceiveRespDTO(); - resp.setSuccess(Objects.equals(status.getReportStatus(), "SUCCESS")); - resp.setErrorCode(status.getErrorMsg()).setErrorMsg(status.getErrorDetail()); - resp.setMobile(status.getMobile()).setReceiveTime(status.getUserReceiveTime()); - resp.setSerialNo(String.valueOf(status.getSid())).setLogId(status.getUid()); - return resp; - }).collect(Collectors.toList()); - } - - @Override - protected SmsCommonResult doGetSmsTemplate(String apiTemplateId) throws Throwable { - return invoke(() -> { - Map request = new HashMap<>(); - request.put(YunpianConstant.APIKEY, properties.getApiKey()); - request.put(YunpianConstant.TPL_ID, apiTemplateId); - return client.tpl().get(request); - }, response -> { - Template template = response.get(0); - return new SmsTemplateRespDTO().setId(String.valueOf(template.getTpl_id())).setContent(template.getTpl_content()) - .setAuditStatus(convertSmsTemplateAuditStatus(template.getCheck_status())).setAuditReason(template.getReason()); - }); - } - - @VisibleForTesting - Integer convertSmsTemplateAuditStatus(String checkStatus) { - switch (checkStatus) { - case "CHECKING": return SmsTemplateAuditStatusEnum.CHECKING.getStatus(); - case "SUCCESS": return SmsTemplateAuditStatusEnum.SUCCESS.getStatus(); - case "FAIL": return SmsTemplateAuditStatusEnum.FAIL.getStatus(); - default: throw new IllegalArgumentException(String.format("未知审核状态(%s)", checkStatus)); - } - } - - @VisibleForTesting - SmsCommonResult invoke(Supplier> requestConsumer, Function responseConsumer) throws Throwable { - // 执行请求 - Result result = requestConsumer.get(); - if (result.getThrowable() != null) { - throw result.getThrowable(); - } - // 解析结果 - R data = null; - if (result.getData() != null) { - data = responseConsumer.apply(result.getData()); - } - // 拼接结果 - return SmsCommonResult.build(String.valueOf(result.getCode()), formatResultMsg(result), null, data, codeMapping); - } - - private static String formatResultMsg(Result sendResult) { - if (StrUtil.isEmpty(sendResult.getDetail())) { - return sendResult.getMsg(); - } - return sendResult.getMsg() + " => " + sendResult.getDetail(); - } - - /** - * 短信接收状态 - * - * 参见 https://www.yunpian.com/official/document/sms/zh_cn/domestic_push_report 文档 - * - * @author 芋道源码 - */ - @Data - public static class SmsReceiveStatus { - - /** - * 接收状态 - * - * 目前仅有 SUCCESS / FAIL,所以使用 Boolean 接收 - */ - @JsonProperty("report_status") - private String reportStatus; - /** - * 接收手机号 - */ - private String mobile; - /** - * 运营商返回的代码,如:"DB:0103" - * - * 由于不同运营商信息不同,此字段仅供参考; - */ - @JsonProperty("error_msg") - private String errorMsg; - /** - * 运营商反馈代码的中文解释 - * - * 默认不推送此字段,如需推送,请联系客服 - */ - @JsonProperty("error_detail") - private String errorDetail; - /** - * 短信编号 - */ - private Long sid; - /** - * 用户自定义 id - * - * 这里我们传递的是 SysSmsLogDO 的日志编号 - */ - private Long uid; - /** - * 用户接收时间 - */ - @JsonProperty("user_receive_time") - @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT) - private Date userReceiveTime; - - } - -} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsCodeMapping.java b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsCodeMapping.java deleted file mode 100644 index 9261684..0000000 --- a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsCodeMapping.java +++ /dev/null @@ -1,45 +0,0 @@ -package cn.iocoder.dashboard.framework.sms.core.client.impl.yunpian; - -import cn.iocoder.yudao.framework.common.exception.ErrorCode; -import cn.iocoder.dashboard.framework.sms.core.client.SmsCodeMapping; - -import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.SUCCESS; -import static cn.iocoder.dashboard.framework.sms.core.enums.SmsFrameworkErrorCodeConstants.*; -import static com.yunpian.sdk.constant.Code.*; - -/** - * 云片的 SmsCodeMapping 实现类 - * - * 参见 https://www.yunpian.com/official/document/sms/zh_CN/returnvalue_common 文档 - * - * @author 芋道源码 - */ -public class YunpianSmsCodeMapping implements SmsCodeMapping { - - @Override - public ErrorCode apply(String apiCode) { - int code = Integer.parseInt(apiCode); - switch (code) { - case OK: return SUCCESS; - case ARGUMENT_MISSING: return SMS_API_PARAM_ERROR; - case BAD_ARGUMENT_FORMAT: return SMS_TEMPLATE_PARAM_ERROR; - case TPL_NOT_FOUND: - case TPL_NOT_VALID: return SMS_TEMPLATE_INVALID; - case MONEY_NOT_ENOUGH: return SMS_ACCOUNT_MONEY_NOT_ENOUGH; - case BLACK_WORD: return SMS_SEND_CONTENT_INVALID; - case DUP_IN_SHORT_TIME: - case TOO_MANY_TIME_IN_5: - case DAY_LIMIT_PER_MOBILE: - case HOUR_LIMIT_PER_MOBILE: return SMS_SEND_BUSINESS_LIMIT_CONTROL; - case BLACK_PHONE_FILTER: return SMS_MOBILE_BLACK; - case SIGN_NOT_MATCH: - case BAD_SIGN_FORMAT: - case SIGN_NOT_VALID: return SMS_SIGN_INVALID; - case BAD_API_KEY: return SMS_ACCOUNT_INVALID; - case API_NOT_ALLOWED: return SMS_PERMISSION_DENY; - case IP_NOT_ALLOWED: return SMS_IP_DENY; - } - return SMS_UNKNOWN; - } - -} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsChannelEnum.java b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsChannelEnum.java deleted file mode 100644 index ba2615d..0000000 --- a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsChannelEnum.java +++ /dev/null @@ -1,37 +0,0 @@ -package cn.iocoder.dashboard.framework.sms.core.enums; - -import cn.hutool.core.util.ArrayUtil; -import lombok.AllArgsConstructor; -import lombok.Getter; - -/** - * 短信渠道枚举 - * - * @author zzf - * @date 2021/1/25 10:56 - */ -@Getter -@AllArgsConstructor -public enum SmsChannelEnum { - - DEBUG_DING_TALK("DEBUG_DING_TALK", "调试(钉钉)"), - YUN_PIAN("YUN_PIAN", "云片"), - ALIYUN("ALIYUN", "阿里云"), -// TENCENT("TENCENT", "腾讯云"), -// HUA_WEI("HUA_WEI", "华为云"), - ; - - /** - * 编码 - */ - private final String code; - /** - * 名字 - */ - private final String name; - - public static SmsChannelEnum getByCode(String code) { - return ArrayUtil.firstMatch(o -> o.getCode().equals(code), values()); - } - -} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsFrameworkErrorCodeConstants.java b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsFrameworkErrorCodeConstants.java deleted file mode 100644 index bfd77fb..0000000 --- a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsFrameworkErrorCodeConstants.java +++ /dev/null @@ -1,47 +0,0 @@ -package cn.iocoder.dashboard.framework.sms.core.enums; - -import cn.iocoder.yudao.framework.common.exception.ErrorCode; - -/** - * 短信框架的错误码枚举 - * - * 短信框架,使用 2-001-000-000 段 - * - * @author 芋道源码 - */ -public interface SmsFrameworkErrorCodeConstants { - - ErrorCode SMS_UNKNOWN = new ErrorCode(2001000000, "未知错误,需要解析"); - - // ========== 权限 / 限流等相关 2001000100 ========== - - ErrorCode SMS_PERMISSION_DENY = new ErrorCode(2001000100, "没有发送短信的权限"); - // 云片:可以配置 IP 白名单,只有在白名单中才可以发送短信 - ErrorCode SMS_IP_DENY = new ErrorCode(2001000100, "IP 不允许发送短信"); - - // 阿里云:将短信发送频率限制在正常的业务限流范围内。默认短信验证码:使用同一签名,对同一个手机号验证码,支持 1 条 / 分钟,5 条 / 小时,累计 10 条 / 天。 - ErrorCode SMS_SEND_BUSINESS_LIMIT_CONTROL = new ErrorCode(2001000102, "指定手机的发送限流"); - // 阿里云:已经达到您在控制台设置的短信日发送量限额值。在国内消息设置 > 安全设置,修改发送总量阈值。 - ErrorCode SMS_SEND_DAY_LIMIT_CONTROL = new ErrorCode(2001000103, "每天的发送限流"); - - ErrorCode SMS_SEND_CONTENT_INVALID = new ErrorCode(2001000104, "短信内容有敏感词"); - - // ========== 模板相关 2001000200 ========== - ErrorCode SMS_TEMPLATE_INVALID = new ErrorCode(2001000200, "短信模板不合法"); // 包括短信模板不存在 - ErrorCode SMS_TEMPLATE_PARAM_ERROR = new ErrorCode(2001000201, "模板参数不正确"); - - // ========== 签名相关 2001000300 ========== - ErrorCode SMS_SIGN_INVALID = new ErrorCode(2001000300, "短信签名不可用"); - - // ========== 账户相关 2001000400 ========== - ErrorCode SMS_ACCOUNT_MONEY_NOT_ENOUGH = new ErrorCode(2001000400, "账户余额不足"); - ErrorCode SMS_ACCOUNT_INVALID = new ErrorCode(2001000401, "apiKey 不存在"); - - // ========== 其它相关 2001000900 开头 ========== - ErrorCode SMS_API_PARAM_ERROR = new ErrorCode(2001000900, "请求参数缺失"); - ErrorCode SMS_MOBILE_INVALID = new ErrorCode(2001000901, "手机格式不正确"); - ErrorCode SMS_MOBILE_BLACK = new ErrorCode(2001000902, "手机号在黑名单中"); - - ErrorCode EXCEPTION = new ErrorCode(2001000999, "调用异常"); - -} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsTemplateAuditStatusEnum.java b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsTemplateAuditStatusEnum.java deleted file mode 100644 index 888b2ee..0000000 --- a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsTemplateAuditStatusEnum.java +++ /dev/null @@ -1,21 +0,0 @@ -package cn.iocoder.dashboard.framework.sms.core.enums; - -import lombok.AllArgsConstructor; -import lombok.Getter; - -/** - * 短信模板的审核状态枚举 - * - * @author 芋道源码 - */ -@AllArgsConstructor -@Getter -public enum SmsTemplateAuditStatusEnum { - - CHECKING(1), - SUCCESS(2), - FAIL(3); - - private final Integer status; - -} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/property/SmsChannelProperties.java b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/property/SmsChannelProperties.java deleted file mode 100644 index 750f2e7..0000000 --- a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/dashboard/framework/sms/core/property/SmsChannelProperties.java +++ /dev/null @@ -1,52 +0,0 @@ -package cn.iocoder.dashboard.framework.sms.core.property; - -import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum; -import lombok.Data; -import org.springframework.validation.annotation.Validated; - -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; - -/** - * 短信渠道配置类 - * - * @author zzf - * @date 2021/1/25 17:01 - */ -@Data -@Validated -public class SmsChannelProperties { - - /** - * 渠道编号 - */ - @NotNull(message = "短信渠道 ID 不能为空") - private Long id; - /** - * 短信签名 - */ - @NotEmpty(message = "短信签名不能为空") - private String signature; - /** - * 渠道编码 - * - * 枚举 {@link SmsChannelEnum} - */ - @NotEmpty(message = "渠道编码不能为空") - private String code; - /** - * 短信 API 的账号 - */ - @NotEmpty(message = "短信 API 的账号不能为空") - private String apiKey; - /** - * 短信 API 的秘钥 - */ - @NotEmpty(message = "短信 API 的秘钥不能为空") - private String apiSecret; - /** - * 短信发送回调 URL - */ - private String callbackUrl; - -} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/config/YudaoSmsAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/config/YudaoSmsAutoConfiguration.java new file mode 100644 index 0000000..e6be483 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/config/YudaoSmsAutoConfiguration.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.framework.sms.config; + +import cn.iocoder.yudao.framework.sms.core.client.SmsClientFactory; +import cn.iocoder.yudao.framework.sms.core.client.impl.SmsClientFactoryImpl; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * 短信配置类 + * + * @author 芋道源码 + */ +@Configuration +public class YudaoSmsAutoConfiguration { + + @Bean + public SmsClientFactory smsClientFactory() { + return new SmsClientFactoryImpl(); + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/SmsClient.java b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/SmsClient.java new file mode 100644 index 0000000..2f936de --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/SmsClient.java @@ -0,0 +1,54 @@ +package cn.iocoder.yudao.framework.sms.core.client; + +import cn.iocoder.yudao.framework.common.core.KeyValue; +import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO; +import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO; +import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO; + +import java.util.List; + +/** + * 短信客户端接口 + * + * @author zzf + * @date 2021/1/25 14:14 + */ +public interface SmsClient { + + /** + * 获得渠道编号 + * + * @return 渠道编号 + */ + Long getId(); + + /** + * 发送消息 + * + * @param logId 日志编号 + * @param mobile 手机号 + * @param apiTemplateId 短信 API 的模板编号 + * @param templateParams 短信模板参数。通过 List 数组,保证参数的顺序 + * @return 短信发送结果 + */ + SmsCommonResult sendSms(Long logId, String mobile, String apiTemplateId, + List> templateParams); + + /** + * 解析接收短信的接收结果 + * + * @param text 结果 + * @return 结果内容 + * @throws Throwable 当解析 text 发生异常时,则会抛出异常 + */ + List parseSmsReceiveStatus(String text) throws Throwable; + + /** + * 查询指定的短信模板 + * + * @param apiTemplateId 短信 API 的模板编号 + * @return 短信模板 + */ + SmsCommonResult getSmsTemplate(String apiTemplateId); + +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/SmsClientFactory.java b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/SmsClientFactory.java new file mode 100644 index 0000000..d880b4e --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/SmsClientFactory.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.framework.sms.core.client; + +import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties; + +/** + * 短信客户端工厂接口 + * + * @author zzf + * @date 2021/1/28 14:01 + */ +public interface SmsClientFactory { + + /** + * 获得短信 Client + * + * @param channelId 渠道编号 + * @return 短信 Client + */ + SmsClient getSmsClient(Long channelId); + + /** + * 获得短信 Client + * + * @param channelCode 渠道编码 + * @return 短信 Client + */ + SmsClient getSmsClient(String channelCode); + + /** + * 创建短信 Client + * + * @param properties 配置对象 + */ + void createOrUpdateSmsClient(SmsChannelProperties properties); + +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/SmsCodeMapping.java b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/SmsCodeMapping.java new file mode 100644 index 0000000..826306f --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/SmsCodeMapping.java @@ -0,0 +1,17 @@ +package cn.iocoder.yudao.framework.sms.core.client; + +import cn.iocoder.yudao.framework.common.exception.ErrorCode; +import cn.iocoder.yudao.framework.sms.core.enums.SmsFrameworkErrorCodeConstants; + +import java.util.function.Function; + +/** + * 将 API 的错误码,转换为通用的错误码 + * + * @see SmsCommonResult + * @see SmsFrameworkErrorCodeConstants + * + * @author 芋道源码 + */ +public interface SmsCodeMapping extends Function { +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/SmsCommonResult.java b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/SmsCommonResult.java new file mode 100644 index 0000000..d314de2 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/SmsCommonResult.java @@ -0,0 +1,68 @@ +package cn.iocoder.yudao.framework.sms.core.client; + +import cn.hutool.core.exceptions.ExceptionUtil; +import cn.hutool.core.lang.Assert; +import cn.iocoder.yudao.framework.common.exception.ErrorCode; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.sms.core.enums.SmsFrameworkErrorCodeConstants; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +/** + * 短信的 CommonResult 拓展类 + * + * 考虑到不同的平台,返回的 code 和 msg 是不同的,所以统一额外返回 {@link #apiCode} 和 {@link #apiMsg} 字段 + * + * 另外,一些短信平台(例如说阿里云、腾讯云)会返回一个请求编号,用于排查请求失败的问题,我们设置到 {@link #apiRequestId} 字段 + * + * @author 芋道源码 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class SmsCommonResult extends CommonResult { + + /** + * API 返回错误码 + * + * 由于第三方的错误码可能是字符串,所以使用 String 类型 + */ + private String apiCode; + /** + * API 返回提示 + */ + private String apiMsg; + + /** + * API 请求编号 + */ + private String apiRequestId; + + private SmsCommonResult() { + } + + public static SmsCommonResult build(String apiCode, String apiMsg, String apiRequestId, + T data, SmsCodeMapping codeMapping) { + Assert.notNull(codeMapping, "参数 codeMapping 不能为空"); + SmsCommonResult result = new SmsCommonResult().setApiCode(apiCode).setApiMsg(apiMsg).setApiRequestId(apiRequestId); + result.setData(data); + // 翻译错误码 + if (codeMapping != null) { + ErrorCode errorCode = codeMapping.apply(apiCode); + if (errorCode == null) { + errorCode = SmsFrameworkErrorCodeConstants.SMS_UNKNOWN; + } + result.setCode(errorCode.getCode()).setMsg(errorCode.getMsg()); + } + return result; + } + + public static SmsCommonResult error(Throwable ex) { + SmsCommonResult result = new SmsCommonResult<>(); + result.setCode(SmsFrameworkErrorCodeConstants.EXCEPTION.getCode()); + result.setMsg(ExceptionUtil.getRootCauseMessage(ex)); + return result; + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/dto/SmsReceiveRespDTO.java b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/dto/SmsReceiveRespDTO.java new file mode 100644 index 0000000..8c841eb --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/dto/SmsReceiveRespDTO.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.framework.sms.core.client.dto; + +import lombok.Data; + +import java.util.Date; + +/** + * 消息接收 Response DTO + * + * @author 芋道源码 + */ +@Data +public class SmsReceiveRespDTO { + + /** + * 是否接收成功 + */ + private Boolean success; + /** + * API 接收结果的编码 + */ + private String errorCode; + /** + * API 接收结果的说明 + */ + private String errorMsg; + + /** + * 手机号 + */ + private String mobile; + /** + * 用户接收时间 + */ + private Date receiveTime; + + /** + * 短信 API 发送返回的序号 + */ + private String serialNo; + /** + * 短信日志编号 + * + * 对应 SysSmsLogDO 的编号 + */ + private Long logId; + +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/dto/SmsSendRespDTO.java b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/dto/SmsSendRespDTO.java new file mode 100644 index 0000000..9d320d5 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/dto/SmsSendRespDTO.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.framework.sms.core.client.dto; + +import lombok.Data; + +/** + * 短信发送 Response DTO + * + * @author 芋道源码 + */ +@Data +public class SmsSendRespDTO { + + /** + * 短信 API 发送返回的序号 + */ + private String serialNo; + +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/dto/SmsTemplateRespDTO.java b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/dto/SmsTemplateRespDTO.java new file mode 100644 index 0000000..70e8df4 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/dto/SmsTemplateRespDTO.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.framework.sms.core.client.dto; + +import cn.iocoder.yudao.framework.sms.core.enums.SmsTemplateAuditStatusEnum; +import lombok.Data; + +/** + * 短信模板 Response DTO + * + * @author 芋道源码 + */ +@Data +public class SmsTemplateRespDTO { + + /** + * 模板编号 + */ + private String id; + /** + * 短信内容 + */ + private String content; + /** + * 审核状态 + * + * 枚举 {@link SmsTemplateAuditStatusEnum} + */ + private Integer auditStatus; + /** + * 审核未通过的理由 + */ + private String auditReason; + +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/AbstractSmsClient.java b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/AbstractSmsClient.java new file mode 100644 index 0000000..a960380 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/AbstractSmsClient.java @@ -0,0 +1,122 @@ +package cn.iocoder.yudao.framework.sms.core.client.impl; + +import cn.iocoder.yudao.framework.common.core.KeyValue; +import cn.iocoder.yudao.framework.sms.core.client.SmsClient; +import cn.iocoder.yudao.framework.sms.core.client.SmsCodeMapping; +import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult; +import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO; +import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO; +import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO; +import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties; +import lombok.extern.slf4j.Slf4j; + +import java.util.List; + +/** + * 短信客户端抽象类 + * + * @author zzf + * @date 2021/2/1 9:28 + */ +@Slf4j +public abstract class AbstractSmsClient implements SmsClient { + + /** + * 短信渠道配置 + */ + protected volatile SmsChannelProperties properties; + /** + * 错误码枚举类 + */ + protected final SmsCodeMapping codeMapping; + + /** + * 短信客户端有参构造函数 + * + * @param properties 短信配置 + */ + public AbstractSmsClient(SmsChannelProperties properties, SmsCodeMapping codeMapping) { + this.properties = properties; + this.codeMapping = codeMapping; + } + + /** + * 初始化 + */ + public final void init() { + doInit(); + log.info("[init][配置({}) 初始化完成]", properties); + } + + public final void refresh(SmsChannelProperties properties) { + // 判断是否更新 + if (properties.equals(this.properties)) { + return; + } + log.info("[refresh][配置({})发生变化,重新初始化]", properties); + this.properties = properties; + // 初始化 + this.init(); + } + + /** + * 自定义初始化 + */ + protected abstract void doInit(); + + @Override + public Long getId() { + return properties.getId(); + } + + @Override + public final SmsCommonResult sendSms(Long logId, String mobile, + String apiTemplateId, List> templateParams) { + // 执行短信发送 + SmsCommonResult result; + try { + result = doSendSms(logId, mobile, apiTemplateId, templateParams); + } catch (Throwable ex) { + // 打印异常日志 + log.error("[sendSms][发送短信异常,sendLogId({}) mobile({}) apiTemplateId({}) templateParams({})]", + logId, mobile, apiTemplateId, templateParams, ex); + // 封装返回 + return SmsCommonResult.error(ex); + } + return result; + } + + protected abstract SmsCommonResult doSendSms(Long sendLogId, String mobile, + String apiTemplateId, List> templateParams) + throws Throwable; + + @Override + public List parseSmsReceiveStatus(String text) throws Throwable { + try { + return doParseSmsReceiveStatus(text); + } catch (Throwable ex) { + log.error("[parseSmsReceiveStatus][text({}) 解析发生异常]", text, ex); + throw ex; + } + } + + protected abstract List doParseSmsReceiveStatus(String text) throws Throwable; + + @Override + public SmsCommonResult getSmsTemplate(String apiTemplateId) { + // 执行短信发送 + SmsCommonResult result; + try { + result = doGetSmsTemplate(apiTemplateId); + } catch (Throwable ex) { + // 打印异常日志 + log.error("[getSmsTemplate][获得短信模板({}) 发生异常]", apiTemplateId, ex); + // 封装返回 + return SmsCommonResult.error(ex); + } + return result; + } + + protected abstract SmsCommonResult doGetSmsTemplate(String apiTemplateId) throws Throwable; + +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/SmsClientFactoryImpl.java b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/SmsClientFactoryImpl.java new file mode 100644 index 0000000..365196a --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/SmsClientFactoryImpl.java @@ -0,0 +1,90 @@ +package cn.iocoder.yudao.framework.sms.core.client.impl; + +import cn.iocoder.yudao.framework.sms.core.client.SmsClient; +import cn.iocoder.yudao.framework.sms.core.client.SmsClientFactory; +import cn.iocoder.yudao.framework.sms.core.client.impl.aliyun.AliyunSmsClient; +import cn.iocoder.yudao.framework.sms.core.client.impl.debug.DebugDingTalkSmsClient; +import cn.iocoder.yudao.framework.sms.core.client.impl.yunpian.YunpianSmsClient; +import cn.iocoder.yudao.framework.sms.core.enums.SmsChannelEnum; +import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties; +import lombok.extern.slf4j.Slf4j; +import org.springframework.util.Assert; +import org.springframework.validation.annotation.Validated; + +import java.util.Arrays; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + * 短信客户端工厂接口 + * + * @author zzf + */ +@Validated +@Slf4j +public class SmsClientFactoryImpl implements SmsClientFactory { + + /** + * 短信客户端 Map + * key:渠道编号,使用 {@link SmsChannelProperties#getId()} + */ + private final ConcurrentMap channelIdClients = new ConcurrentHashMap<>(); + + /** + * 短信客户端 Map + * key:渠道编码,使用 {@link SmsChannelProperties#getCode()} ()} + * + * 注意,一些场景下,需要获得某个渠道类型的客户端,所以需要使用它。 + * 例如说,解析短信接收结果,是相对通用的,不需要使用某个渠道编号的 {@link #channelIdClients} + */ + private final ConcurrentMap channelCodeClients = new ConcurrentHashMap<>(); + + public SmsClientFactoryImpl() { + // 初始化 channelCodeClients 集合 + Arrays.stream(SmsChannelEnum.values()).forEach(channel -> { + // 创建一个空的 SmsChannelProperties 对象 + SmsChannelProperties properties = new SmsChannelProperties().setCode(channel.getCode()) + .setApiKey("default").setApiSecret("default"); + // 创建 Sms 客户端 + AbstractSmsClient smsClient = createSmsClient(properties); + channelCodeClients.put(channel.getCode(), smsClient); + }); + } + + @Override + public SmsClient getSmsClient(Long channelId) { + return channelIdClients.get(channelId); + } + + @Override + public SmsClient getSmsClient(String channelCode) { + return channelCodeClients.get(channelCode); + } + + @Override + public void createOrUpdateSmsClient(SmsChannelProperties properties) { + AbstractSmsClient client = channelIdClients.get(properties.getId()); + if (client == null) { + client = this.createSmsClient(properties); + client.init(); + channelIdClients.put(client.getId(), client); + } else { + client.refresh(properties); + } + } + + private AbstractSmsClient createSmsClient(SmsChannelProperties properties) { + SmsChannelEnum channelEnum = SmsChannelEnum.getByCode(properties.getCode()); + Assert.notNull(channelEnum, String.format("渠道类型(%s) 为空", channelEnum)); + // 创建客户端 + switch (channelEnum) { + case ALIYUN: return new AliyunSmsClient(properties); + case YUN_PIAN: return new YunpianSmsClient(properties); + case DEBUG_DING_TALK: return new DebugDingTalkSmsClient(properties); + } + // 创建失败,错误日志 + 抛出异常 + log.error("[createSmsClient][配置({}) 找不到合适的客户端实现]", properties); + throw new IllegalArgumentException(String.format("配置(%s) 找不到合适的客户端实现", properties)); + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java new file mode 100644 index 0000000..9c206e9 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java @@ -0,0 +1,212 @@ +package cn.iocoder.yudao.framework.sms.core.client.impl.aliyun; + +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.ReflectUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.core.KeyValue; +import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult; +import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO; +import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO; +import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO; +import cn.iocoder.yudao.framework.sms.core.client.impl.AbstractSmsClient; +import cn.iocoder.yudao.framework.sms.core.enums.SmsTemplateAuditStatusEnum; +import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import com.aliyuncs.AcsRequest; +import com.aliyuncs.AcsResponse; +import com.aliyuncs.DefaultAcsClient; +import com.aliyuncs.IAcsClient; +import com.aliyuncs.dysmsapi.model.v20170525.QuerySmsTemplateRequest; +import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest; +import com.aliyuncs.exceptions.ClientException; +import com.aliyuncs.profile.DefaultProfile; +import com.aliyuncs.profile.IClientProfile; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.common.annotations.VisibleForTesting; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +import java.util.Date; +import java.util.List; +import java.util.Objects; +import java.util.function.Function; +import java.util.stream.Collectors; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DEFAULT; + +/** + * 阿里短信客户端的实现类 + * + * @author zzf + * @date 2021/1/25 14:17 + */ +@Slf4j +public class AliyunSmsClient extends AbstractSmsClient { + + /** + * REGION, 使用杭州 + */ + private static final String ENDPOINT = "cn-hangzhou"; + + /** + * 阿里云客户端 + */ + private volatile IAcsClient client; + + public AliyunSmsClient(SmsChannelProperties properties) { + super(properties, new AliyunSmsCodeMapping()); + Assert.notEmpty(properties.getApiKey(), "apiKey 不能为空"); + Assert.notEmpty(properties.getApiSecret(), "apiSecret 不能为空"); + } + + @Override + protected void doInit() { + IClientProfile profile = DefaultProfile.getProfile(ENDPOINT, properties.getApiKey(), properties.getApiSecret()); + client = new DefaultAcsClient(profile); + } + + @Override + protected SmsCommonResult doSendSms(Long sendLogId, String mobile, + String apiTemplateId, List> templateParams) { + // 构建参数 + SendSmsRequest request = new SendSmsRequest(); + request.setPhoneNumbers(mobile); + request.setSignName(properties.getSignature()); + request.setTemplateCode(apiTemplateId); + request.setTemplateParam(JsonUtils.toJsonString(MapUtils.convertMap(templateParams))); + request.setOutId(String.valueOf(sendLogId)); + // 执行请求 + return invoke(request, response -> new SmsSendRespDTO().setSerialNo(response.getBizId())); + } + + @Override + protected List doParseSmsReceiveStatus(String text) throws Throwable { + List statuses = JsonUtils.parseArray(text, SmsReceiveStatus.class); + return statuses.stream().map(status -> { + SmsReceiveRespDTO resp = new SmsReceiveRespDTO(); + resp.setSuccess(status.getSuccess()); + resp.setErrorCode(status.getErrCode()).setErrorMsg(status.getErrMsg()); + resp.setMobile(status.getPhoneNumber()).setReceiveTime(status.getReportTime()); + resp.setSerialNo(status.getBizId()).setLogId(Long.valueOf(status.getOutId())); + return resp; + }).collect(Collectors.toList()); + } + + @Override + protected SmsCommonResult doGetSmsTemplate(String apiTemplateId) { + // 构建参数 + QuerySmsTemplateRequest request = new QuerySmsTemplateRequest(); + request.setTemplateCode(apiTemplateId); + // 执行请求 + return invoke(request, response -> { + SmsTemplateRespDTO data = new SmsTemplateRespDTO(); + data.setId(response.getTemplateCode()).setContent(response.getTemplateContent()); + data.setAuditStatus(convertSmsTemplateAuditStatus(response.getTemplateStatus())).setAuditReason(response.getReason()); + return data; + }); + } + + @VisibleForTesting + Integer convertSmsTemplateAuditStatus(Integer templateStatus) { + switch (templateStatus) { + case 0: return SmsTemplateAuditStatusEnum.CHECKING.getStatus(); + case 1: return SmsTemplateAuditStatusEnum.SUCCESS.getStatus(); + case 2: return SmsTemplateAuditStatusEnum.FAIL.getStatus(); + default: throw new IllegalArgumentException(String.format("未知审核状态(%d)", templateStatus)); + } + } + + @VisibleForTesting + SmsCommonResult invoke(AcsRequest request, Function responseConsumer) { + try { + // 执行发送. 由于阿里云 sms 短信没有统一的 Response,但是有统一的 code、message、requestId 属性,所以只好反射 + T sendResult = client.getAcsResponse(request); + String code = (String) ReflectUtil.getFieldValue(sendResult, "code"); + String message = (String) ReflectUtil.getFieldValue(sendResult, "message"); + String requestId = (String) ReflectUtil.getFieldValue(sendResult, "requestId"); + // 解析结果 + R data = null; + if (Objects.equals(code, "OK")) { // 请求成功的情况下 + data = responseConsumer.apply(sendResult); + } + // 拼接结果 + return SmsCommonResult.build(code, message, requestId, data, codeMapping); + } catch (ClientException ex) { + return SmsCommonResult.build(ex.getErrCode(), formatResultMsg(ex), ex.getRequestId(), null, codeMapping); + } + } + + private static String formatResultMsg(ClientException ex) { + if (StrUtil.isEmpty(ex.getErrorDescription())) { + return ex.getErrMsg(); + } + return ex.getErrMsg() + " => " + ex.getErrorDescription(); + } + + /** + * 短信接收状态 + * + * 参见 https://help.aliyun.com/document_detail/101867.html 文档 + * + * @author 芋道源码 + */ + @Data + public static class SmsReceiveStatus { + + /** + * 手机号 + */ + @JsonProperty("phone_number") + private String phoneNumber; + /** + * 发送时间 + */ + @JsonProperty("send_time") + @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT) + private Date sendTime; + /** + * 状态报告时间 + */ + @JsonProperty("report_time") + @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT) + private Date reportTime; + /** + * 是否接收成功 + */ + private Boolean success; + /** + * 状态报告说明 + */ + @JsonProperty("err_msg") + private String errMsg; + /** + * 状态报告编码 + */ + @JsonProperty("err_code") + private String errCode; + /** + * 发送序列号 + */ + @JsonProperty("biz_id") + private String bizId; + /** + * 用户序列号 + * + * 这里我们传递的是 SysSmsLogDO 的日志编号 + */ + @JsonProperty("out_id") + private String outId; + /** + * 短信长度,例如说 1、2、3 + * + * 140 字节算一条短信,短信长度超过 140 字节时会拆分成多条短信发送 + */ + @JsonProperty("sms_size") + private Integer smsSize; + + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/aliyun/AliyunSmsCodeMapping.java b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/aliyun/AliyunSmsCodeMapping.java new file mode 100644 index 0000000..549bf8b --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/aliyun/AliyunSmsCodeMapping.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.framework.sms.core.client.impl.aliyun; + +import cn.iocoder.yudao.framework.common.exception.ErrorCode; +import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; +import cn.iocoder.yudao.framework.sms.core.client.SmsCodeMapping; +import cn.iocoder.yudao.framework.sms.core.enums.SmsFrameworkErrorCodeConstants; + +/** + * 阿里云的 SmsCodeMapping 实现类 + * + * 参见 https://help.aliyun.com/document_detail/101346.htm 文档 + * + * @author 芋道源码 + */ +public class AliyunSmsCodeMapping implements SmsCodeMapping { + + @Override + public ErrorCode apply(String apiCode) { + switch (apiCode) { + case "OK": return GlobalErrorCodeConstants.SUCCESS; + case "isv.ACCOUNT_NOT_EXISTS": + case "isv.ACCOUNT_ABNORMAL": + case "MissingAccessKeyId": return SmsFrameworkErrorCodeConstants.SMS_ACCOUNT_INVALID; + case "isp.RAM_PERMISSION_DENY": return SmsFrameworkErrorCodeConstants.SMS_PERMISSION_DENY; + case "isv.INVALID_JSON_PARAM": + case "isv.INVALID_PARAMETERS": return SmsFrameworkErrorCodeConstants.SMS_API_PARAM_ERROR; + case "isv.BUSINESS_LIMIT_CONTROL": return SmsFrameworkErrorCodeConstants.SMS_SEND_BUSINESS_LIMIT_CONTROL; + case "isv.DAY_LIMIT_CONTROL": return SmsFrameworkErrorCodeConstants.SMS_SEND_DAY_LIMIT_CONTROL; + case "isv.SMS_CONTENT_ILLEGAL": return SmsFrameworkErrorCodeConstants.SMS_SEND_CONTENT_INVALID; + case "isv.SMS_TEMPLATE_ILLEGAL": return SmsFrameworkErrorCodeConstants.SMS_TEMPLATE_INVALID; + case "isv.SMS_SIGNATURE_ILLEGAL": + case "isv.SIGN_NAME_ILLEGAL": + case "isv.SMS_SIGN_ILLEGAL": return SmsFrameworkErrorCodeConstants.SMS_SIGN_INVALID; + case "isv.AMOUNT_NOT_ENOUGH": + case "isv.OUT_OF_SERVICE": return SmsFrameworkErrorCodeConstants.SMS_ACCOUNT_MONEY_NOT_ENOUGH; + case "isv.MOBILE_NUMBER_ILLEGAL": return SmsFrameworkErrorCodeConstants.SMS_MOBILE_INVALID; + case "isv.TEMPLATE_MISSING_PARAMETERS": return SmsFrameworkErrorCodeConstants.SMS_TEMPLATE_PARAM_ERROR; + } + return SmsFrameworkErrorCodeConstants.SMS_UNKNOWN; + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/debug/DebugDingTalkCodeMapping.java b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/debug/DebugDingTalkCodeMapping.java new file mode 100644 index 0000000..0a7e48b --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/debug/DebugDingTalkCodeMapping.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.framework.sms.core.client.impl.debug; + +import cn.iocoder.yudao.framework.common.exception.ErrorCode; +import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; +import cn.iocoder.yudao.framework.sms.core.client.SmsCodeMapping; +import cn.iocoder.yudao.framework.sms.core.enums.SmsFrameworkErrorCodeConstants; + +import java.util.Objects; + +/** + * 钉钉的 SmsCodeMapping 实现类 + * + * @author 芋道源码 + */ +public class DebugDingTalkCodeMapping implements SmsCodeMapping { + + @Override + public ErrorCode apply(String apiCode) { + return Objects.equals(apiCode, "0") ? GlobalErrorCodeConstants.SUCCESS : SmsFrameworkErrorCodeConstants.SMS_UNKNOWN; + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/debug/DebugDingTalkSmsClient.java b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/debug/DebugDingTalkSmsClient.java new file mode 100644 index 0000000..cedcfb6 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/debug/DebugDingTalkSmsClient.java @@ -0,0 +1,96 @@ +package cn.iocoder.yudao.framework.sms.core.client.impl.debug; + +import cn.hutool.core.codec.Base64; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.crypto.digest.DigestUtil; +import cn.hutool.crypto.digest.HmacAlgorithm; +import cn.hutool.http.HttpUtil; +import cn.iocoder.yudao.framework.common.core.KeyValue; +import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult; +import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO; +import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO; +import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO; +import cn.iocoder.yudao.framework.sms.core.client.impl.AbstractSmsClient; +import cn.iocoder.yudao.framework.sms.core.enums.SmsTemplateAuditStatusEnum; +import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 基于钉钉 WebHook 实现的调试的短信客户端实现类 + * + * 考虑到省钱,我们使用钉钉 WebHook 模拟发送短信,方便调试。 + * + * @author 芋道源码 + */ +public class DebugDingTalkSmsClient extends AbstractSmsClient { + + public DebugDingTalkSmsClient(SmsChannelProperties properties) { + super(properties, new DebugDingTalkCodeMapping()); + Assert.notEmpty(properties.getApiKey(), "apiKey 不能为空"); + Assert.notEmpty(properties.getApiSecret(), "apiSecret 不能为空"); + } + + @Override + protected void doInit() { + } + + @Override + protected SmsCommonResult doSendSms(Long sendLogId, String mobile, + String apiTemplateId, List> templateParams) throws Throwable { + // 构建请求 + String url = buildUrl("robot/send"); + Map params = new HashMap<>(); + params.put("msgtype", "text"); + String content = String.format("【模拟短信】\n手机号:%s\n短信日志编号:%d\n模板参数:%s", + mobile, sendLogId, MapUtils.convertMap(templateParams)); + params.put("text", MapUtil.builder().put("content", content).build()); + // 执行请求 + String responseText = HttpUtil.post(url, JsonUtils.toJsonString(params)); + // 解析结果 + Map responseObj = JsonUtils.parseObject(responseText, Map.class); + return SmsCommonResult.build(MapUtil.getStr(responseObj, "errcode"), MapUtil.getStr(responseObj, "errorMsg"), + null, new SmsSendRespDTO().setSerialNo(StrUtil.uuid()), codeMapping); + } + + /** + * 构建请求地址 + * + * 参见 https://developers.dingtalk.com/document/app/custom-robot-access/title-nfv-794-g71 文档 + * + * @param path 请求路径 + * @return 请求地址 + */ + @SuppressWarnings("SameParameterValue") + private String buildUrl(String path) { + // 生成 timestamp + long timestamp = System.currentTimeMillis(); + // 生成 sign + String secret = properties.getApiSecret(); + String stringToSign = timestamp + "\n" + secret; + byte[] signData = DigestUtil.hmac(HmacAlgorithm.HmacSHA256, StrUtil.bytes(secret)).digest(stringToSign); + String sign = Base64.encode(signData); + // 构建最终 URL + return String.format("https://oapi.dingtalk.com/%s?access_token=%s×tamp=%d&sign=%s", + path, properties.getApiKey(), timestamp, sign); + } + + @Override + protected List doParseSmsReceiveStatus(String text) throws Throwable { + throw new UnsupportedOperationException("模拟短信客户端,暂时无需解析回调"); + } + + @Override + protected SmsCommonResult doGetSmsTemplate(String apiTemplateId) { + SmsTemplateRespDTO data = new SmsTemplateRespDTO().setId(apiTemplateId).setContent("") + .setAuditStatus(SmsTemplateAuditStatusEnum.SUCCESS.getStatus()).setAuditReason(""); + return SmsCommonResult.build("0", "success", null, data, codeMapping); + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java new file mode 100644 index 0000000..8adff8f --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java @@ -0,0 +1,204 @@ +package cn.iocoder.yudao.framework.sms.core.client.impl.yunpian; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.StrUtil; +import cn.hutool.core.util.URLUtil; +import cn.iocoder.yudao.framework.common.core.KeyValue; +import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult; +import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO; +import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO; +import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO; +import cn.iocoder.yudao.framework.sms.core.client.impl.AbstractSmsClient; +import cn.iocoder.yudao.framework.sms.core.enums.SmsTemplateAuditStatusEnum; +import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.common.annotations.VisibleForTesting; +import com.yunpian.sdk.YunpianClient; +import com.yunpian.sdk.constant.YunpianConstant; +import com.yunpian.sdk.model.Result; +import com.yunpian.sdk.model.Template; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +import java.util.*; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DEFAULT; + +/** + * 云片短信客户端的实现类 + * + * @author zzf + * @date 9:48 2021/3/5 + */ +@Slf4j +public class YunpianSmsClient extends AbstractSmsClient { + + /** + * 云信短信客户端 + */ + private volatile YunpianClient client; + + public YunpianSmsClient(SmsChannelProperties properties) { + super(properties, new YunpianSmsCodeMapping()); + Assert.notEmpty(properties.getApiKey(), "apiKey 不能为空"); + } + + @Override + public void doInit() { + YunpianClient oldClient = client; + // 初始化新的客户端 + YunpianClient newClient = new YunpianClient(properties.getApiKey()); + newClient.init(); + this.client = newClient; + // 销毁老的客户端 + if (oldClient != null) { + oldClient.close(); + } + } + + @Override + protected SmsCommonResult doSendSms(Long sendLogId, String mobile, + String apiTemplateId, List> templateParams) throws Throwable { + return invoke(() -> { + Map request = new HashMap<>(); + request.put(YunpianConstant.MOBILE, mobile); + request.put(YunpianConstant.TPL_ID, apiTemplateId); + request.put(YunpianConstant.TPL_VALUE, formatTplValue(templateParams)); + request.put(YunpianConstant.UID, String.valueOf(sendLogId)); + request.put(YunpianConstant.CALLBACK_URL, properties.getCallbackUrl()); + return client.sms().tpl_single_send(request); + }, response -> new SmsSendRespDTO().setSerialNo(String.valueOf(response.getSid()))); + } + + private static String formatTplValue(List> templateParams) { + if (CollUtil.isEmpty(templateParams)) { + return ""; + } + // 参考 https://www.yunpian.com/official/document/sms/zh_cn/introduction_demos_encode_sample 格式化 + StringJoiner joiner = new StringJoiner("&"); + templateParams.forEach(param -> joiner.add(String.format("#%s#=%s", param.getKey(), URLUtil.encode(String.valueOf(param.getValue()))))); + return joiner.toString(); + } + + @Override + protected List doParseSmsReceiveStatus(String text) throws Throwable { + List statuses = JsonUtils.parseArray(text, SmsReceiveStatus.class); + return statuses.stream().map(status -> { + SmsReceiveRespDTO resp = new SmsReceiveRespDTO(); + resp.setSuccess(Objects.equals(status.getReportStatus(), "SUCCESS")); + resp.setErrorCode(status.getErrorMsg()).setErrorMsg(status.getErrorDetail()); + resp.setMobile(status.getMobile()).setReceiveTime(status.getUserReceiveTime()); + resp.setSerialNo(String.valueOf(status.getSid())).setLogId(status.getUid()); + return resp; + }).collect(Collectors.toList()); + } + + @Override + protected SmsCommonResult doGetSmsTemplate(String apiTemplateId) throws Throwable { + return invoke(() -> { + Map request = new HashMap<>(); + request.put(YunpianConstant.APIKEY, properties.getApiKey()); + request.put(YunpianConstant.TPL_ID, apiTemplateId); + return client.tpl().get(request); + }, response -> { + Template template = response.get(0); + return new SmsTemplateRespDTO().setId(String.valueOf(template.getTpl_id())).setContent(template.getTpl_content()) + .setAuditStatus(convertSmsTemplateAuditStatus(template.getCheck_status())).setAuditReason(template.getReason()); + }); + } + + @VisibleForTesting + Integer convertSmsTemplateAuditStatus(String checkStatus) { + switch (checkStatus) { + case "CHECKING": return SmsTemplateAuditStatusEnum.CHECKING.getStatus(); + case "SUCCESS": return SmsTemplateAuditStatusEnum.SUCCESS.getStatus(); + case "FAIL": return SmsTemplateAuditStatusEnum.FAIL.getStatus(); + default: throw new IllegalArgumentException(String.format("未知审核状态(%s)", checkStatus)); + } + } + + @VisibleForTesting + SmsCommonResult invoke(Supplier> requestConsumer, Function responseConsumer) throws Throwable { + // 执行请求 + Result result = requestConsumer.get(); + if (result.getThrowable() != null) { + throw result.getThrowable(); + } + // 解析结果 + R data = null; + if (result.getData() != null) { + data = responseConsumer.apply(result.getData()); + } + // 拼接结果 + return SmsCommonResult.build(String.valueOf(result.getCode()), formatResultMsg(result), null, data, codeMapping); + } + + private static String formatResultMsg(Result sendResult) { + if (StrUtil.isEmpty(sendResult.getDetail())) { + return sendResult.getMsg(); + } + return sendResult.getMsg() + " => " + sendResult.getDetail(); + } + + /** + * 短信接收状态 + * + * 参见 https://www.yunpian.com/official/document/sms/zh_cn/domestic_push_report 文档 + * + * @author 芋道源码 + */ + @Data + public static class SmsReceiveStatus { + + /** + * 接收状态 + * + * 目前仅有 SUCCESS / FAIL,所以使用 Boolean 接收 + */ + @JsonProperty("report_status") + private String reportStatus; + /** + * 接收手机号 + */ + private String mobile; + /** + * 运营商返回的代码,如:"DB:0103" + * + * 由于不同运营商信息不同,此字段仅供参考; + */ + @JsonProperty("error_msg") + private String errorMsg; + /** + * 运营商反馈代码的中文解释 + * + * 默认不推送此字段,如需推送,请联系客服 + */ + @JsonProperty("error_detail") + private String errorDetail; + /** + * 短信编号 + */ + private Long sid; + /** + * 用户自定义 id + * + * 这里我们传递的是 SysSmsLogDO 的日志编号 + */ + private Long uid; + /** + * 用户接收时间 + */ + @JsonProperty("user_receive_time") + @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT) + private Date userReceiveTime; + + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/yunpian/YunpianSmsCodeMapping.java b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/yunpian/YunpianSmsCodeMapping.java new file mode 100644 index 0000000..d6ecdce --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/yunpian/YunpianSmsCodeMapping.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.framework.sms.core.client.impl.yunpian; + +import cn.iocoder.yudao.framework.common.exception.ErrorCode; +import cn.iocoder.yudao.framework.sms.core.client.SmsCodeMapping; +import cn.iocoder.yudao.framework.sms.core.enums.SmsFrameworkErrorCodeConstants; + +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.SUCCESS; +import static com.yunpian.sdk.constant.Code.*; + +/** + * 云片的 SmsCodeMapping 实现类 + * + * 参见 https://www.yunpian.com/official/document/sms/zh_CN/returnvalue_common 文档 + * + * @author 芋道源码 + */ +public class YunpianSmsCodeMapping implements SmsCodeMapping { + + @Override + public ErrorCode apply(String apiCode) { + int code = Integer.parseInt(apiCode); + switch (code) { + case OK: return SUCCESS; + case ARGUMENT_MISSING: return SmsFrameworkErrorCodeConstants.SMS_API_PARAM_ERROR; + case BAD_ARGUMENT_FORMAT: return SmsFrameworkErrorCodeConstants.SMS_TEMPLATE_PARAM_ERROR; + case TPL_NOT_FOUND: + case TPL_NOT_VALID: return SmsFrameworkErrorCodeConstants.SMS_TEMPLATE_INVALID; + case MONEY_NOT_ENOUGH: return SmsFrameworkErrorCodeConstants.SMS_ACCOUNT_MONEY_NOT_ENOUGH; + case BLACK_WORD: return SmsFrameworkErrorCodeConstants.SMS_SEND_CONTENT_INVALID; + case DUP_IN_SHORT_TIME: + case TOO_MANY_TIME_IN_5: + case DAY_LIMIT_PER_MOBILE: + case HOUR_LIMIT_PER_MOBILE: return SmsFrameworkErrorCodeConstants.SMS_SEND_BUSINESS_LIMIT_CONTROL; + case BLACK_PHONE_FILTER: return SmsFrameworkErrorCodeConstants.SMS_MOBILE_BLACK; + case SIGN_NOT_MATCH: + case BAD_SIGN_FORMAT: + case SIGN_NOT_VALID: return SmsFrameworkErrorCodeConstants.SMS_SIGN_INVALID; + case BAD_API_KEY: return SmsFrameworkErrorCodeConstants.SMS_ACCOUNT_INVALID; + case API_NOT_ALLOWED: return SmsFrameworkErrorCodeConstants.SMS_PERMISSION_DENY; + case IP_NOT_ALLOWED: return SmsFrameworkErrorCodeConstants.SMS_IP_DENY; + } + return SmsFrameworkErrorCodeConstants.SMS_UNKNOWN; + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/enums/SmsChannelEnum.java b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/enums/SmsChannelEnum.java new file mode 100644 index 0000000..c62478c --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/enums/SmsChannelEnum.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.framework.sms.core.enums; + +import cn.hutool.core.util.ArrayUtil; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 短信渠道枚举 + * + * @author zzf + * @date 2021/1/25 10:56 + */ +@Getter +@AllArgsConstructor +public enum SmsChannelEnum { + + DEBUG_DING_TALK("DEBUG_DING_TALK", "调试(钉钉)"), + YUN_PIAN("YUN_PIAN", "云片"), + ALIYUN("ALIYUN", "阿里云"), +// TENCENT("TENCENT", "腾讯云"), +// HUA_WEI("HUA_WEI", "华为云"), + ; + + /** + * 编码 + */ + private final String code; + /** + * 名字 + */ + private final String name; + + public static SmsChannelEnum getByCode(String code) { + return ArrayUtil.firstMatch(o -> o.getCode().equals(code), values()); + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/enums/SmsFrameworkErrorCodeConstants.java b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/enums/SmsFrameworkErrorCodeConstants.java new file mode 100644 index 0000000..6770fcf --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/enums/SmsFrameworkErrorCodeConstants.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.framework.sms.core.enums; + +import cn.iocoder.yudao.framework.common.exception.ErrorCode; + +/** + * 短信框架的错误码枚举 + * + * 短信框架,使用 2-001-000-000 段 + * + * @author 芋道源码 + */ +public interface SmsFrameworkErrorCodeConstants { + + ErrorCode SMS_UNKNOWN = new ErrorCode(2001000000, "未知错误,需要解析"); + + // ========== 权限 / 限流等相关 2001000100 ========== + + ErrorCode SMS_PERMISSION_DENY = new ErrorCode(2001000100, "没有发送短信的权限"); + // 云片:可以配置 IP 白名单,只有在白名单中才可以发送短信 + ErrorCode SMS_IP_DENY = new ErrorCode(2001000100, "IP 不允许发送短信"); + + // 阿里云:将短信发送频率限制在正常的业务限流范围内。默认短信验证码:使用同一签名,对同一个手机号验证码,支持 1 条 / 分钟,5 条 / 小时,累计 10 条 / 天。 + ErrorCode SMS_SEND_BUSINESS_LIMIT_CONTROL = new ErrorCode(2001000102, "指定手机的发送限流"); + // 阿里云:已经达到您在控制台设置的短信日发送量限额值。在国内消息设置 > 安全设置,修改发送总量阈值。 + ErrorCode SMS_SEND_DAY_LIMIT_CONTROL = new ErrorCode(2001000103, "每天的发送限流"); + + ErrorCode SMS_SEND_CONTENT_INVALID = new ErrorCode(2001000104, "短信内容有敏感词"); + + // ========== 模板相关 2001000200 ========== + ErrorCode SMS_TEMPLATE_INVALID = new ErrorCode(2001000200, "短信模板不合法"); // 包括短信模板不存在 + ErrorCode SMS_TEMPLATE_PARAM_ERROR = new ErrorCode(2001000201, "模板参数不正确"); + + // ========== 签名相关 2001000300 ========== + ErrorCode SMS_SIGN_INVALID = new ErrorCode(2001000300, "短信签名不可用"); + + // ========== 账户相关 2001000400 ========== + ErrorCode SMS_ACCOUNT_MONEY_NOT_ENOUGH = new ErrorCode(2001000400, "账户余额不足"); + ErrorCode SMS_ACCOUNT_INVALID = new ErrorCode(2001000401, "apiKey 不存在"); + + // ========== 其它相关 2001000900 开头 ========== + ErrorCode SMS_API_PARAM_ERROR = new ErrorCode(2001000900, "请求参数缺失"); + ErrorCode SMS_MOBILE_INVALID = new ErrorCode(2001000901, "手机格式不正确"); + ErrorCode SMS_MOBILE_BLACK = new ErrorCode(2001000902, "手机号在黑名单中"); + + ErrorCode EXCEPTION = new ErrorCode(2001000999, "调用异常"); + +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/enums/SmsTemplateAuditStatusEnum.java b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/enums/SmsTemplateAuditStatusEnum.java new file mode 100644 index 0000000..2555650 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/enums/SmsTemplateAuditStatusEnum.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.framework.sms.core.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 短信模板的审核状态枚举 + * + * @author 芋道源码 + */ +@AllArgsConstructor +@Getter +public enum SmsTemplateAuditStatusEnum { + + CHECKING(1), + SUCCESS(2), + FAIL(3); + + private final Integer status; + +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/property/SmsChannelProperties.java b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/property/SmsChannelProperties.java new file mode 100644 index 0000000..c66ca85 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/property/SmsChannelProperties.java @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.framework.sms.core.property; + +import cn.iocoder.yudao.framework.sms.core.enums.SmsChannelEnum; +import lombok.Data; +import org.springframework.validation.annotation.Validated; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +/** + * 短信渠道配置类 + * + * @author zzf + * @date 2021/1/25 17:01 + */ +@Data +@Validated +public class SmsChannelProperties { + + /** + * 渠道编号 + */ + @NotNull(message = "短信渠道 ID 不能为空") + private Long id; + /** + * 短信签名 + */ + @NotEmpty(message = "短信签名不能为空") + private String signature; + /** + * 渠道编码 + * + * 枚举 {@link SmsChannelEnum} + */ + @NotEmpty(message = "渠道编码不能为空") + private String code; + /** + * 短信 API 的账号 + */ + @NotEmpty(message = "短信 API 的账号不能为空") + private String apiKey; + /** + * 短信 API 的秘钥 + */ + @NotEmpty(message = "短信 API 的秘钥不能为空") + private String apiSecret; + /** + * 短信发送回调 URL + */ + private String callbackUrl; + +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/resources/META-INF/spring.factories b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000..bb26b53 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ + cn.iocoder.yudao.framework.sms.config.YudaoSmsAutoConfiguration diff --git a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/test/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClientTest.java b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/test/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClientTest.java deleted file mode 100644 index ddbd446..0000000 --- a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/test/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClientTest.java +++ /dev/null @@ -1,224 +0,0 @@ -package cn.iocoder.dashboard.framework.sms.core.client.impl.aliyun; - -import cn.hutool.core.util.ReflectUtil; -import cn.iocoder.dashboard.framework.test.core.ut.BaseMockitoUnitTest; -import cn.iocoder.yudao.framework.common.core.KeyValue; -import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; -import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; -import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO; -import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; -import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsTemplateRespDTO; -import cn.iocoder.dashboard.framework.sms.core.enums.SmsTemplateAuditStatusEnum; -import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; -import cn.iocoder.yudao.framework.common.util.collection.MapUtils; -import cn.iocoder.yudao.framework.common.util.date.DateUtils; -import com.aliyuncs.AcsRequest; -import com.aliyuncs.IAcsClient; -import com.aliyuncs.dysmsapi.model.v20170525.QuerySmsTemplateRequest; -import com.aliyuncs.dysmsapi.model.v20170525.QuerySmsTemplateResponse; -import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest; -import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse; -import com.aliyuncs.exceptions.ClientException; -import com.google.common.collect.Lists; -import org.junit.jupiter.api.Test; -import org.mockito.ArgumentMatcher; -import org.mockito.InjectMocks; -import org.mockito.Mock; - -import java.util.List; -import java.util.function.Function; - -import static cn.iocoder.dashboard.framework.sms.core.enums.SmsFrameworkErrorCodeConstants.SMS_API_PARAM_ERROR; -import static cn.iocoder.dashboard.framework.test.core.util.RandomUtils.*; -import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.argThat; -import static org.mockito.Mockito.when; - -/** - * {@link AliyunSmsClient} 的单元测试 - * - * @author 芋道源码 - */ -public class AliyunSmsClientTest extends BaseMockitoUnitTest { - - private final SmsChannelProperties properties = new SmsChannelProperties() - .setApiKey(randomString()) // 随机一个 apiKey,避免构建报错 - .setApiSecret(randomString()) // 随机一个 apiSecret,避免构建报错 - .setSignature("芋道源码"); - - @InjectMocks - private final AliyunSmsClient smsClient = new AliyunSmsClient(properties); - - @Mock - private IAcsClient client; - - @Test - public void testDoInit() { - // 准备参数 - // mock 方法 - - // 调用 - smsClient.doInit(); - // 断言 - assertNotSame(client, ReflectUtil.getFieldValue(smsClient, "acsClient")); - } - - @Test - @SuppressWarnings("unchecked") - public void testDoSendSms() throws ClientException { - // 准备参数 - Long sendLogId = randomLongId(); - String mobile = randomString(); - String apiTemplateId = randomString(); - List> templateParams = Lists.newArrayList( - new KeyValue<>("code", 1234), new KeyValue<>("op", "login")); - // mock 方法 - SendSmsResponse response = randomPojo(SendSmsResponse.class, o -> o.setCode("OK")); - when(client.getAcsResponse(argThat((ArgumentMatcher) acsRequest -> { - assertEquals(mobile, acsRequest.getPhoneNumbers()); - assertEquals(properties.getSignature(), acsRequest.getSignName()); - assertEquals(apiTemplateId, acsRequest.getTemplateCode()); - assertEquals(toJsonString(MapUtils.convertMap(templateParams)), acsRequest.getTemplateParam()); - assertEquals(sendLogId.toString(), acsRequest.getOutId()); - return true; - }))).thenReturn(response); - - // 调用 - SmsCommonResult result = smsClient.doSendSms(sendLogId, mobile, - apiTemplateId, templateParams); - // 断言 - assertEquals(response.getCode(), result.getApiCode()); - assertEquals(response.getMessage(), result.getApiMsg()); - assertEquals(GlobalErrorCodeConstants.SUCCESS.getCode(), result.getCode()); - assertEquals(GlobalErrorCodeConstants.SUCCESS.getMsg(), result.getMsg()); - assertEquals(response.getRequestId(), result.getApiRequestId()); - // 断言结果 - assertEquals(response.getBizId(), result.getData().getSerialNo()); - } - - @Test - public void testDoTParseSmsReceiveStatus() throws Throwable { - // 准备参数 - String text = "[\n" + - " {\n" + - " \"phone_number\" : \"13900000001\",\n" + - " \"send_time\" : \"2017-01-01 11:12:13\",\n" + - " \"report_time\" : \"2017-02-02 22:23:24\",\n" + - " \"success\" : true,\n" + - " \"err_code\" : \"DELIVERED\",\n" + - " \"err_msg\" : \"用户接收成功\",\n" + - " \"sms_size\" : \"1\",\n" + - " \"biz_id\" : \"12345\",\n" + - " \"out_id\" : \"67890\"\n" + - " }\n" + - "]"; - // mock 方法 - - // 调用 - List statuses = smsClient.doParseSmsReceiveStatus(text); - // 断言 - assertEquals(1, statuses.size()); - assertTrue(statuses.get(0).getSuccess()); - assertEquals("DELIVERED", statuses.get(0).getErrorCode()); - assertEquals("用户接收成功", statuses.get(0).getErrorMsg()); - assertEquals("13900000001", statuses.get(0).getMobile()); - assertEquals(DateUtils.buildTime(2017, 2, 2, 22, 23, 24), statuses.get(0).getReceiveTime()); - assertEquals("12345", statuses.get(0).getSerialNo()); - assertEquals(67890L, statuses.get(0).getLogId()); - } - - @Test - public void testDoGetSmsTemplate() throws ClientException { - // 准备参数 - String apiTemplateId = randomString(); - // mock 方法 - QuerySmsTemplateResponse response = randomPojo(QuerySmsTemplateResponse.class, o -> { - o.setCode("OK"); - o.setTemplateStatus(1); // 设置模板通过 - }); - when(client.getAcsResponse(argThat((ArgumentMatcher) acsRequest -> { - assertEquals(apiTemplateId, acsRequest.getTemplateCode()); - return true; - }))).thenReturn(response); - - // 调用 - SmsCommonResult result = smsClient.doGetSmsTemplate(apiTemplateId); - // 断言 - assertEquals(response.getCode(), result.getApiCode()); - assertEquals(response.getMessage(), result.getApiMsg()); - assertEquals(GlobalErrorCodeConstants.SUCCESS.getCode(), result.getCode()); - assertEquals(GlobalErrorCodeConstants.SUCCESS.getMsg(), result.getMsg()); - assertEquals(response.getRequestId(), result.getApiRequestId()); - // 断言结果 - assertEquals(response.getTemplateCode(), result.getData().getId()); - assertEquals(response.getTemplateContent(), result.getData().getContent()); - assertEquals(SmsTemplateAuditStatusEnum.SUCCESS.getStatus(), result.getData().getAuditStatus()); - assertEquals(response.getReason(), result.getData().getAuditReason()); - } - - @Test - public void testConvertSmsTemplateAuditStatus() { - assertEquals(SmsTemplateAuditStatusEnum.CHECKING.getStatus(), - smsClient.convertSmsTemplateAuditStatus(0)); - assertEquals(SmsTemplateAuditStatusEnum.SUCCESS.getStatus(), - smsClient.convertSmsTemplateAuditStatus(1)); - assertEquals(SmsTemplateAuditStatusEnum.FAIL.getStatus(), - smsClient.convertSmsTemplateAuditStatus(2)); - assertThrows(IllegalArgumentException.class, () -> smsClient.convertSmsTemplateAuditStatus(3), - "未知审核状态(3)"); - } - - @Test - @SuppressWarnings("unchecked") - public void testInvoke_throwable() throws ClientException { - // 准备参数 - QuerySmsTemplateRequest request = new QuerySmsTemplateRequest(); - // mock 方法 - ClientException ex = new ClientException("isv.INVALID_PARAMETERS", "参数不正确", randomString()); - when(client.getAcsResponse(any(AcsRequest.class))).thenThrow(ex); - - // 调用,并断言异常 - SmsCommonResult result = smsClient.invoke(request,null); - // 断言 - assertEquals(ex.getErrCode(), result.getApiCode()); - assertEquals(ex.getErrMsg(), result.getApiMsg()); - assertEquals(SMS_API_PARAM_ERROR.getCode(), result.getCode()); - assertEquals(SMS_API_PARAM_ERROR.getMsg(), result.getMsg()); - assertEquals(ex.getRequestId(), result.getApiRequestId()); - } - - @Test - public void testInvoke_success() throws ClientException { - // 准备参数 - QuerySmsTemplateRequest request = new QuerySmsTemplateRequest(); - Function responseConsumer = response -> { - SmsTemplateRespDTO data = new SmsTemplateRespDTO(); - data.setId(response.getTemplateCode()).setContent(response.getTemplateContent()); - data.setAuditStatus(SmsTemplateAuditStatusEnum.SUCCESS.getStatus()).setAuditReason(response.getReason()); - return data; - }; - // mock 方法 - QuerySmsTemplateResponse response = randomPojo(QuerySmsTemplateResponse.class, o -> { - o.setCode("OK"); - o.setTemplateStatus(1); // 设置模板通过 - }); - when(client.getAcsResponse(any(AcsRequest.class))).thenReturn(response); - - // 调用 - SmsCommonResult result = smsClient.invoke(request, responseConsumer); - // 断言 - assertEquals(response.getCode(), result.getApiCode()); - assertEquals(response.getMessage(), result.getApiMsg()); - assertEquals(GlobalErrorCodeConstants.SUCCESS.getCode(), result.getCode()); - assertEquals(GlobalErrorCodeConstants.SUCCESS.getMsg(), result.getMsg()); - assertEquals(response.getRequestId(), result.getApiRequestId()); - // 断言结果 - assertEquals(response.getTemplateCode(), result.getData().getId()); - assertEquals(response.getTemplateContent(), result.getData().getContent()); - assertEquals(SmsTemplateAuditStatusEnum.SUCCESS.getStatus(), result.getData().getAuditStatus()); - assertEquals(response.getReason(), result.getData().getAuditReason()); - } - -} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/test/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsCodeMappingTest.java b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/test/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsCodeMappingTest.java deleted file mode 100644 index 823c7ce..0000000 --- a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/test/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsCodeMappingTest.java +++ /dev/null @@ -1,43 +0,0 @@ -package cn.iocoder.dashboard.framework.sms.core.client.impl.aliyun; - -import cn.iocoder.dashboard.framework.test.core.ut.BaseMockitoUnitTest; -import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; -import cn.iocoder.dashboard.framework.sms.core.enums.SmsFrameworkErrorCodeConstants; -import org.junit.jupiter.api.Test; -import org.mockito.InjectMocks; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -/** - * {@link AliyunSmsCodeMapping} 的单元测试 - * - * @author 芋道源码 - */ -public class AliyunSmsCodeMappingTest extends BaseMockitoUnitTest { - - @InjectMocks - private AliyunSmsCodeMapping codeMapping; - - @Test - public void testApply() { - assertEquals(GlobalErrorCodeConstants.SUCCESS, codeMapping.apply("OK")); - assertEquals(SmsFrameworkErrorCodeConstants.SMS_ACCOUNT_INVALID, codeMapping.apply("MissingAccessKeyId")); - assertEquals(SmsFrameworkErrorCodeConstants.SMS_ACCOUNT_INVALID, codeMapping.apply("isv.ACCOUNT_NOT_EXISTS")); - assertEquals(SmsFrameworkErrorCodeConstants.SMS_ACCOUNT_INVALID, codeMapping.apply("isv.ACCOUNT_ABNORMAL")); - assertEquals(SmsFrameworkErrorCodeConstants.SMS_SEND_DAY_LIMIT_CONTROL, codeMapping.apply("isv.DAY_LIMIT_CONTROL")); - assertEquals(SmsFrameworkErrorCodeConstants.SMS_SEND_CONTENT_INVALID, codeMapping.apply("isv.SMS_CONTENT_ILLEGAL")); - assertEquals(SmsFrameworkErrorCodeConstants.SMS_SIGN_INVALID, codeMapping.apply("isv.SMS_SIGN_ILLEGAL")); - assertEquals(SmsFrameworkErrorCodeConstants.SMS_SIGN_INVALID, codeMapping.apply("isv.SIGN_NAME_ILLEGAL")); - assertEquals(SmsFrameworkErrorCodeConstants.SMS_PERMISSION_DENY, codeMapping.apply("isp.RAM_PERMISSION_DENY")); - assertEquals(SmsFrameworkErrorCodeConstants.SMS_ACCOUNT_MONEY_NOT_ENOUGH, codeMapping.apply("isv.OUT_OF_SERVICE")); - assertEquals(SmsFrameworkErrorCodeConstants.SMS_ACCOUNT_MONEY_NOT_ENOUGH, codeMapping.apply("isv.AMOUNT_NOT_ENOUGH")); - assertEquals(SmsFrameworkErrorCodeConstants.SMS_TEMPLATE_INVALID, codeMapping.apply("isv.SMS_TEMPLATE_ILLEGAL")); - assertEquals(SmsFrameworkErrorCodeConstants.SMS_SIGN_INVALID, codeMapping.apply("isv.SMS_SIGNATURE_ILLEGAL")); - assertEquals(SmsFrameworkErrorCodeConstants.SMS_API_PARAM_ERROR, codeMapping.apply("isv.INVALID_PARAMETERS")); - assertEquals(SmsFrameworkErrorCodeConstants.SMS_API_PARAM_ERROR, codeMapping.apply("isv.INVALID_JSON_PARAM")); - assertEquals(SmsFrameworkErrorCodeConstants.SMS_MOBILE_INVALID, codeMapping.apply("isv.MOBILE_NUMBER_ILLEGAL")); - assertEquals(SmsFrameworkErrorCodeConstants.SMS_TEMPLATE_PARAM_ERROR, codeMapping.apply("isv.TEMPLATE_MISSING_PARAMETERS")); - assertEquals(SmsFrameworkErrorCodeConstants.SMS_SEND_BUSINESS_LIMIT_CONTROL, codeMapping.apply("isv.BUSINESS_LIMIT_CONTROL")); - } - -} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/test/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClientTest.java b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/test/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClientTest.java deleted file mode 100644 index 079bb53..0000000 --- a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/test/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClientTest.java +++ /dev/null @@ -1,202 +0,0 @@ -package cn.iocoder.dashboard.framework.sms.core.client.impl.yunpian; - -import cn.hutool.core.util.ReflectUtil; -import cn.iocoder.dashboard.framework.test.core.ut.BaseMockitoUnitTest; -import cn.iocoder.yudao.framework.common.core.KeyValue; -import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; -import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; -import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO; -import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; -import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsTemplateRespDTO; -import cn.iocoder.dashboard.framework.sms.core.enums.SmsTemplateAuditStatusEnum; -import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; -import cn.iocoder.yudao.framework.common.util.date.DateUtils; -import com.google.common.collect.Lists; -import com.yunpian.sdk.YunpianClient; -import com.yunpian.sdk.api.SmsApi; -import com.yunpian.sdk.api.TplApi; -import com.yunpian.sdk.constant.YunpianConstant; -import com.yunpian.sdk.model.Result; -import com.yunpian.sdk.model.SmsSingleSend; -import com.yunpian.sdk.model.Template; -import org.junit.jupiter.api.Test; -import org.mockito.InjectMocks; -import org.mockito.Mock; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Function; -import java.util.function.Supplier; - -import static cn.iocoder.dashboard.framework.test.core.util.RandomUtils.*; -import static com.yunpian.sdk.constant.Code.OK; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.*; - -/** - * 对 {@link YunpianSmsClient} 的单元测试 - * - * @author 芋道源码 - */ -public class YunpianSmsClientTest extends BaseMockitoUnitTest { - - private final SmsChannelProperties properties = new SmsChannelProperties() - .setApiKey(randomString()); // 随机一个 apiKey,避免构建报错 - - @InjectMocks - private final YunpianSmsClient smsClient = new YunpianSmsClient(properties); - - @Mock - private YunpianClient client; - - @Test - public void testDoInit() { - // 准备参数 - // mock 方法 - - // 调用 - smsClient.doInit(); - // 断言 - assertNotEquals(client, ReflectUtil.getFieldValue(smsClient, "client")); - verify(client, times(1)).close(); - } - - @Test - @SuppressWarnings("unchecked") - public void testDoSendSms() throws Throwable { - // 准备参数 - Long sendLogId = randomLongId(); - String mobile = randomString(); - String apiTemplateId = randomString(); - List> templateParams = Lists.newArrayList( - new KeyValue<>("code", 1234), new KeyValue<>("op", "login")); - // mock sms 方法 - SmsApi smsApi = mock(SmsApi.class); - when(client.sms()).thenReturn(smsApi); - // mock tpl_single_send 方法 - Map request = new HashMap<>(); - request.put(YunpianConstant.MOBILE, mobile); - request.put(YunpianConstant.TPL_ID, apiTemplateId); - request.put(YunpianConstant.TPL_VALUE, "#code#=1234&#op#=login"); - request.put(YunpianConstant.UID, String.valueOf(sendLogId)); - request.put(YunpianConstant.CALLBACK_URL, properties.getCallbackUrl()); - Result responseResult = randomPojo(Result.class, SmsSingleSend.class, - o -> o.setCode(OK)); // API 发送成功的 code - when(smsApi.tpl_single_send(eq(request))).thenReturn(responseResult); - - // 调用 - SmsCommonResult result = smsClient.doSendSms(sendLogId, mobile, - apiTemplateId, templateParams); - // 断言 - assertEquals(String.valueOf(responseResult.getCode()), result.getApiCode()); - assertEquals(responseResult.getMsg() + " => " + responseResult.getDetail(), result.getApiMsg()); - assertEquals(GlobalErrorCodeConstants.SUCCESS.getCode(), result.getCode()); - assertEquals(GlobalErrorCodeConstants.SUCCESS.getMsg(), result.getMsg()); - assertNull(result.getApiRequestId()); - // 断言结果 - assertEquals(String.valueOf(responseResult.getData().getSid()), result.getData().getSerialNo()); - } - - @Test - public void testDoParseSmsReceiveStatus() throws Throwable { - // 准备参数 - String text = "[{\"sid\":9527,\"uid\":1024,\"user_receive_time\":\"2014-03-17 22:55:21\",\"error_msg\":\"\",\"mobile\":\"15205201314\",\"report_status\":\"SUCCESS\"}]"; - // mock 方法 - - // 调用 - - // 断言 - // 调用 - List statuses = smsClient.doParseSmsReceiveStatus(text); - // 断言 - assertEquals(1, statuses.size()); - assertTrue(statuses.get(0).getSuccess()); - assertEquals("", statuses.get(0).getErrorCode()); - assertNull(statuses.get(0).getErrorMsg()); - assertEquals("15205201314", statuses.get(0).getMobile()); - assertEquals(DateUtils.buildTime(2014, 3, 17, 22, 55, 21), statuses.get(0).getReceiveTime()); - assertEquals("9527", statuses.get(0).getSerialNo()); - assertEquals(1024L, statuses.get(0).getLogId()); - } - - @Test - @SuppressWarnings("unchecked") - public void testDoGetSmsTemplate() throws Throwable { - // 准备参数 - String apiTemplateId = randomString(); - // mock tpl 方法 - TplApi tplApi = mock(TplApi.class); - when(client.tpl()).thenReturn(tplApi); - // mock get 方法 - Map request = new HashMap<>(); - request.put(YunpianConstant.APIKEY, properties.getApiKey()); - request.put(YunpianConstant.TPL_ID, apiTemplateId); - Result> responseResult = randomPojo(Result.class, List.class, o -> { - o.setCode(OK); // API 发送成功的 code - o.setData(randomPojoList(Template.class, t -> t.setCheck_status("SUCCESS"))); - }); - when(tplApi.get(eq(request))).thenReturn(responseResult); - - // 调用 - SmsCommonResult result = smsClient.doGetSmsTemplate(apiTemplateId); - // 断言 - assertEquals(String.valueOf(responseResult.getCode()), result.getApiCode()); - assertEquals(responseResult.getMsg() + " => " + responseResult.getDetail(), result.getApiMsg()); - assertEquals(GlobalErrorCodeConstants.SUCCESS.getCode(), result.getCode()); - assertEquals(GlobalErrorCodeConstants.SUCCESS.getMsg(), result.getMsg()); - assertNull(result.getApiRequestId()); - // 断言结果 - Template template = responseResult.getData().get(0); - assertEquals(template.getTpl_id().toString(), result.getData().getId()); - assertEquals(template.getTpl_content(), result.getData().getContent()); - assertEquals(SmsTemplateAuditStatusEnum.SUCCESS.getStatus(), result.getData().getAuditStatus()); - assertEquals(template.getReason(), result.getData().getAuditReason()); - } - - @Test - public void testConvertSmsTemplateAuditStatus() { - assertEquals(SmsTemplateAuditStatusEnum.CHECKING.getStatus(), - smsClient.convertSmsTemplateAuditStatus("CHECKING")); - assertEquals(SmsTemplateAuditStatusEnum.SUCCESS.getStatus(), - smsClient.convertSmsTemplateAuditStatus("SUCCESS")); - assertEquals(SmsTemplateAuditStatusEnum.FAIL.getStatus(), - smsClient.convertSmsTemplateAuditStatus("FAIL")); - assertThrows(IllegalArgumentException.class, () -> smsClient.convertSmsTemplateAuditStatus("test"), - "未知审核状态(test)"); - } - - @Test - public void testInvoke_throwable() { - // 准备参数 - Supplier> requestConsumer = - () -> new Result<>().setThrowable(new NullPointerException()); - // mock 方法 - - // 调用,并断言异常 - assertThrows(NullPointerException.class, - () -> smsClient.invoke(requestConsumer, null)); - } - - @Test - @SuppressWarnings("unchecked") - public void testInvoke_success() throws Throwable { - // 准备参数 - Result responseResult = randomPojo(Result.class, SmsSingleSend.class, o -> o.setCode(OK)); - Supplier> requestConsumer = () -> responseResult; - Function responseConsumer = - smsSingleSend -> new SmsSendRespDTO().setSerialNo(String.valueOf(responseResult.getData().getSid())); - // mock 方法 - - // 调用 - SmsCommonResult result = smsClient.invoke(requestConsumer, responseConsumer); - // 断言 - assertEquals(String.valueOf(responseResult.getCode()), result.getApiCode()); - assertEquals(responseResult.getMsg() + " => " + responseResult.getDetail(), result.getApiMsg()); - assertEquals(GlobalErrorCodeConstants.SUCCESS.getCode(), result.getCode()); - assertEquals(GlobalErrorCodeConstants.SUCCESS.getMsg(), result.getMsg()); - assertNull(result.getApiRequestId()); - assertEquals(String.valueOf(responseResult.getData().getSid()), result.getData().getSerialNo()); - } - -} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/test/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsCodeMappingTest.java b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/test/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsCodeMappingTest.java deleted file mode 100644 index 76d0796..0000000 --- a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/test/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsCodeMappingTest.java +++ /dev/null @@ -1,43 +0,0 @@ -package cn.iocoder.dashboard.framework.sms.core.client.impl.yunpian; - -import cn.iocoder.dashboard.framework.test.core.ut.BaseMockitoUnitTest; -import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; -import cn.iocoder.dashboard.framework.sms.core.enums.SmsFrameworkErrorCodeConstants; -import org.junit.jupiter.api.Test; -import org.mockito.InjectMocks; - -import static com.yunpian.sdk.constant.Code.*; -import static org.junit.jupiter.api.Assertions.assertEquals; - -/** - * {@link YunpianSmsCodeMapping} 的单元测试 - * - * @author 芋道源码 - */ -class YunpianSmsCodeMappingTest extends BaseMockitoUnitTest { - - @InjectMocks - private YunpianSmsCodeMapping codeMapping; - - @Test - public void testApply() { - assertEquals(GlobalErrorCodeConstants.SUCCESS, codeMapping.apply(String.valueOf(OK))); - assertEquals(SmsFrameworkErrorCodeConstants.SMS_API_PARAM_ERROR, codeMapping.apply(String.valueOf(ARGUMENT_MISSING))); - assertEquals(SmsFrameworkErrorCodeConstants.SMS_TEMPLATE_PARAM_ERROR, codeMapping.apply(String.valueOf(BAD_ARGUMENT_FORMAT))); - assertEquals(SmsFrameworkErrorCodeConstants.SMS_ACCOUNT_MONEY_NOT_ENOUGH, codeMapping.apply(String.valueOf(MONEY_NOT_ENOUGH))); - assertEquals(SmsFrameworkErrorCodeConstants.SMS_TEMPLATE_INVALID, codeMapping.apply(String.valueOf(TPL_NOT_FOUND))); - assertEquals(SmsFrameworkErrorCodeConstants.SMS_TEMPLATE_INVALID, codeMapping.apply(String.valueOf(TPL_NOT_VALID))); - assertEquals(SmsFrameworkErrorCodeConstants.SMS_SEND_BUSINESS_LIMIT_CONTROL, codeMapping.apply(String.valueOf(DUP_IN_SHORT_TIME))); - assertEquals(SmsFrameworkErrorCodeConstants.SMS_SEND_BUSINESS_LIMIT_CONTROL, codeMapping.apply(String.valueOf(TOO_MANY_TIME_IN_5))); - assertEquals(SmsFrameworkErrorCodeConstants.SMS_SEND_BUSINESS_LIMIT_CONTROL, codeMapping.apply(String.valueOf(DAY_LIMIT_PER_MOBILE))); - assertEquals(SmsFrameworkErrorCodeConstants.SMS_SEND_BUSINESS_LIMIT_CONTROL, codeMapping.apply(String.valueOf(HOUR_LIMIT_PER_MOBILE))); - assertEquals(SmsFrameworkErrorCodeConstants.SMS_MOBILE_BLACK, codeMapping.apply(String.valueOf(BLACK_PHONE_FILTER))); - assertEquals(SmsFrameworkErrorCodeConstants.SMS_SIGN_INVALID, codeMapping.apply(String.valueOf(SIGN_NOT_MATCH))); - assertEquals(SmsFrameworkErrorCodeConstants.SMS_SIGN_INVALID, codeMapping.apply(String.valueOf(SIGN_NOT_VALID))); - assertEquals(SmsFrameworkErrorCodeConstants.SMS_SIGN_INVALID, codeMapping.apply(String.valueOf(BAD_SIGN_FORMAT))); - assertEquals(SmsFrameworkErrorCodeConstants.SMS_ACCOUNT_INVALID, codeMapping.apply(String.valueOf(BAD_API_KEY))); - assertEquals(SmsFrameworkErrorCodeConstants.SMS_PERMISSION_DENY, codeMapping.apply(String.valueOf(API_NOT_ALLOWED))); - assertEquals(SmsFrameworkErrorCodeConstants.SMS_IP_DENY, codeMapping.apply(String.valueOf(IP_NOT_ALLOWED))); - } - -} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/test/java/cn/iocoder/yudao/framework/sms/core/client/impl/aliyun/AliyunSmsClientTest.java b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/test/java/cn/iocoder/yudao/framework/sms/core/client/impl/aliyun/AliyunSmsClientTest.java new file mode 100644 index 0000000..e65e23d --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/test/java/cn/iocoder/yudao/framework/sms/core/client/impl/aliyun/AliyunSmsClientTest.java @@ -0,0 +1,225 @@ +package cn.iocoder.yudao.framework.sms.core.client.impl.aliyun; + +import cn.hutool.core.util.ReflectUtil; +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import cn.iocoder.yudao.framework.common.core.KeyValue; +import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; +import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult; +import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO; +import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO; +import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO; +import cn.iocoder.yudao.framework.sms.core.enums.SmsTemplateAuditStatusEnum; +import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.date.DateUtils; +import cn.iocoder.yudao.framework.sms.core.enums.SmsFrameworkErrorCodeConstants; +import com.aliyuncs.AcsRequest; +import com.aliyuncs.IAcsClient; +import com.aliyuncs.dysmsapi.model.v20170525.QuerySmsTemplateRequest; +import com.aliyuncs.dysmsapi.model.v20170525.QuerySmsTemplateResponse; +import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest; +import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse; +import com.aliyuncs.exceptions.ClientException; +import com.google.common.collect.Lists; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentMatcher; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +import java.util.List; +import java.util.function.Function; + +import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.Mockito.when; + +/** + * {@link AliyunSmsClient} 的单元测试 + * + * @author 芋道源码 + */ +public class AliyunSmsClientTest extends BaseMockitoUnitTest { + + private final SmsChannelProperties properties = new SmsChannelProperties() + .setApiKey(randomString()) // 随机一个 apiKey,避免构建报错 + .setApiSecret(randomString()) // 随机一个 apiSecret,避免构建报错 + .setSignature("芋道源码"); + + @InjectMocks + private final AliyunSmsClient smsClient = new AliyunSmsClient(properties); + + @Mock + private IAcsClient client; + + @Test + public void testDoInit() { + // 准备参数 + // mock 方法 + + // 调用 + smsClient.doInit(); + // 断言 + assertNotSame(client, ReflectUtil.getFieldValue(smsClient, "acsClient")); + } + + @Test + @SuppressWarnings("unchecked") + public void testDoSendSms() throws ClientException { + // 准备参数 + Long sendLogId = randomLongId(); + String mobile = randomString(); + String apiTemplateId = randomString(); + List> templateParams = Lists.newArrayList( + new KeyValue<>("code", 1234), new KeyValue<>("op", "login")); + // mock 方法 + SendSmsResponse response = randomPojo(SendSmsResponse.class, o -> o.setCode("OK")); + when(client.getAcsResponse(argThat((ArgumentMatcher) acsRequest -> { + assertEquals(mobile, acsRequest.getPhoneNumbers()); + assertEquals(properties.getSignature(), acsRequest.getSignName()); + assertEquals(apiTemplateId, acsRequest.getTemplateCode()); + assertEquals(toJsonString(MapUtils.convertMap(templateParams)), acsRequest.getTemplateParam()); + assertEquals(sendLogId.toString(), acsRequest.getOutId()); + return true; + }))).thenReturn(response); + + // 调用 + SmsCommonResult result = smsClient.doSendSms(sendLogId, mobile, + apiTemplateId, templateParams); + // 断言 + assertEquals(response.getCode(), result.getApiCode()); + assertEquals(response.getMessage(), result.getApiMsg()); + assertEquals(GlobalErrorCodeConstants.SUCCESS.getCode(), result.getCode()); + assertEquals(GlobalErrorCodeConstants.SUCCESS.getMsg(), result.getMsg()); + assertEquals(response.getRequestId(), result.getApiRequestId()); + // 断言结果 + assertEquals(response.getBizId(), result.getData().getSerialNo()); + } + + @Test + public void testDoTParseSmsReceiveStatus() throws Throwable { + // 准备参数 + String text = "[\n" + + " {\n" + + " \"phone_number\" : \"13900000001\",\n" + + " \"send_time\" : \"2017-01-01 11:12:13\",\n" + + " \"report_time\" : \"2017-02-02 22:23:24\",\n" + + " \"success\" : true,\n" + + " \"err_code\" : \"DELIVERED\",\n" + + " \"err_msg\" : \"用户接收成功\",\n" + + " \"sms_size\" : \"1\",\n" + + " \"biz_id\" : \"12345\",\n" + + " \"out_id\" : \"67890\"\n" + + " }\n" + + "]"; + // mock 方法 + + // 调用 + List statuses = smsClient.doParseSmsReceiveStatus(text); + // 断言 + assertEquals(1, statuses.size()); + assertTrue(statuses.get(0).getSuccess()); + assertEquals("DELIVERED", statuses.get(0).getErrorCode()); + assertEquals("用户接收成功", statuses.get(0).getErrorMsg()); + assertEquals("13900000001", statuses.get(0).getMobile()); + assertEquals(DateUtils.buildTime(2017, 2, 2, 22, 23, 24), statuses.get(0).getReceiveTime()); + assertEquals("12345", statuses.get(0).getSerialNo()); + assertEquals(67890L, statuses.get(0).getLogId()); + } + + @Test + public void testDoGetSmsTemplate() throws ClientException { + // 准备参数 + String apiTemplateId = randomString(); + // mock 方法 + QuerySmsTemplateResponse response = randomPojo(QuerySmsTemplateResponse.class, o -> { + o.setCode("OK"); + o.setTemplateStatus(1); // 设置模板通过 + }); + when(client.getAcsResponse(argThat((ArgumentMatcher) acsRequest -> { + assertEquals(apiTemplateId, acsRequest.getTemplateCode()); + return true; + }))).thenReturn(response); + + // 调用 + SmsCommonResult result = smsClient.doGetSmsTemplate(apiTemplateId); + // 断言 + assertEquals(response.getCode(), result.getApiCode()); + assertEquals(response.getMessage(), result.getApiMsg()); + assertEquals(GlobalErrorCodeConstants.SUCCESS.getCode(), result.getCode()); + assertEquals(GlobalErrorCodeConstants.SUCCESS.getMsg(), result.getMsg()); + assertEquals(response.getRequestId(), result.getApiRequestId()); + // 断言结果 + assertEquals(response.getTemplateCode(), result.getData().getId()); + assertEquals(response.getTemplateContent(), result.getData().getContent()); + assertEquals(SmsTemplateAuditStatusEnum.SUCCESS.getStatus(), result.getData().getAuditStatus()); + assertEquals(response.getReason(), result.getData().getAuditReason()); + } + + @Test + public void testConvertSmsTemplateAuditStatus() { + assertEquals(SmsTemplateAuditStatusEnum.CHECKING.getStatus(), + smsClient.convertSmsTemplateAuditStatus(0)); + assertEquals(SmsTemplateAuditStatusEnum.SUCCESS.getStatus(), + smsClient.convertSmsTemplateAuditStatus(1)); + assertEquals(SmsTemplateAuditStatusEnum.FAIL.getStatus(), + smsClient.convertSmsTemplateAuditStatus(2)); + assertThrows(IllegalArgumentException.class, () -> smsClient.convertSmsTemplateAuditStatus(3), + "未知审核状态(3)"); + } + + @Test + @SuppressWarnings("unchecked") + public void testInvoke_throwable() throws ClientException { + // 准备参数 + QuerySmsTemplateRequest request = new QuerySmsTemplateRequest(); + // mock 方法 + ClientException ex = new ClientException("isv.INVALID_PARAMETERS", "参数不正确", randomString()); + when(client.getAcsResponse(any(AcsRequest.class))).thenThrow(ex); + + // 调用,并断言异常 + SmsCommonResult result = smsClient.invoke(request,null); + // 断言 + assertEquals(ex.getErrCode(), result.getApiCode()); + assertEquals(ex.getErrMsg(), result.getApiMsg()); + Assertions.assertEquals(SmsFrameworkErrorCodeConstants.SMS_API_PARAM_ERROR.getCode(), result.getCode()); + Assertions.assertEquals(SmsFrameworkErrorCodeConstants.SMS_API_PARAM_ERROR.getMsg(), result.getMsg()); + assertEquals(ex.getRequestId(), result.getApiRequestId()); + } + + @Test + public void testInvoke_success() throws ClientException { + // 准备参数 + QuerySmsTemplateRequest request = new QuerySmsTemplateRequest(); + Function responseConsumer = response -> { + SmsTemplateRespDTO data = new SmsTemplateRespDTO(); + data.setId(response.getTemplateCode()).setContent(response.getTemplateContent()); + data.setAuditStatus(SmsTemplateAuditStatusEnum.SUCCESS.getStatus()).setAuditReason(response.getReason()); + return data; + }; + // mock 方法 + QuerySmsTemplateResponse response = randomPojo(QuerySmsTemplateResponse.class, o -> { + o.setCode("OK"); + o.setTemplateStatus(1); // 设置模板通过 + }); + when(client.getAcsResponse(any(AcsRequest.class))).thenReturn(response); + + // 调用 + SmsCommonResult result = smsClient.invoke(request, responseConsumer); + // 断言 + assertEquals(response.getCode(), result.getApiCode()); + assertEquals(response.getMessage(), result.getApiMsg()); + assertEquals(GlobalErrorCodeConstants.SUCCESS.getCode(), result.getCode()); + assertEquals(GlobalErrorCodeConstants.SUCCESS.getMsg(), result.getMsg()); + assertEquals(response.getRequestId(), result.getApiRequestId()); + // 断言结果 + assertEquals(response.getTemplateCode(), result.getData().getId()); + assertEquals(response.getTemplateContent(), result.getData().getContent()); + assertEquals(SmsTemplateAuditStatusEnum.SUCCESS.getStatus(), result.getData().getAuditStatus()); + assertEquals(response.getReason(), result.getData().getAuditReason()); + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/test/java/cn/iocoder/yudao/framework/sms/core/client/impl/aliyun/AliyunSmsCodeMappingTest.java b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/test/java/cn/iocoder/yudao/framework/sms/core/client/impl/aliyun/AliyunSmsCodeMappingTest.java new file mode 100644 index 0000000..ef8901d --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/test/java/cn/iocoder/yudao/framework/sms/core/client/impl/aliyun/AliyunSmsCodeMappingTest.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.framework.sms.core.client.impl.aliyun; + +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; +import cn.iocoder.yudao.framework.sms.core.enums.SmsFrameworkErrorCodeConstants; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * {@link AliyunSmsCodeMapping} 的单元测试 + * + * @author 芋道源码 + */ +public class AliyunSmsCodeMappingTest extends BaseMockitoUnitTest { + + @InjectMocks + private AliyunSmsCodeMapping codeMapping; + + @Test + public void testApply() { + assertEquals(GlobalErrorCodeConstants.SUCCESS, codeMapping.apply("OK")); + assertEquals(SmsFrameworkErrorCodeConstants.SMS_ACCOUNT_INVALID, codeMapping.apply("MissingAccessKeyId")); + assertEquals(SmsFrameworkErrorCodeConstants.SMS_ACCOUNT_INVALID, codeMapping.apply("isv.ACCOUNT_NOT_EXISTS")); + assertEquals(SmsFrameworkErrorCodeConstants.SMS_ACCOUNT_INVALID, codeMapping.apply("isv.ACCOUNT_ABNORMAL")); + assertEquals(SmsFrameworkErrorCodeConstants.SMS_SEND_DAY_LIMIT_CONTROL, codeMapping.apply("isv.DAY_LIMIT_CONTROL")); + assertEquals(SmsFrameworkErrorCodeConstants.SMS_SEND_CONTENT_INVALID, codeMapping.apply("isv.SMS_CONTENT_ILLEGAL")); + assertEquals(SmsFrameworkErrorCodeConstants.SMS_SIGN_INVALID, codeMapping.apply("isv.SMS_SIGN_ILLEGAL")); + assertEquals(SmsFrameworkErrorCodeConstants.SMS_SIGN_INVALID, codeMapping.apply("isv.SIGN_NAME_ILLEGAL")); + assertEquals(SmsFrameworkErrorCodeConstants.SMS_PERMISSION_DENY, codeMapping.apply("isp.RAM_PERMISSION_DENY")); + assertEquals(SmsFrameworkErrorCodeConstants.SMS_ACCOUNT_MONEY_NOT_ENOUGH, codeMapping.apply("isv.OUT_OF_SERVICE")); + assertEquals(SmsFrameworkErrorCodeConstants.SMS_ACCOUNT_MONEY_NOT_ENOUGH, codeMapping.apply("isv.AMOUNT_NOT_ENOUGH")); + assertEquals(SmsFrameworkErrorCodeConstants.SMS_TEMPLATE_INVALID, codeMapping.apply("isv.SMS_TEMPLATE_ILLEGAL")); + assertEquals(SmsFrameworkErrorCodeConstants.SMS_SIGN_INVALID, codeMapping.apply("isv.SMS_SIGNATURE_ILLEGAL")); + assertEquals(SmsFrameworkErrorCodeConstants.SMS_API_PARAM_ERROR, codeMapping.apply("isv.INVALID_PARAMETERS")); + assertEquals(SmsFrameworkErrorCodeConstants.SMS_API_PARAM_ERROR, codeMapping.apply("isv.INVALID_JSON_PARAM")); + assertEquals(SmsFrameworkErrorCodeConstants.SMS_MOBILE_INVALID, codeMapping.apply("isv.MOBILE_NUMBER_ILLEGAL")); + assertEquals(SmsFrameworkErrorCodeConstants.SMS_TEMPLATE_PARAM_ERROR, codeMapping.apply("isv.TEMPLATE_MISSING_PARAMETERS")); + assertEquals(SmsFrameworkErrorCodeConstants.SMS_SEND_BUSINESS_LIMIT_CONTROL, codeMapping.apply("isv.BUSINESS_LIMIT_CONTROL")); + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/test/java/cn/iocoder/yudao/framework/sms/core/client/impl/yunpian/YunpianSmsClientTest.java b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/test/java/cn/iocoder/yudao/framework/sms/core/client/impl/yunpian/YunpianSmsClientTest.java new file mode 100644 index 0000000..8271c0d --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/test/java/cn/iocoder/yudao/framework/sms/core/client/impl/yunpian/YunpianSmsClientTest.java @@ -0,0 +1,202 @@ +package cn.iocoder.yudao.framework.sms.core.client.impl.yunpian; + +import cn.hutool.core.util.ReflectUtil; +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import cn.iocoder.yudao.framework.common.core.KeyValue; +import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; +import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult; +import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO; +import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO; +import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO; +import cn.iocoder.yudao.framework.sms.core.enums.SmsTemplateAuditStatusEnum; +import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties; +import cn.iocoder.yudao.framework.common.util.date.DateUtils; +import com.google.common.collect.Lists; +import com.yunpian.sdk.YunpianClient; +import com.yunpian.sdk.api.SmsApi; +import com.yunpian.sdk.api.TplApi; +import com.yunpian.sdk.constant.YunpianConstant; +import com.yunpian.sdk.model.Result; +import com.yunpian.sdk.model.SmsSingleSend; +import com.yunpian.sdk.model.Template; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.function.Supplier; + +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static com.yunpian.sdk.constant.Code.OK; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +/** + * 对 {@link YunpianSmsClient} 的单元测试 + * + * @author 芋道源码 + */ +public class YunpianSmsClientTest extends BaseMockitoUnitTest { + + private final SmsChannelProperties properties = new SmsChannelProperties() + .setApiKey(randomString()); // 随机一个 apiKey,避免构建报错 + + @InjectMocks + private final YunpianSmsClient smsClient = new YunpianSmsClient(properties); + + @Mock + private YunpianClient client; + + @Test + public void testDoInit() { + // 准备参数 + // mock 方法 + + // 调用 + smsClient.doInit(); + // 断言 + assertNotEquals(client, ReflectUtil.getFieldValue(smsClient, "client")); + verify(client, times(1)).close(); + } + + @Test + @SuppressWarnings("unchecked") + public void testDoSendSms() throws Throwable { + // 准备参数 + Long sendLogId = randomLongId(); + String mobile = randomString(); + String apiTemplateId = randomString(); + List> templateParams = Lists.newArrayList( + new KeyValue<>("code", 1234), new KeyValue<>("op", "login")); + // mock sms 方法 + SmsApi smsApi = mock(SmsApi.class); + when(client.sms()).thenReturn(smsApi); + // mock tpl_single_send 方法 + Map request = new HashMap<>(); + request.put(YunpianConstant.MOBILE, mobile); + request.put(YunpianConstant.TPL_ID, apiTemplateId); + request.put(YunpianConstant.TPL_VALUE, "#code#=1234&#op#=login"); + request.put(YunpianConstant.UID, String.valueOf(sendLogId)); + request.put(YunpianConstant.CALLBACK_URL, properties.getCallbackUrl()); + Result responseResult = randomPojo(Result.class, SmsSingleSend.class, + o -> o.setCode(OK)); // API 发送成功的 code + when(smsApi.tpl_single_send(eq(request))).thenReturn(responseResult); + + // 调用 + SmsCommonResult result = smsClient.doSendSms(sendLogId, mobile, + apiTemplateId, templateParams); + // 断言 + assertEquals(String.valueOf(responseResult.getCode()), result.getApiCode()); + assertEquals(responseResult.getMsg() + " => " + responseResult.getDetail(), result.getApiMsg()); + assertEquals(GlobalErrorCodeConstants.SUCCESS.getCode(), result.getCode()); + assertEquals(GlobalErrorCodeConstants.SUCCESS.getMsg(), result.getMsg()); + assertNull(result.getApiRequestId()); + // 断言结果 + assertEquals(String.valueOf(responseResult.getData().getSid()), result.getData().getSerialNo()); + } + + @Test + public void testDoParseSmsReceiveStatus() throws Throwable { + // 准备参数 + String text = "[{\"sid\":9527,\"uid\":1024,\"user_receive_time\":\"2014-03-17 22:55:21\",\"error_msg\":\"\",\"mobile\":\"15205201314\",\"report_status\":\"SUCCESS\"}]"; + // mock 方法 + + // 调用 + + // 断言 + // 调用 + List statuses = smsClient.doParseSmsReceiveStatus(text); + // 断言 + assertEquals(1, statuses.size()); + assertTrue(statuses.get(0).getSuccess()); + assertEquals("", statuses.get(0).getErrorCode()); + assertNull(statuses.get(0).getErrorMsg()); + assertEquals("15205201314", statuses.get(0).getMobile()); + assertEquals(DateUtils.buildTime(2014, 3, 17, 22, 55, 21), statuses.get(0).getReceiveTime()); + assertEquals("9527", statuses.get(0).getSerialNo()); + assertEquals(1024L, statuses.get(0).getLogId()); + } + + @Test + @SuppressWarnings("unchecked") + public void testDoGetSmsTemplate() throws Throwable { + // 准备参数 + String apiTemplateId = randomString(); + // mock tpl 方法 + TplApi tplApi = mock(TplApi.class); + when(client.tpl()).thenReturn(tplApi); + // mock get 方法 + Map request = new HashMap<>(); + request.put(YunpianConstant.APIKEY, properties.getApiKey()); + request.put(YunpianConstant.TPL_ID, apiTemplateId); + Result> responseResult = randomPojo(Result.class, List.class, o -> { + o.setCode(OK); // API 发送成功的 code + o.setData(randomPojoList(Template.class, t -> t.setCheck_status("SUCCESS"))); + }); + when(tplApi.get(eq(request))).thenReturn(responseResult); + + // 调用 + SmsCommonResult result = smsClient.doGetSmsTemplate(apiTemplateId); + // 断言 + assertEquals(String.valueOf(responseResult.getCode()), result.getApiCode()); + assertEquals(responseResult.getMsg() + " => " + responseResult.getDetail(), result.getApiMsg()); + assertEquals(GlobalErrorCodeConstants.SUCCESS.getCode(), result.getCode()); + assertEquals(GlobalErrorCodeConstants.SUCCESS.getMsg(), result.getMsg()); + assertNull(result.getApiRequestId()); + // 断言结果 + Template template = responseResult.getData().get(0); + assertEquals(template.getTpl_id().toString(), result.getData().getId()); + assertEquals(template.getTpl_content(), result.getData().getContent()); + assertEquals(SmsTemplateAuditStatusEnum.SUCCESS.getStatus(), result.getData().getAuditStatus()); + assertEquals(template.getReason(), result.getData().getAuditReason()); + } + + @Test + public void testConvertSmsTemplateAuditStatus() { + assertEquals(SmsTemplateAuditStatusEnum.CHECKING.getStatus(), + smsClient.convertSmsTemplateAuditStatus("CHECKING")); + assertEquals(SmsTemplateAuditStatusEnum.SUCCESS.getStatus(), + smsClient.convertSmsTemplateAuditStatus("SUCCESS")); + assertEquals(SmsTemplateAuditStatusEnum.FAIL.getStatus(), + smsClient.convertSmsTemplateAuditStatus("FAIL")); + assertThrows(IllegalArgumentException.class, () -> smsClient.convertSmsTemplateAuditStatus("test"), + "未知审核状态(test)"); + } + + @Test + public void testInvoke_throwable() { + // 准备参数 + Supplier> requestConsumer = + () -> new Result<>().setThrowable(new NullPointerException()); + // mock 方法 + + // 调用,并断言异常 + assertThrows(NullPointerException.class, + () -> smsClient.invoke(requestConsumer, null)); + } + + @Test + @SuppressWarnings("unchecked") + public void testInvoke_success() throws Throwable { + // 准备参数 + Result responseResult = randomPojo(Result.class, SmsSingleSend.class, o -> o.setCode(OK)); + Supplier> requestConsumer = () -> responseResult; + Function responseConsumer = + smsSingleSend -> new SmsSendRespDTO().setSerialNo(String.valueOf(responseResult.getData().getSid())); + // mock 方法 + + // 调用 + SmsCommonResult result = smsClient.invoke(requestConsumer, responseConsumer); + // 断言 + assertEquals(String.valueOf(responseResult.getCode()), result.getApiCode()); + assertEquals(responseResult.getMsg() + " => " + responseResult.getDetail(), result.getApiMsg()); + assertEquals(GlobalErrorCodeConstants.SUCCESS.getCode(), result.getCode()); + assertEquals(GlobalErrorCodeConstants.SUCCESS.getMsg(), result.getMsg()); + assertNull(result.getApiRequestId()); + assertEquals(String.valueOf(responseResult.getData().getSid()), result.getData().getSerialNo()); + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-sms/src/test/java/cn/iocoder/yudao/framework/sms/core/client/impl/yunpian/YunpianSmsCodeMappingTest.java b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/test/java/cn/iocoder/yudao/framework/sms/core/client/impl/yunpian/YunpianSmsCodeMappingTest.java new file mode 100644 index 0000000..8a292e3 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-sms/src/test/java/cn/iocoder/yudao/framework/sms/core/client/impl/yunpian/YunpianSmsCodeMappingTest.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.framework.sms.core.client.impl.yunpian; + +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; +import cn.iocoder.yudao.framework.sms.core.enums.SmsFrameworkErrorCodeConstants; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; + +import static com.yunpian.sdk.constant.Code.*; +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * {@link YunpianSmsCodeMapping} 的单元测试 + * + * @author 芋道源码 + */ +class YunpianSmsCodeMappingTest extends BaseMockitoUnitTest { + + @InjectMocks + private YunpianSmsCodeMapping codeMapping; + + @Test + public void testApply() { + assertEquals(GlobalErrorCodeConstants.SUCCESS, codeMapping.apply(String.valueOf(OK))); + Assertions.assertEquals(SmsFrameworkErrorCodeConstants.SMS_API_PARAM_ERROR, codeMapping.apply(String.valueOf(ARGUMENT_MISSING))); + assertEquals(SmsFrameworkErrorCodeConstants.SMS_TEMPLATE_PARAM_ERROR, codeMapping.apply(String.valueOf(BAD_ARGUMENT_FORMAT))); + assertEquals(SmsFrameworkErrorCodeConstants.SMS_ACCOUNT_MONEY_NOT_ENOUGH, codeMapping.apply(String.valueOf(MONEY_NOT_ENOUGH))); + assertEquals(SmsFrameworkErrorCodeConstants.SMS_TEMPLATE_INVALID, codeMapping.apply(String.valueOf(TPL_NOT_FOUND))); + assertEquals(SmsFrameworkErrorCodeConstants.SMS_TEMPLATE_INVALID, codeMapping.apply(String.valueOf(TPL_NOT_VALID))); + assertEquals(SmsFrameworkErrorCodeConstants.SMS_SEND_BUSINESS_LIMIT_CONTROL, codeMapping.apply(String.valueOf(DUP_IN_SHORT_TIME))); + assertEquals(SmsFrameworkErrorCodeConstants.SMS_SEND_BUSINESS_LIMIT_CONTROL, codeMapping.apply(String.valueOf(TOO_MANY_TIME_IN_5))); + assertEquals(SmsFrameworkErrorCodeConstants.SMS_SEND_BUSINESS_LIMIT_CONTROL, codeMapping.apply(String.valueOf(DAY_LIMIT_PER_MOBILE))); + assertEquals(SmsFrameworkErrorCodeConstants.SMS_SEND_BUSINESS_LIMIT_CONTROL, codeMapping.apply(String.valueOf(HOUR_LIMIT_PER_MOBILE))); + assertEquals(SmsFrameworkErrorCodeConstants.SMS_MOBILE_BLACK, codeMapping.apply(String.valueOf(BLACK_PHONE_FILTER))); + assertEquals(SmsFrameworkErrorCodeConstants.SMS_SIGN_INVALID, codeMapping.apply(String.valueOf(SIGN_NOT_MATCH))); + assertEquals(SmsFrameworkErrorCodeConstants.SMS_SIGN_INVALID, codeMapping.apply(String.valueOf(SIGN_NOT_VALID))); + assertEquals(SmsFrameworkErrorCodeConstants.SMS_SIGN_INVALID, codeMapping.apply(String.valueOf(BAD_SIGN_FORMAT))); + assertEquals(SmsFrameworkErrorCodeConstants.SMS_ACCOUNT_INVALID, codeMapping.apply(String.valueOf(BAD_API_KEY))); + assertEquals(SmsFrameworkErrorCodeConstants.SMS_PERMISSION_DENY, codeMapping.apply(String.valueOf(API_NOT_ALLOWED))); + assertEquals(SmsFrameworkErrorCodeConstants.SMS_IP_DENY, codeMapping.apply(String.valueOf(IP_NOT_ALLOWED))); + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/dashboard/framework/apollo/core/ConfigConsts.java b/yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/dashboard/framework/apollo/core/ConfigConsts.java deleted file mode 100644 index 8e0fe57..0000000 --- a/yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/dashboard/framework/apollo/core/ConfigConsts.java +++ /dev/null @@ -1,20 +0,0 @@ -package cn.iocoder.dashboard.framework.apollo.core; - -/** - * 针对 {@link com.ctrip.framework.apollo.core.ConfigConsts} 的补充,主要增加: - * - * 1. apollo.jdbc.* 配置项的枚举 - * - * @author 芋道源码 - */ -public class ConfigConsts { - - /** - * {@link cn.iocoder.dashboard.framework.apollo.internals.ConfigFrameworkDAO} 的实现类 - */ - public static final String APOLLO_JDBC_DAO = "apollo.jdbc.dao"; - public static final String APOLLO_JDBC_URL = "apollo.jdbc.url"; - public static final String APOLLO_JDBC_USERNAME = "apollo.jdbc.username"; - public static final String APOLLO_JDBC_PASSWORD = "apollo.jdbc.password"; - -} diff --git a/yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/dashboard/framework/apollo/internals/ConfigFrameworkDAO.java b/yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/dashboard/framework/apollo/internals/ConfigFrameworkDAO.java deleted file mode 100644 index 8f46b2d..0000000 --- a/yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/dashboard/framework/apollo/internals/ConfigFrameworkDAO.java +++ /dev/null @@ -1,32 +0,0 @@ -package cn.iocoder.dashboard.framework.apollo.internals; - -import cn.iocoder.dashboard.framework.apollo.internals.dto.ConfigRespDTO; - -import java.util.Date; -import java.util.List; - -/** - * 配置 Framework DAO 接口 - * - * 注意,实现类必须提供 (String jdbcUrl, String username, String password) 构造方法 - * - * @author 芋道源码 - */ -public interface ConfigFrameworkDAO { - - /** - * 查询是否存在比 maxUpdateTime 更新记录更晚的配置 - * - * @param maxUpdateTime 最大更新时间 - * @return 是否存在 - */ - boolean selectExistsByUpdateTimeAfter(Date maxUpdateTime); - - /** - * 查询配置列表 - * - * @return 配置列表 - */ - List selectList(); - -} diff --git a/yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/dashboard/framework/apollo/internals/DBConfigRepository.java b/yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/dashboard/framework/apollo/internals/DBConfigRepository.java deleted file mode 100644 index 97726d3..0000000 --- a/yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/dashboard/framework/apollo/internals/DBConfigRepository.java +++ /dev/null @@ -1,183 +0,0 @@ -package cn.iocoder.dashboard.framework.apollo.internals; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.ClassUtil; -import cn.hutool.core.util.ReflectUtil; -import cn.iocoder.dashboard.framework.apollo.core.ConfigConsts; -import cn.iocoder.dashboard.framework.apollo.internals.dto.ConfigRespDTO; -import com.ctrip.framework.apollo.Apollo; -import com.ctrip.framework.apollo.build.ApolloInjector; -import com.ctrip.framework.apollo.core.utils.ApolloThreadFactory; -import com.ctrip.framework.apollo.enums.ConfigSourceType; -import com.ctrip.framework.apollo.internals.AbstractConfigRepository; -import com.ctrip.framework.apollo.internals.ConfigRepository; -import com.ctrip.framework.apollo.tracer.Tracer; -import com.ctrip.framework.apollo.util.ConfigUtil; -import com.ctrip.framework.apollo.util.factory.PropertiesFactory; -import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; - -import java.lang.reflect.Constructor; -import java.util.Comparator; -import java.util.Date; -import java.util.List; -import java.util.Properties; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; - -@Slf4j -public class DBConfigRepository extends AbstractConfigRepository { - - private final static ScheduledExecutorService m_executorService; - - private static DBConfigRepository INSTANCE; - - static { - m_executorService = Executors.newScheduledThreadPool(1, - ApolloThreadFactory.create(DBConfigRepository.class.getSimpleName(), true)); - } - - private final ConfigUtil m_configUtil; - private final PropertiesFactory propertiesFactory; - private final String m_namespace; - - /** - * 配置缓存,使用 Properties 存储 - */ - private volatile Properties m_configCache; - /** - * 缓存配置的最大更新时间,用于后续的增量轮询,判断是否有更新 - */ - private volatile Date maxUpdateTime; - - /** - * 配置读取 DAO - */ - private final ConfigFrameworkDAO configFrameworkDAO; - - public DBConfigRepository(String namespace) { - // 初始化变量 - this.m_namespace = namespace; - this.propertiesFactory = ApolloInjector.getInstance(PropertiesFactory.class); - this.m_configUtil = ApolloInjector.getInstance(ConfigUtil.class); - // 初始化 DB - this.configFrameworkDAO = createConfigFrameworkDAO(); - - // 初始化加载 - this.trySync(); - // 初始化定时任务 - this.schedulePeriodicRefresh(); - - // 设置单例 - INSTANCE = this; - } - - @SneakyThrows - private static ConfigFrameworkDAO createConfigFrameworkDAO() { - String dao = System.getProperty(ConfigConsts.APOLLO_JDBC_DAO); - String url = System.getProperty(ConfigConsts.APOLLO_JDBC_URL); - String username = System.getProperty(ConfigConsts.APOLLO_JDBC_USERNAME); - String password = System.getProperty(ConfigConsts.APOLLO_JDBC_PASSWORD); - // 创建 DBConfigRepository 对象 - Class clazz = ClassUtil.loadClass(dao); - Constructor constructor = ReflectUtil.getConstructor(clazz, String.class, String.class, String.class); - return constructor.newInstance(url, username, password); - } - - /** - * 通知同步, - */ - public static void noticeSync() { - // 提交到线程池中,避免和 schedulePeriodicRefresh 并发问题 - m_executorService.submit(() -> { - INSTANCE.trySync(); - }); - } - - @Override - protected void sync() { - // 第一步,尝试获取配置 - List configs = this.loadConfigIfUpdate(this.maxUpdateTime); - if (CollUtil.isEmpty(configs)) { // 如果没有更新,则返回 - return; - } - - // 第二步,构建新的 Properties - Properties newProperties = this.buildProperties(configs); - this.m_configCache = newProperties; - // 第三步,获取最大的配置时间 - assert configs.size() > 0; // 断言,避免告警 - this.maxUpdateTime = configs.stream().max(Comparator.comparing(ConfigRespDTO::getUpdateTime)).get().getUpdateTime(); - // 第四部,触发配置刷新!重要!!!! - super.fireRepositoryChange(m_namespace, newProperties); - log.info("[sync][缓存配置,数量为:{}]", configs.size()); - } - - @Override - public Properties getConfig() { - // 兜底,避免可能存在配置为 null 的情况 - if (m_configCache == null) { - this.trySync(); - } - // 返回配置 - return m_configCache; - } - - @Override - public void setUpstreamRepository(ConfigRepository upstreamConfigRepository) { - // 啥事不做 - } - - @Override - public ConfigSourceType getSourceType() { - return ConfigSourceType.REMOTE; - } - - private Properties buildProperties(List configs) { - Properties properties = propertiesFactory.getPropertiesInstance(); - configs.stream().filter(ConfigRespDTO::getDeleted) // 过滤掉被删除的配置 - .forEach(config -> properties.put(config.getKey(), config.getValue())); - return properties; - } - - // ========== 定时器相关操作 ========== - - private void schedulePeriodicRefresh() { - log.debug("Schedule periodic refresh with interval: {} {}", - m_configUtil.getRefreshInterval(), m_configUtil.getRefreshIntervalTimeUnit()); - m_executorService.scheduleAtFixedRate(() -> { - Tracer.logEvent("Apollo.ConfigService", String.format("periodicRefresh: %s", m_namespace)); - log.debug("refresh config for namespace: {}", m_namespace); - - // 执行同步. 内部已经 try catch 掉异常,无需在处理 - trySync(); - - Tracer.logEvent("Apollo.Client.Version", Apollo.VERSION); - }, m_configUtil.getRefreshInterval(), m_configUtil.getRefreshInterval(), - m_configUtil.getRefreshIntervalTimeUnit()); - } - - // ========== 数据库相关操作 ========== - - /** - * 如果配置发生变化,从数据库中获取最新的全量配置。 - * 如果未发生变化,则返回空 - * - * @param maxUpdateTime 当前配置的最大更新时间 - * @return 配置列表 - */ - private List loadConfigIfUpdate(Date maxUpdateTime) { - // 第一步,判断是否要更新。 - if (maxUpdateTime == null) { // 如果更新时间为空,说明 DB 一定有新数据 - log.info("[loadConfigIfUpdate][首次加载全量配置]"); - } else { // 判断数据库中是否有更新的配置 - if (!configFrameworkDAO.selectExistsByUpdateTimeAfter(maxUpdateTime)) { - return null; - } - log.info("[loadConfigIfUpdate][增量加载全量配置]"); - } - // 第二步,如果有更新,则从数据库加载所有配置 - return configFrameworkDAO.selectList(); - } - -} diff --git a/yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/dashboard/framework/apollo/internals/DefaultXInjector.java b/yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/dashboard/framework/apollo/internals/DefaultXInjector.java deleted file mode 100644 index 587a850..0000000 --- a/yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/dashboard/framework/apollo/internals/DefaultXInjector.java +++ /dev/null @@ -1,75 +0,0 @@ -package cn.iocoder.dashboard.framework.apollo.internals; - -import cn.iocoder.dashboard.framework.apollo.spi.DBConfigFactory; -import com.ctrip.framework.apollo.exceptions.ApolloConfigException; -import com.ctrip.framework.apollo.internals.*; -import com.ctrip.framework.apollo.spi.*; -import com.ctrip.framework.apollo.tracer.Tracer; -import com.ctrip.framework.apollo.util.ConfigUtil; -import com.ctrip.framework.apollo.util.factory.DefaultPropertiesFactory; -import com.ctrip.framework.apollo.util.factory.PropertiesFactory; -import com.ctrip.framework.apollo.util.http.HttpUtil; -import com.ctrip.framework.apollo.util.yaml.YamlParser; -import com.google.inject.AbstractModule; -import com.google.inject.Guice; -import com.google.inject.Singleton; - -/** - * Guice injector - * - * 基于 Guice 注入器实现类 - * - * @author Jason Song(song_s@ctrip.com) - */ -public class DefaultXInjector implements Injector { - - private final com.google.inject.Injector m_injector; - - public DefaultXInjector() { - try { - m_injector = Guice.createInjector(new ApolloModule()); - } catch (Throwable ex) { - ApolloConfigException exception = new ApolloConfigException("Unable to initialize Guice Injector!", ex); - Tracer.logError(exception); - throw exception; - } - } - - @Override - public T getInstance(Class clazz) { - try { - return m_injector.getInstance(clazz); - } catch (Throwable ex) { - Tracer.logError(ex); - throw new ApolloConfigException(String.format("Unable to load instance for %s!", clazz.getName()), ex); - } - } - - @Override - public T getInstance(Class clazz, String name) { - // Guice does not support get instance by type and name - return null; - } - - private static class ApolloModule extends AbstractModule { - - @Override - protected void configure() { - bind(ConfigManager.class).to(DefaultConfigManager.class).in(Singleton.class); - bind(ConfigFactoryManager.class).to(DefaultConfigFactoryManager.class).in(Singleton.class); - bind(ConfigRegistry.class).to(DefaultConfigRegistry.class).in(Singleton.class); - - // 自定义 ConfigFactory 实现,使用 DB 作为数据源 - bind(ConfigFactory.class).to(DBConfigFactory.class).in(Singleton.class); - - bind(ConfigUtil.class).in(Singleton.class); - bind(HttpUtil.class).in(Singleton.class); - bind(ConfigServiceLocator.class).in(Singleton.class); - bind(RemoteConfigLongPollService.class).in(Singleton.class); - bind(YamlParser.class).in(Singleton.class); - bind(PropertiesFactory.class).to(DefaultPropertiesFactory.class).in(Singleton.class); - } - - } - -} diff --git a/yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/dashboard/framework/apollo/internals/dto/ConfigRespDTO.java b/yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/dashboard/framework/apollo/internals/dto/ConfigRespDTO.java deleted file mode 100644 index 3945dfb..0000000 --- a/yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/dashboard/framework/apollo/internals/dto/ConfigRespDTO.java +++ /dev/null @@ -1,33 +0,0 @@ -package cn.iocoder.dashboard.framework.apollo.internals.dto; - -import lombok.Data; - -import java.util.Date; - -/** - * 配置 Response DTO - * - * @author 芋道源码 - */ -@Data -public class ConfigRespDTO { - - /** - * 参数键名 - */ - private String key; - /** - * 参数键值 - */ - private String value; - - /** - * 是否删除 - */ - private Boolean deleted; - /** - * 更新时间 - */ - private Date updateTime; - -} diff --git a/yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/dashboard/framework/apollo/package-info.java b/yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/dashboard/framework/apollo/package-info.java deleted file mode 100644 index 0330411..0000000 --- a/yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/dashboard/framework/apollo/package-info.java +++ /dev/null @@ -1,13 +0,0 @@ -/** - * 配置中心客户端,基于 Apollo Client 进行简化 - * - * 差别在于,我们使用 {@link cn.iocoder.dashboard.modules.infra.dal.dataobject.config.InfConfigDO} 表作为配置源。 - * 当然,功能肯定也会相对少些,满足最小化诉求。 - * - * 1. 项目初始化时,可以使用 SysConfigDO 表的配置 - * 2. 使用 Spring @Value 可以注入属性 - * 3. SysConfigDO 表的配置修改时,注入到 @Value 的属性可以刷新 - * - * 另外,整个包结构会参考 Apollo 为主,方便维护与理解 - */ -package cn.iocoder.dashboard.framework.apollo; diff --git a/yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/dashboard/framework/apollo/spi/DBConfigFactory.java b/yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/dashboard/framework/apollo/spi/DBConfigFactory.java deleted file mode 100644 index bfa9e53..0000000 --- a/yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/dashboard/framework/apollo/spi/DBConfigFactory.java +++ /dev/null @@ -1,32 +0,0 @@ -package cn.iocoder.dashboard.framework.apollo.spi; - -import cn.iocoder.dashboard.framework.apollo.internals.DBConfigRepository; -import com.ctrip.framework.apollo.Config; -import com.ctrip.framework.apollo.ConfigFile; -import com.ctrip.framework.apollo.core.enums.ConfigFileFormat; -import com.ctrip.framework.apollo.internals.ConfigRepository; -import com.ctrip.framework.apollo.internals.DefaultConfig; -import com.ctrip.framework.apollo.spi.ConfigFactory; - -/** - * 基于 DB 的 ConfigFactory 实现类 - * - * @author 芋道源码 - */ -public class DBConfigFactory implements ConfigFactory { - - @Override - public Config create(String namespace) { - return new DefaultConfig(namespace, this.createDBConfigRepository(namespace)); - } - - @Override - public ConfigFile createConfigFile(String namespace, ConfigFileFormat configFileFormat) { - throw new UnsupportedOperationException("暂不支持 Apollo 配置文件"); - } - - private ConfigRepository createDBConfigRepository(String namespace) { - return new DBConfigRepository(namespace); - } - -} diff --git a/yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/dashboard/framework/apollo/spring/boot/ApolloApplicationContextInitializer.java b/yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/dashboard/framework/apollo/spring/boot/ApolloApplicationContextInitializer.java deleted file mode 100644 index 47af6b5..0000000 --- a/yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/dashboard/framework/apollo/spring/boot/ApolloApplicationContextInitializer.java +++ /dev/null @@ -1,63 +0,0 @@ -package cn.iocoder.dashboard.framework.apollo.spring.boot; - -import cn.iocoder.dashboard.framework.apollo.core.ConfigConsts; -import com.google.common.base.Strings; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.env.EnvironmentPostProcessor; -import org.springframework.core.Ordered; -import org.springframework.core.env.ConfigurableEnvironment; - -/** - * 对 {@link com.ctrip.framework.apollo.spring.boot.ApolloApplicationContextInitializer} 的补充,目前的目的有: - * - * 1. 将自定义的 apollo.jdbc 设置到 System 变量中 - * - * @author 芋道源码 - */ -public class ApolloApplicationContextInitializer implements EnvironmentPostProcessor, Ordered { - - /** - * 优先级更高,要早于 Apollo 的 ApolloApplicationContextInitializer 的初始化 - */ - public static final int DEFAULT_ORDER = -1; - - private int order = DEFAULT_ORDER; - - private static final String[] APOLLO_SYSTEM_PROPERTIES = {ConfigConsts.APOLLO_JDBC_DAO, - ConfigConsts.APOLLO_JDBC_URL, ConfigConsts.APOLLO_JDBC_USERNAME, ConfigConsts.APOLLO_JDBC_PASSWORD}; - - @Override - public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { - initializeSystemProperty(environment); - } - - /** - * To fill system properties from environment config - */ - void initializeSystemProperty(ConfigurableEnvironment environment) { - for (String propertyName : APOLLO_SYSTEM_PROPERTIES) { - fillSystemPropertyFromEnvironment(environment, propertyName); - } - } - - private void fillSystemPropertyFromEnvironment(ConfigurableEnvironment environment, String propertyName) { - if (System.getProperty(propertyName) != null) { - return; - } - String propertyValue = environment.getProperty(propertyName); - if (Strings.isNullOrEmpty(propertyValue)) { - return; - } - System.setProperty(propertyName, propertyValue); - } - - @Override - public int getOrder() { - return order; - } - - public void setOrder(int order) { - this.order = order; - } - -} diff --git a/yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/yudao/framework/apollo/core/ConfigConsts.java b/yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/yudao/framework/apollo/core/ConfigConsts.java new file mode 100644 index 0000000..0008a84 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/yudao/framework/apollo/core/ConfigConsts.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.framework.apollo.core; + +import cn.iocoder.yudao.framework.apollo.internals.ConfigFrameworkDAO; + +/** + * 针对 {@link com.ctrip.framework.apollo.core.ConfigConsts} 的补充,主要增加: + * + * 1. apollo.jdbc.* 配置项的枚举 + * + * @author 芋道源码 + */ +public class ConfigConsts { + + /** + * {@link ConfigFrameworkDAO} 的实现类 + */ + public static final String APOLLO_JDBC_DAO = "apollo.jdbc.dao"; + public static final String APOLLO_JDBC_URL = "apollo.jdbc.url"; + public static final String APOLLO_JDBC_USERNAME = "apollo.jdbc.username"; + public static final String APOLLO_JDBC_PASSWORD = "apollo.jdbc.password"; + +} diff --git a/yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/yudao/framework/apollo/internals/ConfigFrameworkDAO.java b/yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/yudao/framework/apollo/internals/ConfigFrameworkDAO.java new file mode 100644 index 0000000..c2fbd29 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/yudao/framework/apollo/internals/ConfigFrameworkDAO.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.framework.apollo.internals; + +import cn.iocoder.yudao.framework.apollo.internals.dto.ConfigRespDTO; + +import java.util.Date; +import java.util.List; + +/** + * 配置 Framework DAO 接口 + * + * 注意,实现类必须提供 (String jdbcUrl, String username, String password) 构造方法 + * + * @author 芋道源码 + */ +public interface ConfigFrameworkDAO { + + /** + * 查询是否存在比 maxUpdateTime 更新记录更晚的配置 + * + * @param maxUpdateTime 最大更新时间 + * @return 是否存在 + */ + boolean selectExistsByUpdateTimeAfter(Date maxUpdateTime); + + /** + * 查询配置列表 + * + * @return 配置列表 + */ + List selectList(); + +} diff --git a/yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/yudao/framework/apollo/internals/DBConfigRepository.java b/yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/yudao/framework/apollo/internals/DBConfigRepository.java new file mode 100644 index 0000000..c88038d --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/yudao/framework/apollo/internals/DBConfigRepository.java @@ -0,0 +1,183 @@ +package cn.iocoder.yudao.framework.apollo.internals; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ClassUtil; +import cn.hutool.core.util.ReflectUtil; +import cn.iocoder.yudao.framework.apollo.core.ConfigConsts; +import cn.iocoder.yudao.framework.apollo.internals.dto.ConfigRespDTO; +import com.ctrip.framework.apollo.Apollo; +import com.ctrip.framework.apollo.build.ApolloInjector; +import com.ctrip.framework.apollo.core.utils.ApolloThreadFactory; +import com.ctrip.framework.apollo.enums.ConfigSourceType; +import com.ctrip.framework.apollo.internals.AbstractConfigRepository; +import com.ctrip.framework.apollo.internals.ConfigRepository; +import com.ctrip.framework.apollo.tracer.Tracer; +import com.ctrip.framework.apollo.util.ConfigUtil; +import com.ctrip.framework.apollo.util.factory.PropertiesFactory; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; + +import java.lang.reflect.Constructor; +import java.util.Comparator; +import java.util.Date; +import java.util.List; +import java.util.Properties; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; + +@Slf4j +public class DBConfigRepository extends AbstractConfigRepository { + + private final static ScheduledExecutorService m_executorService; + + private static DBConfigRepository INSTANCE; + + static { + m_executorService = Executors.newScheduledThreadPool(1, + ApolloThreadFactory.create(DBConfigRepository.class.getSimpleName(), true)); + } + + private final ConfigUtil m_configUtil; + private final PropertiesFactory propertiesFactory; + private final String m_namespace; + + /** + * 配置缓存,使用 Properties 存储 + */ + private volatile Properties m_configCache; + /** + * 缓存配置的最大更新时间,用于后续的增量轮询,判断是否有更新 + */ + private volatile Date maxUpdateTime; + + /** + * 配置读取 DAO + */ + private final ConfigFrameworkDAO configFrameworkDAO; + + public DBConfigRepository(String namespace) { + // 初始化变量 + this.m_namespace = namespace; + this.propertiesFactory = ApolloInjector.getInstance(PropertiesFactory.class); + this.m_configUtil = ApolloInjector.getInstance(ConfigUtil.class); + // 初始化 DB + this.configFrameworkDAO = createConfigFrameworkDAO(); + + // 初始化加载 + this.trySync(); + // 初始化定时任务 + this.schedulePeriodicRefresh(); + + // 设置单例 + INSTANCE = this; + } + + @SneakyThrows + private static ConfigFrameworkDAO createConfigFrameworkDAO() { + String dao = System.getProperty(ConfigConsts.APOLLO_JDBC_DAO); + String url = System.getProperty(ConfigConsts.APOLLO_JDBC_URL); + String username = System.getProperty(ConfigConsts.APOLLO_JDBC_USERNAME); + String password = System.getProperty(ConfigConsts.APOLLO_JDBC_PASSWORD); + // 创建 DBConfigRepository 对象 + Class clazz = ClassUtil.loadClass(dao); + Constructor constructor = ReflectUtil.getConstructor(clazz, String.class, String.class, String.class); + return constructor.newInstance(url, username, password); + } + + /** + * 通知同步, + */ + public static void noticeSync() { + // 提交到线程池中,避免和 schedulePeriodicRefresh 并发问题 + m_executorService.submit(() -> { + INSTANCE.trySync(); + }); + } + + @Override + protected void sync() { + // 第一步,尝试获取配置 + List configs = this.loadConfigIfUpdate(this.maxUpdateTime); + if (CollUtil.isEmpty(configs)) { // 如果没有更新,则返回 + return; + } + + // 第二步,构建新的 Properties + Properties newProperties = this.buildProperties(configs); + this.m_configCache = newProperties; + // 第三步,获取最大的配置时间 + assert configs.size() > 0; // 断言,避免告警 + this.maxUpdateTime = configs.stream().max(Comparator.comparing(ConfigRespDTO::getUpdateTime)).get().getUpdateTime(); + // 第四部,触发配置刷新!重要!!!! + super.fireRepositoryChange(m_namespace, newProperties); + log.info("[sync][缓存配置,数量为:{}]", configs.size()); + } + + @Override + public Properties getConfig() { + // 兜底,避免可能存在配置为 null 的情况 + if (m_configCache == null) { + this.trySync(); + } + // 返回配置 + return m_configCache; + } + + @Override + public void setUpstreamRepository(ConfigRepository upstreamConfigRepository) { + // 啥事不做 + } + + @Override + public ConfigSourceType getSourceType() { + return ConfigSourceType.REMOTE; + } + + private Properties buildProperties(List configs) { + Properties properties = propertiesFactory.getPropertiesInstance(); + configs.stream().filter(ConfigRespDTO::getDeleted) // 过滤掉被删除的配置 + .forEach(config -> properties.put(config.getKey(), config.getValue())); + return properties; + } + + // ========== 定时器相关操作 ========== + + private void schedulePeriodicRefresh() { + log.debug("Schedule periodic refresh with interval: {} {}", + m_configUtil.getRefreshInterval(), m_configUtil.getRefreshIntervalTimeUnit()); + m_executorService.scheduleAtFixedRate(() -> { + Tracer.logEvent("Apollo.ConfigService", String.format("periodicRefresh: %s", m_namespace)); + log.debug("refresh config for namespace: {}", m_namespace); + + // 执行同步. 内部已经 try catch 掉异常,无需在处理 + trySync(); + + Tracer.logEvent("Apollo.Client.Version", Apollo.VERSION); + }, m_configUtil.getRefreshInterval(), m_configUtil.getRefreshInterval(), + m_configUtil.getRefreshIntervalTimeUnit()); + } + + // ========== 数据库相关操作 ========== + + /** + * 如果配置发生变化,从数据库中获取最新的全量配置。 + * 如果未发生变化,则返回空 + * + * @param maxUpdateTime 当前配置的最大更新时间 + * @return 配置列表 + */ + private List loadConfigIfUpdate(Date maxUpdateTime) { + // 第一步,判断是否要更新。 + if (maxUpdateTime == null) { // 如果更新时间为空,说明 DB 一定有新数据 + log.info("[loadConfigIfUpdate][首次加载全量配置]"); + } else { // 判断数据库中是否有更新的配置 + if (!configFrameworkDAO.selectExistsByUpdateTimeAfter(maxUpdateTime)) { + return null; + } + log.info("[loadConfigIfUpdate][增量加载全量配置]"); + } + // 第二步,如果有更新,则从数据库加载所有配置 + return configFrameworkDAO.selectList(); + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/yudao/framework/apollo/internals/DefaultXInjector.java b/yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/yudao/framework/apollo/internals/DefaultXInjector.java new file mode 100644 index 0000000..554bad4 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/yudao/framework/apollo/internals/DefaultXInjector.java @@ -0,0 +1,75 @@ +package cn.iocoder.yudao.framework.apollo.internals; + +import cn.iocoder.yudao.framework.apollo.spi.DBConfigFactory; +import com.ctrip.framework.apollo.exceptions.ApolloConfigException; +import com.ctrip.framework.apollo.internals.*; +import com.ctrip.framework.apollo.spi.*; +import com.ctrip.framework.apollo.tracer.Tracer; +import com.ctrip.framework.apollo.util.ConfigUtil; +import com.ctrip.framework.apollo.util.factory.DefaultPropertiesFactory; +import com.ctrip.framework.apollo.util.factory.PropertiesFactory; +import com.ctrip.framework.apollo.util.http.HttpUtil; +import com.ctrip.framework.apollo.util.yaml.YamlParser; +import com.google.inject.AbstractModule; +import com.google.inject.Guice; +import com.google.inject.Singleton; + +/** + * Guice injector + * + * 基于 Guice 注入器实现类 + * + * @author Jason Song(song_s@ctrip.com) + */ +public class DefaultXInjector implements Injector { + + private final com.google.inject.Injector m_injector; + + public DefaultXInjector() { + try { + m_injector = Guice.createInjector(new ApolloModule()); + } catch (Throwable ex) { + ApolloConfigException exception = new ApolloConfigException("Unable to initialize Guice Injector!", ex); + Tracer.logError(exception); + throw exception; + } + } + + @Override + public T getInstance(Class clazz) { + try { + return m_injector.getInstance(clazz); + } catch (Throwable ex) { + Tracer.logError(ex); + throw new ApolloConfigException(String.format("Unable to load instance for %s!", clazz.getName()), ex); + } + } + + @Override + public T getInstance(Class clazz, String name) { + // Guice does not support get instance by type and name + return null; + } + + private static class ApolloModule extends AbstractModule { + + @Override + protected void configure() { + bind(ConfigManager.class).to(DefaultConfigManager.class).in(Singleton.class); + bind(ConfigFactoryManager.class).to(DefaultConfigFactoryManager.class).in(Singleton.class); + bind(ConfigRegistry.class).to(DefaultConfigRegistry.class).in(Singleton.class); + + // 自定义 ConfigFactory 实现,使用 DB 作为数据源 + bind(ConfigFactory.class).to(DBConfigFactory.class).in(Singleton.class); + + bind(ConfigUtil.class).in(Singleton.class); + bind(HttpUtil.class).in(Singleton.class); + bind(ConfigServiceLocator.class).in(Singleton.class); + bind(RemoteConfigLongPollService.class).in(Singleton.class); + bind(YamlParser.class).in(Singleton.class); + bind(PropertiesFactory.class).to(DefaultPropertiesFactory.class).in(Singleton.class); + } + + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/yudao/framework/apollo/internals/dto/ConfigRespDTO.java b/yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/yudao/framework/apollo/internals/dto/ConfigRespDTO.java new file mode 100644 index 0000000..350c94e --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/yudao/framework/apollo/internals/dto/ConfigRespDTO.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.framework.apollo.internals.dto; + +import lombok.Data; + +import java.util.Date; + +/** + * 配置 Response DTO + * + * @author 芋道源码 + */ +@Data +public class ConfigRespDTO { + + /** + * 参数键名 + */ + private String key; + /** + * 参数键值 + */ + private String value; + + /** + * 是否删除 + */ + private Boolean deleted; + /** + * 更新时间 + */ + private Date updateTime; + +} diff --git a/yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/yudao/framework/apollo/package-info.java b/yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/yudao/framework/apollo/package-info.java new file mode 100644 index 0000000..d31ab43 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/yudao/framework/apollo/package-info.java @@ -0,0 +1,13 @@ +/** + * 配置中心客户端,基于 Apollo Client 进行简化 + * + * 差别在于,我们使用 cn.iocoder.yudao.modules.infra.dal.dataobject.config.InfConfigDO 表作为配置源。 + * 当然,功能肯定也会相对少些,满足最小化诉求。 + * + * 1. 项目初始化时,可以使用 SysConfigDO 表的配置 + * 2. 使用 Spring @Value 可以注入属性 + * 3. SysConfigDO 表的配置修改时,注入到 @Value 的属性可以刷新 + * + * 另外,整个包结构会参考 Apollo 为主,方便维护与理解 + */ +package cn.iocoder.yudao.framework.apollo; diff --git a/yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/yudao/framework/apollo/spi/DBConfigFactory.java b/yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/yudao/framework/apollo/spi/DBConfigFactory.java new file mode 100644 index 0000000..8b30031 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/yudao/framework/apollo/spi/DBConfigFactory.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.framework.apollo.spi; + +import cn.iocoder.yudao.framework.apollo.internals.DBConfigRepository; +import com.ctrip.framework.apollo.Config; +import com.ctrip.framework.apollo.ConfigFile; +import com.ctrip.framework.apollo.core.enums.ConfigFileFormat; +import com.ctrip.framework.apollo.internals.ConfigRepository; +import com.ctrip.framework.apollo.internals.DefaultConfig; +import com.ctrip.framework.apollo.spi.ConfigFactory; + +/** + * 基于 DB 的 ConfigFactory 实现类 + * + * @author 芋道源码 + */ +public class DBConfigFactory implements ConfigFactory { + + @Override + public Config create(String namespace) { + return new DefaultConfig(namespace, this.createDBConfigRepository(namespace)); + } + + @Override + public ConfigFile createConfigFile(String namespace, ConfigFileFormat configFileFormat) { + throw new UnsupportedOperationException("暂不支持 Apollo 配置文件"); + } + + private ConfigRepository createDBConfigRepository(String namespace) { + return new DBConfigRepository(namespace); + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/yudao/framework/apollo/spring/boot/ApolloApplicationContextInitializer.java b/yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/yudao/framework/apollo/spring/boot/ApolloApplicationContextInitializer.java new file mode 100644 index 0000000..b68ca76 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/yudao/framework/apollo/spring/boot/ApolloApplicationContextInitializer.java @@ -0,0 +1,63 @@ +package cn.iocoder.yudao.framework.apollo.spring.boot; + +import cn.iocoder.yudao.framework.apollo.core.ConfigConsts; +import com.google.common.base.Strings; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.env.EnvironmentPostProcessor; +import org.springframework.core.Ordered; +import org.springframework.core.env.ConfigurableEnvironment; + +/** + * 对 {@link com.ctrip.framework.apollo.spring.boot.ApolloApplicationContextInitializer} 的补充,目前的目的有: + * + * 1. 将自定义的 apollo.jdbc 设置到 System 变量中 + * + * @author 芋道源码 + */ +public class ApolloApplicationContextInitializer implements EnvironmentPostProcessor, Ordered { + + /** + * 优先级更高,要早于 Apollo 的 ApolloApplicationContextInitializer 的初始化 + */ + public static final int DEFAULT_ORDER = -1; + + private int order = DEFAULT_ORDER; + + private static final String[] APOLLO_SYSTEM_PROPERTIES = {ConfigConsts.APOLLO_JDBC_DAO, + ConfigConsts.APOLLO_JDBC_URL, ConfigConsts.APOLLO_JDBC_USERNAME, ConfigConsts.APOLLO_JDBC_PASSWORD}; + + @Override + public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { + initializeSystemProperty(environment); + } + + /** + * To fill system properties from environment config + */ + void initializeSystemProperty(ConfigurableEnvironment environment) { + for (String propertyName : APOLLO_SYSTEM_PROPERTIES) { + fillSystemPropertyFromEnvironment(environment, propertyName); + } + } + + private void fillSystemPropertyFromEnvironment(ConfigurableEnvironment environment, String propertyName) { + if (System.getProperty(propertyName) != null) { + return; + } + String propertyValue = environment.getProperty(propertyName); + if (Strings.isNullOrEmpty(propertyValue)) { + return; + } + System.setProperty(propertyName, propertyValue); + } + + @Override + public int getOrder() { + return order; + } + + public void setOrder(int order) { + this.order = order; + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-config/src/main/resources/META-INF/services/com.ctrip.framework.apollo.internals.Injector b/yudao-framework/yudao-spring-boot-starter-config/src/main/resources/META-INF/services/com.ctrip.framework.apollo.internals.Injector new file mode 100644 index 0000000..eb1d20e --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-config/src/main/resources/META-INF/services/com.ctrip.framework.apollo.internals.Injector @@ -0,0 +1 @@ +cn.iocoder.yudao.framework.apollo.internals.DefaultXInjector diff --git a/yudao-framework/yudao-spring-boot-starter-config/src/main/resources/META-INF/spring.factories b/yudao-framework/yudao-spring-boot-starter-config/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000..d98c85d --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-config/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.env.EnvironmentPostProcessor=\ + cn.iocoder.yudao.framework.apollo.spring.boot.ApolloApplicationContextInitializer diff --git a/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/convert/DictConvert.java b/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/convert/DictConvert.java index 6915097..beed26f 100644 --- a/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/convert/DictConvert.java +++ b/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/convert/DictConvert.java @@ -2,7 +2,7 @@ package cn.iocoder.yudao.framework.excel.core.convert; import cn.hutool.core.convert.Convert; import cn.iocoder.yudao.framework.dict.core.dto.DictDataRespDTO; -import cn.iocoder.yudao.framework.dict.core.util.DictUtils; +import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils; import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; import com.alibaba.excel.converters.Converter; import com.alibaba.excel.enums.CellDataTypeEnum; @@ -35,7 +35,7 @@ public class DictConvert implements Converter { // 使用字典解析 String type = getType(contentProperty); String label = cellData.getStringValue(); - DictDataRespDTO dictData = DictUtils.parseDictDataFromCache(type, label); + DictDataRespDTO dictData = DictFrameworkUtils.parseDictDataFromCache(type, label); if (dictData == null) { log.error("[convertToJavaData][type({}) 解析不掉 label({})]", type, label); return null; @@ -56,7 +56,7 @@ public class DictConvert implements Converter { // 使用字典格式化 String type = getType(contentProperty); String value = String.valueOf(object); - DictDataRespDTO dictData = DictUtils.getDictDataFromCache(type, value); + DictDataRespDTO dictData = DictFrameworkUtils.getDictDataFromCache(type, value); if (dictData == null) { log.error("[convertToExcelData][type({}) 转换不了 label({})]", type, value); return new CellData<>(""); diff --git a/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/dashboard/framework/quartz/config/QuartzConfig.java b/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/dashboard/framework/quartz/config/QuartzConfig.java deleted file mode 100644 index 30d8837..0000000 --- a/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/dashboard/framework/quartz/config/QuartzConfig.java +++ /dev/null @@ -1,18 +0,0 @@ -package cn.iocoder.dashboard.framework.quartz.config; - -import cn.iocoder.dashboard.framework.quartz.core.scheduler.SchedulerManager; -import org.quartz.Scheduler; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.scheduling.annotation.EnableScheduling; - -@Configuration -@EnableScheduling // 开启 Spring 自带的定时任务 -public class QuartzConfig { - - @Bean - public SchedulerManager schedulerManager(Scheduler scheduler) { - return new SchedulerManager(scheduler); - } - -} diff --git a/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/dashboard/framework/quartz/core/enums/JobDataKeyEnum.java b/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/dashboard/framework/quartz/core/enums/JobDataKeyEnum.java deleted file mode 100644 index 2849d1a..0000000 --- a/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/dashboard/framework/quartz/core/enums/JobDataKeyEnum.java +++ /dev/null @@ -1,14 +0,0 @@ -package cn.iocoder.dashboard.framework.quartz.core.enums; - -/** - * Quartz Job Data 的 key 枚举 - */ -public enum JobDataKeyEnum { - - JOB_ID, - JOB_HANDLER_NAME, - JOB_HANDLER_PARAM, - JOB_RETRY_COUNT, // 最大重试次数 - JOB_RETRY_INTERVAL, // 每次重试间隔 - -} diff --git a/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/dashboard/framework/quartz/core/handler/JobHandler.java b/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/dashboard/framework/quartz/core/handler/JobHandler.java deleted file mode 100644 index bdf8a1b..0000000 --- a/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/dashboard/framework/quartz/core/handler/JobHandler.java +++ /dev/null @@ -1,19 +0,0 @@ -package cn.iocoder.dashboard.framework.quartz.core.handler; - -/** - * 任务处理器 - * - * @author 芋道源码 - */ -public interface JobHandler { - - /** - * 执行任务 - * - * @param param 参数 - * @return 结果 - * @throws Exception 异常 - */ - String execute(String param) throws Exception; - -} diff --git a/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/dashboard/framework/quartz/core/handler/JobHandlerInvoker.java b/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/dashboard/framework/quartz/core/handler/JobHandlerInvoker.java deleted file mode 100644 index a3dc8bc..0000000 --- a/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/dashboard/framework/quartz/core/handler/JobHandlerInvoker.java +++ /dev/null @@ -1,113 +0,0 @@ -package cn.iocoder.dashboard.framework.quartz.core.handler; - -import cn.hutool.core.lang.Assert; -import cn.hutool.core.thread.ThreadUtil; -import cn.iocoder.dashboard.framework.quartz.core.enums.JobDataKeyEnum; -import cn.iocoder.dashboard.framework.quartz.core.service.JobLogFrameworkService; -import lombok.extern.slf4j.Slf4j; -import org.quartz.DisallowConcurrentExecution; -import org.quartz.JobExecutionContext; -import org.quartz.JobExecutionException; -import org.quartz.PersistJobDataAfterExecution; -import org.springframework.context.ApplicationContext; -import org.springframework.scheduling.quartz.QuartzJobBean; - -import javax.annotation.Resource; -import java.util.Date; - -import static cn.hutool.core.exceptions.ExceptionUtil.getRootCauseMessage; -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.diff; - -/** - * 基础 Job 调用者,负责调用 {@link JobHandler#execute(String)} 执行任务 - * - * @author 芋道源码 - */ -@DisallowConcurrentExecution -@PersistJobDataAfterExecution -@Slf4j -public class JobHandlerInvoker extends QuartzJobBean { - - @Resource - private ApplicationContext applicationContext; - - @Resource - private JobLogFrameworkService jobLogFrameworkService; - - @Override - protected void executeInternal(JobExecutionContext executionContext) throws JobExecutionException { - // 第一步,获得 Job 数据 - Long jobId = executionContext.getMergedJobDataMap().getLong(JobDataKeyEnum.JOB_ID.name()); - String jobHandlerName = executionContext.getMergedJobDataMap().getString(JobDataKeyEnum.JOB_HANDLER_NAME.name()); - String jobHandlerParam = executionContext.getMergedJobDataMap().getString(JobDataKeyEnum.JOB_HANDLER_PARAM.name()); - int refireCount = executionContext.getRefireCount(); - int retryCount = (Integer) executionContext.getMergedJobDataMap().getOrDefault(JobDataKeyEnum.JOB_RETRY_COUNT.name(), 0); - int retryInterval = (Integer) executionContext.getMergedJobDataMap().getOrDefault(JobDataKeyEnum.JOB_RETRY_INTERVAL.name(), 0); - - // 第二步,执行任务 - Long jobLogId = null; - Date startTime = new Date(); - String data = null; - Throwable exception = null; - try { - // 记录 Job 日志(初始) - jobLogId = jobLogFrameworkService.createJobLog(jobId, startTime, jobHandlerName, jobHandlerParam, refireCount + 1); - // 执行任务 - data = this.executeInternal(jobHandlerName, jobHandlerParam); - } catch (Throwable ex) { - exception = ex; - } - - // 第三步,记录执行日志 - this.updateJobLogResultAsync(jobLogId, startTime, data, exception, executionContext); - - // 第四步,处理有异常的情况 - handleException(exception, refireCount, retryCount, retryInterval); - } - - private String executeInternal(String jobHandlerName, String jobHandlerParam) throws Exception { - // 获得 JobHandler 对象 - JobHandler jobHandler = applicationContext.getBean(jobHandlerName, JobHandler.class); - Assert.notNull(jobHandler, "JobHandler 不会为空"); - // 执行任务 - return jobHandler.execute(jobHandlerParam); - } - - private void updateJobLogResultAsync(Long jobLogId, Date startTime, String data, Throwable exception, - JobExecutionContext executionContext) { - Date endTime = new Date(); - // 处理是否成功 - boolean success = exception == null; - if (!success) { - data = getRootCauseMessage(exception); - } - // 更新日志 - try { - jobLogFrameworkService.updateJobLogResultAsync(jobLogId, endTime, (int) diff(endTime, startTime), success, data); - } catch (Exception ex) { - log.error("[executeInternal][Job({}) logId({}) 记录执行日志失败({}/{})]", - executionContext.getJobDetail().getKey(), jobLogId, success, data); - } - } - - private void handleException(Throwable exception, - int refireCount, int retryCount, int retryInterval) throws JobExecutionException { - // 如果有异常,则进行重试 - if (exception == null) { - return; - } - // 情况一:如果到达重试上限,则直接抛出异常即可 - if (refireCount >= retryCount) { - throw new JobExecutionException(exception); - } - - // 情况二:如果未到达重试上限,则 sleep 一定间隔时间,然后重试 - // 这里使用 sleep 来实现,主要还是希望实现比较简单。因为,同一时间,不会存在大量失败的 Job。 - if (retryInterval > 0) { - ThreadUtil.sleep(retryInterval); - } - // 第二个参数,refireImmediately = true,表示立即重试 - throw new JobExecutionException(exception, true); - } - -} diff --git a/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/dashboard/framework/quartz/core/scheduler/SchedulerManager.java b/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/dashboard/framework/quartz/core/scheduler/SchedulerManager.java deleted file mode 100644 index e72c909..0000000 --- a/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/dashboard/framework/quartz/core/scheduler/SchedulerManager.java +++ /dev/null @@ -1,130 +0,0 @@ -package cn.iocoder.dashboard.framework.quartz.core.scheduler; - -import cn.iocoder.dashboard.framework.quartz.core.enums.JobDataKeyEnum; -import cn.iocoder.dashboard.framework.quartz.core.handler.JobHandlerInvoker; -import org.quartz.*; - -/** - * {@link org.quartz.Scheduler} 的管理器,负责创建任务 - * - * 考虑到实现的简洁性,我们使用 jobHandlerName 作为唯一标识,即: - * 1. Job 的 {@link JobDetail#getKey()} - * 2. Trigger 的 {@link Trigger#getKey()} - * - * 另外,jobHandlerName 对应到 Spring Bean 的名字,直接调用 - * - * @author 芋道源码 - */ -public class SchedulerManager { - - private final Scheduler scheduler; - - public SchedulerManager(Scheduler scheduler) { - this.scheduler = scheduler; - } - - /** - * 添加 Job 到 Quartz 中 - * - * @param jobId 任务编号 - * @param jobHandlerName 任务处理器的名字 - * @param jobHandlerParam 任务处理器的参数 - * @param cronExpression CRON 表达式 - * @param retryCount 重试次数 - * @param retryInterval 重试间隔 - * @throws SchedulerException 添加异常 - */ - public void addJob(Long jobId, String jobHandlerName, String jobHandlerParam, String cronExpression, - Integer retryCount, Integer retryInterval) - throws SchedulerException { - // 创建 JobDetail 对象 - JobDetail jobDetail = JobBuilder.newJob(JobHandlerInvoker.class) - .usingJobData(JobDataKeyEnum.JOB_ID.name(), jobId) - .usingJobData(JobDataKeyEnum.JOB_HANDLER_NAME.name(), jobHandlerName) - .withIdentity(jobHandlerName).build(); - // 创建 Trigger 对象 - Trigger trigger = this.buildTrigger(jobHandlerName, jobHandlerParam, cronExpression, retryCount, retryInterval); - // 新增调度 - scheduler.scheduleJob(jobDetail, trigger); - } - - /** - * 更新 Job 到 Quartz - * - * @param jobHandlerName 任务处理器的名字 - * @param jobHandlerParam 任务处理器的参数 - * @param cronExpression CRON 表达式 - * @param retryCount 重试次数 - * @param retryInterval 重试间隔 - * @throws SchedulerException 更新异常 - */ - public void updateJob(String jobHandlerName, String jobHandlerParam, String cronExpression, - Integer retryCount, Integer retryInterval) - throws SchedulerException { - // 创建新 Trigger 对象 - Trigger newTrigger = this.buildTrigger(jobHandlerName, jobHandlerParam, cronExpression, retryCount, retryInterval); - // 修改调度 - scheduler.rescheduleJob(new TriggerKey(jobHandlerName), newTrigger); - } - - /** - * 删除 Quartz 中的 Job - * - * @param jobHandlerName 任务处理器的名字 - * @throws SchedulerException 删除异常 - */ - public void deleteJob(String jobHandlerName) throws SchedulerException { - scheduler.deleteJob(new JobKey(jobHandlerName)); - } - - /** - * 暂停 Quartz 中的 Job - * - * @param jobHandlerName 任务处理器的名字 - * @throws SchedulerException 暂停异常 - */ - public void pauseJob(String jobHandlerName) throws SchedulerException { - scheduler.pauseJob(new JobKey(jobHandlerName)); - } - - /** - * 启动 Quartz 中的 Job - * - * @param jobHandlerName 任务处理器的名字 - * @throws SchedulerException 启动异常 - */ - public void resumeJob(String jobHandlerName) throws SchedulerException { - scheduler.resumeJob(new JobKey(jobHandlerName)); - scheduler.resumeTrigger(new TriggerKey(jobHandlerName)); - } - - /** - * 立即触发一次 Quartz 中的 Job - * - * @param jobId 任务编号 - * @param jobHandlerName 任务处理器的名字 - * @param jobHandlerParam 任务处理器的参数 - * @throws SchedulerException 触发异常 - */ - public void triggerJob(Long jobId, String jobHandlerName, String jobHandlerParam) - throws SchedulerException { - JobDataMap data = new JobDataMap(); // 无需重试,所以不设置 retryCount 和 retryInterval - data.put(JobDataKeyEnum.JOB_ID.name(), jobId); - data.put(JobDataKeyEnum.JOB_HANDLER_NAME.name(), jobHandlerName); - data.put(JobDataKeyEnum.JOB_HANDLER_PARAM.name(), jobHandlerParam); - // 触发任务 - scheduler.triggerJob(new JobKey(jobHandlerName), data); - } - - private Trigger buildTrigger(String jobHandlerName, String jobHandlerParam, String cronExpression, - Integer retryCount, Integer retryInterval) { - return TriggerBuilder.newTrigger() - .withIdentity(jobHandlerName) - .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression)) - .usingJobData(JobDataKeyEnum.JOB_HANDLER_PARAM.name(), jobHandlerParam) - .usingJobData(JobDataKeyEnum.JOB_RETRY_COUNT.name(), retryCount) - .usingJobData(JobDataKeyEnum.JOB_RETRY_INTERVAL.name(), retryInterval) - .build(); - } - -} diff --git a/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/dashboard/framework/quartz/core/service/JobLogFrameworkService.java b/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/dashboard/framework/quartz/core/service/JobLogFrameworkService.java deleted file mode 100644 index a93dfdf..0000000 --- a/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/dashboard/framework/quartz/core/service/JobLogFrameworkService.java +++ /dev/null @@ -1,44 +0,0 @@ -package cn.iocoder.dashboard.framework.quartz.core.service; - -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; -import java.util.Date; - -/** - * Job 日志 Framework Service 接口 - * - * @author 芋道源码 - */ -public interface JobLogFrameworkService { - - /** - * 创建 Job 日志 - * - * @param jobId 任务编号 - * @param beginTime 开始时间 - * @param jobHandlerName Job 处理器的名字 - * @param jobHandlerParam Job 处理器的参数 - * @param executeIndex 第几次执行 - * @return Job 日志的编号 - */ - Long createJobLog(@NotNull(message = "任务编号不能为空") Long jobId, - @NotNull(message = "开始时间") Date beginTime, - @NotEmpty(message = "Job 处理器的名字不能为空") String jobHandlerName, - String jobHandlerParam, - @NotNull(message = "第几次执行不能为空") Integer executeIndex); - - /** - * 更新 Job 日志的执行结果 - * - * @param logId 日志编号 - * @param endTime 结束时间。因为是异步,避免记录时间不准去 - * @param duration 运行时长,单位:毫秒 - * @param success 是否成功 - * @param result 成功数据 - */ - void updateJobLogResultAsync(@NotNull(message = "日志编号不能为空") Long logId, - @NotNull(message = "结束时间不能为空") Date endTime, - @NotNull(message = "运行时长不能为空") Integer duration, - boolean success, String result); - -} diff --git a/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/dashboard/framework/quartz/core/util/CronUtils.java b/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/dashboard/framework/quartz/core/util/CronUtils.java deleted file mode 100644 index 62ba408..0000000 --- a/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/dashboard/framework/quartz/core/util/CronUtils.java +++ /dev/null @@ -1,54 +0,0 @@ -package cn.iocoder.dashboard.framework.quartz.core.util; - -import org.quartz.CronExpression; - -import java.text.ParseException; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; - -/** - * Quartz Cron 表达式的工具类 - * - * @author 芋道源码 - */ -public class CronUtils { - - /** - * 校验 CRON 表达式是否有效 - * - * @param cronExpression CRON 表达式 - * @return 是否有效 - */ - public static boolean isValid(String cronExpression) { - return CronExpression.isValidExpression(cronExpression); - } - - /** - * 基于 CRON 表达式,获得下 n 个满足执行的时间 - * - * @param cronExpression CRON 表达式 - * @param n 数量 - * @return 满足条件的执行时间 - */ - public static List getNextTimes(String cronExpression, int n) { - // 获得 CronExpression 对象 - CronExpression cron; - try { - cron = new CronExpression(cronExpression); - } catch (ParseException e) { - throw new IllegalArgumentException(e.getMessage()); - } - // 从当前开始计算,n 个满足条件的 - Date now = new Date(); - List nextTimes = new ArrayList<>(n); - for (int i = 0; i < n; i++) { - Date nextTime = cron.getNextValidTimeAfter(now); - nextTimes.add(nextTime); - // 切换现在,为下一个触发时间; - now = nextTime; - } - return nextTimes; - } - -} diff --git a/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/dashboard/framework/quartz/package-info.java b/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/dashboard/framework/quartz/package-info.java deleted file mode 100644 index 79d9eeb..0000000 --- a/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/dashboard/framework/quartz/package-info.java +++ /dev/null @@ -1,5 +0,0 @@ -/** - * 定时任务,采用 Quartz 实现进程内的任务执行。 - * 考虑到高可用,使用 Quartz 自带的 MySQL 集群方案。 - */ -package cn.iocoder.dashboard.framework.quartz; diff --git a/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/config/YudaoQuartzAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/config/YudaoQuartzAutoConfiguration.java new file mode 100644 index 0000000..86c47fd --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/config/YudaoQuartzAutoConfiguration.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.framework.quartz.config; + +import cn.iocoder.yudao.framework.quartz.core.scheduler.SchedulerManager; +import org.quartz.Scheduler; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableScheduling; + +@Configuration +@EnableScheduling // 开启 Spring 自带的定时任务 +public class YudaoQuartzAutoConfiguration { + + @Bean + public SchedulerManager schedulerManager(Scheduler scheduler) { + return new SchedulerManager(scheduler); + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/enums/JobDataKeyEnum.java b/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/enums/JobDataKeyEnum.java new file mode 100644 index 0000000..3154c40 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/enums/JobDataKeyEnum.java @@ -0,0 +1,14 @@ +package cn.iocoder.yudao.framework.quartz.core.enums; + +/** + * Quartz Job Data 的 key 枚举 + */ +public enum JobDataKeyEnum { + + JOB_ID, + JOB_HANDLER_NAME, + JOB_HANDLER_PARAM, + JOB_RETRY_COUNT, // 最大重试次数 + JOB_RETRY_INTERVAL, // 每次重试间隔 + +} diff --git a/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/handler/JobHandler.java b/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/handler/JobHandler.java new file mode 100644 index 0000000..381e132 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/handler/JobHandler.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.framework.quartz.core.handler; + +/** + * 任务处理器 + * + * @author 芋道源码 + */ +public interface JobHandler { + + /** + * 执行任务 + * + * @param param 参数 + * @return 结果 + * @throws Exception 异常 + */ + String execute(String param) throws Exception; + +} diff --git a/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/handler/JobHandlerInvoker.java b/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/handler/JobHandlerInvoker.java new file mode 100644 index 0000000..d47be83 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/handler/JobHandlerInvoker.java @@ -0,0 +1,113 @@ +package cn.iocoder.yudao.framework.quartz.core.handler; + +import cn.hutool.core.lang.Assert; +import cn.hutool.core.thread.ThreadUtil; +import cn.iocoder.yudao.framework.quartz.core.enums.JobDataKeyEnum; +import cn.iocoder.yudao.framework.quartz.core.service.JobLogFrameworkService; +import lombok.extern.slf4j.Slf4j; +import org.quartz.DisallowConcurrentExecution; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; +import org.quartz.PersistJobDataAfterExecution; +import org.springframework.context.ApplicationContext; +import org.springframework.scheduling.quartz.QuartzJobBean; + +import javax.annotation.Resource; +import java.util.Date; + +import static cn.hutool.core.exceptions.ExceptionUtil.getRootCauseMessage; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.diff; + +/** + * 基础 Job 调用者,负责调用 {@link JobHandler#execute(String)} 执行任务 + * + * @author 芋道源码 + */ +@DisallowConcurrentExecution +@PersistJobDataAfterExecution +@Slf4j +public class JobHandlerInvoker extends QuartzJobBean { + + @Resource + private ApplicationContext applicationContext; + + @Resource + private JobLogFrameworkService jobLogFrameworkService; + + @Override + protected void executeInternal(JobExecutionContext executionContext) throws JobExecutionException { + // 第一步,获得 Job 数据 + Long jobId = executionContext.getMergedJobDataMap().getLong(JobDataKeyEnum.JOB_ID.name()); + String jobHandlerName = executionContext.getMergedJobDataMap().getString(JobDataKeyEnum.JOB_HANDLER_NAME.name()); + String jobHandlerParam = executionContext.getMergedJobDataMap().getString(JobDataKeyEnum.JOB_HANDLER_PARAM.name()); + int refireCount = executionContext.getRefireCount(); + int retryCount = (Integer) executionContext.getMergedJobDataMap().getOrDefault(JobDataKeyEnum.JOB_RETRY_COUNT.name(), 0); + int retryInterval = (Integer) executionContext.getMergedJobDataMap().getOrDefault(JobDataKeyEnum.JOB_RETRY_INTERVAL.name(), 0); + + // 第二步,执行任务 + Long jobLogId = null; + Date startTime = new Date(); + String data = null; + Throwable exception = null; + try { + // 记录 Job 日志(初始) + jobLogId = jobLogFrameworkService.createJobLog(jobId, startTime, jobHandlerName, jobHandlerParam, refireCount + 1); + // 执行任务 + data = this.executeInternal(jobHandlerName, jobHandlerParam); + } catch (Throwable ex) { + exception = ex; + } + + // 第三步,记录执行日志 + this.updateJobLogResultAsync(jobLogId, startTime, data, exception, executionContext); + + // 第四步,处理有异常的情况 + handleException(exception, refireCount, retryCount, retryInterval); + } + + private String executeInternal(String jobHandlerName, String jobHandlerParam) throws Exception { + // 获得 JobHandler 对象 + JobHandler jobHandler = applicationContext.getBean(jobHandlerName, JobHandler.class); + Assert.notNull(jobHandler, "JobHandler 不会为空"); + // 执行任务 + return jobHandler.execute(jobHandlerParam); + } + + private void updateJobLogResultAsync(Long jobLogId, Date startTime, String data, Throwable exception, + JobExecutionContext executionContext) { + Date endTime = new Date(); + // 处理是否成功 + boolean success = exception == null; + if (!success) { + data = getRootCauseMessage(exception); + } + // 更新日志 + try { + jobLogFrameworkService.updateJobLogResultAsync(jobLogId, endTime, (int) diff(endTime, startTime), success, data); + } catch (Exception ex) { + log.error("[executeInternal][Job({}) logId({}) 记录执行日志失败({}/{})]", + executionContext.getJobDetail().getKey(), jobLogId, success, data); + } + } + + private void handleException(Throwable exception, + int refireCount, int retryCount, int retryInterval) throws JobExecutionException { + // 如果有异常,则进行重试 + if (exception == null) { + return; + } + // 情况一:如果到达重试上限,则直接抛出异常即可 + if (refireCount >= retryCount) { + throw new JobExecutionException(exception); + } + + // 情况二:如果未到达重试上限,则 sleep 一定间隔时间,然后重试 + // 这里使用 sleep 来实现,主要还是希望实现比较简单。因为,同一时间,不会存在大量失败的 Job。 + if (retryInterval > 0) { + ThreadUtil.sleep(retryInterval); + } + // 第二个参数,refireImmediately = true,表示立即重试 + throw new JobExecutionException(exception, true); + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/scheduler/SchedulerManager.java b/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/scheduler/SchedulerManager.java new file mode 100644 index 0000000..1c8aa7b --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/scheduler/SchedulerManager.java @@ -0,0 +1,130 @@ +package cn.iocoder.yudao.framework.quartz.core.scheduler; + +import cn.iocoder.yudao.framework.quartz.core.enums.JobDataKeyEnum; +import cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker; +import org.quartz.*; + +/** + * {@link org.quartz.Scheduler} 的管理器,负责创建任务 + * + * 考虑到实现的简洁性,我们使用 jobHandlerName 作为唯一标识,即: + * 1. Job 的 {@link JobDetail#getKey()} + * 2. Trigger 的 {@link Trigger#getKey()} + * + * 另外,jobHandlerName 对应到 Spring Bean 的名字,直接调用 + * + * @author 芋道源码 + */ +public class SchedulerManager { + + private final Scheduler scheduler; + + public SchedulerManager(Scheduler scheduler) { + this.scheduler = scheduler; + } + + /** + * 添加 Job 到 Quartz 中 + * + * @param jobId 任务编号 + * @param jobHandlerName 任务处理器的名字 + * @param jobHandlerParam 任务处理器的参数 + * @param cronExpression CRON 表达式 + * @param retryCount 重试次数 + * @param retryInterval 重试间隔 + * @throws SchedulerException 添加异常 + */ + public void addJob(Long jobId, String jobHandlerName, String jobHandlerParam, String cronExpression, + Integer retryCount, Integer retryInterval) + throws SchedulerException { + // 创建 JobDetail 对象 + JobDetail jobDetail = JobBuilder.newJob(JobHandlerInvoker.class) + .usingJobData(JobDataKeyEnum.JOB_ID.name(), jobId) + .usingJobData(JobDataKeyEnum.JOB_HANDLER_NAME.name(), jobHandlerName) + .withIdentity(jobHandlerName).build(); + // 创建 Trigger 对象 + Trigger trigger = this.buildTrigger(jobHandlerName, jobHandlerParam, cronExpression, retryCount, retryInterval); + // 新增调度 + scheduler.scheduleJob(jobDetail, trigger); + } + + /** + * 更新 Job 到 Quartz + * + * @param jobHandlerName 任务处理器的名字 + * @param jobHandlerParam 任务处理器的参数 + * @param cronExpression CRON 表达式 + * @param retryCount 重试次数 + * @param retryInterval 重试间隔 + * @throws SchedulerException 更新异常 + */ + public void updateJob(String jobHandlerName, String jobHandlerParam, String cronExpression, + Integer retryCount, Integer retryInterval) + throws SchedulerException { + // 创建新 Trigger 对象 + Trigger newTrigger = this.buildTrigger(jobHandlerName, jobHandlerParam, cronExpression, retryCount, retryInterval); + // 修改调度 + scheduler.rescheduleJob(new TriggerKey(jobHandlerName), newTrigger); + } + + /** + * 删除 Quartz 中的 Job + * + * @param jobHandlerName 任务处理器的名字 + * @throws SchedulerException 删除异常 + */ + public void deleteJob(String jobHandlerName) throws SchedulerException { + scheduler.deleteJob(new JobKey(jobHandlerName)); + } + + /** + * 暂停 Quartz 中的 Job + * + * @param jobHandlerName 任务处理器的名字 + * @throws SchedulerException 暂停异常 + */ + public void pauseJob(String jobHandlerName) throws SchedulerException { + scheduler.pauseJob(new JobKey(jobHandlerName)); + } + + /** + * 启动 Quartz 中的 Job + * + * @param jobHandlerName 任务处理器的名字 + * @throws SchedulerException 启动异常 + */ + public void resumeJob(String jobHandlerName) throws SchedulerException { + scheduler.resumeJob(new JobKey(jobHandlerName)); + scheduler.resumeTrigger(new TriggerKey(jobHandlerName)); + } + + /** + * 立即触发一次 Quartz 中的 Job + * + * @param jobId 任务编号 + * @param jobHandlerName 任务处理器的名字 + * @param jobHandlerParam 任务处理器的参数 + * @throws SchedulerException 触发异常 + */ + public void triggerJob(Long jobId, String jobHandlerName, String jobHandlerParam) + throws SchedulerException { + JobDataMap data = new JobDataMap(); // 无需重试,所以不设置 retryCount 和 retryInterval + data.put(JobDataKeyEnum.JOB_ID.name(), jobId); + data.put(JobDataKeyEnum.JOB_HANDLER_NAME.name(), jobHandlerName); + data.put(JobDataKeyEnum.JOB_HANDLER_PARAM.name(), jobHandlerParam); + // 触发任务 + scheduler.triggerJob(new JobKey(jobHandlerName), data); + } + + private Trigger buildTrigger(String jobHandlerName, String jobHandlerParam, String cronExpression, + Integer retryCount, Integer retryInterval) { + return TriggerBuilder.newTrigger() + .withIdentity(jobHandlerName) + .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression)) + .usingJobData(JobDataKeyEnum.JOB_HANDLER_PARAM.name(), jobHandlerParam) + .usingJobData(JobDataKeyEnum.JOB_RETRY_COUNT.name(), retryCount) + .usingJobData(JobDataKeyEnum.JOB_RETRY_INTERVAL.name(), retryInterval) + .build(); + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/service/JobLogFrameworkService.java b/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/service/JobLogFrameworkService.java new file mode 100644 index 0000000..ca5d0cc --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/service/JobLogFrameworkService.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.framework.quartz.core.service; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.Date; + +/** + * Job 日志 Framework Service 接口 + * + * @author 芋道源码 + */ +public interface JobLogFrameworkService { + + /** + * 创建 Job 日志 + * + * @param jobId 任务编号 + * @param beginTime 开始时间 + * @param jobHandlerName Job 处理器的名字 + * @param jobHandlerParam Job 处理器的参数 + * @param executeIndex 第几次执行 + * @return Job 日志的编号 + */ + Long createJobLog(@NotNull(message = "任务编号不能为空") Long jobId, + @NotNull(message = "开始时间") Date beginTime, + @NotEmpty(message = "Job 处理器的名字不能为空") String jobHandlerName, + String jobHandlerParam, + @NotNull(message = "第几次执行不能为空") Integer executeIndex); + + /** + * 更新 Job 日志的执行结果 + * + * @param logId 日志编号 + * @param endTime 结束时间。因为是异步,避免记录时间不准去 + * @param duration 运行时长,单位:毫秒 + * @param success 是否成功 + * @param result 成功数据 + */ + void updateJobLogResultAsync(@NotNull(message = "日志编号不能为空") Long logId, + @NotNull(message = "结束时间不能为空") Date endTime, + @NotNull(message = "运行时长不能为空") Integer duration, + boolean success, String result); + +} diff --git a/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/util/CronUtils.java b/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/util/CronUtils.java new file mode 100644 index 0000000..ccef9b3 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/util/CronUtils.java @@ -0,0 +1,54 @@ +package cn.iocoder.yudao.framework.quartz.core.util; + +import org.quartz.CronExpression; + +import java.text.ParseException; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * Quartz Cron 表达式的工具类 + * + * @author 芋道源码 + */ +public class CronUtils { + + /** + * 校验 CRON 表达式是否有效 + * + * @param cronExpression CRON 表达式 + * @return 是否有效 + */ + public static boolean isValid(String cronExpression) { + return CronExpression.isValidExpression(cronExpression); + } + + /** + * 基于 CRON 表达式,获得下 n 个满足执行的时间 + * + * @param cronExpression CRON 表达式 + * @param n 数量 + * @return 满足条件的执行时间 + */ + public static List getNextTimes(String cronExpression, int n) { + // 获得 CronExpression 对象 + CronExpression cron; + try { + cron = new CronExpression(cronExpression); + } catch (ParseException e) { + throw new IllegalArgumentException(e.getMessage()); + } + // 从当前开始计算,n 个满足条件的 + Date now = new Date(); + List nextTimes = new ArrayList<>(n); + for (int i = 0; i < n; i++) { + Date nextTime = cron.getNextValidTimeAfter(now); + nextTimes.add(nextTime); + // 切换现在,为下一个触发时间; + now = nextTime; + } + return nextTimes; + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/package-info.java b/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/package-info.java new file mode 100644 index 0000000..69d6812 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/package-info.java @@ -0,0 +1,5 @@ +/** + * 定时任务,采用 Quartz 实现进程内的任务执行。 + * 考虑到高可用,使用 Quartz 自带的 MySQL 集群方案。 + */ +package cn.iocoder.yudao.framework.quartz; diff --git a/yudao-framework/yudao-spring-boot-starter-job/src/main/resources/META-INF/spring.factories b/yudao-framework/yudao-spring-boot-starter-job/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000..553b6e3 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-job/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ + cn.iocoder.yudao.framework.quartz.config.YudaoQuartzAutoConfiguration diff --git a/yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/config/TracerAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/config/TracerAutoConfiguration.java deleted file mode 100644 index 7209cd8..0000000 --- a/yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/config/TracerAutoConfiguration.java +++ /dev/null @@ -1,56 +0,0 @@ -package cn.iocoder.yudao.framework.tracer.config; - -import cn.iocoder.yudao.framework.tracer.core.aop.BizTraceAspect; -import cn.iocoder.yudao.framework.tracer.core.filter.TraceFilter; -import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum; -import io.opentracing.Tracer; -import org.apache.skywalking.apm.toolkit.opentracing.SkywalkingTracer; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.boot.web.servlet.FilterRegistrationBean; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -/** - * Tracer 配置类 - * - * @author mashu - */ -@Configuration -@ConditionalOnClass({BizTraceAspect.class}) -@EnableConfigurationProperties(TracerProperties.class) -@ConditionalOnProperty(prefix = "yudao.tracer", value = "enable", matchIfMissing = true) -public class TracerAutoConfiguration { - - @Bean - @ConditionalOnMissingBean - public TracerProperties bizTracerProperties() { - return new TracerProperties(); - } - - @Bean - @ConditionalOnMissingBean - public BizTraceAspect bizTracingAop() { - return new BizTraceAspect(); - } - - @Bean - @ConditionalOnMissingBean - public Tracer tracer() { - return new SkywalkingTracer(); - } - - /** - * 创建 TraceFilter 过滤器,响应 header 设置 traceId - */ - @Bean - public FilterRegistrationBean traceFilter() { - FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(); - registrationBean.setFilter(new TraceFilter()); - registrationBean.setOrder(WebFilterOrderEnum.TRACE_FILTER); - return registrationBean; - } - -} diff --git a/yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/config/YudaoTracerAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/config/YudaoTracerAutoConfiguration.java new file mode 100644 index 0000000..6c2422a --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/config/YudaoTracerAutoConfiguration.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.framework.tracer.config; + +import cn.iocoder.yudao.framework.tracer.core.aop.BizTraceAspect; +import cn.iocoder.yudao.framework.tracer.core.filter.TraceFilter; +import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum; +import io.opentracing.Tracer; +import org.apache.skywalking.apm.toolkit.opentracing.SkywalkingTracer; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * Tracer 配置类 + * + * @author mashu + */ +@Configuration +@ConditionalOnClass({BizTraceAspect.class}) +@EnableConfigurationProperties(TracerProperties.class) +@ConditionalOnProperty(prefix = "yudao.tracer", value = "enable", matchIfMissing = true) +public class YudaoTracerAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + public TracerProperties bizTracerProperties() { + return new TracerProperties(); + } + + @Bean + @ConditionalOnMissingBean + public BizTraceAspect bizTracingAop() { + return new BizTraceAspect(); + } + + @Bean + @ConditionalOnMissingBean + public Tracer tracer() { + return new SkywalkingTracer(); + } + + /** + * 创建 TraceFilter 过滤器,响应 header 设置 traceId + */ + @Bean + public FilterRegistrationBean traceFilter() { + FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(); + registrationBean.setFilter(new TraceFilter()); + registrationBean.setOrder(WebFilterOrderEnum.TRACE_FILTER); + return registrationBean; + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/《芋道 Spring Boot 链路追踪 SkyWalking 入门》.md b/yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/《芋道 Spring Boot 链路追踪 SkyWalking 入门》.md deleted file mode 100644 index ed9d4fe..0000000 --- a/yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/《芋道 Spring Boot 链路追踪 SkyWalking 入门》.md +++ /dev/null @@ -1 +0,0 @@ - diff --git a/yudao-framework/yudao-spring-boot-starter-monitor/src/main/resources/META-INF/spring.factories b/yudao-framework/yudao-spring-boot-starter-monitor/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000..6f4f606 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-monitor/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ + cn.iocoder.yudao.framework.tracer.config.YudaoTracerAutoConfiguration diff --git a/yudao-framework/yudao-spring-boot-starter-monitor/《芋道 Spring Boot 监控工具 Admin 入门》.md b/yudao-framework/yudao-spring-boot-starter-monitor/《芋道 Spring Boot 监控工具 Admin 入门》.md new file mode 100644 index 0000000..7f898b9 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-monitor/《芋道 Spring Boot 监控工具 Admin 入门》.md @@ -0,0 +1 @@ + diff --git a/yudao-framework/yudao-spring-boot-starter-monitor/《芋道 Spring Boot 监控端点 Actuator 入门》.md b/yudao-framework/yudao-spring-boot-starter-monitor/《芋道 Spring Boot 监控端点 Actuator 入门》.md new file mode 100644 index 0000000..b73a460 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-monitor/《芋道 Spring Boot 监控端点 Actuator 入门》.md @@ -0,0 +1 @@ + diff --git a/yudao-framework/yudao-spring-boot-starter-monitor/《芋道 Spring Boot 链路追踪 SkyWalking 入门》.md b/yudao-framework/yudao-spring-boot-starter-monitor/《芋道 Spring Boot 链路追踪 SkyWalking 入门》.md new file mode 100644 index 0000000..ed9d4fe --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-monitor/《芋道 Spring Boot 链路追踪 SkyWalking 入门》.md @@ -0,0 +1 @@ + diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml b/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml index 0daf802..e72fe0b 100644 --- a/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml +++ b/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml @@ -32,12 +32,6 @@ provided - - - - - - mysql diff --git a/yudao-framework/yudao-spring-boot-starter-protection/pom.xml b/yudao-framework/yudao-spring-boot-starter-protection/pom.xml index 16b5acf..b02d4a1 100644 --- a/yudao-framework/yudao-spring-boot-starter-protection/pom.xml +++ b/yudao-framework/yudao-spring-boot-starter-protection/pom.xml @@ -20,7 +20,6 @@ cn.iocoder.boot yudao-spring-boot-starter-redis - provided diff --git a/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/config/IdempotentConfiguration.java b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/config/IdempotentConfiguration.java deleted file mode 100644 index 4700379..0000000 --- a/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/config/IdempotentConfiguration.java +++ /dev/null @@ -1,42 +0,0 @@ -package cn.iocoder.yudao.framework.idempotent.config; - -import cn.iocoder.yudao.framework.idempotent.core.aop.IdempotentAspect; -import cn.iocoder.yudao.framework.idempotent.core.keyresolver.impl.DefaultIdempotentKeyResolver; -import cn.iocoder.yudao.framework.idempotent.core.keyresolver.impl.ExpressionIdempotentKeyResolver; -import cn.iocoder.yudao.framework.idempotent.core.keyresolver.IdempotentKeyResolver; -import cn.iocoder.yudao.framework.idempotent.core.redis.IdempotentRedisDAO; -import org.springframework.boot.autoconfigure.AutoConfigureAfter; -import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.data.redis.core.StringRedisTemplate; - -import java.util.List; - -@Configuration(proxyBeanMethods = false) -@AutoConfigureAfter(RedisAutoConfiguration.class) -public class IdempotentConfiguration { - - @Bean - public IdempotentAspect idempotentAspect(List keyResolvers, IdempotentRedisDAO idempotentRedisDAO) { - return new IdempotentAspect(keyResolvers, idempotentRedisDAO); - } - - @Bean - public IdempotentRedisDAO idempotentRedisDAO(StringRedisTemplate stringRedisTemplate) { - return new IdempotentRedisDAO(stringRedisTemplate); - } - - // ========== 各种 IdempotentKeyResolver Bean ========== - - @Bean - public DefaultIdempotentKeyResolver defaultIdempotentKeyResolver() { - return new DefaultIdempotentKeyResolver(); - } - - @Bean - public ExpressionIdempotentKeyResolver expressionIdempotentKeyResolver() { - return new ExpressionIdempotentKeyResolver(); - } - -} diff --git a/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/config/YudaoIdempotentConfiguration.java b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/config/YudaoIdempotentConfiguration.java new file mode 100644 index 0000000..8c39ffe --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/config/YudaoIdempotentConfiguration.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.framework.idempotent.config; + +import cn.iocoder.yudao.framework.idempotent.core.aop.IdempotentAspect; +import cn.iocoder.yudao.framework.idempotent.core.keyresolver.impl.DefaultIdempotentKeyResolver; +import cn.iocoder.yudao.framework.idempotent.core.keyresolver.impl.ExpressionIdempotentKeyResolver; +import cn.iocoder.yudao.framework.idempotent.core.keyresolver.IdempotentKeyResolver; +import cn.iocoder.yudao.framework.idempotent.core.redis.IdempotentRedisDAO; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.core.StringRedisTemplate; + +import java.util.List; + +@Configuration(proxyBeanMethods = false) +@AutoConfigureAfter(RedisAutoConfiguration.class) +public class YudaoIdempotentConfiguration { + + @Bean + public IdempotentAspect idempotentAspect(List keyResolvers, IdempotentRedisDAO idempotentRedisDAO) { + return new IdempotentAspect(keyResolvers, idempotentRedisDAO); + } + + @Bean + public IdempotentRedisDAO idempotentRedisDAO(StringRedisTemplate stringRedisTemplate) { + return new IdempotentRedisDAO(stringRedisTemplate); + } + + // ========== 各种 IdempotentKeyResolver Bean ========== + + @Bean + public DefaultIdempotentKeyResolver defaultIdempotentKeyResolver() { + return new DefaultIdempotentKeyResolver(); + } + + @Bean + public ExpressionIdempotentKeyResolver expressionIdempotentKeyResolver() { + return new ExpressionIdempotentKeyResolver(); + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/lock4j/config/Lock4jConfiguration.java b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/lock4j/config/Lock4jConfiguration.java deleted file mode 100644 index 567ff69..0000000 --- a/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/lock4j/config/Lock4jConfiguration.java +++ /dev/null @@ -1,23 +0,0 @@ -package cn.iocoder.yudao.framework.lock4j.config; - -import cn.hutool.core.util.ClassUtil; -import cn.iocoder.yudao.framework.lock4j.core.DefaultLockFailureStrategy; -import cn.iocoder.yudao.framework.lock4j.core.Lock4jRedisKeyConstants; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Configuration -public class Lock4jConfiguration { - - static { - // 手动加载 Lock4jRedisKeyConstants 类,因为它不会被使用到 - // 如果不加载,会导致 Redis 监控,看到它的 Redis Key 枚举 - ClassUtil.loadClass(Lock4jRedisKeyConstants.class.getName()); - } - - @Bean - public DefaultLockFailureStrategy lockFailureStrategy() { - return new DefaultLockFailureStrategy(); - } - -} diff --git a/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/lock4j/config/YudaoLock4jConfiguration.java b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/lock4j/config/YudaoLock4jConfiguration.java new file mode 100644 index 0000000..4919bf7 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/lock4j/config/YudaoLock4jConfiguration.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.framework.lock4j.config; + +import cn.hutool.core.util.ClassUtil; +import cn.iocoder.yudao.framework.lock4j.core.DefaultLockFailureStrategy; +import cn.iocoder.yudao.framework.lock4j.core.Lock4jRedisKeyConstants; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class YudaoLock4jConfiguration { + + static { + // 手动加载 Lock4jRedisKeyConstants 类,因为它不会被使用到 + // 如果不加载,会导致 Redis 监控,看到它的 Redis Key 枚举 + ClassUtil.loadClass(Lock4jRedisKeyConstants.class.getName()); + } + + @Bean + public DefaultLockFailureStrategy lockFailureStrategy() { + return new DefaultLockFailureStrategy(); + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-protection/src/main/resources/resources/META-INF/spring.factories b/yudao-framework/yudao-spring-boot-starter-protection/src/main/resources/resources/META-INF/spring.factories new file mode 100644 index 0000000..0e55a1f --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-protection/src/main/resources/resources/META-INF/spring.factories @@ -0,0 +1,3 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ + cn.iocoder.yudao.framework.idempotent.config.YudaoIdempotentConfiguration,\ + cn.iocoder.yudao.framework.lock4j.config.YudaoLock4jConfiguration diff --git a/yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/RedisConfig.java b/yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/RedisConfig.java deleted file mode 100644 index 354cb27..0000000 --- a/yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/RedisConfig.java +++ /dev/null @@ -1,119 +0,0 @@ -package cn.iocoder.yudao.framework.redis.config; - -import cn.hutool.system.SystemUtil; -import cn.iocoder.yudao.framework.redis.core.pubsub.AbstractChannelMessageListener; -import cn.iocoder.yudao.framework.redis.core.stream.AbstractStreamMessageListener; -import lombok.extern.slf4j.Slf4j; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.data.redis.connection.RedisConnectionFactory; -import org.springframework.data.redis.connection.stream.Consumer; -import org.springframework.data.redis.connection.stream.ObjectRecord; -import org.springframework.data.redis.connection.stream.ReadOffset; -import org.springframework.data.redis.connection.stream.StreamOffset; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.data.redis.listener.ChannelTopic; -import org.springframework.data.redis.listener.RedisMessageListenerContainer; -import org.springframework.data.redis.serializer.RedisSerializer; -import org.springframework.data.redis.stream.StreamMessageListenerContainer; - -import java.util.List; - -/** - * Redis 配置类 - */ -@Configuration -@Slf4j -public class RedisConfig { - - /** - * 创建 RedisTemplate Bean,使用 JSON 序列化方式 - */ - @Bean - public RedisTemplate redisTemplate(RedisConnectionFactory factory) { - // 创建 RedisTemplate 对象 - RedisTemplate template = new RedisTemplate<>(); - // 设置 RedisConnection 工厂。😈 它就是实现多种 Java Redis 客户端接入的秘密工厂。感兴趣的胖友,可以自己去撸下。 - template.setConnectionFactory(factory); - // 使用 String 序列化方式,序列化 KEY 。 - template.setKeySerializer(RedisSerializer.string()); - template.setHashKeySerializer(RedisSerializer.string()); - // 使用 JSON 序列化方式(库是 Jackson ),序列化 VALUE 。 - template.setValueSerializer(RedisSerializer.json()); - template.setHashValueSerializer(RedisSerializer.json()); - return template; - } - - /** - * 创建 Redis Pub/Sub 广播消费的容器 - */ - @Bean - public RedisMessageListenerContainer redisMessageListenerContainer( - RedisConnectionFactory factory, List> listeners) { - // 创建 RedisMessageListenerContainer 对象 - RedisMessageListenerContainer container = new RedisMessageListenerContainer(); - // 设置 RedisConnection 工厂。 - container.setConnectionFactory(factory); - // 添加监听器 - listeners.forEach(listener -> { - container.addMessageListener(listener, new ChannelTopic(listener.getChannel())); - log.info("[redisMessageListenerContainer][注册 Channel({}) 对应的监听器({})]", - listener.getChannel(), listener.getClass().getName()); - }); - return container; - } - - /** - * 创建 Redis Stream 集群消费的容器 - * - * Redis Stream 的 xreadgroup 命令:https://www.geek-book.com/src/docs/redis/redis/redis.io/commands/xreadgroup.html - */ - @Bean(initMethod = "start", destroyMethod = "stop") - public StreamMessageListenerContainer> redisStreamMessageListenerContainer( - RedisTemplate redisTemplate, List> listeners) { - // 第一步,创建 StreamMessageListenerContainer 容器 - // 创建 options 配置 - StreamMessageListenerContainer.StreamMessageListenerContainerOptions> containerOptions = - StreamMessageListenerContainer.StreamMessageListenerContainerOptions.builder() - .batchSize(10) // 一次性最多拉取多少条消息 - .targetType(String.class) // 目标类型。统一使用 String,通过自己封装的 AbstractStreamMessageListener 去反序列化 - .build(); - // 创建 container 对象 - StreamMessageListenerContainer> container = StreamMessageListenerContainer.create( - redisTemplate.getRequiredConnectionFactory(), containerOptions); - - // 第二步,注册监听器,消费对应的 Stream 主题 - String consumerName = buildConsumerName(); -// String consumerName = "110"; - listeners.forEach(listener -> { - // 创建 listener 对应的消费者分组 - try { - redisTemplate.opsForStream().createGroup(listener.getStreamKey(), listener.getGroup()); - } catch (Exception ignore) {} - // 设置 listener 对应的 redisTemplate - listener.setRedisTemplate(redisTemplate); - // 创建 Consumer 对象 - Consumer consumer = Consumer.from(listener.getGroup(), consumerName); - // 设置 Consumer 消费进度,以最小消费进度为准 - StreamOffset streamOffset = StreamOffset.create(listener.getStreamKey(), ReadOffset.lastConsumed()); - // 设置 Consumer 监听 - StreamMessageListenerContainer.StreamReadRequestBuilder builder = StreamMessageListenerContainer.StreamReadRequest - .builder(streamOffset).consumer(consumer) - .autoAcknowledge(false) // 不自动 ack - .cancelOnError(throwable -> false); // 默认配置,发生异常就取消消费,显然不符合预期;因此,我们设置为 false - container.register(builder.build(), listener); - }); - return container; - } - - /** - * 构建消费者名字,使用本地 IP + 进程编号的方式。 - * 参考自 RocketMQ clientId 的实现 - * - * @return 消费者名字 - */ - private static String buildConsumerName() { - return String.format("%s@%d", SystemUtil.getHostInfo().getAddress(), SystemUtil.getCurrentPID()); - } - -} diff --git a/yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoRedisAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoRedisAutoConfiguration.java new file mode 100644 index 0000000..4e9f0a0 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/config/YudaoRedisAutoConfiguration.java @@ -0,0 +1,119 @@ +package cn.iocoder.yudao.framework.redis.config; + +import cn.hutool.system.SystemUtil; +import cn.iocoder.yudao.framework.redis.core.pubsub.AbstractChannelMessageListener; +import cn.iocoder.yudao.framework.redis.core.stream.AbstractStreamMessageListener; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.connection.stream.Consumer; +import org.springframework.data.redis.connection.stream.ObjectRecord; +import org.springframework.data.redis.connection.stream.ReadOffset; +import org.springframework.data.redis.connection.stream.StreamOffset; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.listener.ChannelTopic; +import org.springframework.data.redis.listener.RedisMessageListenerContainer; +import org.springframework.data.redis.serializer.RedisSerializer; +import org.springframework.data.redis.stream.StreamMessageListenerContainer; + +import java.util.List; + +/** + * Redis 配置类 + */ +@Configuration +@Slf4j +public class YudaoRedisAutoConfiguration { + + /** + * 创建 RedisTemplate Bean,使用 JSON 序列化方式 + */ + @Bean + public RedisTemplate redisTemplate(RedisConnectionFactory factory) { + // 创建 RedisTemplate 对象 + RedisTemplate template = new RedisTemplate<>(); + // 设置 RedisConnection 工厂。😈 它就是实现多种 Java Redis 客户端接入的秘密工厂。感兴趣的胖友,可以自己去撸下。 + template.setConnectionFactory(factory); + // 使用 String 序列化方式,序列化 KEY 。 + template.setKeySerializer(RedisSerializer.string()); + template.setHashKeySerializer(RedisSerializer.string()); + // 使用 JSON 序列化方式(库是 Jackson ),序列化 VALUE 。 + template.setValueSerializer(RedisSerializer.json()); + template.setHashValueSerializer(RedisSerializer.json()); + return template; + } + + /** + * 创建 Redis Pub/Sub 广播消费的容器 + */ + @Bean + public RedisMessageListenerContainer redisMessageListenerContainer( + RedisConnectionFactory factory, List> listeners) { + // 创建 RedisMessageListenerContainer 对象 + RedisMessageListenerContainer container = new RedisMessageListenerContainer(); + // 设置 RedisConnection 工厂。 + container.setConnectionFactory(factory); + // 添加监听器 + listeners.forEach(listener -> { + container.addMessageListener(listener, new ChannelTopic(listener.getChannel())); + log.info("[redisMessageListenerContainer][注册 Channel({}) 对应的监听器({})]", + listener.getChannel(), listener.getClass().getName()); + }); + return container; + } + + /** + * 创建 Redis Stream 集群消费的容器 + * + * Redis Stream 的 xreadgroup 命令:https://www.geek-book.com/src/docs/redis/redis/redis.io/commands/xreadgroup.html + */ + @Bean(initMethod = "start", destroyMethod = "stop") + public StreamMessageListenerContainer> redisStreamMessageListenerContainer( + RedisTemplate redisTemplate, List> listeners) { + // 第一步,创建 StreamMessageListenerContainer 容器 + // 创建 options 配置 + StreamMessageListenerContainer.StreamMessageListenerContainerOptions> containerOptions = + StreamMessageListenerContainer.StreamMessageListenerContainerOptions.builder() + .batchSize(10) // 一次性最多拉取多少条消息 + .targetType(String.class) // 目标类型。统一使用 String,通过自己封装的 AbstractStreamMessageListener 去反序列化 + .build(); + // 创建 container 对象 + StreamMessageListenerContainer> container = StreamMessageListenerContainer.create( + redisTemplate.getRequiredConnectionFactory(), containerOptions); + + // 第二步,注册监听器,消费对应的 Stream 主题 + String consumerName = buildConsumerName(); +// String consumerName = "110"; + listeners.forEach(listener -> { + // 创建 listener 对应的消费者分组 + try { + redisTemplate.opsForStream().createGroup(listener.getStreamKey(), listener.getGroup()); + } catch (Exception ignore) {} + // 设置 listener 对应的 redisTemplate + listener.setRedisTemplate(redisTemplate); + // 创建 Consumer 对象 + Consumer consumer = Consumer.from(listener.getGroup(), consumerName); + // 设置 Consumer 消费进度,以最小消费进度为准 + StreamOffset streamOffset = StreamOffset.create(listener.getStreamKey(), ReadOffset.lastConsumed()); + // 设置 Consumer 监听 + StreamMessageListenerContainer.StreamReadRequestBuilder builder = StreamMessageListenerContainer.StreamReadRequest + .builder(streamOffset).consumer(consumer) + .autoAcknowledge(false) // 不自动 ack + .cancelOnError(throwable -> false); // 默认配置,发生异常就取消消费,显然不符合预期;因此,我们设置为 false + container.register(builder.build(), listener); + }); + return container; + } + + /** + * 构建消费者名字,使用本地 IP + 进程编号的方式。 + * 参考自 RocketMQ clientId 的实现 + * + * @return 消费者名字 + */ + private static String buildConsumerName() { + return String.format("%s@%d", SystemUtil.getHostInfo().getAddress(), SystemUtil.getCurrentPID()); + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-redis/src/main/resources/META-INF/spring.factories b/yudao-framework/yudao-spring-boot-starter-redis/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000..c76daf1 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-redis/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ + cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoSecurityAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoSecurityAutoConfiguration.java new file mode 100644 index 0000000..b9e0f34 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoSecurityAutoConfiguration.java @@ -0,0 +1,79 @@ +package cn.iocoder.yudao.framework.security.config; + +import cn.iocoder.yudao.framework.security.core.filter.JwtAuthenticationTokenFilter; +import cn.iocoder.yudao.framework.security.core.handler.AccessDeniedHandlerImpl; +import cn.iocoder.yudao.framework.security.core.handler.AuthenticationEntryPointImpl; +import cn.iocoder.yudao.framework.security.core.handler.LogoutSuccessHandlerImpl; +import cn.iocoder.yudao.framework.security.core.service.SecurityAuthFrameworkService; +import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.security.web.access.AccessDeniedHandler; +import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; + +import javax.annotation.Resource; + +/** + * Spring Security 自动配置类,主要用于相关组件的配置 + * + * 注意,不能和 {@link YudaoWebSecurityConfigurerAdapter} 用一个,原因是会导致初始化报错。 + * 参见 https://stackoverflow.com/questions/53847050/spring-boot-delegatebuilder-cannot-be-null-on-autowiring-authenticationmanager 文档。 + * + * @author 芋道源码 + */ +@Configuration +@EnableConfigurationProperties(SecurityProperties.class) +public class YudaoSecurityAutoConfiguration { + + @Resource + private SecurityProperties securityProperties; + + /** + * 认证失败处理类 Bean + */ + @Bean + public AuthenticationEntryPoint authenticationEntryPoint() { + return new AuthenticationEntryPointImpl(); + } + + /** + * 权限不够处理器 Bean + */ + @Bean + public AccessDeniedHandler accessDeniedHandler() { + return new AccessDeniedHandlerImpl(); + } + + /** + * 退出处理类 Bean + */ + @Bean + public LogoutSuccessHandler logoutSuccessHandler(SecurityAuthFrameworkService securityFrameworkService) { + return new LogoutSuccessHandlerImpl(securityProperties, securityFrameworkService); + } + + /** + * Spring Security 加密器 + * 考虑到安全性,这里采用 BCryptPasswordEncoder 加密器 + * + * @see Password Encoding with Spring Security + */ + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } + + /** + * Token 认证过滤器 Bean + */ + @Bean + public JwtAuthenticationTokenFilter authenticationTokenFilter(SecurityAuthFrameworkService securityFrameworkService, + GlobalExceptionHandler globalExceptionHandler) { + return new JwtAuthenticationTokenFilter(securityProperties, securityFrameworkService, globalExceptionHandler); + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoSecurityConfiguration.java b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoSecurityConfiguration.java deleted file mode 100644 index d095e90..0000000 --- a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoSecurityConfiguration.java +++ /dev/null @@ -1,167 +0,0 @@ -package cn.iocoder.yudao.framework.security.config; - -import cn.iocoder.yudao.framework.security.core.filter.JwtAuthenticationTokenFilter; -import cn.iocoder.yudao.framework.security.core.handler.LogoutSuccessHandlerImpl; -import cn.iocoder.yudao.framework.web.config.WebProperties; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.http.HttpMethod; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; -import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; -import org.springframework.security.config.http.SessionCreationPolicy; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.security.web.AuthenticationEntryPoint; -import org.springframework.security.web.access.AccessDeniedHandler; -import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; - -import javax.annotation.Resource; - -/** - * spring security配置 - * - * @author 芋道源码 - */ -@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true) -@EnableConfigurationProperties(SecurityProperties.class) -public class YudaoSecurityConfiguration extends WebSecurityConfigurerAdapter { - - /** - * 自定义用户认证逻辑 - */ - @Resource - private UserDetailsService userDetailsService; - - /** - * 认证失败处理类 - */ - @Resource - private AuthenticationEntryPoint unauthorizedHandler; - /** - * 权限不够处理器 - */ - @Resource - private AccessDeniedHandler accessDeniedHandler; - /** - * 退出处理类 - */ - @Resource - private LogoutSuccessHandlerImpl logoutSuccessHandler; - - /** - * Token 认证过滤器 - */ - @Resource - private JwtAuthenticationTokenFilter authenticationTokenFilter; - - @Resource - private WebProperties webProperties; - - @Value("${spring.boot.admin.context-path:''}") - private String adminSeverContextPath; - - /** - * 由于 Spring Security 创建 AuthenticationManager 对象时,没声明 @Bean 注解,导致无法被注入 - * 通过覆写父类的该方法,添加 @Bean 注解,解决该问题 - */ - @Override - @Bean - @ConditionalOnMissingBean(AuthenticationManager.class) - public AuthenticationManager authenticationManagerBean() throws Exception { - return super.authenticationManagerBean(); - } - - /** - * Spring Security 加密器 - * 考虑到安全性,这里采用 BCryptPasswordEncoder 加密器 - * - * @see Password Encoding with Spring Security - */ - @Bean - public PasswordEncoder passwordEncoder() { - return new BCryptPasswordEncoder(); - } - - /** - * 身份认证接口 - */ - @Override - protected void configure(AuthenticationManagerBuilder auth) throws Exception { - auth.userDetailsService(userDetailsService) - .passwordEncoder(passwordEncoder()); - } - - /** - * 配置 URL 的安全配置 - * - * anyRequest | 匹配所有请求路径 - * access | SpringEl表达式结果为true时可以访问 - * anonymous | 匿名可以访问 - * denyAll | 用户不能访问 - * fullyAuthenticated | 用户完全认证可以访问(非remember-me下自动登录) - * hasAnyAuthority | 如果有参数,参数表示权限,则其中任何一个权限可以访问 - * hasAnyRole | 如果有参数,参数表示角色,则其中任何一个角色可以访问 - * hasAuthority | 如果有参数,参数表示权限,则其权限可以访问 - * hasIpAddress | 如果有参数,参数表示IP地址,如果用户IP和参数匹配,则可以访问 - * hasRole | 如果有参数,参数表示角色,则其角色可以访问 - * permitAll | 用户可以任意访问 - * rememberMe | 允许通过remember-me登录的用户访问 - * authenticated | 用户登录后可访问 - */ - @Override - protected void configure(HttpSecurity httpSecurity) throws Exception { - httpSecurity - // 开启跨域 - .cors().and() - // CSRF 禁用,因为不使用 Session - .csrf().disable() - // 基于 token 机制,所以不需要 Session - .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() - // 一堆自定义的 Spring Security 处理器 - .exceptionHandling().authenticationEntryPoint(unauthorizedHandler) - .accessDeniedHandler(accessDeniedHandler).and() - // 设置每个请求的权限 - .authorizeRequests() - // 登陆的接口,可匿名访问 - .antMatchers(api("/login")).anonymous() - // 通用的接口,可匿名访问 TODO 芋艿:需要抽象出去 - .antMatchers(api("/system/captcha/**")).anonymous() - // 静态资源,可匿名访问 - .antMatchers(HttpMethod.GET, "/*.html", "/**/*.html", "/**/*.css", "/**/*.js").permitAll() - // 文件的获取接口,可匿名访问 - .antMatchers(api("/infra/file/get/**")).anonymous() - // Swagger 接口文档 - .antMatchers("/swagger-ui.html").anonymous() - .antMatchers("/swagger-resources/**").anonymous() - .antMatchers("/webjars/**").anonymous() - .antMatchers("/*/api-docs").anonymous() - // Spring Boot Admin Server 的安全配置 TODO 芋艿:需要抽象出去 - .antMatchers(adminSeverContextPath).anonymous() - .antMatchers(adminSeverContextPath + "/**").anonymous() - // Spring Boot Actuator 的安全配置 - .antMatchers("/actuator").anonymous() - .antMatchers("/actuator/**").anonymous() - // Druid 监控 TODO 芋艿:需要抽象出去 - .antMatchers("/druid/**").anonymous() - // 短信回调 API TODO 芋艿:需要抽象出去 - .antMatchers(api("/system/sms/callback/**")).anonymous() - // 除上面外的所有请求全部需要鉴权认证 - .anyRequest().authenticated() - .and() - .headers().frameOptions().disable(); - httpSecurity.logout().logoutUrl(api("/logout")).logoutSuccessHandler(logoutSuccessHandler); - // 添加 JWT Filter - httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); - } - - private String api(String url) { - return webProperties.getApiPrefix() + url; - } - -} diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java new file mode 100644 index 0000000..3d678ee --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/config/YudaoWebSecurityConfigurerAdapter.java @@ -0,0 +1,165 @@ +package cn.iocoder.yudao.framework.security.config; + +import cn.iocoder.yudao.framework.security.core.filter.JwtAuthenticationTokenFilter; +import cn.iocoder.yudao.framework.security.core.handler.AccessDeniedHandlerImpl; +import cn.iocoder.yudao.framework.security.core.handler.AuthenticationEntryPointImpl; +import cn.iocoder.yudao.framework.security.core.handler.LogoutSuccessHandlerImpl; +import cn.iocoder.yudao.framework.security.core.service.SecurityAuthFrameworkService; +import cn.iocoder.yudao.framework.web.config.WebProperties; +import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.security.web.access.AccessDeniedHandler; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; + +import javax.annotation.Resource; + +/** + * 自定义的 Spring Security 配置适配器实现 + * + * @author 芋道源码 + */ +@Configuration +@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true) +public class YudaoWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter { + + @Resource + private WebProperties webProperties; + + @Value("${spring.boot.admin.context-path:''}") + private String adminSeverContextPath; + + /** + * 自定义用户【认证】逻辑 + */ + @Resource + private UserDetailsService userDetailsService; + /** + * Spring Security 加密器 + */ + @Resource + private PasswordEncoder passwordEncoder; + /** + * 认证失败处理类 Bean + */ + @Resource + private AuthenticationEntryPoint authenticationEntryPoint; + /** + * 权限不够处理器 Bean + */ + @Resource + private AccessDeniedHandler accessDeniedHandler; + /** + * 退出处理类 Bean + */ + @Resource + private LogoutSuccessHandler logoutSuccessHandler; + /** + * Token 认证过滤器 Bean + */ + @Resource + private JwtAuthenticationTokenFilter authenticationTokenFilter; + + /** + * 由于 Spring Security 创建 AuthenticationManager 对象时,没声明 @Bean 注解,导致无法被注入 + * 通过覆写父类的该方法,添加 @Bean 注解,解决该问题 + */ + @Override + @Bean + @ConditionalOnMissingBean(AuthenticationManager.class) + public AuthenticationManager authenticationManagerBean() throws Exception { + return super.authenticationManagerBean(); + } + + /** + * 身份认证接口 + */ + @Override + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + auth.userDetailsService(userDetailsService) + .passwordEncoder(passwordEncoder); + } + + /** + * 配置 URL 的安全配置 + * + * anyRequest | 匹配所有请求路径 + * access | SpringEl表达式结果为true时可以访问 + * anonymous | 匿名可以访问 + * denyAll | 用户不能访问 + * fullyAuthenticated | 用户完全认证可以访问(非remember-me下自动登录) + * hasAnyAuthority | 如果有参数,参数表示权限,则其中任何一个权限可以访问 + * hasAnyRole | 如果有参数,参数表示角色,则其中任何一个角色可以访问 + * hasAuthority | 如果有参数,参数表示权限,则其权限可以访问 + * hasIpAddress | 如果有参数,参数表示IP地址,如果用户IP和参数匹配,则可以访问 + * hasRole | 如果有参数,参数表示角色,则其角色可以访问 + * permitAll | 用户可以任意访问 + * rememberMe | 允许通过remember-me登录的用户访问 + * authenticated | 用户登录后可访问 + */ + @Override + protected void configure(HttpSecurity httpSecurity) throws Exception { + httpSecurity + // 开启跨域 + .cors().and() + // CSRF 禁用,因为不使用 Session + .csrf().disable() + // 基于 token 机制,所以不需要 Session + .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() + // 一堆自定义的 Spring Security 处理器 + .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint) + .accessDeniedHandler(accessDeniedHandler).and() + // 设置每个请求的权限 + .authorizeRequests() + // 登陆的接口,可匿名访问 + .antMatchers(api("/login")).anonymous() + // 通用的接口,可匿名访问 TODO 芋艿:需要抽象出去 + .antMatchers(api("/system/captcha/**")).anonymous() + // 静态资源,可匿名访问 + .antMatchers(HttpMethod.GET, "/*.html", "/**/*.html", "/**/*.css", "/**/*.js").permitAll() + // 文件的获取接口,可匿名访问 + .antMatchers(api("/infra/file/get/**")).anonymous() + // Swagger 接口文档 + .antMatchers("/swagger-ui.html").anonymous() + .antMatchers("/swagger-resources/**").anonymous() + .antMatchers("/webjars/**").anonymous() + .antMatchers("/*/api-docs").anonymous() + // Spring Boot Admin Server 的安全配置 TODO 芋艿:需要抽象出去 + .antMatchers(adminSeverContextPath).anonymous() + .antMatchers(adminSeverContextPath + "/**").anonymous() + // Spring Boot Actuator 的安全配置 + .antMatchers("/actuator").anonymous() + .antMatchers("/actuator/**").anonymous() + // Druid 监控 TODO 芋艿:需要抽象出去 + .antMatchers("/druid/**").anonymous() + // 短信回调 API TODO 芋艿:需要抽象出去 + .antMatchers(api("/system/sms/callback/**")).anonymous() + // 除上面外的所有请求全部需要鉴权认证 + .anyRequest().authenticated() + .and() + .headers().frameOptions().disable(); + httpSecurity.logout().logoutUrl(api("/logout")).logoutSuccessHandler(logoutSuccessHandler); + // 添加 JWT Filter + httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); + } + + private String api(String url) { + return webProperties.getApiPrefix() + url; + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/filter/JwtAuthenticationTokenFilter.java b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/filter/JwtAuthenticationTokenFilter.java index 2f93433..d451c17 100644 --- a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/filter/JwtAuthenticationTokenFilter.java +++ b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/filter/JwtAuthenticationTokenFilter.java @@ -8,6 +8,7 @@ import cn.iocoder.yudao.framework.security.core.service.SecurityAuthFrameworkSer import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler; import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; +import lombok.AllArgsConstructor; import org.springframework.stereotype.Component; import org.springframework.web.filter.OncePerRequestFilter; @@ -24,15 +25,14 @@ import java.io.IOException; * * @author ruoyi */ -@Component +@AllArgsConstructor public class JwtAuthenticationTokenFilter extends OncePerRequestFilter { - @Resource - private SecurityProperties securityProperties; - @Resource - private SecurityAuthFrameworkService authService; - @Resource - private GlobalExceptionHandler globalExceptionHandler; + private final SecurityProperties securityProperties; + + private final SecurityAuthFrameworkService authService; + + private final GlobalExceptionHandler globalExceptionHandler; @Override @SuppressWarnings("NullableProblems") diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/handler/AccessDeniedHandlerImpl.java b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/handler/AccessDeniedHandlerImpl.java index 517df55..fa0c4b3 100644 --- a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/handler/AccessDeniedHandlerImpl.java +++ b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/handler/AccessDeniedHandlerImpl.java @@ -25,7 +25,6 @@ import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeC * * @author 芋道源码 */ -@Component @Slf4j @SuppressWarnings("JavadocReference") public class AccessDeniedHandlerImpl implements AccessDeniedHandler { @@ -35,7 +34,7 @@ public class AccessDeniedHandlerImpl implements AccessDeniedHandler { throws IOException, ServletException { // 打印 warn 的原因是,不定期合并 warn,看看有没恶意破坏 log.warn("[commence][访问 URL({}) 时,用户({}) 权限不够]", request.getRequestURI(), - SecurityFrameworkUtils.getLoginUser().getId(), e); + SecurityFrameworkUtils.getLoginUserId(), e); // 返回 403 ServletUtils.writeJSON(response, CommonResult.error(UNAUTHORIZED)); } diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/handler/AuthenticationEntryPointImpl.java b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/handler/AuthenticationEntryPointImpl.java index 380f5b7..0a451e0 100644 --- a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/handler/AuthenticationEntryPointImpl.java +++ b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/handler/AuthenticationEntryPointImpl.java @@ -7,7 +7,6 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.security.web.access.ExceptionTranslationFilter; -import org.springframework.stereotype.Component; import javax.servlet.FilterChain; import javax.servlet.http.HttpServletRequest; @@ -22,7 +21,6 @@ import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeC * * @author ruoyi */ -@Component @Slf4j @SuppressWarnings("JavadocReference") // 忽略文档引用报错 public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint { diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/handler/LogoutSuccessHandlerImpl.java b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/handler/LogoutSuccessHandlerImpl.java index ed61cf0..1bf8091 100644 --- a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/handler/LogoutSuccessHandlerImpl.java +++ b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/handler/LogoutSuccessHandlerImpl.java @@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.security.config.SecurityProperties; import cn.iocoder.yudao.framework.security.core.service.SecurityAuthFrameworkService; import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; +import lombok.AllArgsConstructor; import org.springframework.security.core.Authentication; import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; import org.springframework.stereotype.Component; @@ -20,14 +21,12 @@ import javax.servlet.http.HttpServletResponse; * * @author ruoyi */ -@Component +@AllArgsConstructor public class LogoutSuccessHandlerImpl implements LogoutSuccessHandler { - @Resource - private SecurityProperties securityProperties; + private final SecurityProperties securityProperties; - @Resource - private SecurityAuthFrameworkService securityFrameworkService; + private final SecurityAuthFrameworkService securityFrameworkService; @Override public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) { diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/resources/META-INF/spring.factories b/yudao-framework/yudao-spring-boot-starter-security/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000..564bb0f --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-security/src/main/resources/META-INF/spring.factories @@ -0,0 +1,3 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ + cn.iocoder.yudao.framework.security.config.YudaoSecurityAutoConfiguration,\ + cn.iocoder.yudao.framework.security.config.YudaoWebSecurityConfigurerAdapter diff --git a/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/dashboard/framework/test/core/ut/BaseMockitoUnitTest.java b/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/dashboard/framework/test/core/ut/BaseMockitoUnitTest.java deleted file mode 100644 index eb1f3d4..0000000 --- a/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/dashboard/framework/test/core/ut/BaseMockitoUnitTest.java +++ /dev/null @@ -1,13 +0,0 @@ -package cn.iocoder.dashboard.framework.test.core.ut; - -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.junit.jupiter.MockitoExtension; - -/** - * 纯 Mockito 的单元测试 - * - * @author 芋道源码 - */ -@ExtendWith(MockitoExtension.class) -public class BaseMockitoUnitTest { -} diff --git a/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/dashboard/framework/test/core/ut/package-info.java b/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/dashboard/framework/test/core/ut/package-info.java deleted file mode 100644 index 0f33dfb..0000000 --- a/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/dashboard/framework/test/core/ut/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * 提供单元测试 Unit Test 的基类 - */ -package cn.iocoder.dashboard.framework.test.core.ut; diff --git a/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/dashboard/framework/test/core/util/AssertUtils.java b/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/dashboard/framework/test/core/util/AssertUtils.java deleted file mode 100644 index 9f7e501..0000000 --- a/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/dashboard/framework/test/core/util/AssertUtils.java +++ /dev/null @@ -1,97 +0,0 @@ -package cn.iocoder.dashboard.framework.test.core.util; - -import cn.hutool.core.util.ArrayUtil; -import cn.hutool.core.util.ReflectUtil; -import cn.iocoder.yudao.framework.common.exception.ErrorCode; -import cn.iocoder.yudao.framework.common.exception.ServiceException; -import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.function.Executable; - -import java.lang.reflect.Field; -import java.util.Arrays; -import java.util.Objects; - -import static org.junit.jupiter.api.Assertions.assertThrows; - -/** - * 单元测试,assert 断言工具类 - * - * @author 芋道源码 - */ -public class AssertUtils { - - /** - * 比对两个对象的属性是否一致 - * - * 注意,如果 expected 存在的属性,actual 不存在的时候,会进行忽略 - * - * @param expected 期望对象 - * @param actual 实际对象 - * @param ignoreFields 忽略的属性数组 - */ - public static void assertPojoEquals(Object expected, Object actual, String... ignoreFields) { - Field[] expectedFields = ReflectUtil.getFields(expected.getClass()); - Arrays.stream(expectedFields).forEach(expectedField -> { - // 如果是忽略的属性,则不进行比对 - if (ArrayUtil.contains(ignoreFields, expectedField.getName())) { - return; - } - // 忽略不存在的属性 - Field actualField = ReflectUtil.getField(actual.getClass(), expectedField.getName()); - if (actualField == null) { - return; - } - // 比对 - Assertions.assertEquals( - ReflectUtil.getFieldValue(expected, expectedField), - ReflectUtil.getFieldValue(actual, actualField), - String.format("Field(%s) 不匹配", expectedField.getName()) - ); - }); - } - - /** - * 比对两个对象的属性是否一致 - * - * 注意,如果 expected 存在的属性,actual 不存在的时候,会进行忽略 - * - * @param expected 期望对象 - * @param actual 实际对象 - * @param ignoreFields 忽略的属性数组 - * @return 是否一致 - */ - public static boolean isPojoEquals(Object expected, Object actual, String... ignoreFields) { - Field[] expectedFields = ReflectUtil.getFields(expected.getClass()); - return Arrays.stream(expectedFields).allMatch(expectedField -> { - // 如果是忽略的属性,则不进行比对 - if (ArrayUtil.contains(ignoreFields, expectedField.getName())) { - return true; - } - // 忽略不存在的属性 - Field actualField = ReflectUtil.getField(actual.getClass(), expectedField.getName()); - if (actualField == null) { - return true; - } - return Objects.equals(ReflectUtil.getFieldValue(expected, expectedField), - ReflectUtil.getFieldValue(actual, actualField)); - }); - } - - /** - * 执行方法,校验抛出的 Service 是否符合条件 - * - * @param executable 业务异常 - * @param errorCode 错误码对象 - * @param messageParams 消息参数 - */ - public static void assertServiceException(Executable executable, ErrorCode errorCode, Object... messageParams) { - // 调用方法 - ServiceException serviceException = assertThrows(ServiceException.class, executable); - // 校验错误码 - Assertions.assertEquals(errorCode.getCode(), serviceException.getCode(), "错误码不匹配"); - String message = ServiceExceptionUtil.doFormat(errorCode.getCode(), errorCode.getMsg(), messageParams); - Assertions.assertEquals(message, serviceException.getMessage(), "错误提示不匹配"); - } - -} diff --git a/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/dashboard/framework/test/core/util/RandomUtils.java b/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/dashboard/framework/test/core/util/RandomUtils.java deleted file mode 100644 index 7ac7b28..0000000 --- a/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/dashboard/framework/test/core/util/RandomUtils.java +++ /dev/null @@ -1,100 +0,0 @@ -package cn.iocoder.dashboard.framework.test.core.util; - -import cn.hutool.core.util.ArrayUtil; -import cn.hutool.core.util.RandomUtil; -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; -import uk.co.jemos.podam.api.PodamFactory; -import uk.co.jemos.podam.api.PodamFactoryImpl; - -import java.lang.reflect.Type; -import java.util.*; -import java.util.function.Consumer; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -/** - * 随机工具类 - * - * @author 芋道源码 - */ -public class RandomUtils { - - private static final int RANDOM_STRING_LENGTH = 10; - - private static final int RANDOM_DATE_MAX = 30; - - private static final int RANDOM_COLLECTION_LENGTH = 5; - - private static final PodamFactory PODAM_FACTORY = new PodamFactoryImpl(); - - static { - // 字符串 - PODAM_FACTORY.getStrategy().addOrReplaceTypeManufacturer(String.class, - (dataProviderStrategy, attributeMetadata, map) -> randomString()); - // Boolean - PODAM_FACTORY.getStrategy().addOrReplaceTypeManufacturer(Boolean.class, (dataProviderStrategy, attributeMetadata, map) -> { - // 如果是 deleted 的字段,返回非删除 - if (attributeMetadata.getAttributeName().equals("deleted")) { - return false; - } - return RandomUtil.randomBoolean(); - }); - } - - public static String randomString() { - return RandomUtil.randomString(RANDOM_STRING_LENGTH); - } - - public static Long randomLongId() { - return RandomUtil.randomLong(0, Long.MAX_VALUE); - } - - public static Integer randomInteger() { - return RandomUtil.randomInt(0, Integer.MAX_VALUE); - } - - public static Date randomDate() { - return RandomUtil.randomDay(0, RANDOM_DATE_MAX); - } - - public static Short randomShort() { - return (short) RandomUtil.randomInt(0, Short.MAX_VALUE); - } - - public static Set randomSet(Class clazz) { - return Stream.iterate(0, i -> i).limit(RandomUtil.randomInt(0, RANDOM_DATE_MAX)) - .map(i -> randomPojo(clazz)).collect(Collectors.toSet()); - } - - public static Integer randomCommonStatus() { - return RandomUtil.randomEle(CommonStatusEnum.values()).getStatus(); - } - - @SafeVarargs - public static T randomPojo(Class clazz, Consumer... consumers) { - T pojo = PODAM_FACTORY.manufacturePojo(clazz); - // 非空时,回调逻辑。通过它,可以实现 Pojo 的进一步处理 - if (ArrayUtil.isNotEmpty(consumers)) { - Arrays.stream(consumers).forEach(consumer -> consumer.accept(pojo)); - } - return pojo; - } - - @SafeVarargs - public static T randomPojo(Class clazz, Type type, Consumer... consumers) { - T pojo = PODAM_FACTORY.manufacturePojo(clazz, type); - // 非空时,回调逻辑。通过它,可以实现 Pojo 的进一步处理 - if (ArrayUtil.isNotEmpty(consumers)) { - Arrays.stream(consumers).forEach(consumer -> consumer.accept(pojo)); - } - return pojo; - } - - @SafeVarargs - public static List randomPojoList(Class clazz, Consumer... consumers) { - int size = RandomUtil.randomInt(1, RANDOM_COLLECTION_LENGTH); - return Stream.iterate(0, i -> i).limit(size).map(o -> randomPojo(clazz, consumers)) - .collect(Collectors.toList()); - } - -} diff --git a/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/dashboard/framework/test/package-info.java b/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/dashboard/framework/test/package-info.java deleted file mode 100644 index fa02213..0000000 --- a/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/dashboard/framework/test/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * 测试组件,用于单元测试、集成测试等等 - */ -package cn.iocoder.dashboard.framework.test; diff --git a/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/ut/BaseMockitoUnitTest.java b/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/ut/BaseMockitoUnitTest.java new file mode 100644 index 0000000..2604869 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/ut/BaseMockitoUnitTest.java @@ -0,0 +1,13 @@ +package cn.iocoder.yudao.framework.test.core.ut; + +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; + +/** + * 纯 Mockito 的单元测试 + * + * @author 芋道源码 + */ +@ExtendWith(MockitoExtension.class) +public class BaseMockitoUnitTest { +} diff --git a/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/ut/package-info.java b/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/ut/package-info.java new file mode 100644 index 0000000..bda7aad --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/ut/package-info.java @@ -0,0 +1,4 @@ +/** + * 提供单元测试 Unit Test 的基类 + */ +package cn.iocoder.yudao.framework.test.core.ut; diff --git a/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/util/AssertUtils.java b/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/util/AssertUtils.java new file mode 100644 index 0000000..c18bd24 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/util/AssertUtils.java @@ -0,0 +1,97 @@ +package cn.iocoder.yudao.framework.test.core.util; + +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.ReflectUtil; +import cn.iocoder.yudao.framework.common.exception.ErrorCode; +import cn.iocoder.yudao.framework.common.exception.ServiceException; +import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.function.Executable; + +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.Objects; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +/** + * 单元测试,assert 断言工具类 + * + * @author 芋道源码 + */ +public class AssertUtils { + + /** + * 比对两个对象的属性是否一致 + * + * 注意,如果 expected 存在的属性,actual 不存在的时候,会进行忽略 + * + * @param expected 期望对象 + * @param actual 实际对象 + * @param ignoreFields 忽略的属性数组 + */ + public static void assertPojoEquals(Object expected, Object actual, String... ignoreFields) { + Field[] expectedFields = ReflectUtil.getFields(expected.getClass()); + Arrays.stream(expectedFields).forEach(expectedField -> { + // 如果是忽略的属性,则不进行比对 + if (ArrayUtil.contains(ignoreFields, expectedField.getName())) { + return; + } + // 忽略不存在的属性 + Field actualField = ReflectUtil.getField(actual.getClass(), expectedField.getName()); + if (actualField == null) { + return; + } + // 比对 + Assertions.assertEquals( + ReflectUtil.getFieldValue(expected, expectedField), + ReflectUtil.getFieldValue(actual, actualField), + String.format("Field(%s) 不匹配", expectedField.getName()) + ); + }); + } + + /** + * 比对两个对象的属性是否一致 + * + * 注意,如果 expected 存在的属性,actual 不存在的时候,会进行忽略 + * + * @param expected 期望对象 + * @param actual 实际对象 + * @param ignoreFields 忽略的属性数组 + * @return 是否一致 + */ + public static boolean isPojoEquals(Object expected, Object actual, String... ignoreFields) { + Field[] expectedFields = ReflectUtil.getFields(expected.getClass()); + return Arrays.stream(expectedFields).allMatch(expectedField -> { + // 如果是忽略的属性,则不进行比对 + if (ArrayUtil.contains(ignoreFields, expectedField.getName())) { + return true; + } + // 忽略不存在的属性 + Field actualField = ReflectUtil.getField(actual.getClass(), expectedField.getName()); + if (actualField == null) { + return true; + } + return Objects.equals(ReflectUtil.getFieldValue(expected, expectedField), + ReflectUtil.getFieldValue(actual, actualField)); + }); + } + + /** + * 执行方法,校验抛出的 Service 是否符合条件 + * + * @param executable 业务异常 + * @param errorCode 错误码对象 + * @param messageParams 消息参数 + */ + public static void assertServiceException(Executable executable, ErrorCode errorCode, Object... messageParams) { + // 调用方法 + ServiceException serviceException = assertThrows(ServiceException.class, executable); + // 校验错误码 + Assertions.assertEquals(errorCode.getCode(), serviceException.getCode(), "错误码不匹配"); + String message = ServiceExceptionUtil.doFormat(errorCode.getCode(), errorCode.getMsg(), messageParams); + Assertions.assertEquals(message, serviceException.getMessage(), "错误提示不匹配"); + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/util/RandomUtils.java b/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/util/RandomUtils.java new file mode 100644 index 0000000..e8d36ad --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/util/RandomUtils.java @@ -0,0 +1,100 @@ +package cn.iocoder.yudao.framework.test.core.util; + +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.RandomUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import uk.co.jemos.podam.api.PodamFactory; +import uk.co.jemos.podam.api.PodamFactoryImpl; + +import java.lang.reflect.Type; +import java.util.*; +import java.util.function.Consumer; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * 随机工具类 + * + * @author 芋道源码 + */ +public class RandomUtils { + + private static final int RANDOM_STRING_LENGTH = 10; + + private static final int RANDOM_DATE_MAX = 30; + + private static final int RANDOM_COLLECTION_LENGTH = 5; + + private static final PodamFactory PODAM_FACTORY = new PodamFactoryImpl(); + + static { + // 字符串 + PODAM_FACTORY.getStrategy().addOrReplaceTypeManufacturer(String.class, + (dataProviderStrategy, attributeMetadata, map) -> randomString()); + // Boolean + PODAM_FACTORY.getStrategy().addOrReplaceTypeManufacturer(Boolean.class, (dataProviderStrategy, attributeMetadata, map) -> { + // 如果是 deleted 的字段,返回非删除 + if (attributeMetadata.getAttributeName().equals("deleted")) { + return false; + } + return RandomUtil.randomBoolean(); + }); + } + + public static String randomString() { + return RandomUtil.randomString(RANDOM_STRING_LENGTH); + } + + public static Long randomLongId() { + return RandomUtil.randomLong(0, Long.MAX_VALUE); + } + + public static Integer randomInteger() { + return RandomUtil.randomInt(0, Integer.MAX_VALUE); + } + + public static Date randomDate() { + return RandomUtil.randomDay(0, RANDOM_DATE_MAX); + } + + public static Short randomShort() { + return (short) RandomUtil.randomInt(0, Short.MAX_VALUE); + } + + public static Set randomSet(Class clazz) { + return Stream.iterate(0, i -> i).limit(RandomUtil.randomInt(0, RANDOM_DATE_MAX)) + .map(i -> randomPojo(clazz)).collect(Collectors.toSet()); + } + + public static Integer randomCommonStatus() { + return RandomUtil.randomEle(CommonStatusEnum.values()).getStatus(); + } + + @SafeVarargs + public static T randomPojo(Class clazz, Consumer... consumers) { + T pojo = PODAM_FACTORY.manufacturePojo(clazz); + // 非空时,回调逻辑。通过它,可以实现 Pojo 的进一步处理 + if (ArrayUtil.isNotEmpty(consumers)) { + Arrays.stream(consumers).forEach(consumer -> consumer.accept(pojo)); + } + return pojo; + } + + @SafeVarargs + public static T randomPojo(Class clazz, Type type, Consumer... consumers) { + T pojo = PODAM_FACTORY.manufacturePojo(clazz, type); + // 非空时,回调逻辑。通过它,可以实现 Pojo 的进一步处理 + if (ArrayUtil.isNotEmpty(consumers)) { + Arrays.stream(consumers).forEach(consumer -> consumer.accept(pojo)); + } + return pojo; + } + + @SafeVarargs + public static List randomPojoList(Class clazz, Consumer... consumers) { + int size = RandomUtil.randomInt(1, RANDOM_COLLECTION_LENGTH); + return Stream.iterate(0, i -> i).limit(size).map(o -> randomPojo(clazz, consumers)) + .collect(Collectors.toList()); + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/package-info.java b/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/package-info.java new file mode 100644 index 0000000..3a17f51 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/package-info.java @@ -0,0 +1,4 @@ +/** + * 测试组件,用于单元测试、集成测试等等 + */ +package cn.iocoder.yudao.framework.test; diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/WebProperties.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/WebProperties.java index d4444da..2edc3e8 100644 --- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/WebProperties.java +++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/WebProperties.java @@ -29,7 +29,7 @@ public class WebProperties { * * 主要目的是,给该 Controller 设置指定的 {@link #apiPrefix} * - * 因为我们有多个 modules 包里会包含 Controller,所以只需要写到 cn.iocoder.dashboard 这样的层级 + * 因为我们有多个 modules 包里会包含 Controller,所以只需要写到 cn.iocoder.yudao 这样的层级 */ @NotNull(message = "Controller 所在包不能为空") private String controllerPackage; diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/YudaoWebAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/YudaoWebAutoConfiguration.java index 90773f8..5d390cd 100644 --- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/YudaoWebAutoConfiguration.java +++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/YudaoWebAutoConfiguration.java @@ -1,9 +1,13 @@ package cn.iocoder.yudao.framework.web.config; +import cn.iocoder.yudao.framework.apilog.core.service.ApiErrorLogFrameworkService; import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum; import cn.iocoder.yudao.framework.web.core.filter.CacheRequestBodyFilter; import cn.iocoder.yudao.framework.web.core.filter.DemoFilter; import cn.iocoder.yudao.framework.web.core.filter.XssFilter; +import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler; +import cn.iocoder.yudao.framework.web.core.handler.GlobalResponseBodyHandler; +import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.web.servlet.FilterRegistrationBean; @@ -26,6 +30,11 @@ public class YudaoWebAutoConfiguration implements WebMvcConfigurer { @Resource private WebProperties webProperties; + /** + * 应用名 + */ + @Value("${spring.application.name}") + private String applicationName; @Override public void configurePathMatch(PathMatchConfigurer configurer) { @@ -35,6 +44,16 @@ public class YudaoWebAutoConfiguration implements WebMvcConfigurer { && clazz.getPackage().getName().startsWith(webProperties.getControllerPackage())); // 仅仅匹配 controller 包 } + @Bean + public GlobalExceptionHandler globalExceptionHandler(ApiErrorLogFrameworkService ApiErrorLogFrameworkService) { + return new GlobalExceptionHandler(applicationName, ApiErrorLogFrameworkService); + } + + @Bean + public GlobalResponseBodyHandler globalResponseBodyHandler() { + return new GlobalResponseBodyHandler(); + } + // ========== Filter 相关 ========== /** diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java index 3616bd3..a27d87a 100644 --- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java +++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java @@ -12,6 +12,7 @@ import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; import io.github.resilience4j.ratelimiter.RequestNotPermitted; +import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.exception.ExceptionUtils; import org.springframework.beans.factory.annotation.Value; @@ -43,14 +44,13 @@ import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeC * @author 芋道源码 */ @RestControllerAdvice +@AllArgsConstructor @Slf4j public class GlobalExceptionHandler { - @Value("${spring.application.name}") - private String applicationName; + private final String applicationName; - @Resource - private ApiErrorLogFrameworkService apiErrorLogFrameworkService; + private final ApiErrorLogFrameworkService apiErrorLogFrameworkService; /** * 处理所有异常,主要是提供给 Filter 使用 diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/resources/META-INF/spring.factories b/yudao-framework/yudao-spring-boot-starter-web/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000..3b0e1d7 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/resources/META-INF/spring.factories @@ -0,0 +1,5 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ + cn.iocoder.yudao.framework.apilog.config.YudaoApiLogAutoConfiguration,\ + cn.iocoder.yudao.framework.jackson.config.YudaoJacksonAutoConfiguration,\ + cn.iocoder.yudao.framework.swagger.config.YudaoSwaggerAutoConfiguration,\ + cn.iocoder.yudao.framework.web.config.YudaoWebAutoConfiguration -- libgit2 0.21.4