From c47c6db2a5e8a6ad651f34c7775efb06a00b42d8 Mon Sep 17 00:00:00 2001 From: jack ning Date: Tue, 30 Apr 2024 09:37:49 +0800 Subject: [PATCH] update to 0.1.0 update to 0.1.0 --- .DS_Store | Bin 8196 -> 8196 bytes README.md | 5 +- README.zh.md | 6 +- h2db/weiyuim.mv.db | Bin 0 -> 614400 bytes h2db/weiyuim.trace.db | 4098 +++++++++++++++++ modules/.DS_Store | Bin 8196 -> 8196 bytes modules/ai/.DS_Store | Bin 6148 -> 6148 bytes modules/ai/pom.xml | 5 +- .../src/main/java/com/bytedesk/ai/kb/Kb.java | 2 +- .../java/com/bytedesk/ai/kb/KbService.java | 11 +- .../java/com/bytedesk/ai/llm/LlmService.java | 8 +- .../java/com/bytedesk/ai/robot/Robot.java | 2 +- .../com/bytedesk/ai/robot/RobotRequest.java | 4 +- .../com/bytedesk/ai/robot/RobotResponse.java | 2 +- .../com/bytedesk/ai/robot/RobotService.java | 14 +- modules/blog/.DS_Store | Bin 0 -> 6148 bytes modules/{oa => blog}/.gitignore | 0 .../.mvn/wrapper/maven-wrapper.jar | Bin .../.mvn/wrapper/maven-wrapper.properties | 0 modules/{oa => blog}/build.gradle | 11 +- .../gradle/wrapper/gradle-wrapper.jar | Bin .../gradle/wrapper/gradle-wrapper.properties | 0 modules/{oa => blog}/gradlew | 0 modules/{oa => blog}/gradlew.bat | 0 modules/{oa => blog}/mvnw | 0 modules/{oa => blog}/mvnw.cmd | 0 modules/{oa => blog}/pom.xml | 22 +- modules/{oa => blog}/settings.gradle | 2 +- .../com/bytedesk/blog/BlogApplication.java} | 6 +- .../src/main/resources/application.properties | 1 + .../bytedesk/blog/BlogApplicationTests.java} | 4 +- modules/core/.DS_Store | Bin 6148 -> 6148 bytes modules/core/build.gradle | 4 - modules/core/pom.xml | 17 +- .../src/main/java/com/bytedesk/core/.DS_Store | Bin 10244 -> 10244 bytes .../java/com/bytedesk/core/action/Action.java | 58 + .../core/action/ActionController.java | 19 + .../bytedesk/core/action/ActionLogAspect.java | 89 + .../ActionRepository.java} | 14 +- .../bytedesk/core/action/ActionRequest.java | 42 + .../{rbac => }/action/ActionResponse.java | 28 +- .../bytedesk/core/action/ActionService.java | 50 + .../bytedesk/core/annotation/ActionLog.java | 39 + .../core/annotation/ApiRateLimiter.java | 56 + .../core/aop/ApiRateLimiterAspect.java | 80 + .../com/bytedesk/core/asistant/Asistant.java | 67 + .../core/asistant/AsistantController.java | 58 + .../core/asistant/AsistantListener.java | 34 + .../core/asistant/AsistantRepository.java | 21 + .../core/asistant/AsistantRequest.java | 42 + .../core/asistant/AsistantResponse.java | 44 + .../core/asistant/AsistantService.java | 135 + .../com/bytedesk/core/auth/AuthAspect.java | 46 - .../{block/Block.java => black/Black.java} | 6 +- .../com/bytedesk/core/cache/CacheConfig.java | 89 +- .../com/bytedesk/core/cache/RedisConfig.java | 62 - .../Action.java => channel/Channel.java} | 45 +- .../core/channel/ChannelController.java | 55 + .../core/channel/ChannelListener.java | 31 + .../core/channel/ChannelRepository.java | 21 + .../bytedesk/core/channel/ChannelRequest.java | 42 + .../core/channel/ChannelResponse.java | 44 + .../bytedesk/core/channel/ChannelService.java | 97 + .../bytedesk/core/config/BytedeskConfig.java | 9 +- .../core/config/BytedeskProperties.java | 6 +- .../IosService.java => connect/Connect.java} | 8 +- .../bytedesk/core/constant/AvatarConsts.java | 11 +- .../bytedesk/core/constant/BdConstants.java | 3 +- .../com/bytedesk/core/constant/I18Consts.java | 37 + .../core/constant/MessageTypeConsts.java | 13 +- .../bytedesk/core/constant/RedisConsts.java | 3 +- .../bytedesk/core/constant/StatusConsts.java | 17 +- .../core/constant/ThreadTypeConsts.java | 7 +- .../bytedesk/core/constant/TopicConsts.java | 26 + .../bytedesk/core/constant/TypeConsts.java | 23 +- .../core/event/BytedeskEventPublisher.java | 40 +- .../bytedesk/core/event/MessageJsonEvent.java | 4 +- .../core/event/MqttConnectedEvent.java} | 29 +- .../core/event/MqttDisconnectedEvent.java | 33 + .../core/event/MqttSubscribeEvent.java | 35 + .../core/event/MqttUnsubscribeEvent.java | 35 + .../core/event/ThreadCreateEvent.java | 34 + .../core/event/ThreadUpdateEvent.java | 34 + .../core/exception/BaseException.java | 26 + .../core/exception/EmailExistsException.java | 28 + .../exception/EmailNotFoundException.java | 4 +- .../core/exception/ForbiddenException.java | 34 + .../exception/GlobalControllerAdvice.java | 100 + .../core/exception/MobileExistsException.java | 26 + .../exception/MobileNotFoundException.java | 4 +- .../core/exception/NotFoundException.java | 29 + .../core/exception/UserDisabledException.java | 34 + .../com/bytedesk/core/ip/IpController.java | 7 +- .../java/com/bytedesk/core/ip/IpService.java | 24 +- .../com/bytedesk/core/message/Message.java | 66 +- .../core/message/MessageController.java | 31 +- .../core/message/MessageRepository.java | 10 +- .../core/message/MessageResponse.java | 65 +- .../bytedesk/core/message/MessageService.java | 35 +- .../Schedule.java => openid/OpenId.java} | 12 +- .../java/com/bytedesk/core/push/Notifier.java | 22 + .../java/com/bytedesk/core/push/Push.java | 53 +- .../com/bytedesk/core/push/PushConfig.java | 40 + .../{SmsService.java => PushController.java} | 6 +- .../bytedesk/core/push/PushRepository.java | 31 + .../com/bytedesk/core/push/PushRequest.java | 48 + .../com/bytedesk/core/push/PushResponse.java | 39 + .../com/bytedesk/core/push/PushService.java | 177 + .../core/push/PushServiceImplAndroid.java | 39 + .../core/push/PushServiceImplEmail.java | 44 + .../core/push/PushServiceImplIos.java | 38 + .../core/push/PushServiceImplSms.java | 43 + .../core/rbac/action/ActionController.java | 31 - .../core/rbac/action/ActionRepository.java | 32 - .../core/{ => rbac}/auth/AuthController.java | 95 +- .../core/{ => rbac}/auth/AuthEntryPoint.java | 2 +- .../{ => rbac}/auth/AuthJwtTokenFilter.java | 18 +- .../core/{ => rbac}/auth/AuthRequest.java | 12 +- .../core/{ => rbac}/auth/AuthResponse.java | 2 +- .../core/{ => rbac}/auth/AuthService.java | 59 +- .../core/{ => rbac}/auth/AuthToken.java | 2 +- .../core/rbac/authority/Authority.java | 40 +- .../rbac/authority/AuthorityController.java | 49 +- .../rbac/authority/AuthorityRepository.java | 10 +- .../core/rbac/authority/AuthorityRequest.java | 14 +- .../rbac/authority/AuthorityResponse.java | 9 +- .../core/rbac/authority/AuthorityService.java | 69 +- .../com/bytedesk/core/rbac/role/Role.java | 66 +- .../core/rbac/role/RoleController.java | 14 +- .../core/rbac/role/RoleRepository.java | 11 +- .../bytedesk/core/rbac/role/RoleRequest.java | 17 +- .../bytedesk/core/rbac/role/RoleResponse.java | 12 +- .../bytedesk/core/rbac/role/RoleService.java | 175 +- .../com/bytedesk/core/rbac/user/User.java | 82 +- .../bytedesk/core/rbac/user/UserAspect.java | 49 + .../core/rbac/user/UserController.java | 83 +- .../core/rbac/user/UserDetailsImpl.java | 44 +- .../rbac/user/UserDetailsServiceImpl.java | 14 +- .../bytedesk/core/rbac/user/UserListener.java | 63 + .../core/rbac/user/UserRepository.java | 7 +- .../bytedesk/core/rbac/user/UserRequest.java | 30 +- .../bytedesk/core/rbac/user/UserResponse.java | 22 +- .../core/rbac/user/UserResponseSimple.java | 8 +- .../bytedesk/core/rbac/user/UserService.java | 219 +- .../core/redis/RedisLoginService.java | 123 - .../bytedesk/core/redis/RedisUserService.java | 78 - .../core/session/HttpSessionConfig.java | 77 +- .../java/com/bytedesk/core/thread/Thread.java | 66 +- .../core/thread/ThreadController.java | 43 +- .../core/thread/ThreadEventHandler.java | 12 +- .../bytedesk/core/thread/ThreadListener.java | 72 + .../core/thread/ThreadRepository.java | 25 +- .../bytedesk/core/thread/ThreadRequest.java | 19 +- .../bytedesk/core/thread/ThreadResponse.java | 38 +- .../core/thread/ThreadResponseSimple.java | 44 + .../bytedesk/core/thread/ThreadService.java | 162 +- .../java/com/bytedesk/core/topic/Topic.java | 95 + .../TopicController.java} | 8 +- .../bytedesk/core/topic/TopicRepository.java | 50 + .../com/bytedesk/core/topic/TopicRequest.java | 59 + .../bytedesk/core/topic/TopicResponse.java | 56 + .../com/bytedesk/core/topic/TopicService.java | 209 + .../bytedesk/core/uid/UidAutoConfigure.java | 64 + .../com/bytedesk/core/uid/UidGenerator.java | 78 + .../core/uid/UidGeneratorService.java | 44 + .../core/uid/UidGereratorRepository.java | 54 + .../java/com/bytedesk/core/uid/UidUtils.java | 70 + .../uid/buffer/BufferPaddingExecutor.java | 174 + .../core/uid/buffer/BufferedUidProvider.java | 35 + .../uid/buffer/RejectedPutBufferHandler.java | 34 + .../uid/buffer/RejectedTakeBufferHandler.java | 33 + .../bytedesk/core/uid/buffer/RingBuffer.java | 260 ++ .../uid/exception/UidGenerateException.java | 75 + .../bytedesk/core/uid/impl/BitsAllocator.java | 110 + .../core/uid/impl/CachedUidGenerator.java | 209 + .../core/uid/impl/DefaultUidGenerator.java | 216 + .../bytedesk/core/uid/impl/UidProperties.java | 75 + .../main/java/com/bytedesk/core/uid/readme.md | 17 + .../bytedesk/core/uid/utils/DateUtils.java | 122 + .../bytedesk/core/uid/utils/DockerUtils.java | 104 + .../bytedesk/core/uid/utils/EnumUtils.java | 64 + .../core/uid/utils/NamingThreadFactory.java | 165 + .../com/bytedesk/core/uid/utils/NetUtils.java | 115 + .../core/uid/utils/PaddedAtomicLong.java | 52 + .../bytedesk/core/uid/utils/ValuedEnum.java | 32 + .../worker/DisposableWorkerIdAssigner.java | 120 + .../core/uid/worker/WorkerIdAssigner.java | 41 + .../core/uid/worker/WorkerNodeType.java | 59 + .../bytedesk/core/upload/UploadService.java | 4 +- .../core/utils/ApplicationContextHolder.java | 32 + .../com/bytedesk/core/utils/AuditModel.java | 28 +- .../com/bytedesk/core/utils/BaseRequest.java | 12 +- .../com/bytedesk/core/utils/BaseResponse.java | 3 +- .../bytedesk/core/utils/BdConvertUtils.java | 7 +- .../com/bytedesk/core/utils/BdDateUtils.java | 1 - .../com/bytedesk/core/utils/JsonResult.java | 18 +- .../com/bytedesk/core/utils/JwtUtils.java | 82 +- .../core/utils/StringSetConverter.java | 47 + .../java/com/bytedesk/core/utils/Utils.java | 68 +- .../exception/AlreadyExistsException.java | 40 - .../utils/exception/ApiErrorResponse.java | 78 - .../utils/exception/AppNotFoundException.java | 34 - .../exception/AuthorityNotFoundException.java | 34 - .../utils/exception/BadRequestException.java | 47 - .../utils/exception/BeanUtilsException.java | 44 - .../utils/exception/BytedeskException.java | 68 - .../DepartmentNotFoundException.java | 48 - .../utils/exception/ForbiddenException.java | 47 - .../utils/exception/ImageFormatException.java | 35 - .../exception/MenuNotFoundException.java | 34 - .../exception/PrincipalNullException.java | 33 - .../exception/RoleNotFoundException.java | 34 - .../exception/UserNotFoundException.java | 34 - .../core/utils/id/DefaultIdGenerator.java | 78 + .../id/DefaultIdGeneratorConfig.java} | 37 +- .../bytedesk/core/utils/id/IdGenerator.java | 17 + .../core/utils/id/IdGeneratorConfig.java | 47 + modules/local/.DS_Store | Bin 6148 -> 6148 bytes modules/local/pom.xml | 14 +- .../local/caffeine/CaffeineCacheService.java | 71 + .../local/listener/MessageBytesListener.java | 69 +- .../local/listener/MessageJsonListener.java | 47 +- .../listener/QuartzFiveSecondListener.java | 30 +- modules/oa/.DS_Store | Bin 6148 -> 0 bytes modules/oa/readme.md | 1 - .../src/main/resources/application.properties | 1 - modules/pom.xml | 83 +- modules/readme.md | 15 + modules/service/.DS_Store | Bin 6148 -> 6148 bytes modules/service/pom.xml | 33 +- modules/service/proguard.cfg | 39 + modules/service/src/.DS_Store | Bin 6148 -> 6148 bytes modules/service/src/main/.DS_Store | Bin 6148 -> 6148 bytes .../src => service/src/main/java}/.DS_Store | Bin 6148 -> 6148 bytes .../src/main/java/com}/.DS_Store | Bin 6148 -> 6148 bytes .../src/main/java/com/bytedesk/.DS_Store | Bin 6148 -> 6148 bytes .../main/java/com/bytedesk/service/.DS_Store | Bin 10244 -> 10244 bytes .../com/bytedesk/service/agent/Agent.java | 80 +- .../bytedesk/service/agent/AgentConsts.java | 30 + .../service/agent/AgentController.java | 9 +- .../bytedesk/service/agent/AgentListener.java | 71 + .../service/agent/AgentRepository.java | 21 +- .../bytedesk/service/agent/AgentRequest.java | 13 +- .../bytedesk/service/agent/AgentResponse.java | 12 +- .../service/agent/AgentResponseSimple.java} | 25 +- .../bytedesk/service/agent/AgentService.java | 147 +- .../bytedesk/service/customer/Customer.java | 20 +- .../service/customer/CustomerNameOnly.java} | 16 +- .../service/customer/CustomerRepository.java | 14 +- .../CustomerSummary.java} | 15 +- .../{leavemsg => leave_msg}/LeaveMessage.java | 2 +- .../LeaveMessageController.java | 2 +- .../LeaveMessageRepository.java | 2 +- .../LeaveMessageRequest.java | 2 +- .../LeaveMessageResponse.java | 2 +- .../LeaveMessageService.java | 2 +- .../listener/ServiceEventListener.java | 53 + .../QualityCheck.java | 2 +- .../QualityCheckAppeal.java | 2 +- .../QualityCheckPlan.java | 2 +- .../QualityCheckSetting.java | 2 +- .../QualityCheckSettingScore.java | 2 +- .../QualityCheckStatistic.java | 2 +- .../QuickButton.java | 2 +- .../QuickButtonController.java | 2 +- .../QuickButtonRepository.java | 2 +- .../QuickButtonRequest.java | 2 +- .../QuickButtonResponse.java | 2 +- .../QuickButtonService.java | 2 +- .../QuickReply.java | 2 +- .../QuickReplyController.java | 2 +- .../QuickReplyRepository.java | 2 +- .../QuickReplyRequest.java | 2 +- .../QuickReplyResponse.java | 2 +- .../QuickReplyService.java | 2 +- .../service/route/AbstractStrategyRouter.java | 113 + .../bytedesk/service/route/IRouteService.java | 19 + .../com/bytedesk/service/route/Route.java} | 8 +- .../bytedesk/service/route/RouteFactory.java | 19 + .../service/route/RouteRepository.java | 19 + .../service/route/StrategyHandler.java} | 38 +- .../service/thread_log/ThreadLog.java | 115 + .../thread_log/ThreadLogController.java | 19 + .../thread_log/ThreadLogRepository.java | 26 + .../service/thread_log/ThreadLogRequest.java} | 25 +- .../service/thread_log/ThreadLogResponse.java | 55 + .../service/thread_log/ThreadLogService.java | 125 + .../com/bytedesk/service/visitor/Visitor.java | 31 +- .../service/visitor/VisitorAspect.java | 42 +- .../service/visitor/VisitorController.java | 54 +- .../service/visitor/VisitorExtra.java | 55 + .../service/visitor/VisitorRepository.java | 16 +- .../service/visitor/VisitorRequest.java | 43 +- .../service/visitor/VisitorResponse.java | 27 +- .../visitor/VisitorResponseSimple.java} | 38 +- .../service/visitor/VisitorService.java | 324 +- .../bytedesk/service/workgroup/Workgroup.java | 88 +- .../service/workgroup/WorkgroupAspect.java | 35 +- .../workgroup/WorkgroupController.java | 19 +- .../workgroup/WorkgroupRepository.java | 14 +- .../service/workgroup/WorkgroupRequest.java | 42 +- .../service/workgroup/WorkgroupResponse.java | 28 +- .../service/workgroup/WorkgroupService.java | 149 +- .../bytedesk/service/worktime/Worktime.java | 114 + .../service/worktime/WorktimeController.java | 19 + .../service/worktime/WorktimeRepository.java | 19 + .../service/worktime/WorktimeRequest.java | 19 + .../service/worktime/WorktimeResponse.java | 19 + .../service/worktime/WorktimeService.java | 19 + modules/social/.DS_Store | Bin 6148 -> 6148 bytes modules/social/pom.xml | 8 +- modules/socket/.DS_Store | Bin 6148 -> 6148 bytes modules/socket/build.gradle | 2 - modules/socket/mqtt-v3.1.1-os.pdf | Bin 0 -> 2269570 bytes modules/socket/mqtt-v5.0.pdf | Bin 0 -> 1928173 bytes modules/socket/pom.xml | 12 +- modules/socket/readme.md | 1 + modules/socket/src/.DS_Store | Bin 6148 -> 6148 bytes .../{social/src => socket/src/main}/.DS_Store | Bin 6148 -> 6148 bytes .../src/main/java/com/bytedesk}/.DS_Store | Bin 6148 -> 6148 bytes .../controller/MessageRestController.java | 59 + .../cache/MqttSubscribeNotWildcardCache.java | 99 + .../cache/MqttSubscribeWildcardCache.java | 102 + .../socket/mqtt/config/MqttRedisConfig.java | 32 - .../mqtt/handler/MqttTransportHandler.java | 9 +- .../mqtt/listener/MqttEventListener.java | 104 + .../mqtt/model/MqttDupPublishMessage.java | 28 - .../socket/mqtt/model/MqttMqMessage.java | 26 - .../socket/mqtt/protocol/Connect.java | 335 +- .../socket/mqtt/protocol/DisConnect.java | 36 +- .../socket/mqtt/protocol/ProtocolProcess.java | 160 +- .../bytedesk/socket/mqtt/protocol/PubAck.java | 8 +- .../socket/mqtt/protocol/PubComp.java | 8 +- .../bytedesk/socket/mqtt/protocol/PubRec.java | 18 +- .../socket/mqtt/protocol/Publish.java | 127 +- .../socket/mqtt/protocol/Subscribe.java | 94 +- .../socket/mqtt/protocol/UnSubscribe.java | 13 +- .../mqtt/redis/MqttDupPubRelMessageCache.java | 75 - .../redis/MqttDupPublishMessageCache.java | 74 - .../mqtt/redis/MqttRetainMessageCache.java | 67 - .../socket/mqtt/redis/MqttSessionCache.java | 72 - .../redis/MqttSubscribeNotWildcardCache.java | 106 - .../redis/MqttSubscribeWildcardCache.java | 100 - .../socket/mqtt/server/MqttServer.java | 7 +- .../socket/mqtt/service/MqttAuthService.java | 8 +- .../mqtt/service/MqttClientIdService.java | 77 + .../service/MqttClientIdStoreService.java | 77 - .../MqttDupPubRelMessageStoreService.java | 57 - .../MqttDupPublishMessageStoreService.java | 54 - .../MqttRetainMessageStoreService.java | 81 - ...reService.java => MqttSessionService.java} | 11 +- .../mqtt/service/MqttSubscribeService.java | 67 + .../service/MqttSubscribeStoreService.java | 94 - .../socket/mqtt/util/MqttSerializer.java | 43 - .../bytedesk/socket/mqtt/util/MqttUtil.java | 17 +- .../config/ProtobufRedisTemplate.java | 41 - .../util/ProtobufRedisSerializer.java | 60 - .../redis/RedisMessageCacheFetchService.java | 197 - .../RedisMessageCacheOfflineService.java | 57 - .../RedisMessageCacheProtobufService.java | 52 - .../socket/service/MessageJsonService.java | 109 + .../socket/service/MessageProtoService.java | 182 + .../socket/service/MessageSocketService.java | 502 +- .../stomp/controller/StompController.java | 123 +- .../socket/stomp/service/StompMqService.java | 9 +- modules/socket/src/main/proto/message.proto | 193 +- modules/socket/src/main/proto/thread.proto | 26 +- modules/socket/src/main/proto/user.proto | 17 +- modules/team/.DS_Store | Bin 6148 -> 6148 bytes modules/team/pom.xml | 5 +- .../bytedesk/team/department/Department.java | 114 +- .../team/department/DepartmentController.java | 67 +- .../team/department/DepartmentRepository.java | 6 +- .../team/department/DepartmentRequest.java | 32 +- .../team/department/DepartmentResponse.java | 30 +- .../team/department/DepartmentService.java | 87 +- .../java/com/bytedesk/team/group/Group.java | 18 +- .../bytedesk/team/group/GroupController.java | 2 + .../team/group/GroupEventHandler.java | 2 +- .../bytedesk/team/group/GroupListener.java | 62 + .../com/bytedesk/team/group/GroupRequest.java | 3 +- .../bytedesk/team/group/GroupResponse.java | 16 +- .../com/bytedesk/team/group/GroupService.java | 2 +- .../java/com/bytedesk/team/member/Member.java | 44 +- .../team/member/MemberController.java | 34 +- .../team/member/MemberEventHandler.java | 2 + .../bytedesk/team/member/MemberListener.java | 57 + .../team/member/MemberRepository.java | 13 +- .../bytedesk/team/member/MemberRequest.java | 16 +- .../bytedesk/team/member/MemberResponse.java | 6 +- .../bytedesk/team/member/MemberService.java | 351 +- .../team/organization/Organization.java | 40 +- .../organization/OrganizationController.java | 107 +- .../OrganizationEventHandler.java | 2 +- .../organization/OrganizationRepository.java | 11 +- .../organization/OrganizationRequest.java | 13 +- .../organization/OrganizationResponse.java | 41 +- .../organization/OrganizationService.java | 60 +- .../team/DepartmentControllerTests.java | 14 +- .../bytedesk/team/DepartmentServiceTests.java | 160 +- .../team/OrganizationServiceTests.java | 3 +- starter/.DS_Store | Bin 6148 -> 6148 bytes starter/.gitignore | 1 - starter/h2db/weiyuim.mv.db | Bin 0 -> 188416 bytes starter/pom.xml | 124 +- starter/src/.DS_Store | Bin 6148 -> 6148 bytes .../bytedesk/starter/StarterApplication.java | 8 +- .../bytedesk/starter/config/CorsConfig.java | 69 + .../starter/config/SecurityConfig.java | 47 +- .../bytedesk/starter/config/WebMvcConfig.java | 38 +- .../starter/listener/ImEventListener.java | 2 +- .../starter/runner/InitDataRunner.java | 42 +- ...operties => application-dev-h2.properties} | 55 +- .../src/main/resources/application.properties | 11 +- starter/src/main/resources/lib/readme.md | 18 + 415 files changed, 15736 insertions(+), 6076 deletions(-) create mode 100644 h2db/weiyuim.mv.db create mode 100644 h2db/weiyuim.trace.db create mode 100644 modules/blog/.DS_Store rename modules/{oa => blog}/.gitignore (100%) rename modules/{oa => blog}/.mvn/wrapper/maven-wrapper.jar (100%) rename modules/{oa => blog}/.mvn/wrapper/maven-wrapper.properties (100%) rename modules/{oa => blog}/build.gradle (62%) rename modules/{oa => blog}/gradle/wrapper/gradle-wrapper.jar (100%) rename modules/{oa => blog}/gradle/wrapper/gradle-wrapper.properties (100%) rename modules/{oa => blog}/gradlew (100%) rename modules/{oa => blog}/gradlew.bat (100%) rename modules/{oa => blog}/mvnw (100%) rename modules/{oa => blog}/mvnw.cmd (100%) rename modules/{oa => blog}/pom.xml (61%) rename modules/{oa => blog}/settings.gradle (71%) rename modules/{oa/src/main/java/com/bytedesk/oa/OaApplication.java => blog/src/main/java/com/bytedesk/blog/BlogApplication.java} (63%) create mode 100644 modules/blog/src/main/resources/application.properties rename modules/{oa/src/test/java/com/bytedesk/oa/OaApplicationTests.java => blog/src/test/java/com/bytedesk/blog/BlogApplicationTests.java} (72%) create mode 100644 modules/core/src/main/java/com/bytedesk/core/action/Action.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/action/ActionController.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/action/ActionLogAspect.java rename modules/core/src/main/java/com/bytedesk/core/{cache/CaffeineConfig.java => action/ActionRepository.java} (75%) create mode 100644 modules/core/src/main/java/com/bytedesk/core/action/ActionRequest.java rename modules/core/src/main/java/com/bytedesk/core/{rbac => }/action/ActionResponse.java (69%) create mode 100644 modules/core/src/main/java/com/bytedesk/core/action/ActionService.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/annotation/ActionLog.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/annotation/ApiRateLimiter.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/aop/ApiRateLimiterAspect.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/asistant/Asistant.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/asistant/AsistantController.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/asistant/AsistantListener.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/asistant/AsistantRepository.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/asistant/AsistantRequest.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/asistant/AsistantResponse.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/asistant/AsistantService.java delete mode 100644 modules/core/src/main/java/com/bytedesk/core/auth/AuthAspect.java rename modules/core/src/main/java/com/bytedesk/core/{block/Block.java => black/Black.java} (89%) delete mode 100644 modules/core/src/main/java/com/bytedesk/core/cache/RedisConfig.java rename modules/core/src/main/java/com/bytedesk/core/{rbac/action/Action.java => channel/Channel.java} (62%) create mode 100644 modules/core/src/main/java/com/bytedesk/core/channel/ChannelController.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/channel/ChannelListener.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/channel/ChannelRepository.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/channel/ChannelRequest.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/channel/ChannelResponse.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/channel/ChannelService.java rename modules/core/src/main/java/com/bytedesk/core/{push/IosService.java => connect/Connect.java} (85%) create mode 100644 modules/core/src/main/java/com/bytedesk/core/constant/I18Consts.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/constant/TopicConsts.java rename modules/{socket/src/main/java/com/bytedesk/socket/mqtt/model/MqttDupPubRelMessage.java => core/src/main/java/com/bytedesk/core/event/MqttConnectedEvent.java} (63%) mode change 100755 => 100644 create mode 100644 modules/core/src/main/java/com/bytedesk/core/event/MqttDisconnectedEvent.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/event/MqttSubscribeEvent.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/event/MqttUnsubscribeEvent.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/event/ThreadCreateEvent.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/event/ThreadUpdateEvent.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/exception/BaseException.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/exception/EmailExistsException.java rename modules/core/src/main/java/com/bytedesk/core/{utils => }/exception/EmailNotFoundException.java (92%) create mode 100755 modules/core/src/main/java/com/bytedesk/core/exception/ForbiddenException.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/exception/GlobalControllerAdvice.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/exception/MobileExistsException.java rename modules/core/src/main/java/com/bytedesk/core/{utils => }/exception/MobileNotFoundException.java (92%) create mode 100644 modules/core/src/main/java/com/bytedesk/core/exception/NotFoundException.java create mode 100755 modules/core/src/main/java/com/bytedesk/core/exception/UserDisabledException.java rename modules/core/src/main/java/com/bytedesk/core/{schedule/Schedule.java => openid/OpenId.java} (79%) create mode 100644 modules/core/src/main/java/com/bytedesk/core/push/Notifier.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/push/PushConfig.java rename modules/core/src/main/java/com/bytedesk/core/push/{SmsService.java => PushController.java} (88%) create mode 100644 modules/core/src/main/java/com/bytedesk/core/push/PushRepository.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/push/PushRequest.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/push/PushResponse.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/push/PushService.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/push/PushServiceImplAndroid.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/push/PushServiceImplEmail.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/push/PushServiceImplIos.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/push/PushServiceImplSms.java delete mode 100644 modules/core/src/main/java/com/bytedesk/core/rbac/action/ActionController.java delete mode 100644 modules/core/src/main/java/com/bytedesk/core/rbac/action/ActionRepository.java rename modules/core/src/main/java/com/bytedesk/core/{ => rbac}/auth/AuthController.java (55%) rename modules/core/src/main/java/com/bytedesk/core/{ => rbac}/auth/AuthEntryPoint.java (98%) rename modules/core/src/main/java/com/bytedesk/core/{ => rbac}/auth/AuthJwtTokenFilter.java (72%) rename modules/core/src/main/java/com/bytedesk/core/{ => rbac}/auth/AuthRequest.java (76%) rename modules/core/src/main/java/com/bytedesk/core/{ => rbac}/auth/AuthResponse.java (96%) rename modules/core/src/main/java/com/bytedesk/core/{ => rbac}/auth/AuthService.java (72%) rename modules/core/src/main/java/com/bytedesk/core/{ => rbac}/auth/AuthToken.java (98%) create mode 100644 modules/core/src/main/java/com/bytedesk/core/rbac/user/UserAspect.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/rbac/user/UserListener.java delete mode 100644 modules/core/src/main/java/com/bytedesk/core/redis/RedisLoginService.java delete mode 100644 modules/core/src/main/java/com/bytedesk/core/redis/RedisUserService.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/thread/ThreadListener.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/thread/ThreadResponseSimple.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/topic/Topic.java rename modules/core/src/main/java/com/bytedesk/core/{push/AndroidService.java => topic/TopicController.java} (84%) create mode 100644 modules/core/src/main/java/com/bytedesk/core/topic/TopicRepository.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/topic/TopicRequest.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/topic/TopicResponse.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/topic/TopicService.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/uid/UidAutoConfigure.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/uid/UidGenerator.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/uid/UidGeneratorService.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/uid/UidGereratorRepository.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/uid/UidUtils.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/uid/buffer/BufferPaddingExecutor.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/uid/buffer/BufferedUidProvider.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/uid/buffer/RejectedPutBufferHandler.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/uid/buffer/RejectedTakeBufferHandler.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/uid/buffer/RingBuffer.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/uid/exception/UidGenerateException.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/uid/impl/BitsAllocator.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/uid/impl/CachedUidGenerator.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/uid/impl/DefaultUidGenerator.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/uid/impl/UidProperties.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/uid/readme.md create mode 100644 modules/core/src/main/java/com/bytedesk/core/uid/utils/DateUtils.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/uid/utils/DockerUtils.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/uid/utils/EnumUtils.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/uid/utils/NamingThreadFactory.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/uid/utils/NetUtils.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/uid/utils/PaddedAtomicLong.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/uid/utils/ValuedEnum.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/uid/worker/DisposableWorkerIdAssigner.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/uid/worker/WorkerIdAssigner.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/uid/worker/WorkerNodeType.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/utils/ApplicationContextHolder.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/utils/StringSetConverter.java delete mode 100755 modules/core/src/main/java/com/bytedesk/core/utils/exception/AlreadyExistsException.java delete mode 100644 modules/core/src/main/java/com/bytedesk/core/utils/exception/ApiErrorResponse.java delete mode 100644 modules/core/src/main/java/com/bytedesk/core/utils/exception/AppNotFoundException.java delete mode 100644 modules/core/src/main/java/com/bytedesk/core/utils/exception/AuthorityNotFoundException.java delete mode 100755 modules/core/src/main/java/com/bytedesk/core/utils/exception/BadRequestException.java delete mode 100755 modules/core/src/main/java/com/bytedesk/core/utils/exception/BeanUtilsException.java delete mode 100755 modules/core/src/main/java/com/bytedesk/core/utils/exception/BytedeskException.java delete mode 100644 modules/core/src/main/java/com/bytedesk/core/utils/exception/DepartmentNotFoundException.java delete mode 100755 modules/core/src/main/java/com/bytedesk/core/utils/exception/ForbiddenException.java delete mode 100644 modules/core/src/main/java/com/bytedesk/core/utils/exception/ImageFormatException.java delete mode 100644 modules/core/src/main/java/com/bytedesk/core/utils/exception/MenuNotFoundException.java delete mode 100644 modules/core/src/main/java/com/bytedesk/core/utils/exception/PrincipalNullException.java delete mode 100644 modules/core/src/main/java/com/bytedesk/core/utils/exception/RoleNotFoundException.java delete mode 100644 modules/core/src/main/java/com/bytedesk/core/utils/exception/UserNotFoundException.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/utils/id/DefaultIdGenerator.java rename modules/core/src/main/java/com/bytedesk/core/{redis/RedisThreadService.java => utils/id/DefaultIdGeneratorConfig.java} (61%) create mode 100644 modules/core/src/main/java/com/bytedesk/core/utils/id/IdGenerator.java create mode 100644 modules/core/src/main/java/com/bytedesk/core/utils/id/IdGeneratorConfig.java create mode 100644 modules/local/src/main/java/com/bytedesk/local/caffeine/CaffeineCacheService.java delete mode 100644 modules/oa/.DS_Store delete mode 100644 modules/oa/readme.md delete mode 100644 modules/oa/src/main/resources/application.properties create mode 100644 modules/readme.md create mode 100644 modules/service/proguard.cfg rename modules/{local/src => service/src/main/java}/.DS_Store (91%) rename modules/{ai/src => service/src/main/java/com}/.DS_Store (94%) create mode 100644 modules/service/src/main/java/com/bytedesk/service/agent/AgentConsts.java create mode 100644 modules/service/src/main/java/com/bytedesk/service/agent/AgentListener.java rename modules/{socket/src/main/java/com/bytedesk/socket/mqtt/model/MqttRetainMessage.java => service/src/main/java/com/bytedesk/service/agent/AgentResponseSimple.java} (66%) mode change 100755 => 100644 rename modules/{socket/src/main/java/com/bytedesk/socket/mqtt/service/MqttPublishMessageService.java => service/src/main/java/com/bytedesk/service/customer/CustomerNameOnly.java} (71%) rename modules/service/src/main/java/com/bytedesk/service/{doc/Doc.java => customer/CustomerSummary.java} (67%) rename modules/service/src/main/java/com/bytedesk/service/{leavemsg => leave_msg}/LeaveMessage.java (97%) rename modules/service/src/main/java/com/bytedesk/service/{leavemsg => leave_msg}/LeaveMessageController.java (95%) rename modules/service/src/main/java/com/bytedesk/service/{leavemsg => leave_msg}/LeaveMessageRepository.java (95%) rename modules/service/src/main/java/com/bytedesk/service/{leavemsg => leave_msg}/LeaveMessageRequest.java (95%) rename modules/service/src/main/java/com/bytedesk/service/{leavemsg => leave_msg}/LeaveMessageResponse.java (95%) rename modules/service/src/main/java/com/bytedesk/service/{leavemsg => leave_msg}/LeaveMessageService.java (95%) create mode 100644 modules/service/src/main/java/com/bytedesk/service/listener/ServiceEventListener.java rename modules/service/src/main/java/com/bytedesk/service/{qualitycheck => quality_check}/QualityCheck.java (94%) rename modules/service/src/main/java/com/bytedesk/service/{qualitycheck => quality_check}/QualityCheckAppeal.java (95%) rename modules/service/src/main/java/com/bytedesk/service/{qualitycheck => quality_check}/QualityCheckPlan.java (95%) rename modules/service/src/main/java/com/bytedesk/service/{qualitycheck => quality_check}/QualityCheckSetting.java (95%) rename modules/service/src/main/java/com/bytedesk/service/{qualitycheck => quality_check}/QualityCheckSettingScore.java (95%) rename modules/service/src/main/java/com/bytedesk/service/{qualitycheck => quality_check}/QualityCheckStatistic.java (95%) rename modules/service/src/main/java/com/bytedesk/service/{quickbutton => quick_button}/QuickButton.java (97%) rename modules/service/src/main/java/com/bytedesk/service/{quickbutton => quick_button}/QuickButtonController.java (95%) rename modules/service/src/main/java/com/bytedesk/service/{quickbutton => quick_button}/QuickButtonRepository.java (95%) rename modules/service/src/main/java/com/bytedesk/service/{quickbutton => quick_button}/QuickButtonRequest.java (94%) rename modules/service/src/main/java/com/bytedesk/service/{quickbutton => quick_button}/QuickButtonResponse.java (94%) rename modules/service/src/main/java/com/bytedesk/service/{quickbutton => quick_button}/QuickButtonService.java (94%) rename modules/service/src/main/java/com/bytedesk/service/{quickreply => quick_reply}/QuickReply.java (97%) rename modules/service/src/main/java/com/bytedesk/service/{quickreply => quick_reply}/QuickReplyController.java (95%) rename modules/service/src/main/java/com/bytedesk/service/{quickreply => quick_reply}/QuickReplyRepository.java (95%) rename modules/service/src/main/java/com/bytedesk/service/{quickreply => quick_reply}/QuickReplyRequest.java (95%) rename modules/service/src/main/java/com/bytedesk/service/{quickreply => quick_reply}/QuickReplyResponse.java (95%) rename modules/service/src/main/java/com/bytedesk/service/{quickreply => quick_reply}/QuickReplyService.java (95%) create mode 100644 modules/service/src/main/java/com/bytedesk/service/route/AbstractStrategyRouter.java create mode 100644 modules/service/src/main/java/com/bytedesk/service/route/IRouteService.java rename modules/{core/src/main/java/com/bytedesk/core/push/EmailService.java => service/src/main/java/com/bytedesk/service/route/Route.java} (84%) create mode 100644 modules/service/src/main/java/com/bytedesk/service/route/RouteFactory.java create mode 100644 modules/service/src/main/java/com/bytedesk/service/route/RouteRepository.java rename modules/{core/src/main/java/com/bytedesk/core/rbac/action/ActionService.java => service/src/main/java/com/bytedesk/service/route/StrategyHandler.java} (66%) create mode 100644 modules/service/src/main/java/com/bytedesk/service/thread_log/ThreadLog.java create mode 100644 modules/service/src/main/java/com/bytedesk/service/thread_log/ThreadLogController.java create mode 100644 modules/service/src/main/java/com/bytedesk/service/thread_log/ThreadLogRepository.java rename modules/{core/src/main/java/com/bytedesk/core/rbac/action/ActionRequest.java => service/src/main/java/com/bytedesk/service/thread_log/ThreadLogRequest.java} (69%) create mode 100644 modules/service/src/main/java/com/bytedesk/service/thread_log/ThreadLogResponse.java create mode 100644 modules/service/src/main/java/com/bytedesk/service/thread_log/ThreadLogService.java create mode 100644 modules/service/src/main/java/com/bytedesk/service/visitor/VisitorExtra.java rename modules/{socket/src/main/java/com/bytedesk/socket/mqtt/model/MqttWillMessage.java => service/src/main/java/com/bytedesk/service/visitor/VisitorResponseSimple.java} (62%) mode change 100755 => 100644 create mode 100644 modules/service/src/main/java/com/bytedesk/service/worktime/Worktime.java create mode 100644 modules/service/src/main/java/com/bytedesk/service/worktime/WorktimeController.java create mode 100644 modules/service/src/main/java/com/bytedesk/service/worktime/WorktimeRepository.java create mode 100644 modules/service/src/main/java/com/bytedesk/service/worktime/WorktimeRequest.java create mode 100644 modules/service/src/main/java/com/bytedesk/service/worktime/WorktimeResponse.java create mode 100644 modules/service/src/main/java/com/bytedesk/service/worktime/WorktimeService.java create mode 100644 modules/socket/mqtt-v3.1.1-os.pdf create mode 100644 modules/socket/mqtt-v5.0.pdf rename modules/{social/src => socket/src/main}/.DS_Store (88%) rename modules/{oa/src => socket/src/main/java/com/bytedesk}/.DS_Store (88%) create mode 100644 modules/socket/src/main/java/com/bytedesk/socket/controller/MessageRestController.java create mode 100755 modules/socket/src/main/java/com/bytedesk/socket/mqtt/cache/MqttSubscribeNotWildcardCache.java create mode 100755 modules/socket/src/main/java/com/bytedesk/socket/mqtt/cache/MqttSubscribeWildcardCache.java delete mode 100755 modules/socket/src/main/java/com/bytedesk/socket/mqtt/config/MqttRedisConfig.java create mode 100644 modules/socket/src/main/java/com/bytedesk/socket/mqtt/listener/MqttEventListener.java delete mode 100755 modules/socket/src/main/java/com/bytedesk/socket/mqtt/model/MqttDupPublishMessage.java delete mode 100755 modules/socket/src/main/java/com/bytedesk/socket/mqtt/model/MqttMqMessage.java delete mode 100755 modules/socket/src/main/java/com/bytedesk/socket/mqtt/redis/MqttDupPubRelMessageCache.java delete mode 100755 modules/socket/src/main/java/com/bytedesk/socket/mqtt/redis/MqttDupPublishMessageCache.java delete mode 100755 modules/socket/src/main/java/com/bytedesk/socket/mqtt/redis/MqttRetainMessageCache.java delete mode 100755 modules/socket/src/main/java/com/bytedesk/socket/mqtt/redis/MqttSessionCache.java delete mode 100755 modules/socket/src/main/java/com/bytedesk/socket/mqtt/redis/MqttSubscribeNotWildcardCache.java delete mode 100755 modules/socket/src/main/java/com/bytedesk/socket/mqtt/redis/MqttSubscribeWildcardCache.java create mode 100644 modules/socket/src/main/java/com/bytedesk/socket/mqtt/service/MqttClientIdService.java delete mode 100644 modules/socket/src/main/java/com/bytedesk/socket/mqtt/service/MqttClientIdStoreService.java delete mode 100755 modules/socket/src/main/java/com/bytedesk/socket/mqtt/service/MqttDupPubRelMessageStoreService.java delete mode 100755 modules/socket/src/main/java/com/bytedesk/socket/mqtt/service/MqttDupPublishMessageStoreService.java delete mode 100755 modules/socket/src/main/java/com/bytedesk/socket/mqtt/service/MqttRetainMessageStoreService.java rename modules/socket/src/main/java/com/bytedesk/socket/mqtt/service/{MqttSessionStoreService.java => MqttSessionService.java} (82%) create mode 100755 modules/socket/src/main/java/com/bytedesk/socket/mqtt/service/MqttSubscribeService.java delete mode 100755 modules/socket/src/main/java/com/bytedesk/socket/mqtt/service/MqttSubscribeStoreService.java delete mode 100755 modules/socket/src/main/java/com/bytedesk/socket/mqtt/util/MqttSerializer.java delete mode 100644 modules/socket/src/main/java/com/bytedesk/socket/protobuf/config/ProtobufRedisTemplate.java delete mode 100644 modules/socket/src/main/java/com/bytedesk/socket/protobuf/util/ProtobufRedisSerializer.java delete mode 100644 modules/socket/src/main/java/com/bytedesk/socket/redis/RedisMessageCacheFetchService.java delete mode 100644 modules/socket/src/main/java/com/bytedesk/socket/redis/RedisMessageCacheOfflineService.java delete mode 100644 modules/socket/src/main/java/com/bytedesk/socket/redis/RedisMessageCacheProtobufService.java create mode 100644 modules/socket/src/main/java/com/bytedesk/socket/service/MessageJsonService.java create mode 100644 modules/socket/src/main/java/com/bytedesk/socket/service/MessageProtoService.java create mode 100644 modules/team/src/main/java/com/bytedesk/team/group/GroupListener.java create mode 100644 modules/team/src/main/java/com/bytedesk/team/member/MemberListener.java create mode 100644 starter/h2db/weiyuim.mv.db create mode 100644 starter/src/main/java/com/bytedesk/starter/config/CorsConfig.java rename starter/src/main/resources/{application-dev.properties => application-dev-h2.properties} (88%) create mode 100644 starter/src/main/resources/lib/readme.md diff --git a/.DS_Store b/.DS_Store index 7f5d6117ad8f8bd791580505357dc6bc94d4d9a0..a47eeb692869f3c2a125367b3eac36339977edad 100644 GIT binary patch delta 165 zcmZp1XmQxUDLna*XsM`~rG<`yv9W2bjzYDefsuiZf|V&;WjHpc8pi*7HImeBOg=5b#Rd_Wd>g1(IFVuVKM{83&Fm82SfD%>W&r9L BG=l&D delta 226 zcmZp1XmQxUDa^QivW{S(ns{}!iJ^{ynSp7ojzYDik%5kaiLqI2EhmSlvc7dte0EN5 zUVi7~I5BzmE(Qh$c7|Mre1;T;QidFcREFZ5bi?4}{M-Vd3B7Z%^hFQDB2I^+gnz**71U93*0^!IvQI0oGs4P{NSNPy{4X8H$kghZ}NU hNVz?EJ5WEAc^9akuj|4lQFi9dtP($17=cVSW&m~hJ=p*N diff --git a/README.md b/README.md index 79fe1f3ad5..c2e3c9f6c7 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-29 16:43:44 * @LastEditors: jack ning github@bytedesk.com - * @LastEditTime: 2024-04-26 14:11:29 + * @LastEditTime: 2024-04-30 09:34:00 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -42,9 +42,6 @@ AI powered customer service & team collaboration ```bash git clone https://github.com/Bytedesk/bytedesk.git -# open bytedesk/starter/src/main/resources/application-dev.properties -# change the value of spring.datasource.url and spring.datasource.username and spring.datasource.password -# change the value of spring.redis.host and spring.redis.port cd bytedesk/starter mvn spring-boot:run # diff --git a/README.zh.md b/README.zh.md index 53bd34eb5e..9439e9d450 100644 --- a/README.zh.md +++ b/README.zh.md @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-29 16:43:44 * @LastEditors: jack ning github@bytedesk.com - * @LastEditTime: 2024-04-26 14:11:35 + * @LastEditTime: 2024-04-30 09:26:12 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -13,9 +13,9 @@ * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. --> -# 微语 - 企业即时通讯 & 在线客服系统 & 大模型AI助手 +# 微语 -面向对数据安全比较敏感的中大型企业和组织,提供基于AI的企业即时通讯和在线客服系统 +基于AI的企业即时通讯和在线客服系统 ## 语言 diff --git a/h2db/weiyuim.mv.db b/h2db/weiyuim.mv.db new file mode 100644 index 0000000000000000000000000000000000000000..12e392c97a76008b1de5c6c988de9f905d4ff6fd GIT binary patch literal 614400 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�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%0ANBY06FCTY4d(<%wFT}iP9{PaWt0f0?j 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 literal 0 HcmV?d00001 diff --git a/h2db/weiyuim.trace.db b/h2db/weiyuim.trace.db new file mode 100644 index 0000000000..fe84973316 --- /dev/null +++ b/h2db/weiyuim.trace.db @@ -0,0 +1,4098 @@ +2024-04-30 09:36:01.384720+08:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "QRTZ_CALENDARS" already exists; SQL statement: +CREATE TABLE QRTZ_CALENDARS ( SCHED_NAME VARCHAR(120) NOT NULL, CALENDAR_NAME VARCHAR (200) NOT NULL , CALENDAR IMAGE NOT NULL ) [42101-224] +2024-04-30 09:36:01.385716+08:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "QRTZ_CRON_TRIGGERS" already exists; SQL statement: +CREATE TABLE QRTZ_CRON_TRIGGERS ( SCHED_NAME VARCHAR(120) NOT NULL, TRIGGER_NAME VARCHAR (200) NOT NULL , TRIGGER_GROUP VARCHAR (200) NOT NULL , CRON_EXPRESSION VARCHAR (120) NOT NULL , TIME_ZONE_ID VARCHAR (80) ) [42101-224] +2024-04-30 09:36:01.386004+08:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "QRTZ_FIRED_TRIGGERS" already exists; SQL statement: +CREATE TABLE QRTZ_FIRED_TRIGGERS ( SCHED_NAME VARCHAR(120) NOT NULL, ENTRY_ID VARCHAR (95) NOT NULL , TRIGGER_NAME VARCHAR (200) NOT NULL , TRIGGER_GROUP VARCHAR (200) NOT NULL , INSTANCE_NAME VARCHAR (200) NOT NULL , FIRED_TIME BIGINT NOT NULL , SCHED_TIME BIGINT NOT NULL , PRIORITY INTEGER NOT NULL , STATE VARCHAR (16) NOT NULL, JOB_NAME VARCHAR (200) NULL , JOB_GROUP VARCHAR (200) NULL , IS_NONCONCURRENT BOOLEAN NULL , REQUESTS_RECOVERY BOOLEAN NULL ) [42101-224] +2024-04-30 09:36:01.386175+08:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "QRTZ_PAUSED_TRIGGER_GRPS" already exists; SQL statement: +CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS ( SCHED_NAME VARCHAR(120) NOT NULL, TRIGGER_GROUP VARCHAR (200) NOT NULL ) [42101-224] +2024-04-30 09:36:01.386333+08:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "QRTZ_SCHEDULER_STATE" already exists; SQL statement: +CREATE TABLE QRTZ_SCHEDULER_STATE ( SCHED_NAME VARCHAR(120) NOT NULL, INSTANCE_NAME VARCHAR (200) NOT NULL , LAST_CHECKIN_TIME BIGINT NOT NULL , CHECKIN_INTERVAL BIGINT NOT NULL ) [42101-224] +2024-04-30 09:36:01.386539+08:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "QRTZ_LOCKS" already exists; SQL statement: +CREATE TABLE QRTZ_LOCKS ( SCHED_NAME VARCHAR(120) NOT NULL, LOCK_NAME VARCHAR (40) NOT NULL ) [42101-224] +2024-04-30 09:36:01.386757+08:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "QRTZ_JOB_DETAILS" already exists; SQL statement: +CREATE TABLE QRTZ_JOB_DETAILS ( SCHED_NAME VARCHAR(120) NOT NULL, JOB_NAME VARCHAR (200) NOT NULL , JOB_GROUP VARCHAR (200) NOT NULL , DESCRIPTION VARCHAR (250) NULL , JOB_CLASS_NAME VARCHAR (250) NOT NULL , IS_DURABLE BOOLEAN NOT NULL , IS_NONCONCURRENT BOOLEAN NOT NULL , IS_UPDATE_DATA BOOLEAN NOT NULL , REQUESTS_RECOVERY BOOLEAN NOT NULL , JOB_DATA IMAGE NULL ) [42101-224] +2024-04-30 09:36:01.386928+08:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "QRTZ_SIMPLE_TRIGGERS" already exists; SQL statement: +CREATE TABLE QRTZ_SIMPLE_TRIGGERS ( SCHED_NAME VARCHAR(120) NOT NULL, TRIGGER_NAME VARCHAR (200) NOT NULL , TRIGGER_GROUP VARCHAR (200) NOT NULL , REPEAT_COUNT BIGINT NOT NULL , REPEAT_INTERVAL BIGINT NOT NULL , TIMES_TRIGGERED BIGINT NOT NULL ) [42101-224] +2024-04-30 09:36:01.387125+08:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "QRTZ_SIMPROP_TRIGGERS" already exists; SQL statement: +CREATE TABLE QRTZ_SIMPROP_TRIGGERS ( SCHED_NAME VARCHAR(120) NOT NULL, TRIGGER_NAME VARCHAR(200) NOT NULL, TRIGGER_GROUP VARCHAR(200) NOT NULL, STR_PROP_1 VARCHAR(512) NULL, STR_PROP_2 VARCHAR(512) NULL, STR_PROP_3 VARCHAR(512) NULL, INT_PROP_1 INTEGER NULL, INT_PROP_2 INTEGER NULL, LONG_PROP_1 BIGINT NULL, LONG_PROP_2 BIGINT NULL, DEC_PROP_1 NUMERIC(13,4) NULL, DEC_PROP_2 NUMERIC(13,4) NULL, BOOL_PROP_1 BOOLEAN NULL, BOOL_PROP_2 BOOLEAN NULL ) [42101-224] +2024-04-30 09:36:01.387293+08:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "QRTZ_BLOB_TRIGGERS" already exists; SQL statement: +CREATE TABLE QRTZ_BLOB_TRIGGERS ( SCHED_NAME VARCHAR(120) NOT NULL, TRIGGER_NAME VARCHAR (200) NOT NULL , TRIGGER_GROUP VARCHAR (200) NOT NULL , BLOB_DATA IMAGE NULL ) [42101-224] +2024-04-30 09:36:01.387523+08:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "QRTZ_TRIGGERS" already exists; SQL statement: +CREATE TABLE QRTZ_TRIGGERS ( SCHED_NAME VARCHAR(120) NOT NULL, TRIGGER_NAME VARCHAR (200) NOT NULL , TRIGGER_GROUP VARCHAR (200) NOT NULL , JOB_NAME VARCHAR (200) NOT NULL , JOB_GROUP VARCHAR (200) NOT NULL , DESCRIPTION VARCHAR (250) NULL , NEXT_FIRE_TIME BIGINT NULL , PREV_FIRE_TIME BIGINT NULL , PRIORITY INTEGER NULL , TRIGGER_STATE VARCHAR (16) NOT NULL , TRIGGER_TYPE VARCHAR (8) NOT NULL , START_TIME BIGINT NOT NULL , END_TIME BIGINT NULL , CALENDAR_NAME VARCHAR (200) NULL , MISFIRE_INSTR SMALLINT NULL , JOB_DATA IMAGE NULL ) [42101-224] +2024-04-30 09:36:01.387735+08:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Constraint "PK_QRTZ_CALENDARS" already exists; SQL statement: +ALTER TABLE QRTZ_CALENDARS ADD CONSTRAINT PK_QRTZ_CALENDARS PRIMARY KEY ( SCHED_NAME, CALENDAR_NAME ) [90045-224] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:644) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:489) + at org.h2.message.DbException.get(DbException.java:223) + at org.h2.message.DbException.get(DbException.java:199) + at org.h2.command.ddl.AlterTableAddConstraint.tryUpdate(AlterTableAddConstraint.java:111) + at org.h2.command.ddl.AlterTableAddConstraint.update(AlterTableAddConstraint.java:74) + at org.h2.command.ddl.AlterTable.update(AlterTable.java:46) + at org.h2.command.CommandContainer.update(CommandContainer.java:169) + at org.h2.command.Command.executeUpdate(Command.java:256) + at org.h2.jdbc.JdbcStatement.executeInternal(JdbcStatement.java:262) + at org.h2.jdbc.JdbcStatement.execute(JdbcStatement.java:231) + at com.zaxxer.hikari.pool.ProxyStatement.execute(ProxyStatement.java:94) + at com.zaxxer.hikari.pool.HikariProxyStatement.execute(HikariProxyStatement.java) + at org.springframework.jdbc.datasource.init.ScriptUtils.executeSqlScript(ScriptUtils.java:261) + at org.springframework.jdbc.datasource.init.ResourceDatabasePopulator.populate(ResourceDatabasePopulator.java:254) + at org.springframework.jdbc.datasource.init.DatabasePopulatorUtils.execute(DatabasePopulatorUtils.java:54) + at org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer.runScripts(DataSourceScriptDatabaseInitializer.java:87) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.runScripts(AbstractScriptDatabaseInitializer.java:146) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applyScripts(AbstractScriptDatabaseInitializer.java:108) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applySchemaScripts(AbstractScriptDatabaseInitializer.java:98) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.initializeDatabase(AbstractScriptDatabaseInitializer.java:76) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.afterPropertiesSet(AbstractScriptDatabaseInitializer.java:66) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:312) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1441) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:911) + at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:789) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:546) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1173) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.lambda$createEndpointBean$1(EndpointDiscoverer.java:145) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer$EndpointBean.getBean(EndpointDiscoverer.java:456) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getFilterEndpoint(EndpointDiscoverer.java:314) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isFilterMatch(EndpointDiscoverer.java:290) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isExtensionExposed(EndpointDiscoverer.java:244) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBean(EndpointDiscoverer.java:170) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBeans(EndpointDiscoverer.java:159) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.discoverEndpoints(EndpointDiscoverer.java:124) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getEndpoints(EndpointDiscoverer.java:117) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration.getHealthEndpoint(HealthEndpointWebExtensionConfiguration.java:80) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration$MvcAdditionalHealthEndpointPathsConfiguration.healthEndpointWebMvcHandlerMapping(HealthEndpointWebExtensionConfiguration.java:95) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:663) + at org.springframework.context.support.AbstractApplicationContext.getBeansOfType(AbstractApplicationContext.java:1327) + at org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors(BeanFactoryUtils.java:368) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.initHandlerMappings(HandlerMappingIntrospector.java:130) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.afterPropertiesSet(HandlerMappingIntrospector.java:118) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:204) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1179) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.createMvcMatchers(AbstractRequestMatcherRegistry.java:116) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:207) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:360) + at com.bytedesk.starter.config.SecurityConfig.lambda$securityFilterChain$3(SecurityConfig.java:62) + at org.springframework.security.config.annotation.web.builders.HttpSecurity.authorizeHttpRequests(HttpSecurity.java:1467) + at com.bytedesk.starter.config.SecurityConfig.securityFilterChain(SecurityConfig.java:61) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.CGLIB$securityFilterChain$0() + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$FastClass$$1.invoke() + at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:258) + at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.securityFilterChain() + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.addCandidateEntry(DefaultListableBeanFactory.java:1687) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1651) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeanCollection(DefaultListableBeanFactory.java:1541) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeans(DefaultListableBeanFactory.java:1509) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1390) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.resolveMethodArguments(AutowiredAnnotationBeanPostProcessor.java:872) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:833) + at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:145) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:493) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1420) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:600) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:973) + at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:946) + at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:616) + at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) + at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:753) + at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:455) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:323) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1342) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1331) + at com.bytedesk.starter.StarterApplication.main(StarterApplication.java:30) +2024-04-30 09:36:01.389311+08:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Constraint "PK_QRTZ_CRON_TRIGGERS" already exists; SQL statement: +ALTER TABLE QRTZ_CRON_TRIGGERS ADD CONSTRAINT PK_QRTZ_CRON_TRIGGERS PRIMARY KEY ( SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP ) [90045-224] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:644) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:489) + at org.h2.message.DbException.get(DbException.java:223) + at org.h2.message.DbException.get(DbException.java:199) + at org.h2.command.ddl.AlterTableAddConstraint.tryUpdate(AlterTableAddConstraint.java:111) + at org.h2.command.ddl.AlterTableAddConstraint.update(AlterTableAddConstraint.java:74) + at org.h2.command.ddl.AlterTable.update(AlterTable.java:46) + at org.h2.command.CommandContainer.update(CommandContainer.java:169) + at org.h2.command.Command.executeUpdate(Command.java:256) + at org.h2.jdbc.JdbcStatement.executeInternal(JdbcStatement.java:262) + at org.h2.jdbc.JdbcStatement.execute(JdbcStatement.java:231) + at com.zaxxer.hikari.pool.ProxyStatement.execute(ProxyStatement.java:94) + at com.zaxxer.hikari.pool.HikariProxyStatement.execute(HikariProxyStatement.java) + at org.springframework.jdbc.datasource.init.ScriptUtils.executeSqlScript(ScriptUtils.java:261) + at org.springframework.jdbc.datasource.init.ResourceDatabasePopulator.populate(ResourceDatabasePopulator.java:254) + at org.springframework.jdbc.datasource.init.DatabasePopulatorUtils.execute(DatabasePopulatorUtils.java:54) + at org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer.runScripts(DataSourceScriptDatabaseInitializer.java:87) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.runScripts(AbstractScriptDatabaseInitializer.java:146) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applyScripts(AbstractScriptDatabaseInitializer.java:108) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applySchemaScripts(AbstractScriptDatabaseInitializer.java:98) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.initializeDatabase(AbstractScriptDatabaseInitializer.java:76) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.afterPropertiesSet(AbstractScriptDatabaseInitializer.java:66) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:312) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1441) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:911) + at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:789) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:546) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1173) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.lambda$createEndpointBean$1(EndpointDiscoverer.java:145) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer$EndpointBean.getBean(EndpointDiscoverer.java:456) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getFilterEndpoint(EndpointDiscoverer.java:314) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isFilterMatch(EndpointDiscoverer.java:290) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isExtensionExposed(EndpointDiscoverer.java:244) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBean(EndpointDiscoverer.java:170) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBeans(EndpointDiscoverer.java:159) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.discoverEndpoints(EndpointDiscoverer.java:124) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getEndpoints(EndpointDiscoverer.java:117) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration.getHealthEndpoint(HealthEndpointWebExtensionConfiguration.java:80) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration$MvcAdditionalHealthEndpointPathsConfiguration.healthEndpointWebMvcHandlerMapping(HealthEndpointWebExtensionConfiguration.java:95) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:663) + at org.springframework.context.support.AbstractApplicationContext.getBeansOfType(AbstractApplicationContext.java:1327) + at org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors(BeanFactoryUtils.java:368) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.initHandlerMappings(HandlerMappingIntrospector.java:130) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.afterPropertiesSet(HandlerMappingIntrospector.java:118) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:204) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1179) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.createMvcMatchers(AbstractRequestMatcherRegistry.java:116) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:207) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:360) + at com.bytedesk.starter.config.SecurityConfig.lambda$securityFilterChain$3(SecurityConfig.java:62) + at org.springframework.security.config.annotation.web.builders.HttpSecurity.authorizeHttpRequests(HttpSecurity.java:1467) + at com.bytedesk.starter.config.SecurityConfig.securityFilterChain(SecurityConfig.java:61) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.CGLIB$securityFilterChain$0() + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$FastClass$$1.invoke() + at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:258) + at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.securityFilterChain() + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.addCandidateEntry(DefaultListableBeanFactory.java:1687) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1651) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeanCollection(DefaultListableBeanFactory.java:1541) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeans(DefaultListableBeanFactory.java:1509) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1390) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.resolveMethodArguments(AutowiredAnnotationBeanPostProcessor.java:872) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:833) + at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:145) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:493) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1420) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:600) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:973) + at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:946) + at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:616) + at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) + at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:753) + at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:455) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:323) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1342) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1331) + at com.bytedesk.starter.StarterApplication.main(StarterApplication.java:30) +2024-04-30 09:36:01.390664+08:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Constraint "PK_QRTZ_FIRED_TRIGGERS" already exists; SQL statement: +ALTER TABLE QRTZ_FIRED_TRIGGERS ADD CONSTRAINT PK_QRTZ_FIRED_TRIGGERS PRIMARY KEY ( SCHED_NAME, ENTRY_ID ) [90045-224] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:644) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:489) + at org.h2.message.DbException.get(DbException.java:223) + at org.h2.message.DbException.get(DbException.java:199) + at org.h2.command.ddl.AlterTableAddConstraint.tryUpdate(AlterTableAddConstraint.java:111) + at org.h2.command.ddl.AlterTableAddConstraint.update(AlterTableAddConstraint.java:74) + at org.h2.command.ddl.AlterTable.update(AlterTable.java:46) + at org.h2.command.CommandContainer.update(CommandContainer.java:169) + at org.h2.command.Command.executeUpdate(Command.java:256) + at org.h2.jdbc.JdbcStatement.executeInternal(JdbcStatement.java:262) + at org.h2.jdbc.JdbcStatement.execute(JdbcStatement.java:231) + at com.zaxxer.hikari.pool.ProxyStatement.execute(ProxyStatement.java:94) + at com.zaxxer.hikari.pool.HikariProxyStatement.execute(HikariProxyStatement.java) + at org.springframework.jdbc.datasource.init.ScriptUtils.executeSqlScript(ScriptUtils.java:261) + at org.springframework.jdbc.datasource.init.ResourceDatabasePopulator.populate(ResourceDatabasePopulator.java:254) + at org.springframework.jdbc.datasource.init.DatabasePopulatorUtils.execute(DatabasePopulatorUtils.java:54) + at org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer.runScripts(DataSourceScriptDatabaseInitializer.java:87) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.runScripts(AbstractScriptDatabaseInitializer.java:146) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applyScripts(AbstractScriptDatabaseInitializer.java:108) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applySchemaScripts(AbstractScriptDatabaseInitializer.java:98) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.initializeDatabase(AbstractScriptDatabaseInitializer.java:76) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.afterPropertiesSet(AbstractScriptDatabaseInitializer.java:66) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:312) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1441) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:911) + at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:789) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:546) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1173) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.lambda$createEndpointBean$1(EndpointDiscoverer.java:145) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer$EndpointBean.getBean(EndpointDiscoverer.java:456) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getFilterEndpoint(EndpointDiscoverer.java:314) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isFilterMatch(EndpointDiscoverer.java:290) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isExtensionExposed(EndpointDiscoverer.java:244) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBean(EndpointDiscoverer.java:170) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBeans(EndpointDiscoverer.java:159) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.discoverEndpoints(EndpointDiscoverer.java:124) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getEndpoints(EndpointDiscoverer.java:117) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration.getHealthEndpoint(HealthEndpointWebExtensionConfiguration.java:80) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration$MvcAdditionalHealthEndpointPathsConfiguration.healthEndpointWebMvcHandlerMapping(HealthEndpointWebExtensionConfiguration.java:95) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:663) + at org.springframework.context.support.AbstractApplicationContext.getBeansOfType(AbstractApplicationContext.java:1327) + at org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors(BeanFactoryUtils.java:368) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.initHandlerMappings(HandlerMappingIntrospector.java:130) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.afterPropertiesSet(HandlerMappingIntrospector.java:118) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:204) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1179) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.createMvcMatchers(AbstractRequestMatcherRegistry.java:116) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:207) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:360) + at com.bytedesk.starter.config.SecurityConfig.lambda$securityFilterChain$3(SecurityConfig.java:62) + at org.springframework.security.config.annotation.web.builders.HttpSecurity.authorizeHttpRequests(HttpSecurity.java:1467) + at com.bytedesk.starter.config.SecurityConfig.securityFilterChain(SecurityConfig.java:61) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.CGLIB$securityFilterChain$0() + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$FastClass$$1.invoke() + at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:258) + at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.securityFilterChain() + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.addCandidateEntry(DefaultListableBeanFactory.java:1687) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1651) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeanCollection(DefaultListableBeanFactory.java:1541) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeans(DefaultListableBeanFactory.java:1509) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1390) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.resolveMethodArguments(AutowiredAnnotationBeanPostProcessor.java:872) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:833) + at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:145) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:493) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1420) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:600) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:973) + at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:946) + at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:616) + at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) + at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:753) + at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:455) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:323) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1342) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1331) + at com.bytedesk.starter.StarterApplication.main(StarterApplication.java:30) +2024-04-30 09:36:01.392340+08:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Constraint "PK_QRTZ_PAUSED_TRIGGER_GRPS" already exists; SQL statement: +ALTER TABLE QRTZ_PAUSED_TRIGGER_GRPS ADD CONSTRAINT PK_QRTZ_PAUSED_TRIGGER_GRPS PRIMARY KEY ( SCHED_NAME, TRIGGER_GROUP ) [90045-224] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:644) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:489) + at org.h2.message.DbException.get(DbException.java:223) + at org.h2.message.DbException.get(DbException.java:199) + at org.h2.command.ddl.AlterTableAddConstraint.tryUpdate(AlterTableAddConstraint.java:111) + at org.h2.command.ddl.AlterTableAddConstraint.update(AlterTableAddConstraint.java:74) + at org.h2.command.ddl.AlterTable.update(AlterTable.java:46) + at org.h2.command.CommandContainer.update(CommandContainer.java:169) + at org.h2.command.Command.executeUpdate(Command.java:256) + at org.h2.jdbc.JdbcStatement.executeInternal(JdbcStatement.java:262) + at org.h2.jdbc.JdbcStatement.execute(JdbcStatement.java:231) + at com.zaxxer.hikari.pool.ProxyStatement.execute(ProxyStatement.java:94) + at com.zaxxer.hikari.pool.HikariProxyStatement.execute(HikariProxyStatement.java) + at org.springframework.jdbc.datasource.init.ScriptUtils.executeSqlScript(ScriptUtils.java:261) + at org.springframework.jdbc.datasource.init.ResourceDatabasePopulator.populate(ResourceDatabasePopulator.java:254) + at org.springframework.jdbc.datasource.init.DatabasePopulatorUtils.execute(DatabasePopulatorUtils.java:54) + at org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer.runScripts(DataSourceScriptDatabaseInitializer.java:87) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.runScripts(AbstractScriptDatabaseInitializer.java:146) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applyScripts(AbstractScriptDatabaseInitializer.java:108) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applySchemaScripts(AbstractScriptDatabaseInitializer.java:98) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.initializeDatabase(AbstractScriptDatabaseInitializer.java:76) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.afterPropertiesSet(AbstractScriptDatabaseInitializer.java:66) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:312) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1441) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:911) + at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:789) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:546) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1173) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.lambda$createEndpointBean$1(EndpointDiscoverer.java:145) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer$EndpointBean.getBean(EndpointDiscoverer.java:456) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getFilterEndpoint(EndpointDiscoverer.java:314) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isFilterMatch(EndpointDiscoverer.java:290) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isExtensionExposed(EndpointDiscoverer.java:244) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBean(EndpointDiscoverer.java:170) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBeans(EndpointDiscoverer.java:159) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.discoverEndpoints(EndpointDiscoverer.java:124) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getEndpoints(EndpointDiscoverer.java:117) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration.getHealthEndpoint(HealthEndpointWebExtensionConfiguration.java:80) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration$MvcAdditionalHealthEndpointPathsConfiguration.healthEndpointWebMvcHandlerMapping(HealthEndpointWebExtensionConfiguration.java:95) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:663) + at org.springframework.context.support.AbstractApplicationContext.getBeansOfType(AbstractApplicationContext.java:1327) + at org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors(BeanFactoryUtils.java:368) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.initHandlerMappings(HandlerMappingIntrospector.java:130) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.afterPropertiesSet(HandlerMappingIntrospector.java:118) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:204) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1179) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.createMvcMatchers(AbstractRequestMatcherRegistry.java:116) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:207) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:360) + at com.bytedesk.starter.config.SecurityConfig.lambda$securityFilterChain$3(SecurityConfig.java:62) + at org.springframework.security.config.annotation.web.builders.HttpSecurity.authorizeHttpRequests(HttpSecurity.java:1467) + at com.bytedesk.starter.config.SecurityConfig.securityFilterChain(SecurityConfig.java:61) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.CGLIB$securityFilterChain$0() + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$FastClass$$1.invoke() + at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:258) + at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.securityFilterChain() + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.addCandidateEntry(DefaultListableBeanFactory.java:1687) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1651) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeanCollection(DefaultListableBeanFactory.java:1541) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeans(DefaultListableBeanFactory.java:1509) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1390) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.resolveMethodArguments(AutowiredAnnotationBeanPostProcessor.java:872) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:833) + at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:145) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:493) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1420) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:600) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:973) + at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:946) + at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:616) + at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) + at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:753) + at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:455) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:323) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1342) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1331) + at com.bytedesk.starter.StarterApplication.main(StarterApplication.java:30) +2024-04-30 09:36:01.393472+08:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Constraint "PK_QRTZ_SCHEDULER_STATE" already exists; SQL statement: +ALTER TABLE QRTZ_SCHEDULER_STATE ADD CONSTRAINT PK_QRTZ_SCHEDULER_STATE PRIMARY KEY ( SCHED_NAME, INSTANCE_NAME ) [90045-224] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:644) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:489) + at org.h2.message.DbException.get(DbException.java:223) + at org.h2.message.DbException.get(DbException.java:199) + at org.h2.command.ddl.AlterTableAddConstraint.tryUpdate(AlterTableAddConstraint.java:111) + at org.h2.command.ddl.AlterTableAddConstraint.update(AlterTableAddConstraint.java:74) + at org.h2.command.ddl.AlterTable.update(AlterTable.java:46) + at org.h2.command.CommandContainer.update(CommandContainer.java:169) + at org.h2.command.Command.executeUpdate(Command.java:256) + at org.h2.jdbc.JdbcStatement.executeInternal(JdbcStatement.java:262) + at org.h2.jdbc.JdbcStatement.execute(JdbcStatement.java:231) + at com.zaxxer.hikari.pool.ProxyStatement.execute(ProxyStatement.java:94) + at com.zaxxer.hikari.pool.HikariProxyStatement.execute(HikariProxyStatement.java) + at org.springframework.jdbc.datasource.init.ScriptUtils.executeSqlScript(ScriptUtils.java:261) + at org.springframework.jdbc.datasource.init.ResourceDatabasePopulator.populate(ResourceDatabasePopulator.java:254) + at org.springframework.jdbc.datasource.init.DatabasePopulatorUtils.execute(DatabasePopulatorUtils.java:54) + at org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer.runScripts(DataSourceScriptDatabaseInitializer.java:87) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.runScripts(AbstractScriptDatabaseInitializer.java:146) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applyScripts(AbstractScriptDatabaseInitializer.java:108) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applySchemaScripts(AbstractScriptDatabaseInitializer.java:98) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.initializeDatabase(AbstractScriptDatabaseInitializer.java:76) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.afterPropertiesSet(AbstractScriptDatabaseInitializer.java:66) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:312) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1441) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:911) + at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:789) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:546) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1173) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.lambda$createEndpointBean$1(EndpointDiscoverer.java:145) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer$EndpointBean.getBean(EndpointDiscoverer.java:456) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getFilterEndpoint(EndpointDiscoverer.java:314) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isFilterMatch(EndpointDiscoverer.java:290) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isExtensionExposed(EndpointDiscoverer.java:244) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBean(EndpointDiscoverer.java:170) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBeans(EndpointDiscoverer.java:159) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.discoverEndpoints(EndpointDiscoverer.java:124) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getEndpoints(EndpointDiscoverer.java:117) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration.getHealthEndpoint(HealthEndpointWebExtensionConfiguration.java:80) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration$MvcAdditionalHealthEndpointPathsConfiguration.healthEndpointWebMvcHandlerMapping(HealthEndpointWebExtensionConfiguration.java:95) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:663) + at org.springframework.context.support.AbstractApplicationContext.getBeansOfType(AbstractApplicationContext.java:1327) + at org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors(BeanFactoryUtils.java:368) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.initHandlerMappings(HandlerMappingIntrospector.java:130) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.afterPropertiesSet(HandlerMappingIntrospector.java:118) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:204) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1179) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.createMvcMatchers(AbstractRequestMatcherRegistry.java:116) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:207) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:360) + at com.bytedesk.starter.config.SecurityConfig.lambda$securityFilterChain$3(SecurityConfig.java:62) + at org.springframework.security.config.annotation.web.builders.HttpSecurity.authorizeHttpRequests(HttpSecurity.java:1467) + at com.bytedesk.starter.config.SecurityConfig.securityFilterChain(SecurityConfig.java:61) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.CGLIB$securityFilterChain$0() + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$FastClass$$1.invoke() + at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:258) + at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.securityFilterChain() + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.addCandidateEntry(DefaultListableBeanFactory.java:1687) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1651) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeanCollection(DefaultListableBeanFactory.java:1541) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeans(DefaultListableBeanFactory.java:1509) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1390) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.resolveMethodArguments(AutowiredAnnotationBeanPostProcessor.java:872) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:833) + at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:145) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:493) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1420) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:600) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:973) + at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:946) + at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:616) + at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) + at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:753) + at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:455) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:323) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1342) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1331) + at com.bytedesk.starter.StarterApplication.main(StarterApplication.java:30) +2024-04-30 09:36:01.394804+08:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Constraint "PK_QRTZ_LOCKS" already exists; SQL statement: +ALTER TABLE QRTZ_LOCKS ADD CONSTRAINT PK_QRTZ_LOCKS PRIMARY KEY ( SCHED_NAME, LOCK_NAME ) [90045-224] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:644) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:489) + at org.h2.message.DbException.get(DbException.java:223) + at org.h2.message.DbException.get(DbException.java:199) + at org.h2.command.ddl.AlterTableAddConstraint.tryUpdate(AlterTableAddConstraint.java:111) + at org.h2.command.ddl.AlterTableAddConstraint.update(AlterTableAddConstraint.java:74) + at org.h2.command.ddl.AlterTable.update(AlterTable.java:46) + at org.h2.command.CommandContainer.update(CommandContainer.java:169) + at org.h2.command.Command.executeUpdate(Command.java:256) + at org.h2.jdbc.JdbcStatement.executeInternal(JdbcStatement.java:262) + at org.h2.jdbc.JdbcStatement.execute(JdbcStatement.java:231) + at com.zaxxer.hikari.pool.ProxyStatement.execute(ProxyStatement.java:94) + at com.zaxxer.hikari.pool.HikariProxyStatement.execute(HikariProxyStatement.java) + at org.springframework.jdbc.datasource.init.ScriptUtils.executeSqlScript(ScriptUtils.java:261) + at org.springframework.jdbc.datasource.init.ResourceDatabasePopulator.populate(ResourceDatabasePopulator.java:254) + at org.springframework.jdbc.datasource.init.DatabasePopulatorUtils.execute(DatabasePopulatorUtils.java:54) + at org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer.runScripts(DataSourceScriptDatabaseInitializer.java:87) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.runScripts(AbstractScriptDatabaseInitializer.java:146) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applyScripts(AbstractScriptDatabaseInitializer.java:108) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applySchemaScripts(AbstractScriptDatabaseInitializer.java:98) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.initializeDatabase(AbstractScriptDatabaseInitializer.java:76) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.afterPropertiesSet(AbstractScriptDatabaseInitializer.java:66) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:312) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1441) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:911) + at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:789) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:546) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1173) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.lambda$createEndpointBean$1(EndpointDiscoverer.java:145) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer$EndpointBean.getBean(EndpointDiscoverer.java:456) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getFilterEndpoint(EndpointDiscoverer.java:314) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isFilterMatch(EndpointDiscoverer.java:290) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isExtensionExposed(EndpointDiscoverer.java:244) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBean(EndpointDiscoverer.java:170) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBeans(EndpointDiscoverer.java:159) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.discoverEndpoints(EndpointDiscoverer.java:124) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getEndpoints(EndpointDiscoverer.java:117) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration.getHealthEndpoint(HealthEndpointWebExtensionConfiguration.java:80) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration$MvcAdditionalHealthEndpointPathsConfiguration.healthEndpointWebMvcHandlerMapping(HealthEndpointWebExtensionConfiguration.java:95) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:663) + at org.springframework.context.support.AbstractApplicationContext.getBeansOfType(AbstractApplicationContext.java:1327) + at org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors(BeanFactoryUtils.java:368) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.initHandlerMappings(HandlerMappingIntrospector.java:130) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.afterPropertiesSet(HandlerMappingIntrospector.java:118) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:204) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1179) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.createMvcMatchers(AbstractRequestMatcherRegistry.java:116) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:207) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:360) + at com.bytedesk.starter.config.SecurityConfig.lambda$securityFilterChain$3(SecurityConfig.java:62) + at org.springframework.security.config.annotation.web.builders.HttpSecurity.authorizeHttpRequests(HttpSecurity.java:1467) + at com.bytedesk.starter.config.SecurityConfig.securityFilterChain(SecurityConfig.java:61) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.CGLIB$securityFilterChain$0() + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$FastClass$$1.invoke() + at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:258) + at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.securityFilterChain() + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.addCandidateEntry(DefaultListableBeanFactory.java:1687) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1651) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeanCollection(DefaultListableBeanFactory.java:1541) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeans(DefaultListableBeanFactory.java:1509) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1390) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.resolveMethodArguments(AutowiredAnnotationBeanPostProcessor.java:872) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:833) + at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:145) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:493) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1420) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:600) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:973) + at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:946) + at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:616) + at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) + at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:753) + at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:455) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:323) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1342) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1331) + at com.bytedesk.starter.StarterApplication.main(StarterApplication.java:30) +2024-04-30 09:36:01.395927+08:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Constraint "PK_QRTZ_JOB_DETAILS" already exists; SQL statement: +ALTER TABLE QRTZ_JOB_DETAILS ADD CONSTRAINT PK_QRTZ_JOB_DETAILS PRIMARY KEY ( SCHED_NAME, JOB_NAME, JOB_GROUP ) [90045-224] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:644) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:489) + at org.h2.message.DbException.get(DbException.java:223) + at org.h2.message.DbException.get(DbException.java:199) + at org.h2.command.ddl.AlterTableAddConstraint.tryUpdate(AlterTableAddConstraint.java:111) + at org.h2.command.ddl.AlterTableAddConstraint.update(AlterTableAddConstraint.java:74) + at org.h2.command.ddl.AlterTable.update(AlterTable.java:46) + at org.h2.command.CommandContainer.update(CommandContainer.java:169) + at org.h2.command.Command.executeUpdate(Command.java:256) + at org.h2.jdbc.JdbcStatement.executeInternal(JdbcStatement.java:262) + at org.h2.jdbc.JdbcStatement.execute(JdbcStatement.java:231) + at com.zaxxer.hikari.pool.ProxyStatement.execute(ProxyStatement.java:94) + at com.zaxxer.hikari.pool.HikariProxyStatement.execute(HikariProxyStatement.java) + at org.springframework.jdbc.datasource.init.ScriptUtils.executeSqlScript(ScriptUtils.java:261) + at org.springframework.jdbc.datasource.init.ResourceDatabasePopulator.populate(ResourceDatabasePopulator.java:254) + at org.springframework.jdbc.datasource.init.DatabasePopulatorUtils.execute(DatabasePopulatorUtils.java:54) + at org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer.runScripts(DataSourceScriptDatabaseInitializer.java:87) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.runScripts(AbstractScriptDatabaseInitializer.java:146) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applyScripts(AbstractScriptDatabaseInitializer.java:108) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applySchemaScripts(AbstractScriptDatabaseInitializer.java:98) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.initializeDatabase(AbstractScriptDatabaseInitializer.java:76) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.afterPropertiesSet(AbstractScriptDatabaseInitializer.java:66) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:312) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1441) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:911) + at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:789) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:546) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1173) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.lambda$createEndpointBean$1(EndpointDiscoverer.java:145) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer$EndpointBean.getBean(EndpointDiscoverer.java:456) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getFilterEndpoint(EndpointDiscoverer.java:314) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isFilterMatch(EndpointDiscoverer.java:290) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isExtensionExposed(EndpointDiscoverer.java:244) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBean(EndpointDiscoverer.java:170) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBeans(EndpointDiscoverer.java:159) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.discoverEndpoints(EndpointDiscoverer.java:124) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getEndpoints(EndpointDiscoverer.java:117) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration.getHealthEndpoint(HealthEndpointWebExtensionConfiguration.java:80) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration$MvcAdditionalHealthEndpointPathsConfiguration.healthEndpointWebMvcHandlerMapping(HealthEndpointWebExtensionConfiguration.java:95) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:663) + at org.springframework.context.support.AbstractApplicationContext.getBeansOfType(AbstractApplicationContext.java:1327) + at org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors(BeanFactoryUtils.java:368) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.initHandlerMappings(HandlerMappingIntrospector.java:130) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.afterPropertiesSet(HandlerMappingIntrospector.java:118) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:204) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1179) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.createMvcMatchers(AbstractRequestMatcherRegistry.java:116) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:207) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:360) + at com.bytedesk.starter.config.SecurityConfig.lambda$securityFilterChain$3(SecurityConfig.java:62) + at org.springframework.security.config.annotation.web.builders.HttpSecurity.authorizeHttpRequests(HttpSecurity.java:1467) + at com.bytedesk.starter.config.SecurityConfig.securityFilterChain(SecurityConfig.java:61) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.CGLIB$securityFilterChain$0() + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$FastClass$$1.invoke() + at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:258) + at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.securityFilterChain() + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.addCandidateEntry(DefaultListableBeanFactory.java:1687) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1651) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeanCollection(DefaultListableBeanFactory.java:1541) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeans(DefaultListableBeanFactory.java:1509) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1390) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.resolveMethodArguments(AutowiredAnnotationBeanPostProcessor.java:872) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:833) + at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:145) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:493) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1420) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:600) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:973) + at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:946) + at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:616) + at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) + at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:753) + at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:455) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:323) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1342) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1331) + at com.bytedesk.starter.StarterApplication.main(StarterApplication.java:30) +2024-04-30 09:36:01.396974+08:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Constraint "PK_QRTZ_SIMPLE_TRIGGERS" already exists; SQL statement: +ALTER TABLE QRTZ_SIMPLE_TRIGGERS ADD CONSTRAINT PK_QRTZ_SIMPLE_TRIGGERS PRIMARY KEY ( SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP ) [90045-224] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:644) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:489) + at org.h2.message.DbException.get(DbException.java:223) + at org.h2.message.DbException.get(DbException.java:199) + at org.h2.command.ddl.AlterTableAddConstraint.tryUpdate(AlterTableAddConstraint.java:111) + at org.h2.command.ddl.AlterTableAddConstraint.update(AlterTableAddConstraint.java:74) + at org.h2.command.ddl.AlterTable.update(AlterTable.java:46) + at org.h2.command.CommandContainer.update(CommandContainer.java:169) + at org.h2.command.Command.executeUpdate(Command.java:256) + at org.h2.jdbc.JdbcStatement.executeInternal(JdbcStatement.java:262) + at org.h2.jdbc.JdbcStatement.execute(JdbcStatement.java:231) + at com.zaxxer.hikari.pool.ProxyStatement.execute(ProxyStatement.java:94) + at com.zaxxer.hikari.pool.HikariProxyStatement.execute(HikariProxyStatement.java) + at org.springframework.jdbc.datasource.init.ScriptUtils.executeSqlScript(ScriptUtils.java:261) + at org.springframework.jdbc.datasource.init.ResourceDatabasePopulator.populate(ResourceDatabasePopulator.java:254) + at org.springframework.jdbc.datasource.init.DatabasePopulatorUtils.execute(DatabasePopulatorUtils.java:54) + at org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer.runScripts(DataSourceScriptDatabaseInitializer.java:87) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.runScripts(AbstractScriptDatabaseInitializer.java:146) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applyScripts(AbstractScriptDatabaseInitializer.java:108) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applySchemaScripts(AbstractScriptDatabaseInitializer.java:98) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.initializeDatabase(AbstractScriptDatabaseInitializer.java:76) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.afterPropertiesSet(AbstractScriptDatabaseInitializer.java:66) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:312) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1441) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:911) + at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:789) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:546) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1173) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.lambda$createEndpointBean$1(EndpointDiscoverer.java:145) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer$EndpointBean.getBean(EndpointDiscoverer.java:456) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getFilterEndpoint(EndpointDiscoverer.java:314) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isFilterMatch(EndpointDiscoverer.java:290) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isExtensionExposed(EndpointDiscoverer.java:244) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBean(EndpointDiscoverer.java:170) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBeans(EndpointDiscoverer.java:159) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.discoverEndpoints(EndpointDiscoverer.java:124) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getEndpoints(EndpointDiscoverer.java:117) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration.getHealthEndpoint(HealthEndpointWebExtensionConfiguration.java:80) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration$MvcAdditionalHealthEndpointPathsConfiguration.healthEndpointWebMvcHandlerMapping(HealthEndpointWebExtensionConfiguration.java:95) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:663) + at org.springframework.context.support.AbstractApplicationContext.getBeansOfType(AbstractApplicationContext.java:1327) + at org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors(BeanFactoryUtils.java:368) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.initHandlerMappings(HandlerMappingIntrospector.java:130) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.afterPropertiesSet(HandlerMappingIntrospector.java:118) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:204) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1179) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.createMvcMatchers(AbstractRequestMatcherRegistry.java:116) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:207) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:360) + at com.bytedesk.starter.config.SecurityConfig.lambda$securityFilterChain$3(SecurityConfig.java:62) + at org.springframework.security.config.annotation.web.builders.HttpSecurity.authorizeHttpRequests(HttpSecurity.java:1467) + at com.bytedesk.starter.config.SecurityConfig.securityFilterChain(SecurityConfig.java:61) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.CGLIB$securityFilterChain$0() + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$FastClass$$1.invoke() + at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:258) + at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.securityFilterChain() + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.addCandidateEntry(DefaultListableBeanFactory.java:1687) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1651) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeanCollection(DefaultListableBeanFactory.java:1541) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeans(DefaultListableBeanFactory.java:1509) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1390) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.resolveMethodArguments(AutowiredAnnotationBeanPostProcessor.java:872) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:833) + at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:145) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:493) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1420) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:600) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:973) + at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:946) + at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:616) + at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) + at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:753) + at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:455) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:323) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1342) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1331) + at com.bytedesk.starter.StarterApplication.main(StarterApplication.java:30) +2024-04-30 09:36:01.397894+08:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Constraint "PK_QRTZ_SIMPROP_TRIGGERS" already exists; SQL statement: +ALTER TABLE QRTZ_SIMPROP_TRIGGERS ADD CONSTRAINT PK_QRTZ_SIMPROP_TRIGGERS PRIMARY KEY ( SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP ) [90045-224] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:644) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:489) + at org.h2.message.DbException.get(DbException.java:223) + at org.h2.message.DbException.get(DbException.java:199) + at org.h2.command.ddl.AlterTableAddConstraint.tryUpdate(AlterTableAddConstraint.java:111) + at org.h2.command.ddl.AlterTableAddConstraint.update(AlterTableAddConstraint.java:74) + at org.h2.command.ddl.AlterTable.update(AlterTable.java:46) + at org.h2.command.CommandContainer.update(CommandContainer.java:169) + at org.h2.command.Command.executeUpdate(Command.java:256) + at org.h2.jdbc.JdbcStatement.executeInternal(JdbcStatement.java:262) + at org.h2.jdbc.JdbcStatement.execute(JdbcStatement.java:231) + at com.zaxxer.hikari.pool.ProxyStatement.execute(ProxyStatement.java:94) + at com.zaxxer.hikari.pool.HikariProxyStatement.execute(HikariProxyStatement.java) + at org.springframework.jdbc.datasource.init.ScriptUtils.executeSqlScript(ScriptUtils.java:261) + at org.springframework.jdbc.datasource.init.ResourceDatabasePopulator.populate(ResourceDatabasePopulator.java:254) + at org.springframework.jdbc.datasource.init.DatabasePopulatorUtils.execute(DatabasePopulatorUtils.java:54) + at org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer.runScripts(DataSourceScriptDatabaseInitializer.java:87) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.runScripts(AbstractScriptDatabaseInitializer.java:146) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applyScripts(AbstractScriptDatabaseInitializer.java:108) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applySchemaScripts(AbstractScriptDatabaseInitializer.java:98) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.initializeDatabase(AbstractScriptDatabaseInitializer.java:76) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.afterPropertiesSet(AbstractScriptDatabaseInitializer.java:66) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:312) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1441) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:911) + at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:789) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:546) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1173) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.lambda$createEndpointBean$1(EndpointDiscoverer.java:145) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer$EndpointBean.getBean(EndpointDiscoverer.java:456) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getFilterEndpoint(EndpointDiscoverer.java:314) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isFilterMatch(EndpointDiscoverer.java:290) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isExtensionExposed(EndpointDiscoverer.java:244) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBean(EndpointDiscoverer.java:170) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBeans(EndpointDiscoverer.java:159) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.discoverEndpoints(EndpointDiscoverer.java:124) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getEndpoints(EndpointDiscoverer.java:117) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration.getHealthEndpoint(HealthEndpointWebExtensionConfiguration.java:80) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration$MvcAdditionalHealthEndpointPathsConfiguration.healthEndpointWebMvcHandlerMapping(HealthEndpointWebExtensionConfiguration.java:95) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:663) + at org.springframework.context.support.AbstractApplicationContext.getBeansOfType(AbstractApplicationContext.java:1327) + at org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors(BeanFactoryUtils.java:368) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.initHandlerMappings(HandlerMappingIntrospector.java:130) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.afterPropertiesSet(HandlerMappingIntrospector.java:118) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:204) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1179) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.createMvcMatchers(AbstractRequestMatcherRegistry.java:116) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:207) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:360) + at com.bytedesk.starter.config.SecurityConfig.lambda$securityFilterChain$3(SecurityConfig.java:62) + at org.springframework.security.config.annotation.web.builders.HttpSecurity.authorizeHttpRequests(HttpSecurity.java:1467) + at com.bytedesk.starter.config.SecurityConfig.securityFilterChain(SecurityConfig.java:61) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.CGLIB$securityFilterChain$0() + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$FastClass$$1.invoke() + at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:258) + at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.securityFilterChain() + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.addCandidateEntry(DefaultListableBeanFactory.java:1687) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1651) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeanCollection(DefaultListableBeanFactory.java:1541) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeans(DefaultListableBeanFactory.java:1509) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1390) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.resolveMethodArguments(AutowiredAnnotationBeanPostProcessor.java:872) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:833) + at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:145) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:493) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1420) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:600) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:973) + at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:946) + at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:616) + at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) + at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:753) + at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:455) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:323) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1342) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1331) + at com.bytedesk.starter.StarterApplication.main(StarterApplication.java:30) +2024-04-30 09:36:01.398719+08:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Constraint "PK_QRTZ_TRIGGERS" already exists; SQL statement: +ALTER TABLE QRTZ_TRIGGERS ADD CONSTRAINT PK_QRTZ_TRIGGERS PRIMARY KEY ( SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP ) [90045-224] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:644) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:489) + at org.h2.message.DbException.get(DbException.java:223) + at org.h2.message.DbException.get(DbException.java:199) + at org.h2.command.ddl.AlterTableAddConstraint.tryUpdate(AlterTableAddConstraint.java:111) + at org.h2.command.ddl.AlterTableAddConstraint.update(AlterTableAddConstraint.java:74) + at org.h2.command.ddl.AlterTable.update(AlterTable.java:46) + at org.h2.command.CommandContainer.update(CommandContainer.java:169) + at org.h2.command.Command.executeUpdate(Command.java:256) + at org.h2.jdbc.JdbcStatement.executeInternal(JdbcStatement.java:262) + at org.h2.jdbc.JdbcStatement.execute(JdbcStatement.java:231) + at com.zaxxer.hikari.pool.ProxyStatement.execute(ProxyStatement.java:94) + at com.zaxxer.hikari.pool.HikariProxyStatement.execute(HikariProxyStatement.java) + at org.springframework.jdbc.datasource.init.ScriptUtils.executeSqlScript(ScriptUtils.java:261) + at org.springframework.jdbc.datasource.init.ResourceDatabasePopulator.populate(ResourceDatabasePopulator.java:254) + at org.springframework.jdbc.datasource.init.DatabasePopulatorUtils.execute(DatabasePopulatorUtils.java:54) + at org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer.runScripts(DataSourceScriptDatabaseInitializer.java:87) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.runScripts(AbstractScriptDatabaseInitializer.java:146) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applyScripts(AbstractScriptDatabaseInitializer.java:108) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applySchemaScripts(AbstractScriptDatabaseInitializer.java:98) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.initializeDatabase(AbstractScriptDatabaseInitializer.java:76) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.afterPropertiesSet(AbstractScriptDatabaseInitializer.java:66) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:312) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1441) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:911) + at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:789) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:546) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1173) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.lambda$createEndpointBean$1(EndpointDiscoverer.java:145) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer$EndpointBean.getBean(EndpointDiscoverer.java:456) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getFilterEndpoint(EndpointDiscoverer.java:314) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isFilterMatch(EndpointDiscoverer.java:290) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isExtensionExposed(EndpointDiscoverer.java:244) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBean(EndpointDiscoverer.java:170) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBeans(EndpointDiscoverer.java:159) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.discoverEndpoints(EndpointDiscoverer.java:124) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getEndpoints(EndpointDiscoverer.java:117) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration.getHealthEndpoint(HealthEndpointWebExtensionConfiguration.java:80) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration$MvcAdditionalHealthEndpointPathsConfiguration.healthEndpointWebMvcHandlerMapping(HealthEndpointWebExtensionConfiguration.java:95) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:663) + at org.springframework.context.support.AbstractApplicationContext.getBeansOfType(AbstractApplicationContext.java:1327) + at org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors(BeanFactoryUtils.java:368) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.initHandlerMappings(HandlerMappingIntrospector.java:130) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.afterPropertiesSet(HandlerMappingIntrospector.java:118) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:204) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1179) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.createMvcMatchers(AbstractRequestMatcherRegistry.java:116) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:207) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:360) + at com.bytedesk.starter.config.SecurityConfig.lambda$securityFilterChain$3(SecurityConfig.java:62) + at org.springframework.security.config.annotation.web.builders.HttpSecurity.authorizeHttpRequests(HttpSecurity.java:1467) + at com.bytedesk.starter.config.SecurityConfig.securityFilterChain(SecurityConfig.java:61) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.CGLIB$securityFilterChain$0() + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$FastClass$$1.invoke() + at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:258) + at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.securityFilterChain() + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.addCandidateEntry(DefaultListableBeanFactory.java:1687) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1651) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeanCollection(DefaultListableBeanFactory.java:1541) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeans(DefaultListableBeanFactory.java:1509) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1390) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.resolveMethodArguments(AutowiredAnnotationBeanPostProcessor.java:872) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:833) + at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:145) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:493) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1420) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:600) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:973) + at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:946) + at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:616) + at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) + at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:753) + at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:455) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:323) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1342) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1331) + at com.bytedesk.starter.StarterApplication.main(StarterApplication.java:30) +2024-04-30 09:36:01.399632+08:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Constraint "FK_QRTZ_CRON_TRIGGERS_QRTZ_TRIGGERS" already exists; SQL statement: +ALTER TABLE QRTZ_CRON_TRIGGERS ADD CONSTRAINT FK_QRTZ_CRON_TRIGGERS_QRTZ_TRIGGERS FOREIGN KEY ( SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP ) REFERENCES QRTZ_TRIGGERS ( SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP ) ON DELETE CASCADE [90045-224] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:644) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:489) + at org.h2.message.DbException.get(DbException.java:223) + at org.h2.message.DbException.get(DbException.java:199) + at org.h2.command.ddl.AlterTableAddConstraint.tryUpdate(AlterTableAddConstraint.java:111) + at org.h2.command.ddl.AlterTableAddConstraint.update(AlterTableAddConstraint.java:74) + at org.h2.command.ddl.AlterTable.update(AlterTable.java:46) + at org.h2.command.CommandContainer.update(CommandContainer.java:169) + at org.h2.command.Command.executeUpdate(Command.java:256) + at org.h2.jdbc.JdbcStatement.executeInternal(JdbcStatement.java:262) + at org.h2.jdbc.JdbcStatement.execute(JdbcStatement.java:231) + at com.zaxxer.hikari.pool.ProxyStatement.execute(ProxyStatement.java:94) + at com.zaxxer.hikari.pool.HikariProxyStatement.execute(HikariProxyStatement.java) + at org.springframework.jdbc.datasource.init.ScriptUtils.executeSqlScript(ScriptUtils.java:261) + at org.springframework.jdbc.datasource.init.ResourceDatabasePopulator.populate(ResourceDatabasePopulator.java:254) + at org.springframework.jdbc.datasource.init.DatabasePopulatorUtils.execute(DatabasePopulatorUtils.java:54) + at org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer.runScripts(DataSourceScriptDatabaseInitializer.java:87) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.runScripts(AbstractScriptDatabaseInitializer.java:146) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applyScripts(AbstractScriptDatabaseInitializer.java:108) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applySchemaScripts(AbstractScriptDatabaseInitializer.java:98) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.initializeDatabase(AbstractScriptDatabaseInitializer.java:76) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.afterPropertiesSet(AbstractScriptDatabaseInitializer.java:66) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:312) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1441) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:911) + at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:789) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:546) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1173) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.lambda$createEndpointBean$1(EndpointDiscoverer.java:145) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer$EndpointBean.getBean(EndpointDiscoverer.java:456) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getFilterEndpoint(EndpointDiscoverer.java:314) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isFilterMatch(EndpointDiscoverer.java:290) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isExtensionExposed(EndpointDiscoverer.java:244) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBean(EndpointDiscoverer.java:170) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBeans(EndpointDiscoverer.java:159) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.discoverEndpoints(EndpointDiscoverer.java:124) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getEndpoints(EndpointDiscoverer.java:117) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration.getHealthEndpoint(HealthEndpointWebExtensionConfiguration.java:80) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration$MvcAdditionalHealthEndpointPathsConfiguration.healthEndpointWebMvcHandlerMapping(HealthEndpointWebExtensionConfiguration.java:95) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:663) + at org.springframework.context.support.AbstractApplicationContext.getBeansOfType(AbstractApplicationContext.java:1327) + at org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors(BeanFactoryUtils.java:368) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.initHandlerMappings(HandlerMappingIntrospector.java:130) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.afterPropertiesSet(HandlerMappingIntrospector.java:118) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:204) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1179) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.createMvcMatchers(AbstractRequestMatcherRegistry.java:116) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:207) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:360) + at com.bytedesk.starter.config.SecurityConfig.lambda$securityFilterChain$3(SecurityConfig.java:62) + at org.springframework.security.config.annotation.web.builders.HttpSecurity.authorizeHttpRequests(HttpSecurity.java:1467) + at com.bytedesk.starter.config.SecurityConfig.securityFilterChain(SecurityConfig.java:61) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.CGLIB$securityFilterChain$0() + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$FastClass$$1.invoke() + at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:258) + at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.securityFilterChain() + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.addCandidateEntry(DefaultListableBeanFactory.java:1687) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1651) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeanCollection(DefaultListableBeanFactory.java:1541) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeans(DefaultListableBeanFactory.java:1509) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1390) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.resolveMethodArguments(AutowiredAnnotationBeanPostProcessor.java:872) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:833) + at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:145) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:493) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1420) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:600) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:973) + at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:946) + at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:616) + at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) + at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:753) + at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:455) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:323) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1342) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1331) + at com.bytedesk.starter.StarterApplication.main(StarterApplication.java:30) +2024-04-30 09:36:01.400547+08:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Constraint "FK_QRTZ_SIMPLE_TRIGGERS_QRTZ_TRIGGERS" already exists; SQL statement: +ALTER TABLE QRTZ_SIMPLE_TRIGGERS ADD CONSTRAINT FK_QRTZ_SIMPLE_TRIGGERS_QRTZ_TRIGGERS FOREIGN KEY ( SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP ) REFERENCES QRTZ_TRIGGERS ( SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP ) ON DELETE CASCADE [90045-224] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:644) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:489) + at org.h2.message.DbException.get(DbException.java:223) + at org.h2.message.DbException.get(DbException.java:199) + at org.h2.command.ddl.AlterTableAddConstraint.tryUpdate(AlterTableAddConstraint.java:111) + at org.h2.command.ddl.AlterTableAddConstraint.update(AlterTableAddConstraint.java:74) + at org.h2.command.ddl.AlterTable.update(AlterTable.java:46) + at org.h2.command.CommandContainer.update(CommandContainer.java:169) + at org.h2.command.Command.executeUpdate(Command.java:256) + at org.h2.jdbc.JdbcStatement.executeInternal(JdbcStatement.java:262) + at org.h2.jdbc.JdbcStatement.execute(JdbcStatement.java:231) + at com.zaxxer.hikari.pool.ProxyStatement.execute(ProxyStatement.java:94) + at com.zaxxer.hikari.pool.HikariProxyStatement.execute(HikariProxyStatement.java) + at org.springframework.jdbc.datasource.init.ScriptUtils.executeSqlScript(ScriptUtils.java:261) + at org.springframework.jdbc.datasource.init.ResourceDatabasePopulator.populate(ResourceDatabasePopulator.java:254) + at org.springframework.jdbc.datasource.init.DatabasePopulatorUtils.execute(DatabasePopulatorUtils.java:54) + at org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer.runScripts(DataSourceScriptDatabaseInitializer.java:87) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.runScripts(AbstractScriptDatabaseInitializer.java:146) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applyScripts(AbstractScriptDatabaseInitializer.java:108) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applySchemaScripts(AbstractScriptDatabaseInitializer.java:98) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.initializeDatabase(AbstractScriptDatabaseInitializer.java:76) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.afterPropertiesSet(AbstractScriptDatabaseInitializer.java:66) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:312) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1441) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:911) + at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:789) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:546) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1173) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.lambda$createEndpointBean$1(EndpointDiscoverer.java:145) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer$EndpointBean.getBean(EndpointDiscoverer.java:456) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getFilterEndpoint(EndpointDiscoverer.java:314) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isFilterMatch(EndpointDiscoverer.java:290) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isExtensionExposed(EndpointDiscoverer.java:244) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBean(EndpointDiscoverer.java:170) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBeans(EndpointDiscoverer.java:159) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.discoverEndpoints(EndpointDiscoverer.java:124) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getEndpoints(EndpointDiscoverer.java:117) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration.getHealthEndpoint(HealthEndpointWebExtensionConfiguration.java:80) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration$MvcAdditionalHealthEndpointPathsConfiguration.healthEndpointWebMvcHandlerMapping(HealthEndpointWebExtensionConfiguration.java:95) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:663) + at org.springframework.context.support.AbstractApplicationContext.getBeansOfType(AbstractApplicationContext.java:1327) + at org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors(BeanFactoryUtils.java:368) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.initHandlerMappings(HandlerMappingIntrospector.java:130) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.afterPropertiesSet(HandlerMappingIntrospector.java:118) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:204) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1179) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.createMvcMatchers(AbstractRequestMatcherRegistry.java:116) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:207) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:360) + at com.bytedesk.starter.config.SecurityConfig.lambda$securityFilterChain$3(SecurityConfig.java:62) + at org.springframework.security.config.annotation.web.builders.HttpSecurity.authorizeHttpRequests(HttpSecurity.java:1467) + at com.bytedesk.starter.config.SecurityConfig.securityFilterChain(SecurityConfig.java:61) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.CGLIB$securityFilterChain$0() + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$FastClass$$1.invoke() + at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:258) + at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.securityFilterChain() + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.addCandidateEntry(DefaultListableBeanFactory.java:1687) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1651) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeanCollection(DefaultListableBeanFactory.java:1541) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeans(DefaultListableBeanFactory.java:1509) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1390) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.resolveMethodArguments(AutowiredAnnotationBeanPostProcessor.java:872) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:833) + at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:145) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:493) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1420) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:600) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:973) + at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:946) + at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:616) + at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) + at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:753) + at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:455) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:323) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1342) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1331) + at com.bytedesk.starter.StarterApplication.main(StarterApplication.java:30) +2024-04-30 09:36:01.402504+08:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Constraint "FK_QRTZ_SIMPROP_TRIGGERS_QRTZ_TRIGGERS" already exists; SQL statement: +ALTER TABLE QRTZ_SIMPROP_TRIGGERS ADD CONSTRAINT FK_QRTZ_SIMPROP_TRIGGERS_QRTZ_TRIGGERS FOREIGN KEY ( SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP ) REFERENCES QRTZ_TRIGGERS ( SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP ) ON DELETE CASCADE [90045-224] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:644) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:489) + at org.h2.message.DbException.get(DbException.java:223) + at org.h2.message.DbException.get(DbException.java:199) + at org.h2.command.ddl.AlterTableAddConstraint.tryUpdate(AlterTableAddConstraint.java:111) + at org.h2.command.ddl.AlterTableAddConstraint.update(AlterTableAddConstraint.java:74) + at org.h2.command.ddl.AlterTable.update(AlterTable.java:46) + at org.h2.command.CommandContainer.update(CommandContainer.java:169) + at org.h2.command.Command.executeUpdate(Command.java:256) + at org.h2.jdbc.JdbcStatement.executeInternal(JdbcStatement.java:262) + at org.h2.jdbc.JdbcStatement.execute(JdbcStatement.java:231) + at com.zaxxer.hikari.pool.ProxyStatement.execute(ProxyStatement.java:94) + at com.zaxxer.hikari.pool.HikariProxyStatement.execute(HikariProxyStatement.java) + at org.springframework.jdbc.datasource.init.ScriptUtils.executeSqlScript(ScriptUtils.java:261) + at org.springframework.jdbc.datasource.init.ResourceDatabasePopulator.populate(ResourceDatabasePopulator.java:254) + at org.springframework.jdbc.datasource.init.DatabasePopulatorUtils.execute(DatabasePopulatorUtils.java:54) + at org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer.runScripts(DataSourceScriptDatabaseInitializer.java:87) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.runScripts(AbstractScriptDatabaseInitializer.java:146) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applyScripts(AbstractScriptDatabaseInitializer.java:108) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applySchemaScripts(AbstractScriptDatabaseInitializer.java:98) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.initializeDatabase(AbstractScriptDatabaseInitializer.java:76) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.afterPropertiesSet(AbstractScriptDatabaseInitializer.java:66) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:312) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1441) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:911) + at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:789) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:546) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1173) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.lambda$createEndpointBean$1(EndpointDiscoverer.java:145) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer$EndpointBean.getBean(EndpointDiscoverer.java:456) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getFilterEndpoint(EndpointDiscoverer.java:314) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isFilterMatch(EndpointDiscoverer.java:290) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isExtensionExposed(EndpointDiscoverer.java:244) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBean(EndpointDiscoverer.java:170) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBeans(EndpointDiscoverer.java:159) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.discoverEndpoints(EndpointDiscoverer.java:124) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getEndpoints(EndpointDiscoverer.java:117) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration.getHealthEndpoint(HealthEndpointWebExtensionConfiguration.java:80) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration$MvcAdditionalHealthEndpointPathsConfiguration.healthEndpointWebMvcHandlerMapping(HealthEndpointWebExtensionConfiguration.java:95) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:663) + at org.springframework.context.support.AbstractApplicationContext.getBeansOfType(AbstractApplicationContext.java:1327) + at org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors(BeanFactoryUtils.java:368) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.initHandlerMappings(HandlerMappingIntrospector.java:130) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.afterPropertiesSet(HandlerMappingIntrospector.java:118) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:204) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1179) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.createMvcMatchers(AbstractRequestMatcherRegistry.java:116) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:207) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:360) + at com.bytedesk.starter.config.SecurityConfig.lambda$securityFilterChain$3(SecurityConfig.java:62) + at org.springframework.security.config.annotation.web.builders.HttpSecurity.authorizeHttpRequests(HttpSecurity.java:1467) + at com.bytedesk.starter.config.SecurityConfig.securityFilterChain(SecurityConfig.java:61) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.CGLIB$securityFilterChain$0() + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$FastClass$$1.invoke() + at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:258) + at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.securityFilterChain() + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.addCandidateEntry(DefaultListableBeanFactory.java:1687) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1651) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeanCollection(DefaultListableBeanFactory.java:1541) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeans(DefaultListableBeanFactory.java:1509) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1390) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.resolveMethodArguments(AutowiredAnnotationBeanPostProcessor.java:872) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:833) + at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:145) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:493) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1420) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:600) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:973) + at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:946) + at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:616) + at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) + at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:753) + at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:455) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:323) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1342) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1331) + at com.bytedesk.starter.StarterApplication.main(StarterApplication.java:30) +2024-04-30 09:36:01.403482+08:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Constraint "FK_QRTZ_TRIGGERS_QRTZ_JOB_DETAILS" already exists; SQL statement: +ALTER TABLE QRTZ_TRIGGERS ADD CONSTRAINT FK_QRTZ_TRIGGERS_QRTZ_JOB_DETAILS FOREIGN KEY ( SCHED_NAME, JOB_NAME, JOB_GROUP ) REFERENCES QRTZ_JOB_DETAILS ( SCHED_NAME, JOB_NAME, JOB_GROUP ) [90045-224] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:644) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:489) + at org.h2.message.DbException.get(DbException.java:223) + at org.h2.message.DbException.get(DbException.java:199) + at org.h2.command.ddl.AlterTableAddConstraint.tryUpdate(AlterTableAddConstraint.java:111) + at org.h2.command.ddl.AlterTableAddConstraint.update(AlterTableAddConstraint.java:74) + at org.h2.command.ddl.AlterTable.update(AlterTable.java:46) + at org.h2.command.CommandContainer.update(CommandContainer.java:169) + at org.h2.command.Command.executeUpdate(Command.java:256) + at org.h2.jdbc.JdbcStatement.executeInternal(JdbcStatement.java:262) + at org.h2.jdbc.JdbcStatement.execute(JdbcStatement.java:231) + at com.zaxxer.hikari.pool.ProxyStatement.execute(ProxyStatement.java:94) + at com.zaxxer.hikari.pool.HikariProxyStatement.execute(HikariProxyStatement.java) + at org.springframework.jdbc.datasource.init.ScriptUtils.executeSqlScript(ScriptUtils.java:261) + at org.springframework.jdbc.datasource.init.ResourceDatabasePopulator.populate(ResourceDatabasePopulator.java:254) + at org.springframework.jdbc.datasource.init.DatabasePopulatorUtils.execute(DatabasePopulatorUtils.java:54) + at org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer.runScripts(DataSourceScriptDatabaseInitializer.java:87) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.runScripts(AbstractScriptDatabaseInitializer.java:146) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applyScripts(AbstractScriptDatabaseInitializer.java:108) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applySchemaScripts(AbstractScriptDatabaseInitializer.java:98) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.initializeDatabase(AbstractScriptDatabaseInitializer.java:76) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.afterPropertiesSet(AbstractScriptDatabaseInitializer.java:66) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:312) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1441) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:911) + at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:789) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:546) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1173) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.lambda$createEndpointBean$1(EndpointDiscoverer.java:145) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer$EndpointBean.getBean(EndpointDiscoverer.java:456) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getFilterEndpoint(EndpointDiscoverer.java:314) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isFilterMatch(EndpointDiscoverer.java:290) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isExtensionExposed(EndpointDiscoverer.java:244) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBean(EndpointDiscoverer.java:170) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBeans(EndpointDiscoverer.java:159) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.discoverEndpoints(EndpointDiscoverer.java:124) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getEndpoints(EndpointDiscoverer.java:117) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration.getHealthEndpoint(HealthEndpointWebExtensionConfiguration.java:80) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration$MvcAdditionalHealthEndpointPathsConfiguration.healthEndpointWebMvcHandlerMapping(HealthEndpointWebExtensionConfiguration.java:95) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:663) + at org.springframework.context.support.AbstractApplicationContext.getBeansOfType(AbstractApplicationContext.java:1327) + at org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors(BeanFactoryUtils.java:368) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.initHandlerMappings(HandlerMappingIntrospector.java:130) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.afterPropertiesSet(HandlerMappingIntrospector.java:118) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:204) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1179) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.createMvcMatchers(AbstractRequestMatcherRegistry.java:116) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:207) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:360) + at com.bytedesk.starter.config.SecurityConfig.lambda$securityFilterChain$3(SecurityConfig.java:62) + at org.springframework.security.config.annotation.web.builders.HttpSecurity.authorizeHttpRequests(HttpSecurity.java:1467) + at com.bytedesk.starter.config.SecurityConfig.securityFilterChain(SecurityConfig.java:61) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.CGLIB$securityFilterChain$0() + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$FastClass$$1.invoke() + at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:258) + at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.securityFilterChain() + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.addCandidateEntry(DefaultListableBeanFactory.java:1687) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1651) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeanCollection(DefaultListableBeanFactory.java:1541) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeans(DefaultListableBeanFactory.java:1509) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1390) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.resolveMethodArguments(AutowiredAnnotationBeanPostProcessor.java:872) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:833) + at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:145) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:493) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1420) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:600) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:973) + at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:946) + at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:616) + at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) + at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:753) + at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:455) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:323) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1342) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1331) + at com.bytedesk.starter.StarterApplication.main(StarterApplication.java:30) +2024-04-30 09:36:44.191145+08:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "QRTZ_CALENDARS" already exists; SQL statement: +CREATE TABLE QRTZ_CALENDARS ( SCHED_NAME VARCHAR(120) NOT NULL, CALENDAR_NAME VARCHAR (200) NOT NULL , CALENDAR IMAGE NOT NULL ) [42101-224] +2024-04-30 09:36:44.192067+08:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "QRTZ_CRON_TRIGGERS" already exists; SQL statement: +CREATE TABLE QRTZ_CRON_TRIGGERS ( SCHED_NAME VARCHAR(120) NOT NULL, TRIGGER_NAME VARCHAR (200) NOT NULL , TRIGGER_GROUP VARCHAR (200) NOT NULL , CRON_EXPRESSION VARCHAR (120) NOT NULL , TIME_ZONE_ID VARCHAR (80) ) [42101-224] +2024-04-30 09:36:44.192283+08:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "QRTZ_FIRED_TRIGGERS" already exists; SQL statement: +CREATE TABLE QRTZ_FIRED_TRIGGERS ( SCHED_NAME VARCHAR(120) NOT NULL, ENTRY_ID VARCHAR (95) NOT NULL , TRIGGER_NAME VARCHAR (200) NOT NULL , TRIGGER_GROUP VARCHAR (200) NOT NULL , INSTANCE_NAME VARCHAR (200) NOT NULL , FIRED_TIME BIGINT NOT NULL , SCHED_TIME BIGINT NOT NULL , PRIORITY INTEGER NOT NULL , STATE VARCHAR (16) NOT NULL, JOB_NAME VARCHAR (200) NULL , JOB_GROUP VARCHAR (200) NULL , IS_NONCONCURRENT BOOLEAN NULL , REQUESTS_RECOVERY BOOLEAN NULL ) [42101-224] +2024-04-30 09:36:44.192429+08:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "QRTZ_PAUSED_TRIGGER_GRPS" already exists; SQL statement: +CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS ( SCHED_NAME VARCHAR(120) NOT NULL, TRIGGER_GROUP VARCHAR (200) NOT NULL ) [42101-224] +2024-04-30 09:36:44.192603+08:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "QRTZ_SCHEDULER_STATE" already exists; SQL statement: +CREATE TABLE QRTZ_SCHEDULER_STATE ( SCHED_NAME VARCHAR(120) NOT NULL, INSTANCE_NAME VARCHAR (200) NOT NULL , LAST_CHECKIN_TIME BIGINT NOT NULL , CHECKIN_INTERVAL BIGINT NOT NULL ) [42101-224] +2024-04-30 09:36:44.192742+08:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "QRTZ_LOCKS" already exists; SQL statement: +CREATE TABLE QRTZ_LOCKS ( SCHED_NAME VARCHAR(120) NOT NULL, LOCK_NAME VARCHAR (40) NOT NULL ) [42101-224] +2024-04-30 09:36:44.193062+08:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "QRTZ_JOB_DETAILS" already exists; SQL statement: +CREATE TABLE QRTZ_JOB_DETAILS ( SCHED_NAME VARCHAR(120) NOT NULL, JOB_NAME VARCHAR (200) NOT NULL , JOB_GROUP VARCHAR (200) NOT NULL , DESCRIPTION VARCHAR (250) NULL , JOB_CLASS_NAME VARCHAR (250) NOT NULL , IS_DURABLE BOOLEAN NOT NULL , IS_NONCONCURRENT BOOLEAN NOT NULL , IS_UPDATE_DATA BOOLEAN NOT NULL , REQUESTS_RECOVERY BOOLEAN NOT NULL , JOB_DATA IMAGE NULL ) [42101-224] +2024-04-30 09:36:44.193291+08:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "QRTZ_SIMPLE_TRIGGERS" already exists; SQL statement: +CREATE TABLE QRTZ_SIMPLE_TRIGGERS ( SCHED_NAME VARCHAR(120) NOT NULL, TRIGGER_NAME VARCHAR (200) NOT NULL , TRIGGER_GROUP VARCHAR (200) NOT NULL , REPEAT_COUNT BIGINT NOT NULL , REPEAT_INTERVAL BIGINT NOT NULL , TIMES_TRIGGERED BIGINT NOT NULL ) [42101-224] +2024-04-30 09:36:44.193499+08:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "QRTZ_SIMPROP_TRIGGERS" already exists; SQL statement: +CREATE TABLE QRTZ_SIMPROP_TRIGGERS ( SCHED_NAME VARCHAR(120) NOT NULL, TRIGGER_NAME VARCHAR(200) NOT NULL, TRIGGER_GROUP VARCHAR(200) NOT NULL, STR_PROP_1 VARCHAR(512) NULL, STR_PROP_2 VARCHAR(512) NULL, STR_PROP_3 VARCHAR(512) NULL, INT_PROP_1 INTEGER NULL, INT_PROP_2 INTEGER NULL, LONG_PROP_1 BIGINT NULL, LONG_PROP_2 BIGINT NULL, DEC_PROP_1 NUMERIC(13,4) NULL, DEC_PROP_2 NUMERIC(13,4) NULL, BOOL_PROP_1 BOOLEAN NULL, BOOL_PROP_2 BOOLEAN NULL ) [42101-224] +2024-04-30 09:36:44.193660+08:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "QRTZ_BLOB_TRIGGERS" already exists; SQL statement: +CREATE TABLE QRTZ_BLOB_TRIGGERS ( SCHED_NAME VARCHAR(120) NOT NULL, TRIGGER_NAME VARCHAR (200) NOT NULL , TRIGGER_GROUP VARCHAR (200) NOT NULL , BLOB_DATA IMAGE NULL ) [42101-224] +2024-04-30 09:36:44.193885+08:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "QRTZ_TRIGGERS" already exists; SQL statement: +CREATE TABLE QRTZ_TRIGGERS ( SCHED_NAME VARCHAR(120) NOT NULL, TRIGGER_NAME VARCHAR (200) NOT NULL , TRIGGER_GROUP VARCHAR (200) NOT NULL , JOB_NAME VARCHAR (200) NOT NULL , JOB_GROUP VARCHAR (200) NOT NULL , DESCRIPTION VARCHAR (250) NULL , NEXT_FIRE_TIME BIGINT NULL , PREV_FIRE_TIME BIGINT NULL , PRIORITY INTEGER NULL , TRIGGER_STATE VARCHAR (16) NOT NULL , TRIGGER_TYPE VARCHAR (8) NOT NULL , START_TIME BIGINT NOT NULL , END_TIME BIGINT NULL , CALENDAR_NAME VARCHAR (200) NULL , MISFIRE_INSTR SMALLINT NULL , JOB_DATA IMAGE NULL ) [42101-224] +2024-04-30 09:36:44.194112+08:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Constraint "PK_QRTZ_CALENDARS" already exists; SQL statement: +ALTER TABLE QRTZ_CALENDARS ADD CONSTRAINT PK_QRTZ_CALENDARS PRIMARY KEY ( SCHED_NAME, CALENDAR_NAME ) [90045-224] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:644) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:489) + at org.h2.message.DbException.get(DbException.java:223) + at org.h2.message.DbException.get(DbException.java:199) + at org.h2.command.ddl.AlterTableAddConstraint.tryUpdate(AlterTableAddConstraint.java:111) + at org.h2.command.ddl.AlterTableAddConstraint.update(AlterTableAddConstraint.java:74) + at org.h2.command.ddl.AlterTable.update(AlterTable.java:46) + at org.h2.command.CommandContainer.update(CommandContainer.java:169) + at org.h2.command.Command.executeUpdate(Command.java:256) + at org.h2.jdbc.JdbcStatement.executeInternal(JdbcStatement.java:262) + at org.h2.jdbc.JdbcStatement.execute(JdbcStatement.java:231) + at com.zaxxer.hikari.pool.ProxyStatement.execute(ProxyStatement.java:94) + at com.zaxxer.hikari.pool.HikariProxyStatement.execute(HikariProxyStatement.java) + at org.springframework.jdbc.datasource.init.ScriptUtils.executeSqlScript(ScriptUtils.java:261) + at org.springframework.jdbc.datasource.init.ResourceDatabasePopulator.populate(ResourceDatabasePopulator.java:254) + at org.springframework.jdbc.datasource.init.DatabasePopulatorUtils.execute(DatabasePopulatorUtils.java:54) + at org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer.runScripts(DataSourceScriptDatabaseInitializer.java:87) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.runScripts(AbstractScriptDatabaseInitializer.java:146) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applyScripts(AbstractScriptDatabaseInitializer.java:108) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applySchemaScripts(AbstractScriptDatabaseInitializer.java:98) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.initializeDatabase(AbstractScriptDatabaseInitializer.java:76) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.afterPropertiesSet(AbstractScriptDatabaseInitializer.java:66) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:312) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1441) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:911) + at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:789) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:546) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1173) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.lambda$createEndpointBean$1(EndpointDiscoverer.java:145) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer$EndpointBean.getBean(EndpointDiscoverer.java:456) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getFilterEndpoint(EndpointDiscoverer.java:314) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isFilterMatch(EndpointDiscoverer.java:290) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isExtensionExposed(EndpointDiscoverer.java:244) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBean(EndpointDiscoverer.java:170) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBeans(EndpointDiscoverer.java:159) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.discoverEndpoints(EndpointDiscoverer.java:124) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getEndpoints(EndpointDiscoverer.java:117) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration.getHealthEndpoint(HealthEndpointWebExtensionConfiguration.java:80) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration$MvcAdditionalHealthEndpointPathsConfiguration.healthEndpointWebMvcHandlerMapping(HealthEndpointWebExtensionConfiguration.java:95) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:663) + at org.springframework.context.support.AbstractApplicationContext.getBeansOfType(AbstractApplicationContext.java:1327) + at org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors(BeanFactoryUtils.java:368) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.initHandlerMappings(HandlerMappingIntrospector.java:130) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.afterPropertiesSet(HandlerMappingIntrospector.java:118) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:204) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1179) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.createMvcMatchers(AbstractRequestMatcherRegistry.java:116) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:207) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:360) + at com.bytedesk.starter.config.SecurityConfig.lambda$securityFilterChain$3(SecurityConfig.java:62) + at org.springframework.security.config.annotation.web.builders.HttpSecurity.authorizeHttpRequests(HttpSecurity.java:1467) + at com.bytedesk.starter.config.SecurityConfig.securityFilterChain(SecurityConfig.java:61) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.CGLIB$securityFilterChain$3() + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$FastClass$$1.invoke() + at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:258) + at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.securityFilterChain() + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.addCandidateEntry(DefaultListableBeanFactory.java:1687) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1651) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeanCollection(DefaultListableBeanFactory.java:1541) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeans(DefaultListableBeanFactory.java:1509) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1390) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.resolveMethodArguments(AutowiredAnnotationBeanPostProcessor.java:872) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:833) + at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:145) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:493) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1420) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:600) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:973) + at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:946) + at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:616) + at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) + at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:753) + at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:455) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:323) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1342) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1331) + at com.bytedesk.starter.StarterApplication.main(StarterApplication.java:30) +2024-04-30 09:36:44.195810+08:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Constraint "PK_QRTZ_CRON_TRIGGERS" already exists; SQL statement: +ALTER TABLE QRTZ_CRON_TRIGGERS ADD CONSTRAINT PK_QRTZ_CRON_TRIGGERS PRIMARY KEY ( SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP ) [90045-224] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:644) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:489) + at org.h2.message.DbException.get(DbException.java:223) + at org.h2.message.DbException.get(DbException.java:199) + at org.h2.command.ddl.AlterTableAddConstraint.tryUpdate(AlterTableAddConstraint.java:111) + at org.h2.command.ddl.AlterTableAddConstraint.update(AlterTableAddConstraint.java:74) + at org.h2.command.ddl.AlterTable.update(AlterTable.java:46) + at org.h2.command.CommandContainer.update(CommandContainer.java:169) + at org.h2.command.Command.executeUpdate(Command.java:256) + at org.h2.jdbc.JdbcStatement.executeInternal(JdbcStatement.java:262) + at org.h2.jdbc.JdbcStatement.execute(JdbcStatement.java:231) + at com.zaxxer.hikari.pool.ProxyStatement.execute(ProxyStatement.java:94) + at com.zaxxer.hikari.pool.HikariProxyStatement.execute(HikariProxyStatement.java) + at org.springframework.jdbc.datasource.init.ScriptUtils.executeSqlScript(ScriptUtils.java:261) + at org.springframework.jdbc.datasource.init.ResourceDatabasePopulator.populate(ResourceDatabasePopulator.java:254) + at org.springframework.jdbc.datasource.init.DatabasePopulatorUtils.execute(DatabasePopulatorUtils.java:54) + at org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer.runScripts(DataSourceScriptDatabaseInitializer.java:87) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.runScripts(AbstractScriptDatabaseInitializer.java:146) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applyScripts(AbstractScriptDatabaseInitializer.java:108) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applySchemaScripts(AbstractScriptDatabaseInitializer.java:98) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.initializeDatabase(AbstractScriptDatabaseInitializer.java:76) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.afterPropertiesSet(AbstractScriptDatabaseInitializer.java:66) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:312) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1441) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:911) + at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:789) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:546) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1173) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.lambda$createEndpointBean$1(EndpointDiscoverer.java:145) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer$EndpointBean.getBean(EndpointDiscoverer.java:456) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getFilterEndpoint(EndpointDiscoverer.java:314) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isFilterMatch(EndpointDiscoverer.java:290) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isExtensionExposed(EndpointDiscoverer.java:244) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBean(EndpointDiscoverer.java:170) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBeans(EndpointDiscoverer.java:159) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.discoverEndpoints(EndpointDiscoverer.java:124) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getEndpoints(EndpointDiscoverer.java:117) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration.getHealthEndpoint(HealthEndpointWebExtensionConfiguration.java:80) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration$MvcAdditionalHealthEndpointPathsConfiguration.healthEndpointWebMvcHandlerMapping(HealthEndpointWebExtensionConfiguration.java:95) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:663) + at org.springframework.context.support.AbstractApplicationContext.getBeansOfType(AbstractApplicationContext.java:1327) + at org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors(BeanFactoryUtils.java:368) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.initHandlerMappings(HandlerMappingIntrospector.java:130) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.afterPropertiesSet(HandlerMappingIntrospector.java:118) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:204) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1179) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.createMvcMatchers(AbstractRequestMatcherRegistry.java:116) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:207) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:360) + at com.bytedesk.starter.config.SecurityConfig.lambda$securityFilterChain$3(SecurityConfig.java:62) + at org.springframework.security.config.annotation.web.builders.HttpSecurity.authorizeHttpRequests(HttpSecurity.java:1467) + at com.bytedesk.starter.config.SecurityConfig.securityFilterChain(SecurityConfig.java:61) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.CGLIB$securityFilterChain$3() + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$FastClass$$1.invoke() + at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:258) + at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.securityFilterChain() + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.addCandidateEntry(DefaultListableBeanFactory.java:1687) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1651) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeanCollection(DefaultListableBeanFactory.java:1541) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeans(DefaultListableBeanFactory.java:1509) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1390) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.resolveMethodArguments(AutowiredAnnotationBeanPostProcessor.java:872) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:833) + at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:145) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:493) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1420) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:600) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:973) + at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:946) + at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:616) + at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) + at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:753) + at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:455) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:323) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1342) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1331) + at com.bytedesk.starter.StarterApplication.main(StarterApplication.java:30) +2024-04-30 09:36:44.197198+08:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Constraint "PK_QRTZ_FIRED_TRIGGERS" already exists; SQL statement: +ALTER TABLE QRTZ_FIRED_TRIGGERS ADD CONSTRAINT PK_QRTZ_FIRED_TRIGGERS PRIMARY KEY ( SCHED_NAME, ENTRY_ID ) [90045-224] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:644) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:489) + at org.h2.message.DbException.get(DbException.java:223) + at org.h2.message.DbException.get(DbException.java:199) + at org.h2.command.ddl.AlterTableAddConstraint.tryUpdate(AlterTableAddConstraint.java:111) + at org.h2.command.ddl.AlterTableAddConstraint.update(AlterTableAddConstraint.java:74) + at org.h2.command.ddl.AlterTable.update(AlterTable.java:46) + at org.h2.command.CommandContainer.update(CommandContainer.java:169) + at org.h2.command.Command.executeUpdate(Command.java:256) + at org.h2.jdbc.JdbcStatement.executeInternal(JdbcStatement.java:262) + at org.h2.jdbc.JdbcStatement.execute(JdbcStatement.java:231) + at com.zaxxer.hikari.pool.ProxyStatement.execute(ProxyStatement.java:94) + at com.zaxxer.hikari.pool.HikariProxyStatement.execute(HikariProxyStatement.java) + at org.springframework.jdbc.datasource.init.ScriptUtils.executeSqlScript(ScriptUtils.java:261) + at org.springframework.jdbc.datasource.init.ResourceDatabasePopulator.populate(ResourceDatabasePopulator.java:254) + at org.springframework.jdbc.datasource.init.DatabasePopulatorUtils.execute(DatabasePopulatorUtils.java:54) + at org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer.runScripts(DataSourceScriptDatabaseInitializer.java:87) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.runScripts(AbstractScriptDatabaseInitializer.java:146) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applyScripts(AbstractScriptDatabaseInitializer.java:108) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applySchemaScripts(AbstractScriptDatabaseInitializer.java:98) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.initializeDatabase(AbstractScriptDatabaseInitializer.java:76) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.afterPropertiesSet(AbstractScriptDatabaseInitializer.java:66) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:312) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1441) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:911) + at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:789) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:546) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1173) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.lambda$createEndpointBean$1(EndpointDiscoverer.java:145) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer$EndpointBean.getBean(EndpointDiscoverer.java:456) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getFilterEndpoint(EndpointDiscoverer.java:314) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isFilterMatch(EndpointDiscoverer.java:290) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isExtensionExposed(EndpointDiscoverer.java:244) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBean(EndpointDiscoverer.java:170) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBeans(EndpointDiscoverer.java:159) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.discoverEndpoints(EndpointDiscoverer.java:124) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getEndpoints(EndpointDiscoverer.java:117) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration.getHealthEndpoint(HealthEndpointWebExtensionConfiguration.java:80) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration$MvcAdditionalHealthEndpointPathsConfiguration.healthEndpointWebMvcHandlerMapping(HealthEndpointWebExtensionConfiguration.java:95) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:663) + at org.springframework.context.support.AbstractApplicationContext.getBeansOfType(AbstractApplicationContext.java:1327) + at org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors(BeanFactoryUtils.java:368) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.initHandlerMappings(HandlerMappingIntrospector.java:130) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.afterPropertiesSet(HandlerMappingIntrospector.java:118) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:204) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1179) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.createMvcMatchers(AbstractRequestMatcherRegistry.java:116) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:207) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:360) + at com.bytedesk.starter.config.SecurityConfig.lambda$securityFilterChain$3(SecurityConfig.java:62) + at org.springframework.security.config.annotation.web.builders.HttpSecurity.authorizeHttpRequests(HttpSecurity.java:1467) + at com.bytedesk.starter.config.SecurityConfig.securityFilterChain(SecurityConfig.java:61) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.CGLIB$securityFilterChain$3() + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$FastClass$$1.invoke() + at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:258) + at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.securityFilterChain() + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.addCandidateEntry(DefaultListableBeanFactory.java:1687) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1651) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeanCollection(DefaultListableBeanFactory.java:1541) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeans(DefaultListableBeanFactory.java:1509) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1390) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.resolveMethodArguments(AutowiredAnnotationBeanPostProcessor.java:872) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:833) + at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:145) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:493) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1420) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:600) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:973) + at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:946) + at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:616) + at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) + at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:753) + at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:455) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:323) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1342) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1331) + at com.bytedesk.starter.StarterApplication.main(StarterApplication.java:30) +2024-04-30 09:36:44.198669+08:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Constraint "PK_QRTZ_PAUSED_TRIGGER_GRPS" already exists; SQL statement: +ALTER TABLE QRTZ_PAUSED_TRIGGER_GRPS ADD CONSTRAINT PK_QRTZ_PAUSED_TRIGGER_GRPS PRIMARY KEY ( SCHED_NAME, TRIGGER_GROUP ) [90045-224] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:644) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:489) + at org.h2.message.DbException.get(DbException.java:223) + at org.h2.message.DbException.get(DbException.java:199) + at org.h2.command.ddl.AlterTableAddConstraint.tryUpdate(AlterTableAddConstraint.java:111) + at org.h2.command.ddl.AlterTableAddConstraint.update(AlterTableAddConstraint.java:74) + at org.h2.command.ddl.AlterTable.update(AlterTable.java:46) + at org.h2.command.CommandContainer.update(CommandContainer.java:169) + at org.h2.command.Command.executeUpdate(Command.java:256) + at org.h2.jdbc.JdbcStatement.executeInternal(JdbcStatement.java:262) + at org.h2.jdbc.JdbcStatement.execute(JdbcStatement.java:231) + at com.zaxxer.hikari.pool.ProxyStatement.execute(ProxyStatement.java:94) + at com.zaxxer.hikari.pool.HikariProxyStatement.execute(HikariProxyStatement.java) + at org.springframework.jdbc.datasource.init.ScriptUtils.executeSqlScript(ScriptUtils.java:261) + at org.springframework.jdbc.datasource.init.ResourceDatabasePopulator.populate(ResourceDatabasePopulator.java:254) + at org.springframework.jdbc.datasource.init.DatabasePopulatorUtils.execute(DatabasePopulatorUtils.java:54) + at org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer.runScripts(DataSourceScriptDatabaseInitializer.java:87) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.runScripts(AbstractScriptDatabaseInitializer.java:146) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applyScripts(AbstractScriptDatabaseInitializer.java:108) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applySchemaScripts(AbstractScriptDatabaseInitializer.java:98) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.initializeDatabase(AbstractScriptDatabaseInitializer.java:76) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.afterPropertiesSet(AbstractScriptDatabaseInitializer.java:66) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:312) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1441) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:911) + at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:789) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:546) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1173) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.lambda$createEndpointBean$1(EndpointDiscoverer.java:145) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer$EndpointBean.getBean(EndpointDiscoverer.java:456) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getFilterEndpoint(EndpointDiscoverer.java:314) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isFilterMatch(EndpointDiscoverer.java:290) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isExtensionExposed(EndpointDiscoverer.java:244) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBean(EndpointDiscoverer.java:170) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBeans(EndpointDiscoverer.java:159) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.discoverEndpoints(EndpointDiscoverer.java:124) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getEndpoints(EndpointDiscoverer.java:117) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration.getHealthEndpoint(HealthEndpointWebExtensionConfiguration.java:80) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration$MvcAdditionalHealthEndpointPathsConfiguration.healthEndpointWebMvcHandlerMapping(HealthEndpointWebExtensionConfiguration.java:95) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:663) + at org.springframework.context.support.AbstractApplicationContext.getBeansOfType(AbstractApplicationContext.java:1327) + at org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors(BeanFactoryUtils.java:368) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.initHandlerMappings(HandlerMappingIntrospector.java:130) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.afterPropertiesSet(HandlerMappingIntrospector.java:118) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:204) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1179) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.createMvcMatchers(AbstractRequestMatcherRegistry.java:116) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:207) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:360) + at com.bytedesk.starter.config.SecurityConfig.lambda$securityFilterChain$3(SecurityConfig.java:62) + at org.springframework.security.config.annotation.web.builders.HttpSecurity.authorizeHttpRequests(HttpSecurity.java:1467) + at com.bytedesk.starter.config.SecurityConfig.securityFilterChain(SecurityConfig.java:61) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.CGLIB$securityFilterChain$3() + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$FastClass$$1.invoke() + at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:258) + at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.securityFilterChain() + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.addCandidateEntry(DefaultListableBeanFactory.java:1687) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1651) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeanCollection(DefaultListableBeanFactory.java:1541) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeans(DefaultListableBeanFactory.java:1509) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1390) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.resolveMethodArguments(AutowiredAnnotationBeanPostProcessor.java:872) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:833) + at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:145) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:493) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1420) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:600) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:973) + at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:946) + at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:616) + at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) + at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:753) + at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:455) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:323) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1342) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1331) + at com.bytedesk.starter.StarterApplication.main(StarterApplication.java:30) +2024-04-30 09:36:44.199771+08:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Constraint "PK_QRTZ_SCHEDULER_STATE" already exists; SQL statement: +ALTER TABLE QRTZ_SCHEDULER_STATE ADD CONSTRAINT PK_QRTZ_SCHEDULER_STATE PRIMARY KEY ( SCHED_NAME, INSTANCE_NAME ) [90045-224] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:644) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:489) + at org.h2.message.DbException.get(DbException.java:223) + at org.h2.message.DbException.get(DbException.java:199) + at org.h2.command.ddl.AlterTableAddConstraint.tryUpdate(AlterTableAddConstraint.java:111) + at org.h2.command.ddl.AlterTableAddConstraint.update(AlterTableAddConstraint.java:74) + at org.h2.command.ddl.AlterTable.update(AlterTable.java:46) + at org.h2.command.CommandContainer.update(CommandContainer.java:169) + at org.h2.command.Command.executeUpdate(Command.java:256) + at org.h2.jdbc.JdbcStatement.executeInternal(JdbcStatement.java:262) + at org.h2.jdbc.JdbcStatement.execute(JdbcStatement.java:231) + at com.zaxxer.hikari.pool.ProxyStatement.execute(ProxyStatement.java:94) + at com.zaxxer.hikari.pool.HikariProxyStatement.execute(HikariProxyStatement.java) + at org.springframework.jdbc.datasource.init.ScriptUtils.executeSqlScript(ScriptUtils.java:261) + at org.springframework.jdbc.datasource.init.ResourceDatabasePopulator.populate(ResourceDatabasePopulator.java:254) + at org.springframework.jdbc.datasource.init.DatabasePopulatorUtils.execute(DatabasePopulatorUtils.java:54) + at org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer.runScripts(DataSourceScriptDatabaseInitializer.java:87) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.runScripts(AbstractScriptDatabaseInitializer.java:146) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applyScripts(AbstractScriptDatabaseInitializer.java:108) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applySchemaScripts(AbstractScriptDatabaseInitializer.java:98) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.initializeDatabase(AbstractScriptDatabaseInitializer.java:76) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.afterPropertiesSet(AbstractScriptDatabaseInitializer.java:66) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:312) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1441) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:911) + at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:789) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:546) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1173) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.lambda$createEndpointBean$1(EndpointDiscoverer.java:145) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer$EndpointBean.getBean(EndpointDiscoverer.java:456) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getFilterEndpoint(EndpointDiscoverer.java:314) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isFilterMatch(EndpointDiscoverer.java:290) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isExtensionExposed(EndpointDiscoverer.java:244) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBean(EndpointDiscoverer.java:170) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBeans(EndpointDiscoverer.java:159) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.discoverEndpoints(EndpointDiscoverer.java:124) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getEndpoints(EndpointDiscoverer.java:117) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration.getHealthEndpoint(HealthEndpointWebExtensionConfiguration.java:80) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration$MvcAdditionalHealthEndpointPathsConfiguration.healthEndpointWebMvcHandlerMapping(HealthEndpointWebExtensionConfiguration.java:95) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:663) + at org.springframework.context.support.AbstractApplicationContext.getBeansOfType(AbstractApplicationContext.java:1327) + at org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors(BeanFactoryUtils.java:368) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.initHandlerMappings(HandlerMappingIntrospector.java:130) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.afterPropertiesSet(HandlerMappingIntrospector.java:118) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:204) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1179) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.createMvcMatchers(AbstractRequestMatcherRegistry.java:116) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:207) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:360) + at com.bytedesk.starter.config.SecurityConfig.lambda$securityFilterChain$3(SecurityConfig.java:62) + at org.springframework.security.config.annotation.web.builders.HttpSecurity.authorizeHttpRequests(HttpSecurity.java:1467) + at com.bytedesk.starter.config.SecurityConfig.securityFilterChain(SecurityConfig.java:61) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.CGLIB$securityFilterChain$3() + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$FastClass$$1.invoke() + at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:258) + at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.securityFilterChain() + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.addCandidateEntry(DefaultListableBeanFactory.java:1687) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1651) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeanCollection(DefaultListableBeanFactory.java:1541) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeans(DefaultListableBeanFactory.java:1509) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1390) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.resolveMethodArguments(AutowiredAnnotationBeanPostProcessor.java:872) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:833) + at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:145) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:493) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1420) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:600) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:973) + at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:946) + at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:616) + at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) + at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:753) + at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:455) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:323) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1342) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1331) + at com.bytedesk.starter.StarterApplication.main(StarterApplication.java:30) +2024-04-30 09:36:44.200827+08:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Constraint "PK_QRTZ_LOCKS" already exists; SQL statement: +ALTER TABLE QRTZ_LOCKS ADD CONSTRAINT PK_QRTZ_LOCKS PRIMARY KEY ( SCHED_NAME, LOCK_NAME ) [90045-224] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:644) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:489) + at org.h2.message.DbException.get(DbException.java:223) + at org.h2.message.DbException.get(DbException.java:199) + at org.h2.command.ddl.AlterTableAddConstraint.tryUpdate(AlterTableAddConstraint.java:111) + at org.h2.command.ddl.AlterTableAddConstraint.update(AlterTableAddConstraint.java:74) + at org.h2.command.ddl.AlterTable.update(AlterTable.java:46) + at org.h2.command.CommandContainer.update(CommandContainer.java:169) + at org.h2.command.Command.executeUpdate(Command.java:256) + at org.h2.jdbc.JdbcStatement.executeInternal(JdbcStatement.java:262) + at org.h2.jdbc.JdbcStatement.execute(JdbcStatement.java:231) + at com.zaxxer.hikari.pool.ProxyStatement.execute(ProxyStatement.java:94) + at com.zaxxer.hikari.pool.HikariProxyStatement.execute(HikariProxyStatement.java) + at org.springframework.jdbc.datasource.init.ScriptUtils.executeSqlScript(ScriptUtils.java:261) + at org.springframework.jdbc.datasource.init.ResourceDatabasePopulator.populate(ResourceDatabasePopulator.java:254) + at org.springframework.jdbc.datasource.init.DatabasePopulatorUtils.execute(DatabasePopulatorUtils.java:54) + at org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer.runScripts(DataSourceScriptDatabaseInitializer.java:87) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.runScripts(AbstractScriptDatabaseInitializer.java:146) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applyScripts(AbstractScriptDatabaseInitializer.java:108) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applySchemaScripts(AbstractScriptDatabaseInitializer.java:98) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.initializeDatabase(AbstractScriptDatabaseInitializer.java:76) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.afterPropertiesSet(AbstractScriptDatabaseInitializer.java:66) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:312) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1441) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:911) + at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:789) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:546) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1173) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.lambda$createEndpointBean$1(EndpointDiscoverer.java:145) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer$EndpointBean.getBean(EndpointDiscoverer.java:456) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getFilterEndpoint(EndpointDiscoverer.java:314) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isFilterMatch(EndpointDiscoverer.java:290) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isExtensionExposed(EndpointDiscoverer.java:244) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBean(EndpointDiscoverer.java:170) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBeans(EndpointDiscoverer.java:159) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.discoverEndpoints(EndpointDiscoverer.java:124) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getEndpoints(EndpointDiscoverer.java:117) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration.getHealthEndpoint(HealthEndpointWebExtensionConfiguration.java:80) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration$MvcAdditionalHealthEndpointPathsConfiguration.healthEndpointWebMvcHandlerMapping(HealthEndpointWebExtensionConfiguration.java:95) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:663) + at org.springframework.context.support.AbstractApplicationContext.getBeansOfType(AbstractApplicationContext.java:1327) + at org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors(BeanFactoryUtils.java:368) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.initHandlerMappings(HandlerMappingIntrospector.java:130) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.afterPropertiesSet(HandlerMappingIntrospector.java:118) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:204) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1179) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.createMvcMatchers(AbstractRequestMatcherRegistry.java:116) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:207) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:360) + at com.bytedesk.starter.config.SecurityConfig.lambda$securityFilterChain$3(SecurityConfig.java:62) + at org.springframework.security.config.annotation.web.builders.HttpSecurity.authorizeHttpRequests(HttpSecurity.java:1467) + at com.bytedesk.starter.config.SecurityConfig.securityFilterChain(SecurityConfig.java:61) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.CGLIB$securityFilterChain$3() + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$FastClass$$1.invoke() + at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:258) + at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.securityFilterChain() + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.addCandidateEntry(DefaultListableBeanFactory.java:1687) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1651) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeanCollection(DefaultListableBeanFactory.java:1541) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeans(DefaultListableBeanFactory.java:1509) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1390) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.resolveMethodArguments(AutowiredAnnotationBeanPostProcessor.java:872) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:833) + at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:145) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:493) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1420) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:600) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:973) + at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:946) + at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:616) + at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) + at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:753) + at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:455) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:323) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1342) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1331) + at com.bytedesk.starter.StarterApplication.main(StarterApplication.java:30) +2024-04-30 09:36:44.201884+08:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Constraint "PK_QRTZ_JOB_DETAILS" already exists; SQL statement: +ALTER TABLE QRTZ_JOB_DETAILS ADD CONSTRAINT PK_QRTZ_JOB_DETAILS PRIMARY KEY ( SCHED_NAME, JOB_NAME, JOB_GROUP ) [90045-224] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:644) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:489) + at org.h2.message.DbException.get(DbException.java:223) + at org.h2.message.DbException.get(DbException.java:199) + at org.h2.command.ddl.AlterTableAddConstraint.tryUpdate(AlterTableAddConstraint.java:111) + at org.h2.command.ddl.AlterTableAddConstraint.update(AlterTableAddConstraint.java:74) + at org.h2.command.ddl.AlterTable.update(AlterTable.java:46) + at org.h2.command.CommandContainer.update(CommandContainer.java:169) + at org.h2.command.Command.executeUpdate(Command.java:256) + at org.h2.jdbc.JdbcStatement.executeInternal(JdbcStatement.java:262) + at org.h2.jdbc.JdbcStatement.execute(JdbcStatement.java:231) + at com.zaxxer.hikari.pool.ProxyStatement.execute(ProxyStatement.java:94) + at com.zaxxer.hikari.pool.HikariProxyStatement.execute(HikariProxyStatement.java) + at org.springframework.jdbc.datasource.init.ScriptUtils.executeSqlScript(ScriptUtils.java:261) + at org.springframework.jdbc.datasource.init.ResourceDatabasePopulator.populate(ResourceDatabasePopulator.java:254) + at org.springframework.jdbc.datasource.init.DatabasePopulatorUtils.execute(DatabasePopulatorUtils.java:54) + at org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer.runScripts(DataSourceScriptDatabaseInitializer.java:87) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.runScripts(AbstractScriptDatabaseInitializer.java:146) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applyScripts(AbstractScriptDatabaseInitializer.java:108) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applySchemaScripts(AbstractScriptDatabaseInitializer.java:98) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.initializeDatabase(AbstractScriptDatabaseInitializer.java:76) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.afterPropertiesSet(AbstractScriptDatabaseInitializer.java:66) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:312) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1441) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:911) + at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:789) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:546) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1173) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.lambda$createEndpointBean$1(EndpointDiscoverer.java:145) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer$EndpointBean.getBean(EndpointDiscoverer.java:456) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getFilterEndpoint(EndpointDiscoverer.java:314) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isFilterMatch(EndpointDiscoverer.java:290) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isExtensionExposed(EndpointDiscoverer.java:244) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBean(EndpointDiscoverer.java:170) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBeans(EndpointDiscoverer.java:159) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.discoverEndpoints(EndpointDiscoverer.java:124) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getEndpoints(EndpointDiscoverer.java:117) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration.getHealthEndpoint(HealthEndpointWebExtensionConfiguration.java:80) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration$MvcAdditionalHealthEndpointPathsConfiguration.healthEndpointWebMvcHandlerMapping(HealthEndpointWebExtensionConfiguration.java:95) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:663) + at org.springframework.context.support.AbstractApplicationContext.getBeansOfType(AbstractApplicationContext.java:1327) + at org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors(BeanFactoryUtils.java:368) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.initHandlerMappings(HandlerMappingIntrospector.java:130) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.afterPropertiesSet(HandlerMappingIntrospector.java:118) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:204) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1179) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.createMvcMatchers(AbstractRequestMatcherRegistry.java:116) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:207) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:360) + at com.bytedesk.starter.config.SecurityConfig.lambda$securityFilterChain$3(SecurityConfig.java:62) + at org.springframework.security.config.annotation.web.builders.HttpSecurity.authorizeHttpRequests(HttpSecurity.java:1467) + at com.bytedesk.starter.config.SecurityConfig.securityFilterChain(SecurityConfig.java:61) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.CGLIB$securityFilterChain$3() + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$FastClass$$1.invoke() + at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:258) + at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.securityFilterChain() + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.addCandidateEntry(DefaultListableBeanFactory.java:1687) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1651) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeanCollection(DefaultListableBeanFactory.java:1541) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeans(DefaultListableBeanFactory.java:1509) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1390) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.resolveMethodArguments(AutowiredAnnotationBeanPostProcessor.java:872) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:833) + at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:145) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:493) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1420) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:600) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:973) + at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:946) + at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:616) + at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) + at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:753) + at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:455) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:323) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1342) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1331) + at com.bytedesk.starter.StarterApplication.main(StarterApplication.java:30) +2024-04-30 09:36:44.202928+08:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Constraint "PK_QRTZ_SIMPLE_TRIGGERS" already exists; SQL statement: +ALTER TABLE QRTZ_SIMPLE_TRIGGERS ADD CONSTRAINT PK_QRTZ_SIMPLE_TRIGGERS PRIMARY KEY ( SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP ) [90045-224] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:644) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:489) + at org.h2.message.DbException.get(DbException.java:223) + at org.h2.message.DbException.get(DbException.java:199) + at org.h2.command.ddl.AlterTableAddConstraint.tryUpdate(AlterTableAddConstraint.java:111) + at org.h2.command.ddl.AlterTableAddConstraint.update(AlterTableAddConstraint.java:74) + at org.h2.command.ddl.AlterTable.update(AlterTable.java:46) + at org.h2.command.CommandContainer.update(CommandContainer.java:169) + at org.h2.command.Command.executeUpdate(Command.java:256) + at org.h2.jdbc.JdbcStatement.executeInternal(JdbcStatement.java:262) + at org.h2.jdbc.JdbcStatement.execute(JdbcStatement.java:231) + at com.zaxxer.hikari.pool.ProxyStatement.execute(ProxyStatement.java:94) + at com.zaxxer.hikari.pool.HikariProxyStatement.execute(HikariProxyStatement.java) + at org.springframework.jdbc.datasource.init.ScriptUtils.executeSqlScript(ScriptUtils.java:261) + at org.springframework.jdbc.datasource.init.ResourceDatabasePopulator.populate(ResourceDatabasePopulator.java:254) + at org.springframework.jdbc.datasource.init.DatabasePopulatorUtils.execute(DatabasePopulatorUtils.java:54) + at org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer.runScripts(DataSourceScriptDatabaseInitializer.java:87) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.runScripts(AbstractScriptDatabaseInitializer.java:146) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applyScripts(AbstractScriptDatabaseInitializer.java:108) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applySchemaScripts(AbstractScriptDatabaseInitializer.java:98) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.initializeDatabase(AbstractScriptDatabaseInitializer.java:76) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.afterPropertiesSet(AbstractScriptDatabaseInitializer.java:66) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:312) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1441) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:911) + at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:789) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:546) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1173) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.lambda$createEndpointBean$1(EndpointDiscoverer.java:145) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer$EndpointBean.getBean(EndpointDiscoverer.java:456) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getFilterEndpoint(EndpointDiscoverer.java:314) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isFilterMatch(EndpointDiscoverer.java:290) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isExtensionExposed(EndpointDiscoverer.java:244) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBean(EndpointDiscoverer.java:170) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBeans(EndpointDiscoverer.java:159) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.discoverEndpoints(EndpointDiscoverer.java:124) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getEndpoints(EndpointDiscoverer.java:117) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration.getHealthEndpoint(HealthEndpointWebExtensionConfiguration.java:80) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration$MvcAdditionalHealthEndpointPathsConfiguration.healthEndpointWebMvcHandlerMapping(HealthEndpointWebExtensionConfiguration.java:95) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:663) + at org.springframework.context.support.AbstractApplicationContext.getBeansOfType(AbstractApplicationContext.java:1327) + at org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors(BeanFactoryUtils.java:368) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.initHandlerMappings(HandlerMappingIntrospector.java:130) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.afterPropertiesSet(HandlerMappingIntrospector.java:118) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:204) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1179) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.createMvcMatchers(AbstractRequestMatcherRegistry.java:116) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:207) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:360) + at com.bytedesk.starter.config.SecurityConfig.lambda$securityFilterChain$3(SecurityConfig.java:62) + at org.springframework.security.config.annotation.web.builders.HttpSecurity.authorizeHttpRequests(HttpSecurity.java:1467) + at com.bytedesk.starter.config.SecurityConfig.securityFilterChain(SecurityConfig.java:61) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.CGLIB$securityFilterChain$3() + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$FastClass$$1.invoke() + at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:258) + at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.securityFilterChain() + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.addCandidateEntry(DefaultListableBeanFactory.java:1687) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1651) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeanCollection(DefaultListableBeanFactory.java:1541) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeans(DefaultListableBeanFactory.java:1509) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1390) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.resolveMethodArguments(AutowiredAnnotationBeanPostProcessor.java:872) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:833) + at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:145) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:493) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1420) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:600) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:973) + at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:946) + at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:616) + at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) + at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:753) + at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:455) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:323) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1342) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1331) + at com.bytedesk.starter.StarterApplication.main(StarterApplication.java:30) +2024-04-30 09:36:44.204597+08:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Constraint "PK_QRTZ_SIMPROP_TRIGGERS" already exists; SQL statement: +ALTER TABLE QRTZ_SIMPROP_TRIGGERS ADD CONSTRAINT PK_QRTZ_SIMPROP_TRIGGERS PRIMARY KEY ( SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP ) [90045-224] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:644) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:489) + at org.h2.message.DbException.get(DbException.java:223) + at org.h2.message.DbException.get(DbException.java:199) + at org.h2.command.ddl.AlterTableAddConstraint.tryUpdate(AlterTableAddConstraint.java:111) + at org.h2.command.ddl.AlterTableAddConstraint.update(AlterTableAddConstraint.java:74) + at org.h2.command.ddl.AlterTable.update(AlterTable.java:46) + at org.h2.command.CommandContainer.update(CommandContainer.java:169) + at org.h2.command.Command.executeUpdate(Command.java:256) + at org.h2.jdbc.JdbcStatement.executeInternal(JdbcStatement.java:262) + at org.h2.jdbc.JdbcStatement.execute(JdbcStatement.java:231) + at com.zaxxer.hikari.pool.ProxyStatement.execute(ProxyStatement.java:94) + at com.zaxxer.hikari.pool.HikariProxyStatement.execute(HikariProxyStatement.java) + at org.springframework.jdbc.datasource.init.ScriptUtils.executeSqlScript(ScriptUtils.java:261) + at org.springframework.jdbc.datasource.init.ResourceDatabasePopulator.populate(ResourceDatabasePopulator.java:254) + at org.springframework.jdbc.datasource.init.DatabasePopulatorUtils.execute(DatabasePopulatorUtils.java:54) + at org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer.runScripts(DataSourceScriptDatabaseInitializer.java:87) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.runScripts(AbstractScriptDatabaseInitializer.java:146) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applyScripts(AbstractScriptDatabaseInitializer.java:108) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applySchemaScripts(AbstractScriptDatabaseInitializer.java:98) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.initializeDatabase(AbstractScriptDatabaseInitializer.java:76) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.afterPropertiesSet(AbstractScriptDatabaseInitializer.java:66) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:312) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1441) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:911) + at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:789) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:546) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1173) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.lambda$createEndpointBean$1(EndpointDiscoverer.java:145) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer$EndpointBean.getBean(EndpointDiscoverer.java:456) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getFilterEndpoint(EndpointDiscoverer.java:314) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isFilterMatch(EndpointDiscoverer.java:290) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isExtensionExposed(EndpointDiscoverer.java:244) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBean(EndpointDiscoverer.java:170) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBeans(EndpointDiscoverer.java:159) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.discoverEndpoints(EndpointDiscoverer.java:124) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getEndpoints(EndpointDiscoverer.java:117) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration.getHealthEndpoint(HealthEndpointWebExtensionConfiguration.java:80) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration$MvcAdditionalHealthEndpointPathsConfiguration.healthEndpointWebMvcHandlerMapping(HealthEndpointWebExtensionConfiguration.java:95) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:663) + at org.springframework.context.support.AbstractApplicationContext.getBeansOfType(AbstractApplicationContext.java:1327) + at org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors(BeanFactoryUtils.java:368) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.initHandlerMappings(HandlerMappingIntrospector.java:130) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.afterPropertiesSet(HandlerMappingIntrospector.java:118) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:204) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1179) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.createMvcMatchers(AbstractRequestMatcherRegistry.java:116) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:207) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:360) + at com.bytedesk.starter.config.SecurityConfig.lambda$securityFilterChain$3(SecurityConfig.java:62) + at org.springframework.security.config.annotation.web.builders.HttpSecurity.authorizeHttpRequests(HttpSecurity.java:1467) + at com.bytedesk.starter.config.SecurityConfig.securityFilterChain(SecurityConfig.java:61) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.CGLIB$securityFilterChain$3() + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$FastClass$$1.invoke() + at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:258) + at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.securityFilterChain() + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.addCandidateEntry(DefaultListableBeanFactory.java:1687) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1651) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeanCollection(DefaultListableBeanFactory.java:1541) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeans(DefaultListableBeanFactory.java:1509) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1390) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.resolveMethodArguments(AutowiredAnnotationBeanPostProcessor.java:872) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:833) + at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:145) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:493) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1420) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:600) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:973) + at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:946) + at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:616) + at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) + at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:753) + at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:455) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:323) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1342) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1331) + at com.bytedesk.starter.StarterApplication.main(StarterApplication.java:30) +2024-04-30 09:36:44.205731+08:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Constraint "PK_QRTZ_TRIGGERS" already exists; SQL statement: +ALTER TABLE QRTZ_TRIGGERS ADD CONSTRAINT PK_QRTZ_TRIGGERS PRIMARY KEY ( SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP ) [90045-224] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:644) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:489) + at org.h2.message.DbException.get(DbException.java:223) + at org.h2.message.DbException.get(DbException.java:199) + at org.h2.command.ddl.AlterTableAddConstraint.tryUpdate(AlterTableAddConstraint.java:111) + at org.h2.command.ddl.AlterTableAddConstraint.update(AlterTableAddConstraint.java:74) + at org.h2.command.ddl.AlterTable.update(AlterTable.java:46) + at org.h2.command.CommandContainer.update(CommandContainer.java:169) + at org.h2.command.Command.executeUpdate(Command.java:256) + at org.h2.jdbc.JdbcStatement.executeInternal(JdbcStatement.java:262) + at org.h2.jdbc.JdbcStatement.execute(JdbcStatement.java:231) + at com.zaxxer.hikari.pool.ProxyStatement.execute(ProxyStatement.java:94) + at com.zaxxer.hikari.pool.HikariProxyStatement.execute(HikariProxyStatement.java) + at org.springframework.jdbc.datasource.init.ScriptUtils.executeSqlScript(ScriptUtils.java:261) + at org.springframework.jdbc.datasource.init.ResourceDatabasePopulator.populate(ResourceDatabasePopulator.java:254) + at org.springframework.jdbc.datasource.init.DatabasePopulatorUtils.execute(DatabasePopulatorUtils.java:54) + at org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer.runScripts(DataSourceScriptDatabaseInitializer.java:87) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.runScripts(AbstractScriptDatabaseInitializer.java:146) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applyScripts(AbstractScriptDatabaseInitializer.java:108) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applySchemaScripts(AbstractScriptDatabaseInitializer.java:98) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.initializeDatabase(AbstractScriptDatabaseInitializer.java:76) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.afterPropertiesSet(AbstractScriptDatabaseInitializer.java:66) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:312) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1441) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:911) + at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:789) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:546) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1173) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.lambda$createEndpointBean$1(EndpointDiscoverer.java:145) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer$EndpointBean.getBean(EndpointDiscoverer.java:456) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getFilterEndpoint(EndpointDiscoverer.java:314) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isFilterMatch(EndpointDiscoverer.java:290) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isExtensionExposed(EndpointDiscoverer.java:244) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBean(EndpointDiscoverer.java:170) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBeans(EndpointDiscoverer.java:159) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.discoverEndpoints(EndpointDiscoverer.java:124) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getEndpoints(EndpointDiscoverer.java:117) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration.getHealthEndpoint(HealthEndpointWebExtensionConfiguration.java:80) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration$MvcAdditionalHealthEndpointPathsConfiguration.healthEndpointWebMvcHandlerMapping(HealthEndpointWebExtensionConfiguration.java:95) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:663) + at org.springframework.context.support.AbstractApplicationContext.getBeansOfType(AbstractApplicationContext.java:1327) + at org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors(BeanFactoryUtils.java:368) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.initHandlerMappings(HandlerMappingIntrospector.java:130) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.afterPropertiesSet(HandlerMappingIntrospector.java:118) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:204) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1179) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.createMvcMatchers(AbstractRequestMatcherRegistry.java:116) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:207) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:360) + at com.bytedesk.starter.config.SecurityConfig.lambda$securityFilterChain$3(SecurityConfig.java:62) + at org.springframework.security.config.annotation.web.builders.HttpSecurity.authorizeHttpRequests(HttpSecurity.java:1467) + at com.bytedesk.starter.config.SecurityConfig.securityFilterChain(SecurityConfig.java:61) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.CGLIB$securityFilterChain$3() + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$FastClass$$1.invoke() + at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:258) + at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.securityFilterChain() + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.addCandidateEntry(DefaultListableBeanFactory.java:1687) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1651) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeanCollection(DefaultListableBeanFactory.java:1541) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeans(DefaultListableBeanFactory.java:1509) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1390) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.resolveMethodArguments(AutowiredAnnotationBeanPostProcessor.java:872) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:833) + at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:145) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:493) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1420) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:600) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:973) + at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:946) + at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:616) + at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) + at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:753) + at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:455) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:323) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1342) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1331) + at com.bytedesk.starter.StarterApplication.main(StarterApplication.java:30) +2024-04-30 09:36:44.206971+08:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Constraint "FK_QRTZ_CRON_TRIGGERS_QRTZ_TRIGGERS" already exists; SQL statement: +ALTER TABLE QRTZ_CRON_TRIGGERS ADD CONSTRAINT FK_QRTZ_CRON_TRIGGERS_QRTZ_TRIGGERS FOREIGN KEY ( SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP ) REFERENCES QRTZ_TRIGGERS ( SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP ) ON DELETE CASCADE [90045-224] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:644) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:489) + at org.h2.message.DbException.get(DbException.java:223) + at org.h2.message.DbException.get(DbException.java:199) + at org.h2.command.ddl.AlterTableAddConstraint.tryUpdate(AlterTableAddConstraint.java:111) + at org.h2.command.ddl.AlterTableAddConstraint.update(AlterTableAddConstraint.java:74) + at org.h2.command.ddl.AlterTable.update(AlterTable.java:46) + at org.h2.command.CommandContainer.update(CommandContainer.java:169) + at org.h2.command.Command.executeUpdate(Command.java:256) + at org.h2.jdbc.JdbcStatement.executeInternal(JdbcStatement.java:262) + at org.h2.jdbc.JdbcStatement.execute(JdbcStatement.java:231) + at com.zaxxer.hikari.pool.ProxyStatement.execute(ProxyStatement.java:94) + at com.zaxxer.hikari.pool.HikariProxyStatement.execute(HikariProxyStatement.java) + at org.springframework.jdbc.datasource.init.ScriptUtils.executeSqlScript(ScriptUtils.java:261) + at org.springframework.jdbc.datasource.init.ResourceDatabasePopulator.populate(ResourceDatabasePopulator.java:254) + at org.springframework.jdbc.datasource.init.DatabasePopulatorUtils.execute(DatabasePopulatorUtils.java:54) + at org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer.runScripts(DataSourceScriptDatabaseInitializer.java:87) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.runScripts(AbstractScriptDatabaseInitializer.java:146) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applyScripts(AbstractScriptDatabaseInitializer.java:108) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applySchemaScripts(AbstractScriptDatabaseInitializer.java:98) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.initializeDatabase(AbstractScriptDatabaseInitializer.java:76) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.afterPropertiesSet(AbstractScriptDatabaseInitializer.java:66) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:312) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1441) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:911) + at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:789) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:546) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1173) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.lambda$createEndpointBean$1(EndpointDiscoverer.java:145) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer$EndpointBean.getBean(EndpointDiscoverer.java:456) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getFilterEndpoint(EndpointDiscoverer.java:314) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isFilterMatch(EndpointDiscoverer.java:290) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isExtensionExposed(EndpointDiscoverer.java:244) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBean(EndpointDiscoverer.java:170) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBeans(EndpointDiscoverer.java:159) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.discoverEndpoints(EndpointDiscoverer.java:124) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getEndpoints(EndpointDiscoverer.java:117) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration.getHealthEndpoint(HealthEndpointWebExtensionConfiguration.java:80) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration$MvcAdditionalHealthEndpointPathsConfiguration.healthEndpointWebMvcHandlerMapping(HealthEndpointWebExtensionConfiguration.java:95) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:663) + at org.springframework.context.support.AbstractApplicationContext.getBeansOfType(AbstractApplicationContext.java:1327) + at org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors(BeanFactoryUtils.java:368) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.initHandlerMappings(HandlerMappingIntrospector.java:130) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.afterPropertiesSet(HandlerMappingIntrospector.java:118) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:204) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1179) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.createMvcMatchers(AbstractRequestMatcherRegistry.java:116) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:207) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:360) + at com.bytedesk.starter.config.SecurityConfig.lambda$securityFilterChain$3(SecurityConfig.java:62) + at org.springframework.security.config.annotation.web.builders.HttpSecurity.authorizeHttpRequests(HttpSecurity.java:1467) + at com.bytedesk.starter.config.SecurityConfig.securityFilterChain(SecurityConfig.java:61) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.CGLIB$securityFilterChain$3() + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$FastClass$$1.invoke() + at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:258) + at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.securityFilterChain() + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.addCandidateEntry(DefaultListableBeanFactory.java:1687) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1651) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeanCollection(DefaultListableBeanFactory.java:1541) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeans(DefaultListableBeanFactory.java:1509) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1390) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.resolveMethodArguments(AutowiredAnnotationBeanPostProcessor.java:872) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:833) + at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:145) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:493) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1420) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:600) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:973) + at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:946) + at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:616) + at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) + at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:753) + at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:455) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:323) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1342) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1331) + at com.bytedesk.starter.StarterApplication.main(StarterApplication.java:30) +2024-04-30 09:36:44.207859+08:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Constraint "FK_QRTZ_SIMPLE_TRIGGERS_QRTZ_TRIGGERS" already exists; SQL statement: +ALTER TABLE QRTZ_SIMPLE_TRIGGERS ADD CONSTRAINT FK_QRTZ_SIMPLE_TRIGGERS_QRTZ_TRIGGERS FOREIGN KEY ( SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP ) REFERENCES QRTZ_TRIGGERS ( SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP ) ON DELETE CASCADE [90045-224] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:644) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:489) + at org.h2.message.DbException.get(DbException.java:223) + at org.h2.message.DbException.get(DbException.java:199) + at org.h2.command.ddl.AlterTableAddConstraint.tryUpdate(AlterTableAddConstraint.java:111) + at org.h2.command.ddl.AlterTableAddConstraint.update(AlterTableAddConstraint.java:74) + at org.h2.command.ddl.AlterTable.update(AlterTable.java:46) + at org.h2.command.CommandContainer.update(CommandContainer.java:169) + at org.h2.command.Command.executeUpdate(Command.java:256) + at org.h2.jdbc.JdbcStatement.executeInternal(JdbcStatement.java:262) + at org.h2.jdbc.JdbcStatement.execute(JdbcStatement.java:231) + at com.zaxxer.hikari.pool.ProxyStatement.execute(ProxyStatement.java:94) + at com.zaxxer.hikari.pool.HikariProxyStatement.execute(HikariProxyStatement.java) + at org.springframework.jdbc.datasource.init.ScriptUtils.executeSqlScript(ScriptUtils.java:261) + at org.springframework.jdbc.datasource.init.ResourceDatabasePopulator.populate(ResourceDatabasePopulator.java:254) + at org.springframework.jdbc.datasource.init.DatabasePopulatorUtils.execute(DatabasePopulatorUtils.java:54) + at org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer.runScripts(DataSourceScriptDatabaseInitializer.java:87) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.runScripts(AbstractScriptDatabaseInitializer.java:146) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applyScripts(AbstractScriptDatabaseInitializer.java:108) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applySchemaScripts(AbstractScriptDatabaseInitializer.java:98) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.initializeDatabase(AbstractScriptDatabaseInitializer.java:76) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.afterPropertiesSet(AbstractScriptDatabaseInitializer.java:66) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:312) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1441) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:911) + at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:789) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:546) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1173) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.lambda$createEndpointBean$1(EndpointDiscoverer.java:145) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer$EndpointBean.getBean(EndpointDiscoverer.java:456) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getFilterEndpoint(EndpointDiscoverer.java:314) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isFilterMatch(EndpointDiscoverer.java:290) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isExtensionExposed(EndpointDiscoverer.java:244) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBean(EndpointDiscoverer.java:170) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBeans(EndpointDiscoverer.java:159) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.discoverEndpoints(EndpointDiscoverer.java:124) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getEndpoints(EndpointDiscoverer.java:117) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration.getHealthEndpoint(HealthEndpointWebExtensionConfiguration.java:80) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration$MvcAdditionalHealthEndpointPathsConfiguration.healthEndpointWebMvcHandlerMapping(HealthEndpointWebExtensionConfiguration.java:95) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:663) + at org.springframework.context.support.AbstractApplicationContext.getBeansOfType(AbstractApplicationContext.java:1327) + at org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors(BeanFactoryUtils.java:368) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.initHandlerMappings(HandlerMappingIntrospector.java:130) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.afterPropertiesSet(HandlerMappingIntrospector.java:118) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:204) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1179) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.createMvcMatchers(AbstractRequestMatcherRegistry.java:116) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:207) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:360) + at com.bytedesk.starter.config.SecurityConfig.lambda$securityFilterChain$3(SecurityConfig.java:62) + at org.springframework.security.config.annotation.web.builders.HttpSecurity.authorizeHttpRequests(HttpSecurity.java:1467) + at com.bytedesk.starter.config.SecurityConfig.securityFilterChain(SecurityConfig.java:61) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.CGLIB$securityFilterChain$3() + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$FastClass$$1.invoke() + at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:258) + at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.securityFilterChain() + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.addCandidateEntry(DefaultListableBeanFactory.java:1687) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1651) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeanCollection(DefaultListableBeanFactory.java:1541) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeans(DefaultListableBeanFactory.java:1509) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1390) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.resolveMethodArguments(AutowiredAnnotationBeanPostProcessor.java:872) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:833) + at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:145) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:493) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1420) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:600) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:973) + at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:946) + at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:616) + at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) + at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:753) + at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:455) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:323) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1342) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1331) + at com.bytedesk.starter.StarterApplication.main(StarterApplication.java:30) +2024-04-30 09:36:44.208681+08:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Constraint "FK_QRTZ_SIMPROP_TRIGGERS_QRTZ_TRIGGERS" already exists; SQL statement: +ALTER TABLE QRTZ_SIMPROP_TRIGGERS ADD CONSTRAINT FK_QRTZ_SIMPROP_TRIGGERS_QRTZ_TRIGGERS FOREIGN KEY ( SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP ) REFERENCES QRTZ_TRIGGERS ( SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP ) ON DELETE CASCADE [90045-224] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:644) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:489) + at org.h2.message.DbException.get(DbException.java:223) + at org.h2.message.DbException.get(DbException.java:199) + at org.h2.command.ddl.AlterTableAddConstraint.tryUpdate(AlterTableAddConstraint.java:111) + at org.h2.command.ddl.AlterTableAddConstraint.update(AlterTableAddConstraint.java:74) + at org.h2.command.ddl.AlterTable.update(AlterTable.java:46) + at org.h2.command.CommandContainer.update(CommandContainer.java:169) + at org.h2.command.Command.executeUpdate(Command.java:256) + at org.h2.jdbc.JdbcStatement.executeInternal(JdbcStatement.java:262) + at org.h2.jdbc.JdbcStatement.execute(JdbcStatement.java:231) + at com.zaxxer.hikari.pool.ProxyStatement.execute(ProxyStatement.java:94) + at com.zaxxer.hikari.pool.HikariProxyStatement.execute(HikariProxyStatement.java) + at org.springframework.jdbc.datasource.init.ScriptUtils.executeSqlScript(ScriptUtils.java:261) + at org.springframework.jdbc.datasource.init.ResourceDatabasePopulator.populate(ResourceDatabasePopulator.java:254) + at org.springframework.jdbc.datasource.init.DatabasePopulatorUtils.execute(DatabasePopulatorUtils.java:54) + at org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer.runScripts(DataSourceScriptDatabaseInitializer.java:87) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.runScripts(AbstractScriptDatabaseInitializer.java:146) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applyScripts(AbstractScriptDatabaseInitializer.java:108) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applySchemaScripts(AbstractScriptDatabaseInitializer.java:98) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.initializeDatabase(AbstractScriptDatabaseInitializer.java:76) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.afterPropertiesSet(AbstractScriptDatabaseInitializer.java:66) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:312) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1441) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:911) + at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:789) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:546) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1173) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.lambda$createEndpointBean$1(EndpointDiscoverer.java:145) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer$EndpointBean.getBean(EndpointDiscoverer.java:456) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getFilterEndpoint(EndpointDiscoverer.java:314) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isFilterMatch(EndpointDiscoverer.java:290) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isExtensionExposed(EndpointDiscoverer.java:244) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBean(EndpointDiscoverer.java:170) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBeans(EndpointDiscoverer.java:159) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.discoverEndpoints(EndpointDiscoverer.java:124) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getEndpoints(EndpointDiscoverer.java:117) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration.getHealthEndpoint(HealthEndpointWebExtensionConfiguration.java:80) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration$MvcAdditionalHealthEndpointPathsConfiguration.healthEndpointWebMvcHandlerMapping(HealthEndpointWebExtensionConfiguration.java:95) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:663) + at org.springframework.context.support.AbstractApplicationContext.getBeansOfType(AbstractApplicationContext.java:1327) + at org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors(BeanFactoryUtils.java:368) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.initHandlerMappings(HandlerMappingIntrospector.java:130) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.afterPropertiesSet(HandlerMappingIntrospector.java:118) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:204) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1179) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.createMvcMatchers(AbstractRequestMatcherRegistry.java:116) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:207) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:360) + at com.bytedesk.starter.config.SecurityConfig.lambda$securityFilterChain$3(SecurityConfig.java:62) + at org.springframework.security.config.annotation.web.builders.HttpSecurity.authorizeHttpRequests(HttpSecurity.java:1467) + at com.bytedesk.starter.config.SecurityConfig.securityFilterChain(SecurityConfig.java:61) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.CGLIB$securityFilterChain$3() + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$FastClass$$1.invoke() + at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:258) + at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.securityFilterChain() + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.addCandidateEntry(DefaultListableBeanFactory.java:1687) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1651) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeanCollection(DefaultListableBeanFactory.java:1541) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeans(DefaultListableBeanFactory.java:1509) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1390) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.resolveMethodArguments(AutowiredAnnotationBeanPostProcessor.java:872) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:833) + at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:145) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:493) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1420) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:600) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:973) + at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:946) + at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:616) + at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) + at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:753) + at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:455) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:323) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1342) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1331) + at com.bytedesk.starter.StarterApplication.main(StarterApplication.java:30) +2024-04-30 09:36:44.209494+08:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Constraint "FK_QRTZ_TRIGGERS_QRTZ_JOB_DETAILS" already exists; SQL statement: +ALTER TABLE QRTZ_TRIGGERS ADD CONSTRAINT FK_QRTZ_TRIGGERS_QRTZ_JOB_DETAILS FOREIGN KEY ( SCHED_NAME, JOB_NAME, JOB_GROUP ) REFERENCES QRTZ_JOB_DETAILS ( SCHED_NAME, JOB_NAME, JOB_GROUP ) [90045-224] + at org.h2.message.DbException.getJdbcSQLException(DbException.java:644) + at org.h2.message.DbException.getJdbcSQLException(DbException.java:489) + at org.h2.message.DbException.get(DbException.java:223) + at org.h2.message.DbException.get(DbException.java:199) + at org.h2.command.ddl.AlterTableAddConstraint.tryUpdate(AlterTableAddConstraint.java:111) + at org.h2.command.ddl.AlterTableAddConstraint.update(AlterTableAddConstraint.java:74) + at org.h2.command.ddl.AlterTable.update(AlterTable.java:46) + at org.h2.command.CommandContainer.update(CommandContainer.java:169) + at org.h2.command.Command.executeUpdate(Command.java:256) + at org.h2.jdbc.JdbcStatement.executeInternal(JdbcStatement.java:262) + at org.h2.jdbc.JdbcStatement.execute(JdbcStatement.java:231) + at com.zaxxer.hikari.pool.ProxyStatement.execute(ProxyStatement.java:94) + at com.zaxxer.hikari.pool.HikariProxyStatement.execute(HikariProxyStatement.java) + at org.springframework.jdbc.datasource.init.ScriptUtils.executeSqlScript(ScriptUtils.java:261) + at org.springframework.jdbc.datasource.init.ResourceDatabasePopulator.populate(ResourceDatabasePopulator.java:254) + at org.springframework.jdbc.datasource.init.DatabasePopulatorUtils.execute(DatabasePopulatorUtils.java:54) + at org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer.runScripts(DataSourceScriptDatabaseInitializer.java:87) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.runScripts(AbstractScriptDatabaseInitializer.java:146) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applyScripts(AbstractScriptDatabaseInitializer.java:108) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.applySchemaScripts(AbstractScriptDatabaseInitializer.java:98) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.initializeDatabase(AbstractScriptDatabaseInitializer.java:76) + at org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer.afterPropertiesSet(AbstractScriptDatabaseInitializer.java:66) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:312) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1441) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:911) + at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:789) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:546) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1173) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.lambda$createEndpointBean$1(EndpointDiscoverer.java:145) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer$EndpointBean.getBean(EndpointDiscoverer.java:456) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getFilterEndpoint(EndpointDiscoverer.java:314) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isFilterMatch(EndpointDiscoverer.java:290) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.isExtensionExposed(EndpointDiscoverer.java:244) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBean(EndpointDiscoverer.java:170) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.addExtensionBeans(EndpointDiscoverer.java:159) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.discoverEndpoints(EndpointDiscoverer.java:124) + at org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer.getEndpoints(EndpointDiscoverer.java:117) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration.getHealthEndpoint(HealthEndpointWebExtensionConfiguration.java:80) + at org.springframework.boot.actuate.autoconfigure.health.HealthEndpointWebExtensionConfiguration$MvcAdditionalHealthEndpointPathsConfiguration.healthEndpointWebMvcHandlerMapping(HealthEndpointWebExtensionConfiguration.java:95) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:663) + at org.springframework.context.support.AbstractApplicationContext.getBeansOfType(AbstractApplicationContext.java:1327) + at org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors(BeanFactoryUtils.java:368) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.initHandlerMappings(HandlerMappingIntrospector.java:130) + at org.springframework.web.servlet.handler.HandlerMappingIntrospector.afterPropertiesSet(HandlerMappingIntrospector.java:118) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:204) + at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1179) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.createMvcMatchers(AbstractRequestMatcherRegistry.java:116) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:207) + at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:360) + at com.bytedesk.starter.config.SecurityConfig.lambda$securityFilterChain$3(SecurityConfig.java:62) + at org.springframework.security.config.annotation.web.builders.HttpSecurity.authorizeHttpRequests(HttpSecurity.java:1467) + at com.bytedesk.starter.config.SecurityConfig.securityFilterChain(SecurityConfig.java:61) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.CGLIB$securityFilterChain$3() + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$FastClass$$1.invoke() + at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:258) + at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331) + at com.bytedesk.starter.config.SecurityConfig$$SpringCGLIB$$0.securityFilterChain() + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) + at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) + at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:643) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1166) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:563) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.addCandidateEntry(DefaultListableBeanFactory.java:1687) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1651) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeanCollection(DefaultListableBeanFactory.java:1541) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeans(DefaultListableBeanFactory.java:1509) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1390) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1348) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.resolveMethodArguments(AutowiredAnnotationBeanPostProcessor.java:872) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:833) + at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:145) + at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:493) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1420) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:600) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:973) + at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:946) + at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:616) + at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) + at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:753) + at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:455) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:323) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1342) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1331) + at com.bytedesk.starter.StarterApplication.main(StarterApplication.java:30) diff --git a/modules/.DS_Store b/modules/.DS_Store index 1d954d5a01790c63318d351d2f31f371c10a8925..1b187718cb0ee6a4f8d6eafd816309eb4d31065b 100644 GIT binary patch delta 534 zcmZp1XmOa}FRH}Az`)4BAi$8EpIZQAGcd4j^50lEjeTMR?`C!m77k;O3MPg`hRmFF z!(e1pF!9`c7nh`*{3IZsW5Ss0Rm))q0OqF5{)K56m< z0SPuOXRs&M2}r@1=LDpgbOI*77La8+bzm}=pcLDuRInN?K^Yj+M^KJYVDe?b@65ar z7bl+;l4DDJ^%fKuAB7YUOp(dj!n{n94<=g)TeC1Q1^${`DJ;VlCI>ccwy+$GxnEe0 znSr@s@&h3K*J#INMiCh;zP%t-VBfPb6azhw%#h8H%20wF0uVKm-9_Y>8QCsO{vaa7 p%&uQCnO9VTZNd?-bF@XJU`%gO8ODZmaGcb&4L{Iuii|~~>kQ(@-3a&TkT5S97h_zZ!3@8Q^1BwB~fMQ@07=U*+ zX?np)q$@H@IDn%K?+j9cjGy&^WTjD-?~QLwtjpBQ3|I8WjVIfl&rX?H)m8V?&4+{|YYfq*o9|O=L@0dzX)iIuS3O z*|}e2ctc+ibDUnnJ@Sj-P9Ya?D{z*sgdF+#T-J)%-#vKL-FxSJOzI<|1$7cm^ew?jpcb-$-!0_8+1ggO)!)$5r>OFZZ;=)yCt@>mxFpS(+}2p|KdwA#5}`n#4Hm%`VG#Hu?e?CTjK2Vv$~K6 z)r)ytdb027VaAvgL(C)0M$7~K_y{n-M;n-EqS{CvL>thHd0aXEaPB&L0HqjW9$_|8 z9t@a6C3!+k~Uae4`N`UOK)qheqp8Hlp1(xm>s82O& Ya$F9WgcWH2{X>9y|5M)8u)7)f1Lccv1^@s6 diff --git a/modules/ai/.DS_Store b/modules/ai/.DS_Store index c05305064f0baeebc51550e35afe3ba6dbf68a6b..c6286d2b2bd4725e86fa3ab9a73595f51cefc8ba 100644 GIT binary patch delta 89 zcmZoMXffEJ!pwB>*JL&35JrW`)y#6tO!Ijs&taBfTYY71{-L*%_c6< com.bytedesk modules - 0.0.1-SNAPSHOT - weiyu-ai + im-ai ai Demo project for Spring Boot @@ -59,7 +58,7 @@ com.bytedesk - weiyu-core + im-core ${im.version} provided diff --git a/modules/ai/src/main/java/com/bytedesk/ai/kb/Kb.java b/modules/ai/src/main/java/com/bytedesk/ai/kb/Kb.java index ef54781f70..985286c86f 100644 --- a/modules/ai/src/main/java/com/bytedesk/ai/kb/Kb.java +++ b/modules/ai/src/main/java/com/bytedesk/ai/kb/Kb.java @@ -56,7 +56,7 @@ public class Kb extends AuditModel { private String embeddings; // is_published or not - // private Boolean published; + // private boolean published; /** * 所属用户 diff --git a/modules/ai/src/main/java/com/bytedesk/ai/kb/KbService.java b/modules/ai/src/main/java/com/bytedesk/ai/kb/KbService.java index a63fc5fcb9..cacd155134 100644 --- a/modules/ai/src/main/java/com/bytedesk/ai/kb/KbService.java +++ b/modules/ai/src/main/java/com/bytedesk/ai/kb/KbService.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-03-22 16:46:24 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-03-26 16:52:17 + * @LastEditTime: 2024-04-11 12:08:49 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -20,8 +20,8 @@ import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; +import com.bytedesk.core.uid.UidUtils; import com.bytedesk.core.utils.JsonResult; -import com.bytedesk.core.utils.Utils; import lombok.AllArgsConstructor; @@ -33,6 +33,8 @@ public class KbService { private final ModelMapper modelMapper; + private final UidUtils uidUtils; + public Page query(KbRequest kbRequest) { Pageable pageable = PageRequest.of(kbRequest.getPageNumber(), kbRequest.getPageSize(), Sort.Direction.DESC, @@ -44,7 +46,7 @@ public class KbService { public JsonResult create(KbRequest kbRequest) { Kb kb = modelMapper.map(kbRequest, Kb.class); - kb.setKid(Utils.getUid()); + kb.setKid(uidUtils.getCacheSerialUid()); // kb.setUser(authService.getCurrentUser()); @@ -54,11 +56,10 @@ public class KbService { } - @SuppressWarnings("null") public Kb getKb(String name) { Kb kb = Kb.builder() - .kid(Utils.getUid()) + .kid(uidUtils.getCacheSerialUid()) .name(name) .vectorStore("redis") .embeddings("m3e-base") diff --git a/modules/ai/src/main/java/com/bytedesk/ai/llm/LlmService.java b/modules/ai/src/main/java/com/bytedesk/ai/llm/LlmService.java index b8d367871d..a2cae1a8d6 100644 --- a/modules/ai/src/main/java/com/bytedesk/ai/llm/LlmService.java +++ b/modules/ai/src/main/java/com/bytedesk/ai/llm/LlmService.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-03-25 12:08:16 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-03-26 16:03:31 + * @LastEditTime: 2024-04-11 12:09:01 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -15,8 +15,8 @@ package com.bytedesk.ai.llm; import org.springframework.stereotype.Service; +import com.bytedesk.core.uid.UidUtils; import com.bytedesk.core.utils.JsonResult; -import com.bytedesk.core.utils.Utils; import lombok.AllArgsConstructor; @@ -26,7 +26,7 @@ public class LlmService { private LlmRepository llmRepository; - + private final UidUtils uidUtils; public JsonResult create(LlmRequest llmRequest) { @@ -36,7 +36,7 @@ public class LlmService { public Llm getLlm(String type) { Llm llm = new Llm(); - llm.setLid(Utils.getUid()); + llm.setLid(uidUtils.getCacheSerialUid()); llm.setName("智谱AI"); llm.setDescription("对接智谱API"); llm.setType(type); diff --git a/modules/ai/src/main/java/com/bytedesk/ai/robot/Robot.java b/modules/ai/src/main/java/com/bytedesk/ai/robot/Robot.java index d5917c2a15..a1d77f9761 100644 --- a/modules/ai/src/main/java/com/bytedesk/ai/robot/Robot.java +++ b/modules/ai/src/main/java/com/bytedesk/ai/robot/Robot.java @@ -74,7 +74,7 @@ public class Robot extends AuditModel { private String type; // is_published or not - private Boolean published; + private boolean published; /** * llm diff --git a/modules/ai/src/main/java/com/bytedesk/ai/robot/RobotRequest.java b/modules/ai/src/main/java/com/bytedesk/ai/robot/RobotRequest.java index 807af1b16c..ff5346d415 100644 --- a/modules/ai/src/main/java/com/bytedesk/ai/robot/RobotRequest.java +++ b/modules/ai/src/main/java/com/bytedesk/ai/robot/RobotRequest.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-03-22 16:45:07 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-03-25 16:42:02 + * @LastEditTime: 2024-04-16 12:01:55 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -35,7 +35,7 @@ public class RobotRequest extends BaseRequest { private String welcome; - private Boolean published; + // private boolean published; // diff --git a/modules/ai/src/main/java/com/bytedesk/ai/robot/RobotResponse.java b/modules/ai/src/main/java/com/bytedesk/ai/robot/RobotResponse.java index 6c95e0a86b..18801d8170 100644 --- a/modules/ai/src/main/java/com/bytedesk/ai/robot/RobotResponse.java +++ b/modules/ai/src/main/java/com/bytedesk/ai/robot/RobotResponse.java @@ -35,5 +35,5 @@ public class RobotResponse { private String welcome; - private Boolean published; + private boolean published; } diff --git a/modules/ai/src/main/java/com/bytedesk/ai/robot/RobotService.java b/modules/ai/src/main/java/com/bytedesk/ai/robot/RobotService.java index d48adb7e24..7a33bce20d 100644 --- a/modules/ai/src/main/java/com/bytedesk/ai/robot/RobotService.java +++ b/modules/ai/src/main/java/com/bytedesk/ai/robot/RobotService.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-03-22 16:44:41 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-03-27 17:14:46 + * @LastEditTime: 2024-04-17 23:57:32 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -24,12 +24,12 @@ import org.springframework.stereotype.Service; import com.bytedesk.ai.kb.KbService; import com.bytedesk.ai.llm.LlmService; -import com.bytedesk.core.auth.AuthService; import com.bytedesk.core.constant.AvatarConsts; +import com.bytedesk.core.rbac.auth.AuthService; import com.bytedesk.core.rbac.user.User; import com.bytedesk.core.rbac.user.UserService; +import com.bytedesk.core.uid.UidUtils; import com.bytedesk.core.utils.JsonResult; -import com.bytedesk.core.utils.Utils; import lombok.AllArgsConstructor; @@ -49,6 +49,8 @@ public class RobotService { private final ModelMapper modelMapper; + private final UidUtils uidUtils; + public Page query(RobotRequest robotRequest) { User user = authService.getCurrentUser(); @@ -71,7 +73,7 @@ public class RobotService { // Robot robot = modelMapper.map(robotRequest, Robot.class); // - String rid = Utils.getUid(); + String rid = uidUtils.getCacheSerialUid(); robot.setRid(rid); robot.setAvatar(AvatarConsts.DEFAULT_AVATAR_URL); @@ -90,7 +92,7 @@ public class RobotService { } - @SuppressWarnings("null") + // @SuppressWarnings("null") public void initData() { if (robotRepository.count() > 0) { @@ -101,7 +103,7 @@ public class RobotService { Optional adminOptional = userService.getAdmin(); if (adminOptional.isPresent()) { // - String rid = Utils.getUid(); + String rid = uidUtils.getCacheSerialUid(); Robot robot = Robot.builder() .rid(rid) .name("客服机器人") diff --git a/modules/blog/.DS_Store b/modules/blog/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..c8e40f1f7ee20f88f144cef0605667041fad0faf GIT binary patch literal 6148 zcmeHKyH3L}6uoY%s)&KY#Dx3>i0%xb3gQF$0hB&ehJ;k5FlXma_zHx?w=gj>AQ(8; z*J|yCFd_u^O7=Jm{0jj^$X?hE5Mw~95qhl>r5kpXPNXQ+m-PeVz)o9Fj z#C&a9V$}<*eoD)jb?1FE9&+F9eiV-{PWNbxa0Ycb@jUb|$~Qty75K*rV9#djYzu0y z3aA3Az)AsrKUg%z#A7MwULEM%5dheN+ZnFiw;j;31DJR$1>u1iDFsTY@kb0J0.0.1-SNAPSHOT - - weiyu-oa - + im-blog - oa + blog Demo project for Spring Boot - + + + - - - - - com.bytedesk - weiyu-core - ${im.version} - provided - - diff --git a/modules/oa/settings.gradle b/modules/blog/settings.gradle similarity index 71% rename from modules/oa/settings.gradle rename to modules/blog/settings.gradle index 6ef3a2607a..d0b56e297b 100644 --- a/modules/oa/settings.gradle +++ b/modules/blog/settings.gradle @@ -1,3 +1,3 @@ -rootProject.name = 'oa' +rootProject.name = 'blog' include ':core' project(':core').projectDir = new File('../core') \ No newline at end of file diff --git a/modules/oa/src/main/java/com/bytedesk/oa/OaApplication.java b/modules/blog/src/main/java/com/bytedesk/blog/BlogApplication.java similarity index 63% rename from modules/oa/src/main/java/com/bytedesk/oa/OaApplication.java rename to modules/blog/src/main/java/com/bytedesk/blog/BlogApplication.java index 4497c9a1e1..005183f96e 100644 --- a/modules/oa/src/main/java/com/bytedesk/oa/OaApplication.java +++ b/modules/blog/src/main/java/com/bytedesk/blog/BlogApplication.java @@ -1,13 +1,13 @@ -package com.bytedesk.oa; +package com.bytedesk.blog; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication -public class OaApplication { +public class BlogApplication { public static void main(String[] args) { - SpringApplication.run(OaApplication.class, args); + SpringApplication.run(BlogApplication.class, args); } } diff --git a/modules/blog/src/main/resources/application.properties b/modules/blog/src/main/resources/application.properties new file mode 100644 index 0000000000..4d636cbf1a --- /dev/null +++ b/modules/blog/src/main/resources/application.properties @@ -0,0 +1 @@ +spring.application.name=blog diff --git a/modules/oa/src/test/java/com/bytedesk/oa/OaApplicationTests.java b/modules/blog/src/test/java/com/bytedesk/blog/BlogApplicationTests.java similarity index 72% rename from modules/oa/src/test/java/com/bytedesk/oa/OaApplicationTests.java rename to modules/blog/src/test/java/com/bytedesk/blog/BlogApplicationTests.java index 926998573d..5d0c65ed41 100644 --- a/modules/oa/src/test/java/com/bytedesk/oa/OaApplicationTests.java +++ b/modules/blog/src/test/java/com/bytedesk/blog/BlogApplicationTests.java @@ -1,10 +1,10 @@ -package com.bytedesk.oa; +package com.bytedesk.blog; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; @SpringBootTest -class OaApplicationTests { +class BlogApplicationTests { @Test void contextLoads() { diff --git a/modules/core/.DS_Store b/modules/core/.DS_Store index 6bffcdbabeae23c442404b8f58189302224ec4f6..4a0beaf22b85842de4c74283349cd07a4528d3d6 100644 GIT binary patch delta 149 zcmZoMXffEJ%xudsb20.0.1-SNAPSHOT - weiyu-core - jar + im-core core Demo project for Spring Boot + 0.12.5 @@ -53,14 +53,14 @@ io.jsonwebtoken jjwt-api - 0.12.3 + ${jsonwebtoken.version} io.jsonwebtoken jjwt-impl - 0.12.3 + ${jsonwebtoken.version} runtime @@ -68,17 +68,10 @@ io.jsonwebtoken jjwt-jackson - 0.12.3 + ${jsonwebtoken.version} runtime - - - cn.hutool - hutool-all - 5.8.25 - - diff --git a/modules/core/src/main/java/com/bytedesk/core/.DS_Store b/modules/core/src/main/java/com/bytedesk/core/.DS_Store index 39a56b49cef839f5f47cc1d0424bdcb5109d0f47..4c93fb161bb435ef9d9a2bc3163462de1102e847 100644 GIT binary patch delta 48 xcmZn(XbG6$&*-}`U^hRb?`9r>)vTM%#S|DfKNnZv*jOOIxS3sH16)X#5deu84=Dfu delta 583 zcmZn(XbG6$<KfU^hQw=w=>))vWcb3`Gp73@Hqm48=L=hQZ1CxdjYhAhRDxA<5?E zySOCf { -@Configuration -public class CaffeineConfig { -} +} \ No newline at end of file diff --git a/modules/core/src/main/java/com/bytedesk/core/action/ActionRequest.java b/modules/core/src/main/java/com/bytedesk/core/action/ActionRequest.java new file mode 100644 index 0000000000..83bc1c7d68 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/action/ActionRequest.java @@ -0,0 +1,42 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-25 15:40:29 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-25 23:41:25 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.action; + +import com.bytedesk.core.utils.BaseRequest; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +@Data +@Builder +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = false) +@AllArgsConstructor +public class ActionRequest extends BaseRequest { + + private static final long serialVersionUID = 2108168382L; + + private String aid; + + private String title; + + private String action; + + private String description; + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/rbac/action/ActionResponse.java b/modules/core/src/main/java/com/bytedesk/core/action/ActionResponse.java similarity index 69% rename from modules/core/src/main/java/com/bytedesk/core/rbac/action/ActionResponse.java rename to modules/core/src/main/java/com/bytedesk/core/action/ActionResponse.java index 7192492ef9..df05728bfe 100644 --- a/modules/core/src/main/java/com/bytedesk/core/rbac/action/ActionResponse.java +++ b/modules/core/src/main/java/com/bytedesk/core/action/ActionResponse.java @@ -1,8 +1,8 @@ /* * @Author: jackning 270580156@qq.com - * @Date: 2024-01-29 16:21:24 + * @Date: 2024-04-25 15:40:39 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-03-29 14:03:33 + * @LastEditTime: 2024-04-25 15:46:33 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -12,26 +12,28 @@ * 联系:270580156@qq.com * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. */ -package com.bytedesk.core.rbac.action; +package com.bytedesk.core.action; import com.bytedesk.core.utils.BaseResponse; +import lombok.Builder; import lombok.Data; import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; -/** - * 对应权限Authority中操作:query/create/update/delete/import/export - * - * @author bytedesk.com on 2019-08-05 - */ @Data -@EqualsAndHashCode(callSuper = true) +@Builder +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = false) public class ActionResponse extends BaseResponse { - + + private static final long serialVersionUID = -4636716962L; + private String aid; + + private String title; - private String name; - - private String value; + private String action; + private String description; } diff --git a/modules/core/src/main/java/com/bytedesk/core/action/ActionService.java b/modules/core/src/main/java/com/bytedesk/core/action/ActionService.java new file mode 100644 index 0000000000..8249129ceb --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/action/ActionService.java @@ -0,0 +1,50 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-25 15:41:47 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-25 15:52:51 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.action; + +import org.modelmapper.ModelMapper; +import org.springframework.stereotype.Service; + +import com.bytedesk.core.uid.UidUtils; + +import lombok.AllArgsConstructor; + +@Service +@AllArgsConstructor +public class ActionService { + + private final ActionRepository actionRepository; + + private final ModelMapper modelMapper; + + private final UidUtils uidUtils; + + public Action create(ActionRequest actionRequest) { + + Action action = modelMapper.map(actionRequest, Action.class); + action.setAid(uidUtils.getCacheSerialUid()); + + return save(action); + } + + public Action save(Action action) { + return actionRepository.save(action); + } + + public ActionResponse convertToActionResponse(Action action) { + return modelMapper.map(action, ActionResponse.class); + } + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/annotation/ActionLog.java b/modules/core/src/main/java/com/bytedesk/core/annotation/ActionLog.java new file mode 100644 index 0000000000..1f60741f8f --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/annotation/ActionLog.java @@ -0,0 +1,39 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-17 16:53:05 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-25 15:38:58 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 自定义操作日志记录注解 + * + * @author jackning + * + */ +@Target({ ElementType.PARAMETER, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface ActionLog { + + public String title() default ""; + + public String action() default ""; + + public String description() default ""; +} diff --git a/modules/core/src/main/java/com/bytedesk/core/annotation/ApiRateLimiter.java b/modules/core/src/main/java/com/bytedesk/core/annotation/ApiRateLimiter.java new file mode 100644 index 0000000000..e3df9852e9 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/annotation/ApiRateLimiter.java @@ -0,0 +1,56 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-09 11:58:06 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-09 11:58:12 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.annotation; + +import java.lang.annotation.*; +import java.util.concurrent.TimeUnit; + +import org.springframework.core.annotation.AliasFor; + +/** + * https://blog.csdn.net/MICHAELKING1/article/details/106058874 + * + * @author dyz + * @version 1.0 + * @date 2020/5/11 15:40 api rate limiter + */ +@Target({ ElementType.METHOD, ElementType.TYPE }) +@Retention(value = RetentionPolicy.RUNTIME) +@Documented +public @interface ApiRateLimiter { + + // + int NOT_LIMITED = 0; + + /** + * qps + */ + @AliasFor("qps") double value() default NOT_LIMITED; + + /** + * qps + */ + @AliasFor("value") double qps() default NOT_LIMITED; + + /** + * 超时时长 + */ + int timeout() default 0; + + /** + * 超时时间单位 + */ + TimeUnit timeUnit() default TimeUnit.SECONDS; +} diff --git a/modules/core/src/main/java/com/bytedesk/core/aop/ApiRateLimiterAspect.java b/modules/core/src/main/java/com/bytedesk/core/aop/ApiRateLimiterAspect.java new file mode 100644 index 0000000000..c4a32cf73f --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/aop/ApiRateLimiterAspect.java @@ -0,0 +1,80 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-09 11:59:04 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-09 12:49:23 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.aop; + +import java.lang.reflect.Method; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.stereotype.Component; + +import com.bytedesk.core.annotation.ApiRateLimiter; +import com.bytedesk.core.utils.JsonResult; + +import lombok.extern.slf4j.Slf4j; +import com.google.common.util.concurrent.RateLimiter; + + +/** + * https://blog.csdn.net/MICHAELKING1/article/details/106058874 + */ +@Slf4j +@Aspect +@Component +public class ApiRateLimiterAspect { + + private static final ConcurrentMap RATE_LIMITER_CACHE = new ConcurrentHashMap<>(); + + @Pointcut("@annotation(com.bytedesk.core.annotation.ApiRateLimiter)") + public void apiRateLimit() {} + + @Around("apiRateLimit()") + public Object pointcut(ProceedingJoinPoint point) throws Throwable { + // + MethodSignature signature = (MethodSignature) point.getSignature(); + Method method = signature.getMethod(); + // 通过 AnnotationUtils.findAnnotation 获取 RateLimiter 注解 + ApiRateLimiter apiRateLimiter = AnnotationUtils.findAnnotation(method, ApiRateLimiter.class); + // + boolean proceed = true; + if (apiRateLimiter != null && apiRateLimiter.qps() > ApiRateLimiter.NOT_LIMITED) { + double qps = apiRateLimiter.qps(); + if (RATE_LIMITER_CACHE.get(method.getName()) == null) { + // 初始化 QPS + RATE_LIMITER_CACHE.put(method.getName(), RateLimiter.create(qps)); + } + log.debug("api {}, {}", method.getName(), RATE_LIMITER_CACHE.get(method.getName()).getRate()); + // 尝试获取令牌 + if (RATE_LIMITER_CACHE.get(method.getName()) != null && !RATE_LIMITER_CACHE.get(method.getName()) + .tryAcquire(apiRateLimiter.timeout(), apiRateLimiter.timeUnit())) { + proceed = false; + log.debug("api out of limit, please try later"); + } + } + // + if (proceed) { + return point.proceed(); + } + // + return JsonResult.error("api out of limit, please try later"); + } + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/asistant/Asistant.java b/modules/core/src/main/java/com/bytedesk/core/asistant/Asistant.java new file mode 100644 index 0000000000..6aa5755ade --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/asistant/Asistant.java @@ -0,0 +1,67 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-26 20:32:23 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-28 10:55:02 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.asistant; + +import com.bytedesk.core.utils.AuditModel; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EntityListeners; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +/** + * asistant - 如:文件助手 + */ +@Entity +@Data +@Builder +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = true) +@AllArgsConstructor +@NoArgsConstructor +@EntityListeners({ AsistantListener.class }) +@Table(name = "core_asistant") +public class Asistant extends AuditModel { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private Long id; + + @Column(unique = true, nullable = false, length = 127) + private String aid; + + private String topic; + + @Column(name = "by_type") + private String type; + + private String name; + + private String avatar; + + private String description; + + /** belong to org */ + private String orgOid; +} diff --git a/modules/core/src/main/java/com/bytedesk/core/asistant/AsistantController.java b/modules/core/src/main/java/com/bytedesk/core/asistant/AsistantController.java new file mode 100644 index 0000000000..07b690eae3 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/asistant/AsistantController.java @@ -0,0 +1,58 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-26 21:04:43 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-26 22:54:06 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.asistant; + +import org.springframework.data.domain.Page; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.bytedesk.core.utils.JsonResult; + +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; + +/** + * + * http://localhost:9003/swagger-ui/index.html + */ +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/v1/asistant") +@Tag(name = "asistant - 助手", description = "asistant apis") +public class AsistantController { + + private final AsistantService asistantService; + + /** + * query asistant + * + * @return json + */ + @GetMapping("/query") + public ResponseEntity query(AsistantRequest asistantRequest) { + // + Page asistantPage = asistantService.query(asistantRequest); + // + return ResponseEntity.ok(JsonResult.success(asistantPage)); + } + + + + + + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/asistant/AsistantListener.java b/modules/core/src/main/java/com/bytedesk/core/asistant/AsistantListener.java new file mode 100644 index 0000000000..4b3701b958 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/asistant/AsistantListener.java @@ -0,0 +1,34 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-27 12:09:59 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-27 13:00:43 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.asistant; + +import org.springframework.stereotype.Component; + +import jakarta.persistence.PostPersist; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Component +public class AsistantListener { + + + @PostPersist + public void onPostPersist(Asistant asistant) { + log.debug("AsistantListener: onPostPersist {}", asistant.getName()); + + + } + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/asistant/AsistantRepository.java b/modules/core/src/main/java/com/bytedesk/core/asistant/AsistantRepository.java new file mode 100644 index 0000000000..075defdb0b --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/asistant/AsistantRepository.java @@ -0,0 +1,21 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-26 21:07:55 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-26 21:10:46 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.asistant; + +import org.springframework.data.jpa.repository.JpaRepository; + +public interface AsistantRepository extends JpaRepository { + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/asistant/AsistantRequest.java b/modules/core/src/main/java/com/bytedesk/core/asistant/AsistantRequest.java new file mode 100644 index 0000000000..a69ae9ea51 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/asistant/AsistantRequest.java @@ -0,0 +1,42 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-26 21:05:09 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-27 12:51:21 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.asistant; + +import com.bytedesk.core.utils.BaseRequest; + +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +@Data +@Builder +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = false) +public class AsistantRequest extends BaseRequest { + + private String aid; + + private String topic; + + private String name; + + private String avatar; + + private String description; + + /** belong to org */ + private String orgOid; +} diff --git a/modules/core/src/main/java/com/bytedesk/core/asistant/AsistantResponse.java b/modules/core/src/main/java/com/bytedesk/core/asistant/AsistantResponse.java new file mode 100644 index 0000000000..fc153d8dc7 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/asistant/AsistantResponse.java @@ -0,0 +1,44 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-26 21:05:21 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-28 10:55:31 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.asistant; + +import com.bytedesk.core.utils.BaseResponse; + +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +@Data +@Builder +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = false) +public class AsistantResponse extends BaseResponse { + + private String aid; + + private String topic; + + private String type; + + private String name; + + private String avatar; + + private String description; + + /** belong to org */ + private String orgOid; +} diff --git a/modules/core/src/main/java/com/bytedesk/core/asistant/AsistantService.java b/modules/core/src/main/java/com/bytedesk/core/asistant/AsistantService.java new file mode 100644 index 0000000000..16bf06908c --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/asistant/AsistantService.java @@ -0,0 +1,135 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-26 21:04:54 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-28 11:14:48 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.asistant; + +import java.util.Optional; + +import org.modelmapper.ModelMapper; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.stereotype.Service; + +import com.alibaba.fastjson2.JSON; +import com.bytedesk.core.constant.AvatarConsts; +import com.bytedesk.core.constant.I18Consts; +import com.bytedesk.core.constant.StatusConsts; +import com.bytedesk.core.constant.ThreadTypeConsts; +import com.bytedesk.core.constant.TopicConsts; +import com.bytedesk.core.constant.TypeConsts; +import com.bytedesk.core.rbac.user.User; +import com.bytedesk.core.rbac.user.UserRequest; +import com.bytedesk.core.rbac.user.UserResponseSimple; +import com.bytedesk.core.rbac.user.UserService; +import com.bytedesk.core.thread.ThreadService; +import com.bytedesk.core.thread.Thread; +import com.bytedesk.core.uid.UidUtils; + +import lombok.AllArgsConstructor; + +@Service +@AllArgsConstructor +public class AsistantService { + + private final AsistantRepository asistantRepository; + + private final UserService userService; + + private final ThreadService threadService; + + private final ModelMapper modelMapper; + + private final UidUtils uidUtils; + + public Page query(AsistantRequest asistantRequest) { + + Pageable pageable = PageRequest.of(asistantRequest.getPageNumber(), asistantRequest.getPageSize(), Sort.Direction.ASC, + "id"); + + Page asistantPage = asistantRepository.findAll(pageable); + + return asistantPage.map(asistant -> convertToAsistantResponse(asistant)); + } + + public Asistant create(AsistantRequest asistantRequest) { + + Asistant asistant = modelMapper.map(asistantRequest, Asistant.class); + asistant.setAid(uidUtils.getCacheSerialUid()); + + return save(asistant); + } + + private Asistant save(Asistant asistant) { + return asistantRepository.save(asistant); + } + + public AsistantResponse convertToAsistantResponse(Asistant asistant) { + return modelMapper.map(asistant, AsistantResponse.class); + } + + + // + public void initData() { + + if (asistantRepository.count() > 0) { + return; + } + + Optional adminOptional = userService.getAdmin(); + + AsistantRequest asistantRequest = AsistantRequest.builder() + .topic(TopicConsts.TOPIC_FILE_ASISTANT) + .name(I18Consts.I18_FILE_ASISTANT_NAME) + .avatar(AvatarConsts.DEFAULT_FILE_ASISTANT_AVATAR_URL) + .description(I18Consts.I18_FILE_ASISTANT_DESCRIPTION) + .orgOid(adminOptional.get().getOrgOid()) + .build(); + asistantRequest.setType(TypeConsts.TYPE_SYSTEM); + create(asistantRequest); + + // 方便测试,默认给每个初始用户生成一个跟 文件助手 的对话 + UserRequest userRequest = new UserRequest(); + userRequest.setPageNumber(0); + userRequest.setPageSize(10); + // + Page userPage = userService.query(userRequest); + userPage.forEach(user -> { + // + UserResponseSimple userSimple = UserResponseSimple.builder() + .uid(asistantRequest.getAid()) + .nickname(asistantRequest.getName()) + .avatar(asistantRequest.getAvatar()) + .build(); + // + Thread thread = Thread.builder() + .tid(uidUtils.getCacheSerialUid()) + .type(ThreadTypeConsts.ASISTANT) + .topic(TopicConsts.TOPIC_FILE_ASISTANT + "/" + user.getUid()) + .status(StatusConsts.THREAD_STATUS_INIT) + .client(TypeConsts.TYPE_SYSTEM) + .user(JSON.toJSONString(userSimple)) + .owner(user) + .orgOid(asistantRequest.getOrgOid()) + .build(); + + threadService.save(thread); + }); + + } + + + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/auth/AuthAspect.java b/modules/core/src/main/java/com/bytedesk/core/auth/AuthAspect.java deleted file mode 100644 index 7d6aaa3287..0000000000 --- a/modules/core/src/main/java/com/bytedesk/core/auth/AuthAspect.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * @Author: jackning 270580156@qq.com - * @Date: 2024-02-26 11:45:58 - * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-02-26 12:02:57 - * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk - * Please be aware of the BSL license restrictions before installing Bytedesk IM – - * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. - * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 - * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE - * contact: 270580156@qq.com - * 联系:270580156@qq.com - * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. - */ -package com.bytedesk.core.auth; - -import org.aspectj.lang.annotation.After; -import org.aspectj.lang.annotation.Aspect; -import org.aspectj.lang.annotation.Before; -import org.aspectj.lang.annotation.Pointcut; -import org.springframework.stereotype.Component; - -import lombok.extern.slf4j.Slf4j; - -@Slf4j -@Aspect -@Component -public class AuthAspect { - - @Pointcut("execution(* com.bytedesk.core.auth.AuthController.*(..))") - public void authLog() { - log.debug("ActionAspect authLog"); - }; - - @Before("authLog()") - public void beforeAuthLog() { - log.debug("ActionAspect beforeAuthLog"); - } - - @After("authLog()") - public void afterAuthLog() { - log.debug("ActionAspect afterAuthLog"); - // TODO: action log save to db - } - -} diff --git a/modules/core/src/main/java/com/bytedesk/core/block/Block.java b/modules/core/src/main/java/com/bytedesk/core/black/Black.java similarity index 89% rename from modules/core/src/main/java/com/bytedesk/core/block/Block.java rename to modules/core/src/main/java/com/bytedesk/core/black/Black.java index 8af769e15b..e437ed46f1 100644 --- a/modules/core/src/main/java/com/bytedesk/core/block/Block.java +++ b/modules/core/src/main/java/com/bytedesk/core/black/Black.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-03-28 22:02:34 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-03-28 22:02:36 + * @LastEditTime: 2024-04-13 15:24:14 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -12,11 +12,11 @@ * 联系:270580156@qq.com * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. */ -package com.bytedesk.core.block; +package com.bytedesk.core.black; /** * 黑名单 */ -public class Block { +public class Black { } diff --git a/modules/core/src/main/java/com/bytedesk/core/cache/CacheConfig.java b/modules/core/src/main/java/com/bytedesk/core/cache/CacheConfig.java index 19953d934b..99109d602f 100644 --- a/modules/core/src/main/java/com/bytedesk/core/cache/CacheConfig.java +++ b/modules/core/src/main/java/com/bytedesk/core/cache/CacheConfig.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-03-27 18:45:02 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-04-05 00:04:11 + * @LastEditTime: 2024-04-15 15:23:56 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -14,102 +14,17 @@ */ package com.bytedesk.core.cache; -// import java.time.Duration; -import java.util.Arrays; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.EnableCaching; -import org.springframework.cache.caffeine.CaffeineCacheManager; -import org.springframework.cache.support.CompositeCacheManager; -// import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.redis.cache.RedisCacheConfiguration; -import org.springframework.data.redis.cache.RedisCacheManager; -import org.springframework.data.redis.connection.RedisConnectionFactory; -import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; -import org.springframework.data.redis.serializer.RedisSerializationContext.SerializationPair; /** * cache config + * https://docs.spring.io/spring-framework/reference/integration/cache/annotations.html#cache-spel-context * https://docs.spring.io/spring-boot/docs/3.2.0/reference/htmlsingle/#io.caching * https://www.51cto.com/article/753777.html */ @Configuration @EnableCaching public class CacheConfig { - - // @Autowired - // private BytedeskProperties bytedeskProperties; - - @Autowired - private RedisConnectionFactory redisConnectionFactory; - - // @Value("${cache.caffeine.maximumSize}") - // private int maximumSize; - - // @Value("${cache.caffeine.expireAfterWriteSeconds}") - // private int expireAfterWriteSeconds; - - // @Value("${spring.cache.redis.time-to-live}") - // private long redisTimeToLiveSeconds; - - // @Bean - // public CacheManager cacheManager() { - // if (bytedeskProperties.getCacheLevel() == 0) { - // return new NoOpCacheManager(); - // } else if (bytedeskProperties.getCacheLevel() == 1) { - // return caffeineCacheManager(); - // } else { - // return compositeCacheManager(caffeineCacheManager(), redisCacheManager()); - // } - // } - - // @SuppressWarnings("null") - public CaffeineCacheManager caffeineCacheManager() { - CaffeineCacheManager cacheManager = new CaffeineCacheManager(); - // cacheManager.setCaffeine(caffeineCacheBuilder()); - return cacheManager; - } - - // private Caffeine caffeineCacheBuilder() { - // return Caffeine.newBuilder() - // .expireAfterWrite(expireAfterWriteSeconds, TimeUnit.SECONDS) - // .maximumSize(maximumSize); - // } - - /** - * https://docs.spring.io/spring-data/redis/reference/redis/redis-cache.html - * 使用自定义rediscache时,遇到下面错误: - * FIXME: SerializationException: Could not read JSON:failed to lazily initialize a collection: could not initialize proxy - no Session - * @return - */ - // @Bean - // @SuppressWarnings("null") - public RedisCacheManager redisCacheManager() { - return RedisCacheManager.builder(redisConnectionFactory) - .cacheDefaults(cacheConfiguration()) - .build(); - } - - public RedisCacheConfiguration cacheConfiguration() { - return RedisCacheConfiguration.defaultCacheConfig() - .serializeValuesWith(SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer())); - } - - /** - * FIXME: 二级缓存未触发redis缓存? - * @param caffeineCacheManager - * @param redisCacheManager - * @return - */ - // @SuppressWarnings("null") - public CompositeCacheManager compositeCacheManager(CaffeineCacheManager caffeineCacheManager, - RedisCacheManager redisCacheManager) { - CompositeCacheManager compositeCacheManager = new CompositeCacheManager(); - // Arrays.asList(caffeineCacheManager, redisCacheManager) 中caffeineCacheManager放在前面, - // 即先查询caffeineCacheManager缓存,未命中则查询redisCacheManager。顺序很重要,别搞错 - compositeCacheManager.setCacheManagers(Arrays.asList(caffeineCacheManager, redisCacheManager)); - compositeCacheManager.setFallbackToNoOpCache(false); // 关闭缓存未命中时自动创建的空缓存 - return compositeCacheManager; - } } diff --git a/modules/core/src/main/java/com/bytedesk/core/cache/RedisConfig.java b/modules/core/src/main/java/com/bytedesk/core/cache/RedisConfig.java deleted file mode 100644 index 46917055b6..0000000000 --- a/modules/core/src/main/java/com/bytedesk/core/cache/RedisConfig.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * @Author: jackning 270580156@qq.com - * @Date: 2024-03-28 13:00:34 - * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-03-29 09:30:38 - * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk - * Please be aware of the BSL license restrictions before installing Bytedesk IM – - * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. - * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 - * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE - * contact: 270580156@qq.com - * 联系:270580156@qq.com - * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. - */ -package com.bytedesk.core.cache; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.data.redis.connection.RedisConnectionFactory; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.data.redis.core.StringRedisTemplate; -import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; -// import org.springframework.data.redis.serializer.GenericToStringSerializer; -// import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; -// import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer; -import org.springframework.data.redis.serializer.StringRedisSerializer; - -/** - * https://docs.spring.io/spring-data/redis/reference/redis/template.html - */ -@Configuration -public class RedisConfig { - - @Autowired - private RedisConnectionFactory redisConnectionFactory; - - @Bean - StringRedisTemplate stringRedisTemplate() { - StringRedisTemplate template = new StringRedisTemplate(); - template.setConnectionFactory(redisConnectionFactory); - return template; - } - - // @Bean - // RedisTemplate redisTemplate() { - // RedisTemplate template = new RedisTemplate<>(); - // template.setConnectionFactory(redisConnectionFactory); - // return template; - // } - - @Bean - public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { - RedisTemplate redisTemplate = new RedisTemplate<>(); - redisTemplate.setKeySerializer(new StringRedisSerializer()); - redisTemplate.setHashKeySerializer(new StringRedisSerializer()); - redisTemplate.setHashValueSerializer(new StringRedisSerializer()); - redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer()); - redisTemplate.setConnectionFactory(redisConnectionFactory); - return redisTemplate; - } -} diff --git a/modules/core/src/main/java/com/bytedesk/core/rbac/action/Action.java b/modules/core/src/main/java/com/bytedesk/core/channel/Channel.java similarity index 62% rename from modules/core/src/main/java/com/bytedesk/core/rbac/action/Action.java rename to modules/core/src/main/java/com/bytedesk/core/channel/Channel.java index 99086f5621..2f115a7c94 100644 --- a/modules/core/src/main/java/com/bytedesk/core/rbac/action/Action.java +++ b/modules/core/src/main/java/com/bytedesk/core/channel/Channel.java @@ -1,60 +1,69 @@ /* * @Author: jackning 270580156@qq.com - * @Date: 2024-01-29 16:21:24 + * @Date: 2024-04-26 20:34:52 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-03-29 14:02:22 + * @LastEditTime: 2024-04-28 11:20:53 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. - * 仅支持企业内部员工自用,严禁用于销售、二次销售或者部署SaaS方式销售 + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE * contact: 270580156@qq.com * 联系:270580156@qq.com * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. */ -package com.bytedesk.core.rbac.action; +package com.bytedesk.core.channel; import com.bytedesk.core.utils.AuditModel; import jakarta.persistence.Column; import jakarta.persistence.Entity; +import jakarta.persistence.EntityListeners; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; import lombok.experimental.Accessors; /** - * 对应权限Authority中操作:query/create/update/delete/export/import - * - * @author bytedesk.com on 2019-08-05 + * channel 频道 - 类似公众号 */ +@Entity @Data +@Builder @Accessors(chain = true) @EqualsAndHashCode(callSuper = true) -@Entity -@Table(name = "core_action") -public class Action extends AuditModel { - - private static final long serialVersionUID = -4364459013162121569L; +@AllArgsConstructor +@NoArgsConstructor +@EntityListeners({ChannelListener.class}) +@Table(name = "core_channel") +public class Channel extends AuditModel { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; @Column(unique = true, nullable = false, length = 127) - private String aid; + private String cid; + private String topic; + + @Column(name = "by_type") + private String type; + private String name; - - private String value; + + private String avatar; private String description; - // @JsonIgnore - // @ManyToMany(mappedBy = "actions", fetch = FetchType.LAZY) - // private Set authorities = new HashSet<>(); + /** belong to org */ + private String orgOid; + } diff --git a/modules/core/src/main/java/com/bytedesk/core/channel/ChannelController.java b/modules/core/src/main/java/com/bytedesk/core/channel/ChannelController.java new file mode 100644 index 0000000000..7c0dea7bfd --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/channel/ChannelController.java @@ -0,0 +1,55 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-26 21:06:00 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-26 23:01:00 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.channel; + +import org.springframework.data.domain.Page; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.bytedesk.core.utils.JsonResult; + +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; + +/** + * + * http://localhost:9003/swagger-ui/index.html + */ +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/v1/channel") +@Tag(name = "channel - 频道", description = "channel apis") +public class ChannelController { + + private final ChannelService channelService; + + /** + * query channel + * + * @return json + */ + @GetMapping("/query") + public ResponseEntity query(ChannelRequest channelRequest) { + // + Page channelPage = channelService.query(channelRequest); + // + return ResponseEntity.ok(JsonResult.success(channelPage)); + } + + + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/channel/ChannelListener.java b/modules/core/src/main/java/com/bytedesk/core/channel/ChannelListener.java new file mode 100644 index 0000000000..aba37d19fe --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/channel/ChannelListener.java @@ -0,0 +1,31 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-28 11:19:41 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-28 11:19:44 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.channel; + +import org.springframework.stereotype.Component; + +import jakarta.persistence.PostPersist; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Component +public class ChannelListener { + + @PostPersist + public void onPostPersist(Channel channel) { + log.info("onPostPersist: {}", channel.getName()); + } + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/channel/ChannelRepository.java b/modules/core/src/main/java/com/bytedesk/core/channel/ChannelRepository.java new file mode 100644 index 0000000000..0841600ad0 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/channel/ChannelRepository.java @@ -0,0 +1,21 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-26 21:07:38 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-26 21:10:57 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.channel; + +import org.springframework.data.jpa.repository.JpaRepository; + +public interface ChannelRepository extends JpaRepository { + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/channel/ChannelRequest.java b/modules/core/src/main/java/com/bytedesk/core/channel/ChannelRequest.java new file mode 100644 index 0000000000..b666cb192b --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/channel/ChannelRequest.java @@ -0,0 +1,42 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-26 21:07:10 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-26 21:44:27 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.channel; + +import com.bytedesk.core.utils.BaseRequest; + +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +@Data +@Builder +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = false) +public class ChannelRequest extends BaseRequest { + + private String cid; + + private String topic; + + private String name; + + private String avatar; + + private String description; + + /** belong to org */ + private String orgOid; +} diff --git a/modules/core/src/main/java/com/bytedesk/core/channel/ChannelResponse.java b/modules/core/src/main/java/com/bytedesk/core/channel/ChannelResponse.java new file mode 100644 index 0000000000..170de66301 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/channel/ChannelResponse.java @@ -0,0 +1,44 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-26 21:07:22 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-28 10:55:42 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.channel; + +import com.bytedesk.core.utils.BaseResponse; + +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +@Data +@Builder +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = false) +public class ChannelResponse extends BaseResponse { + + private String cid; + + private String topic; + + private String type; + + private String name; + + private String avatar; + + private String description; + + /** belong to org */ + private String orgOid; +} diff --git a/modules/core/src/main/java/com/bytedesk/core/channel/ChannelService.java b/modules/core/src/main/java/com/bytedesk/core/channel/ChannelService.java new file mode 100644 index 0000000000..7e1232dafb --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/channel/ChannelService.java @@ -0,0 +1,97 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-26 21:06:12 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-28 11:40:10 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.channel; + +import java.util.Optional; + +import org.modelmapper.ModelMapper; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.stereotype.Service; + +import com.bytedesk.core.constant.AvatarConsts; +import com.bytedesk.core.constant.I18Consts; +import com.bytedesk.core.constant.TopicConsts; +import com.bytedesk.core.constant.TypeConsts; +import com.bytedesk.core.rbac.user.User; +import com.bytedesk.core.rbac.user.UserService; +import com.bytedesk.core.uid.UidUtils; + +import lombok.AllArgsConstructor; + +@Service +@AllArgsConstructor +public class ChannelService { + + private final ChannelRepository channelRepository; + + private final UserService userService; + + private final ModelMapper modelMapper; + + private final UidUtils uidUtils; + + public Page query(ChannelRequest channelRequest) { + + Pageable pageable = PageRequest.of(channelRequest.getPageNumber(), channelRequest.getPageSize(), Sort.Direction.ASC, + "id"); + + Page channelPage = channelRepository.findAll(pageable); + + return channelPage.map(channel -> convertToChannelResponse(channel)); + } + + public Channel create(ChannelRequest channelRequest) { + + Channel channel = modelMapper.map(channelRequest, Channel.class); + channel.setCid(uidUtils.getCacheSerialUid()); + + return save(channel); + } + + private Channel save(Channel channel) { + return channelRepository.save(channel); + } + + public ChannelResponse convertToChannelResponse(Channel channel) { + return modelMapper.map(channel, ChannelResponse.class); + } + + public void initData() { + + if (channelRepository.count() > 0) { + return; + } + + Optional adminOptional = userService.getAdmin(); + + ChannelRequest channelRequest = ChannelRequest.builder() + .topic(TopicConsts.TOPIC_SYSTEM_NOTIFICATION) + .name(I18Consts.I18_SYSTEM_NOTIFICATION_NAME) + .avatar(AvatarConsts.DEFAULT_SYSTEM_NOTIFICATION_AVATAR_URL) + .description(I18Consts.I18_SYSTEM_NOTIFICATION_DESCRIPTION) + .orgOid(adminOptional.get().getOrgOid()) + .build(); + channelRequest.setType(TypeConsts.TYPE_SYSTEM); + create(channelRequest); + // + + + } + + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/config/BytedeskConfig.java b/modules/core/src/main/java/com/bytedesk/core/config/BytedeskConfig.java index b51b2ea3a3..e23fc17699 100644 --- a/modules/core/src/main/java/com/bytedesk/core/config/BytedeskConfig.java +++ b/modules/core/src/main/java/com/bytedesk/core/config/BytedeskConfig.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-30 07:52:26 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-04-05 14:08:54 + * @LastEditTime: 2024-04-22 23:32:51 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -26,6 +26,8 @@ import org.springframework.security.config.annotation.authentication.configurati import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.web.client.RestTemplate; +import com.bytedesk.core.utils.ApplicationContextHolder; + import lombok.Getter; /** @@ -58,4 +60,9 @@ public class BytedeskConfig { return restTemplate; } + @Bean + public ApplicationContextHolder applicationContextHolder() { + return new ApplicationContextHolder(); + } + } diff --git a/modules/core/src/main/java/com/bytedesk/core/config/BytedeskProperties.java b/modules/core/src/main/java/com/bytedesk/core/config/BytedeskProperties.java index 81a1a02a13..f35f9f4596 100644 --- a/modules/core/src/main/java/com/bytedesk/core/config/BytedeskProperties.java +++ b/modules/core/src/main/java/com/bytedesk/core/config/BytedeskProperties.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-30 09:14:39 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-03-28 10:55:27 + * @LastEditTime: 2024-04-24 10:18:37 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -30,13 +30,15 @@ public class BytedeskProperties { private String password; + private String nickname; + private String email; private String mobile; private String company; - private String timezone; + // private String timezone; // cors private String corsAllowedOrigins; diff --git a/modules/core/src/main/java/com/bytedesk/core/push/IosService.java b/modules/core/src/main/java/com/bytedesk/core/connect/Connect.java similarity index 85% rename from modules/core/src/main/java/com/bytedesk/core/push/IosService.java rename to modules/core/src/main/java/com/bytedesk/core/connect/Connect.java index d8c2c5c75d..94a239c1b2 100644 --- a/modules/core/src/main/java/com/bytedesk/core/push/IosService.java +++ b/modules/core/src/main/java/com/bytedesk/core/connect/Connect.java @@ -1,8 +1,8 @@ /* * @Author: jackning 270580156@qq.com - * @Date: 2024-03-31 15:30:08 + * @Date: 2024-04-15 16:58:27 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-03-31 15:30:11 + * @LastEditTime: 2024-04-15 16:58:30 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -12,8 +12,8 @@ * 联系:270580156@qq.com * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. */ -package com.bytedesk.core.push; +package com.bytedesk.core.connect; -public class IosService { +public class Connect { } diff --git a/modules/core/src/main/java/com/bytedesk/core/constant/AvatarConsts.java b/modules/core/src/main/java/com/bytedesk/core/constant/AvatarConsts.java index 67bc2cc43d..d80981c864 100644 --- a/modules/core/src/main/java/com/bytedesk/core/constant/AvatarConsts.java +++ b/modules/core/src/main/java/com/bytedesk/core/constant/AvatarConsts.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-29 16:21:24 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-03-25 16:39:55 + * @LastEditTime: 2024-04-28 11:10:14 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -15,7 +15,8 @@ package com.bytedesk.core.constant; /** - * 头像常量 + * 头像常量, 可以去这里获取 https://www.iconfont.cn/ + * TODO: 头像不能引用外部链接,使用本地或本服务器地址 * * @author bytedesk.com */ @@ -134,6 +135,12 @@ public class AvatarConsts { */ public static final String DEFAULT_GROUP_AVATAR_URL = "https://bytedesk.oss-cn-shenzhen.aliyuncs.com/avatars/group_default_avatar.png"; + // 文件助手头像 + public static final String DEFAULT_FILE_ASISTANT_AVATAR_URL = "https://chainsnow.oss-cn-shenzhen.aliyuncs.com/avatars/file_asistant_avatar.png"; + + // 系统通知-公众号头像 + public static final String DEFAULT_SYSTEM_NOTIFICATION_AVATAR_URL = "https://chainsnow.oss-cn-shenzhen.aliyuncs.com/avatars/notification.png"; + /** * 测试头像: * https://bytedesk.oss-cn-shenzhen.aliyuncs.com/avatars/girl.png diff --git a/modules/core/src/main/java/com/bytedesk/core/constant/BdConstants.java b/modules/core/src/main/java/com/bytedesk/core/constant/BdConstants.java index 83c57a029e..49196d1a99 100644 --- a/modules/core/src/main/java/com/bytedesk/core/constant/BdConstants.java +++ b/modules/core/src/main/java/com/bytedesk/core/constant/BdConstants.java @@ -19,7 +19,8 @@ public class BdConstants { public static final boolean IS_DEBUG = false; // 空字符串 - public static final String EMPTY = ""; + public static final String EMPTY_STRING = ""; + public static final String EMPTY_JSON_STRING = "{}"; /** * Path separator. diff --git a/modules/core/src/main/java/com/bytedesk/core/constant/I18Consts.java b/modules/core/src/main/java/com/bytedesk/core/constant/I18Consts.java new file mode 100644 index 0000000000..5d7792b3cf --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/constant/I18Consts.java @@ -0,0 +1,37 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-26 22:25:47 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-28 11:11:03 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.constant; + +// 国际化常量 +public class I18Consts { + + private I18Consts() { + } + + public static final String EN = "en"; + public static final String ZH = "zh"; + // public static final String EN_US = "en-us"; + // public static final String ZH_CN = "zh-cn"; + + // "文件助手" + public static final String I18_FILE_ASISTANT_NAME = "file_asistant"; + // "手机、电脑文件互传" + public static final String I18_FILE_ASISTANT_DESCRIPTION = "file_asistant_description"; + // 系统通知 + public static final String I18_SYSTEM_NOTIFICATION_NAME = "system_notification"; + public static final String I18_SYSTEM_NOTIFICATION_DESCRIPTION = "system_notification_description"; + + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/constant/MessageTypeConsts.java b/modules/core/src/main/java/com/bytedesk/core/constant/MessageTypeConsts.java index 626932099b..aa07153c05 100644 --- a/modules/core/src/main/java/com/bytedesk/core/constant/MessageTypeConsts.java +++ b/modules/core/src/main/java/com/bytedesk/core/constant/MessageTypeConsts.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-02-22 15:51:39 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-02-22 15:59:49 + * @LastEditTime: 2024-04-11 17:20:01 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -581,4 +581,15 @@ public class MessageTypeConsts { public static final String NOTIFICATION_GROUP_DISMISS = "notification_group_dismiss"; + + /** + * 回执 + */ + // 服务器回复客户端,已经收到。消息发送成功 + public static final String NOTIFICATION_ACK_SUCCESS = "notification_ack_success"; + // 消息送达 + public static final String NOTIFICATION_ACK_RECEIVED = "notification_ack_received"; + // 消息已读 + public static final String NOTIFICATION_ACK_READ = "notification_ack_read"; + } diff --git a/modules/core/src/main/java/com/bytedesk/core/constant/RedisConsts.java b/modules/core/src/main/java/com/bytedesk/core/constant/RedisConsts.java index 45a00ff1fd..e0eedaca1a 100644 --- a/modules/core/src/main/java/com/bytedesk/core/constant/RedisConsts.java +++ b/modules/core/src/main/java/com/bytedesk/core/constant/RedisConsts.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-27 10:55:25 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-02-26 13:02:38 + * @LastEditTime: 2024-04-16 12:39:23 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -285,5 +285,6 @@ public class RedisConsts { // redis pub/sub public static final String REDIS_PUBSUB_CHANNEL_TOPIC = "redispubsubchannel:message"; public static final String REDIS_PUBSUB_CHANNEL_TOPIC_OBJECT = "redispubsubchannel:messageobject"; + public static final String REDIS_PUBSUB_CHANNEL_TOPIC_RESPONSE = "redispubsubchannel:messageresponse"; } diff --git a/modules/core/src/main/java/com/bytedesk/core/constant/StatusConsts.java b/modules/core/src/main/java/com/bytedesk/core/constant/StatusConsts.java index 5db5c57d61..74909585f0 100644 --- a/modules/core/src/main/java/com/bytedesk/core/constant/StatusConsts.java +++ b/modules/core/src/main/java/com/bytedesk/core/constant/StatusConsts.java @@ -237,13 +237,16 @@ public class StatusConsts { public static final String ANSWER_STATUS_PUBLISHED = "published"; public static final String ANSWER_STATUS_UNPUBLISHED = "unpublished"; - /** - * 学校认领:待审核、审核通过、审核拒绝 - */ - public static final String CLAIM_STATUS_WAITING = "waiting"; - public static final String CLAIM_STATUS_ACCEPT = "accept"; - public static final String CLAIM_STATUS_REJECT = "reject"; - + // 同事和群组会话初始值为init + public static final String THREAD_STATUS_INIT = "init"; + // 只有客服会话会有open + public static final String THREAD_STATUS_OPEN = "open"; + public static final String THREAD_STATUS_CLOSED_AUTO = "closed_auto"; + public static final String THREAD_STATUS_CLOSED_AGENT = "closed_agent"; + // 发送验证码状态 + public static final String CODE_STATUS_PENDING = "pending"; + public static final String CODE_STATUS_CONFIRM = "confirmed"; + public static final String CODE_STATUS_EXPIRED = "expired"; } diff --git a/modules/core/src/main/java/com/bytedesk/core/constant/ThreadTypeConsts.java b/modules/core/src/main/java/com/bytedesk/core/constant/ThreadTypeConsts.java index 192f7e550a..1b76322279 100644 --- a/modules/core/src/main/java/com/bytedesk/core/constant/ThreadTypeConsts.java +++ b/modules/core/src/main/java/com/bytedesk/core/constant/ThreadTypeConsts.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-02-22 16:01:14 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-02-22 16:01:17 + * @LastEditTime: 2024-04-27 12:37:31 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -15,17 +15,20 @@ package com.bytedesk.core.constant; public class ThreadTypeConsts { + private ThreadTypeConsts() { } /** * thread type */ - public static final String WORKGROUP = "workgroup"; public static final String APPOINTED = "appointed"; + public static final String WORKGROUP = "workgroup"; public static final String MEMBER = "member"; public static final String GROUP = "group"; public static final String ROBOT = "robot"; public static final String LEAVEMSG = "leavemsg"; public static final String FEEDBACK = "feedback"; + public static final String ASISTANT = "assistant"; + public static final String CHANNEL = "channel"; } diff --git a/modules/core/src/main/java/com/bytedesk/core/constant/TopicConsts.java b/modules/core/src/main/java/com/bytedesk/core/constant/TopicConsts.java new file mode 100644 index 0000000000..f4cd5229c0 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/constant/TopicConsts.java @@ -0,0 +1,26 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-26 21:51:31 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-26 21:51:34 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.constant; + +public class TopicConsts { + + private TopicConsts() { + } + + // public static final String TOPIC_PREFIX = "topic"; + public static final String TOPIC_FILE_ASISTANT = "fileAssistant"; + public static final String TOPIC_SYSTEM_NOTIFICATION = "systemNotification"; + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/constant/TypeConsts.java b/modules/core/src/main/java/com/bytedesk/core/constant/TypeConsts.java index c2c286eace..919c6fb10d 100644 --- a/modules/core/src/main/java/com/bytedesk/core/constant/TypeConsts.java +++ b/modules/core/src/main/java/com/bytedesk/core/constant/TypeConsts.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-29 16:21:24 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-02-22 16:02:05 + * @LastEditTime: 2024-04-26 09:41:28 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -20,31 +20,47 @@ public class TypeConsts { } public static final String TYPE_SYSTEM = "system"; + public static final String TYPE_MOBILE = "mobile"; + public static final String TYPE_EMAIL = "email"; // ROLES - 角色 + public static final String ROLE_ = "ROLE_"; + + // super - 超级管理员 + public static final String ROLE_SUPER = "ROLE_SUPER"; + public static final String AUTHORITY_SUPER = "SUPER"; + // admin - 管理员 public static final String ROLE_ADMIN = "ROLE_ADMIN"; + public static final String AUTHORITY_ADMIN = "ADMIN"; // hr - 人事 public static final String ROLE_HR = "ROLE_HR"; + public static final String AUTHORITY_HR = "HR"; // org - 行政 public static final String ROLE_ORG = "ROLE_ORG"; + public static final String AUTHORITY_ORG = "ORG"; // it - IT public static final String ROLE_IT = "ROLE_IT"; + public static final String AUTHORITY_IT = "IT"; // money - 财务 public static final String ROLE_MONEY = "ROLE_MONEY"; + public static final String AUTHORITY_MONEY = "MONEY"; // marketing - 市场 public static final String ROLE_MARKETING = "ROLE_MARKETING"; + public static final String AUTHORITY_MARKETING = "MARKETING"; // sales - 销售 public static final String ROLE_SALES = "ROLE_SALES"; + public static final String AUTHORITY_SALES = "SALES"; // customer service - 客服 public static final String ROLE_CUSTOMER_SERVICE = "ROLE_CS"; + public static final String AUTHORITY_CUSTOMER_SERVICE = "CS"; /// 部门 // hr - 人事 @@ -69,6 +85,11 @@ public class TypeConsts { public static final String DEPT_CUSTOMER_SERVICE = "DEPT_CS"; + // + public static final String SEND_MOBILE_CODE_TYPE_LOGIN = "login"; + public static final String SEND_MOBILE_CODE_TYPE_REGISTER = "register"; + public static final String SEND_MOBILE_CODE_TYPE_FORGET = "forget"; + public static final String SEND_MOBILE_CODE_TYPE_VERIFY = "verify"; diff --git a/modules/core/src/main/java/com/bytedesk/core/event/BytedeskEventPublisher.java b/modules/core/src/main/java/com/bytedesk/core/event/BytedeskEventPublisher.java index 24adebb2ca..c9486f2a83 100644 --- a/modules/core/src/main/java/com/bytedesk/core/event/BytedeskEventPublisher.java +++ b/modules/core/src/main/java/com/bytedesk/core/event/BytedeskEventPublisher.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-02-23 14:42:58 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-02-28 14:38:43 + * @LastEditTime: 2024-04-23 08:55:55 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -15,8 +15,10 @@ package com.bytedesk.core.event; import org.springframework.context.ApplicationEventPublisher; +import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; +import com.bytedesk.core.thread.Thread; import lombok.AllArgsConstructor; @Component @@ -25,16 +27,50 @@ public class BytedeskEventPublisher { private final ApplicationEventPublisher applicationEventPublisher; + @Async public void publishMessageBytesEvent(byte[] messageBytes) { applicationEventPublisher.publishEvent(new MessageBytesEvent(this, messageBytes)); } + @Async public void publishMessageJsonEvent(String json) { applicationEventPublisher.publishEvent(new MessageJsonEvent(this, json)); } + @Async public void publishQuartzFiveSecondEvent() { applicationEventPublisher.publishEvent(new QuartzFiveSecondEvent(this)); } - + + @Async + public void publishMqttConnectedEvent(String client) { + applicationEventPublisher.publishEvent(new MqttConnectedEvent(this, client)); + } + + @Async + public void publishMqttDisconnectedEvent(String client) { + applicationEventPublisher.publishEvent(new MqttDisconnectedEvent(this, client)); + } + + // @Async + // public void publishMqttSubscribeEvent(String uid, String topic) { + // applicationEventPublisher.publishEvent(new MqttSubscribeEvent(this, uid, topic)); + // } + + // @Async + // public void publishMqttUnsubscribeEvent(String uid, String topic) { + // applicationEventPublisher.publishEvent(new MqttUnsubscribeEvent(this, uid, topic)); + // } + + @Async + public void publishThreadCreateEvent(Thread thread) { + applicationEventPublisher.publishEvent(new ThreadCreateEvent(this, thread)); + } + + @Async + public void publishThreadUpdateEvent(Thread thread) { + applicationEventPublisher.publishEvent(new ThreadUpdateEvent(this, thread)); + } + + } diff --git a/modules/core/src/main/java/com/bytedesk/core/event/MessageJsonEvent.java b/modules/core/src/main/java/com/bytedesk/core/event/MessageJsonEvent.java index 172e463c37..d57656184c 100644 --- a/modules/core/src/main/java/com/bytedesk/core/event/MessageJsonEvent.java +++ b/modules/core/src/main/java/com/bytedesk/core/event/MessageJsonEvent.java @@ -1,8 +1,8 @@ /* * @Author: jackning 270580156@qq.com - * @Date: 2024-02-23 14:43:57 + * @Date: 2024-02-28 11:43:29 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-02-28 11:43:44 + * @LastEditTime: 2024-04-12 18:02:15 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. diff --git a/modules/socket/src/main/java/com/bytedesk/socket/mqtt/model/MqttDupPubRelMessage.java b/modules/core/src/main/java/com/bytedesk/core/event/MqttConnectedEvent.java old mode 100755 new mode 100644 similarity index 63% rename from modules/socket/src/main/java/com/bytedesk/socket/mqtt/model/MqttDupPubRelMessage.java rename to modules/core/src/main/java/com/bytedesk/core/event/MqttConnectedEvent.java index 17312c586e..38be286a0e --- a/modules/socket/src/main/java/com/bytedesk/socket/mqtt/model/MqttDupPubRelMessage.java +++ b/modules/core/src/main/java/com/bytedesk/core/event/MqttConnectedEvent.java @@ -1,8 +1,8 @@ /* * @Author: jackning 270580156@qq.com - * @Date: 2024-01-29 16:21:46 + * @Date: 2024-02-23 14:43:57 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-02-29 10:42:59 + * @LastEditTime: 2024-04-15 14:21:09 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -12,25 +12,22 @@ * 联系:270580156@qq.com * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. */ -package com.bytedesk.socket.mqtt.model; +package com.bytedesk.core.event; -import java.io.Serializable; +import org.springframework.context.ApplicationEvent; import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.experimental.Accessors; +import lombok.EqualsAndHashCode; -/** - * PUBREL重发消息存储 - */ @Data -@Accessors(chain = true) -@NoArgsConstructor -public class MqttDupPubRelMessage implements Serializable { - - private static final long serialVersionUID = -4111642532532950980L; - +@EqualsAndHashCode(callSuper = false) +public class MqttConnectedEvent extends ApplicationEvent { + private String clientId; - private int messageId; + public MqttConnectedEvent(Object source, String clientId) { + super(source); + this.clientId = clientId; + } + } diff --git a/modules/core/src/main/java/com/bytedesk/core/event/MqttDisconnectedEvent.java b/modules/core/src/main/java/com/bytedesk/core/event/MqttDisconnectedEvent.java new file mode 100644 index 0000000000..4975ca36f5 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/event/MqttDisconnectedEvent.java @@ -0,0 +1,33 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-02-23 14:43:57 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-15 14:21:25 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.event; + +import org.springframework.context.ApplicationEvent; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = false) +public class MqttDisconnectedEvent extends ApplicationEvent { + + private String clientId; + + public MqttDisconnectedEvent(Object source, String clientId) { + super(source); + this.clientId = clientId; + } + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/event/MqttSubscribeEvent.java b/modules/core/src/main/java/com/bytedesk/core/event/MqttSubscribeEvent.java new file mode 100644 index 0000000000..9ca01db61a --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/event/MqttSubscribeEvent.java @@ -0,0 +1,35 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-02-23 14:43:57 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-16 10:16:12 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.event; + +// import org.springframework.context.ApplicationEvent; + +// import lombok.Data; +// import lombok.EqualsAndHashCode; + +// @Data +// @EqualsAndHashCode(callSuper = false) +// public class MqttSubscribeEvent extends ApplicationEvent { + +// private String uid; +// private String topic; + +// public MqttSubscribeEvent(Object source, String uid, String topic) { +// super(source); +// this.uid = uid; +// this.topic = topic; +// } + +// } diff --git a/modules/core/src/main/java/com/bytedesk/core/event/MqttUnsubscribeEvent.java b/modules/core/src/main/java/com/bytedesk/core/event/MqttUnsubscribeEvent.java new file mode 100644 index 0000000000..ffc9a166a0 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/event/MqttUnsubscribeEvent.java @@ -0,0 +1,35 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-02-23 14:43:57 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-16 10:16:17 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.event; + +// import org.springframework.context.ApplicationEvent; + +// import lombok.Data; +// import lombok.EqualsAndHashCode; + +// @Data +// @EqualsAndHashCode(callSuper = false) +// public class MqttUnsubscribeEvent extends ApplicationEvent { + +// private String uid; +// private String topic; + +// public MqttUnsubscribeEvent(Object source, String uid, String topic) { +// super(source); +// this.uid = uid; +// this.topic = topic; +// } + +// } diff --git a/modules/core/src/main/java/com/bytedesk/core/event/ThreadCreateEvent.java b/modules/core/src/main/java/com/bytedesk/core/event/ThreadCreateEvent.java new file mode 100644 index 0000000000..08ed532d70 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/event/ThreadCreateEvent.java @@ -0,0 +1,34 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-23 08:51:27 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-23 08:54:21 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.event; + +import com.bytedesk.core.thread.Thread; +import org.springframework.context.ApplicationEvent; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = false) +public class ThreadCreateEvent extends ApplicationEvent { + + private Thread thread; + + public ThreadCreateEvent(Object source, Thread thread) { + super(source); + this.thread = thread; + } + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/event/ThreadUpdateEvent.java b/modules/core/src/main/java/com/bytedesk/core/event/ThreadUpdateEvent.java new file mode 100644 index 0000000000..7b69e573fe --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/event/ThreadUpdateEvent.java @@ -0,0 +1,34 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-23 08:51:27 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-23 08:54:08 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.event; + +import com.bytedesk.core.thread.Thread; +import org.springframework.context.ApplicationEvent; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = false) +public class ThreadUpdateEvent extends ApplicationEvent { + + private Thread thread; + + public ThreadUpdateEvent(Object source, Thread thread) { + super(source); + this.thread = thread; + } + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/exception/BaseException.java b/modules/core/src/main/java/com/bytedesk/core/exception/BaseException.java new file mode 100644 index 0000000000..bd42010ae1 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/exception/BaseException.java @@ -0,0 +1,26 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-26 09:29:11 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-26 09:59:23 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.exception; + +public abstract class BaseException extends RuntimeException { + + public BaseException(String message) { + super(message); + } + + public BaseException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/modules/core/src/main/java/com/bytedesk/core/exception/EmailExistsException.java b/modules/core/src/main/java/com/bytedesk/core/exception/EmailExistsException.java new file mode 100644 index 0000000000..ec1d9920d7 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/exception/EmailExistsException.java @@ -0,0 +1,28 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-26 09:28:30 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-26 09:58:48 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.exception; + +public class EmailExistsException extends BaseException { + + private static final long serialVersionUID = 5543722167L; + + public EmailExistsException(String message) { + super(message); + //TODO Auto-generated constructor stub + } + + + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/utils/exception/EmailNotFoundException.java b/modules/core/src/main/java/com/bytedesk/core/exception/EmailNotFoundException.java similarity index 92% rename from modules/core/src/main/java/com/bytedesk/core/utils/exception/EmailNotFoundException.java rename to modules/core/src/main/java/com/bytedesk/core/exception/EmailNotFoundException.java index 9269591066..9883801bfb 100644 --- a/modules/core/src/main/java/com/bytedesk/core/utils/exception/EmailNotFoundException.java +++ b/modules/core/src/main/java/com/bytedesk/core/exception/EmailNotFoundException.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-02-03 10:58:01 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-02-03 10:59:43 + * @LastEditTime: 2024-04-26 11:26:30 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -12,7 +12,7 @@ * 联系:270580156@qq.com * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. */ -package com.bytedesk.core.utils.exception; +package com.bytedesk.core.exception; import org.springframework.security.core.AuthenticationException; diff --git a/modules/core/src/main/java/com/bytedesk/core/exception/ForbiddenException.java b/modules/core/src/main/java/com/bytedesk/core/exception/ForbiddenException.java new file mode 100755 index 0000000000..97cc3a5658 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/exception/ForbiddenException.java @@ -0,0 +1,34 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-01-29 16:21:24 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-26 11:26:36 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.exception; + +/** + * Exception caused by accessing forbidden resources. + * + * @author johnniang + */ +public class ForbiddenException extends BaseException { + + private static final long serialVersionUID = -6029126336570526306L; + + public ForbiddenException(String message) { + super(message); + } + + public ForbiddenException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/exception/GlobalControllerAdvice.java b/modules/core/src/main/java/com/bytedesk/core/exception/GlobalControllerAdvice.java new file mode 100644 index 0000000000..e5f09add31 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/exception/GlobalControllerAdvice.java @@ -0,0 +1,100 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-26 09:31:29 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-26 15:06:12 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.exception; + +import org.springframework.http.ResponseEntity; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.authentication.InternalAuthenticationServiceException; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.servlet.resource.NoResourceFoundException; + +import com.bytedesk.core.utils.JsonResult; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@ControllerAdvice +public class GlobalControllerAdvice { + + @ExceptionHandler(EmailExistsException.class) + public ResponseEntity handleEmailExistsException(EmailExistsException e) { + return ResponseEntity.ok().body(JsonResult.error("Email already exists, please login or use another one")); + } + + @ExceptionHandler(MobileExistsException.class) + public ResponseEntity handleMobileExistsException(MobileExistsException e) { + return ResponseEntity.ok().body(JsonResult.error("Mobile already exists, please login or use another one")); + } + + @ExceptionHandler(UsernameNotFoundException.class) + public ResponseEntity handleUsernameNotFoundException(UsernameNotFoundException e) { + return ResponseEntity.ok().body(JsonResult.error("User not found, please signup first")); + } + + @ExceptionHandler(EmailNotFoundException.class) + public ResponseEntity handleEmailNotFoundException(EmailNotFoundException e) { + return ResponseEntity.ok().body(JsonResult.error("Email not found, please signup first")); + } + + @ExceptionHandler(MobileNotFoundException.class) + public ResponseEntity handleMobileNotFoundException(MobileNotFoundException e) { + return ResponseEntity.ok().body(JsonResult.error("Mobile not found, please signup first")); + } + + @ExceptionHandler(NotFoundException.class) + public ResponseEntity handleNotFoundException(NotFoundException e) { + return ResponseEntity.ok().body(JsonResult.error("Resource not found, usually is uuids not exist")); + } + + @ExceptionHandler(UserDisabledException.class) + public ResponseEntity handleUserDisabledException(UserDisabledException e) { + return ResponseEntity.ok().body(JsonResult.error("User disabled, please contact admin")); + } + + @ExceptionHandler(ForbiddenException.class) + public ResponseEntity handleForbiddenException(ForbiddenException e) { + return ResponseEntity.ok().body(JsonResult.error("Forbidden to access this resource")); + } + + @ExceptionHandler(InternalAuthenticationServiceException.class) + public ResponseEntity handleInternalAuthenticationServiceException(InternalAuthenticationServiceException e) { + return ResponseEntity.ok().body(JsonResult.error("User blocked, please contact admin")); + } + + @ExceptionHandler(NoResourceFoundException.class) + public ResponseEntity handleNoResourceFoundException(NoResourceFoundException e) { + return ResponseEntity.ok().body(JsonResult.error( + "Api Resource not found, or It's a vip api, you should contact 270580156@qq.com or visit http://www.weiyuai.cn", + 404)); + } + + @ExceptionHandler(BadCredentialsException.class) + public ResponseEntity handleBadCredentialsException(BadCredentialsException e) { + return ResponseEntity.ok().body(JsonResult.error("Username or password is incorrect")); + } + + @ExceptionHandler(value = NullPointerException.class) + public ResponseEntity handleNullPointerException(NullPointerException ex) { + return ResponseEntity.badRequest().body(JsonResult.error("Null Pointer Exception")); + } + + @ExceptionHandler(Exception.class) + public ResponseEntity handleException(Exception e) { + log.error("not handled exception:", e); + return ResponseEntity.badRequest().body(JsonResult.error("Internal Server Error")); + } +} diff --git a/modules/core/src/main/java/com/bytedesk/core/exception/MobileExistsException.java b/modules/core/src/main/java/com/bytedesk/core/exception/MobileExistsException.java new file mode 100644 index 0000000000..b3ba445b2e --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/exception/MobileExistsException.java @@ -0,0 +1,26 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-26 09:28:30 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-26 09:59:04 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.exception; + +public class MobileExistsException extends BaseException { + + private static final long serialVersionUID = -873386350L; + + public MobileExistsException(String message) { + super(message); + //TODO Auto-generated constructor stub + } + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/utils/exception/MobileNotFoundException.java b/modules/core/src/main/java/com/bytedesk/core/exception/MobileNotFoundException.java similarity index 92% rename from modules/core/src/main/java/com/bytedesk/core/utils/exception/MobileNotFoundException.java rename to modules/core/src/main/java/com/bytedesk/core/exception/MobileNotFoundException.java index 69526a53d8..8163018f0e 100644 --- a/modules/core/src/main/java/com/bytedesk/core/utils/exception/MobileNotFoundException.java +++ b/modules/core/src/main/java/com/bytedesk/core/exception/MobileNotFoundException.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-02-03 10:58:01 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-02-03 10:59:04 + * @LastEditTime: 2024-04-26 11:28:23 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -12,7 +12,7 @@ * 联系:270580156@qq.com * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. */ -package com.bytedesk.core.utils.exception; +package com.bytedesk.core.exception; import org.springframework.security.core.AuthenticationException; diff --git a/modules/core/src/main/java/com/bytedesk/core/exception/NotFoundException.java b/modules/core/src/main/java/com/bytedesk/core/exception/NotFoundException.java new file mode 100644 index 0000000000..ed55e67961 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/exception/NotFoundException.java @@ -0,0 +1,29 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-26 12:35:08 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-26 12:35:10 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.exception; + +/** + * Resource not found + */ +public class NotFoundException extends BaseException { + + private static final long serialVersionUID = -984846602L; + + public NotFoundException(String message) { + super(message); + //TODO Auto-generated constructor stub + } + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/exception/UserDisabledException.java b/modules/core/src/main/java/com/bytedesk/core/exception/UserDisabledException.java new file mode 100755 index 0000000000..217c389f48 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/exception/UserDisabledException.java @@ -0,0 +1,34 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-01-29 16:21:24 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-26 11:33:41 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.exception; + +/** + * Exception caused by disabled user. + * + * @author jackning + */ +public class UserDisabledException extends BaseException { + + private static final long serialVersionUID = -3297016350L; + + public UserDisabledException(String message) { + super(message); + } + + public UserDisabledException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/ip/IpController.java b/modules/core/src/main/java/com/bytedesk/core/ip/IpController.java index 2505606fc0..50fe3627fc 100644 --- a/modules/core/src/main/java/com/bytedesk/core/ip/IpController.java +++ b/modules/core/src/main/java/com/bytedesk/core/ip/IpController.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-04-05 14:15:17 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-04-05 14:37:36 + * @LastEditTime: 2024-04-08 00:08:19 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -51,6 +51,8 @@ public class IpController { /** * http://localhost:9003/ip/api/v1/location + * location: "国家|区域|省份|城市|ISP" + * location: "中国|0|湖北省|武汉市|联通" * * @param request * @return @@ -59,6 +61,7 @@ public class IpController { public JsonResult location(HttpServletRequest request) { String ip = IpUtils.clientIp(request); + // location: "中国|0|湖北省|武汉市|联通" String location = ipService.getIpLocation(ip); // JSONObject jsonObject = new JSONObject(); @@ -77,6 +80,8 @@ public class IpController { @GetMapping("/ip/location") public JsonResult ipLocation(@RequestParam String ip) { + // location: "国家|区域|省份|城市|ISP" + // location: "中国|0|湖北省|武汉市|联通" String location = ipService.getIpLocation(ip); // JSONObject jsonObject = new JSONObject(); diff --git a/modules/core/src/main/java/com/bytedesk/core/ip/IpService.java b/modules/core/src/main/java/com/bytedesk/core/ip/IpService.java index 1dd331bdbd..077cfbb38b 100644 --- a/modules/core/src/main/java/com/bytedesk/core/ip/IpService.java +++ b/modules/core/src/main/java/com/bytedesk/core/ip/IpService.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-03-16 13:28:03 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-04-05 14:34:16 + * @LastEditTime: 2024-04-08 10:24:39 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -17,6 +17,7 @@ package com.bytedesk.core.ip; import org.lionsoul.ip2region.xdb.Searcher; import org.springframework.stereotype.Service; +import jakarta.servlet.http.HttpServletRequest; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -30,6 +31,22 @@ public class IpService { private final Searcher searcher; + + /** + * 获取客户端ip + * @param request + * @return + */ + public String getIp(HttpServletRequest request) { + return IpUtils.clientIp(request); + } + + /** + * location: "国家|区域|省份|城市|ISP" + * location: "中国|0|湖北省|武汉市|联通" + * @param ip + * @return + */ public String getIpLocation(String ip) { try { return searcher.search(ip); @@ -39,4 +56,9 @@ public class IpService { return null; } + public String getIpLocation(HttpServletRequest request) { + String ip = getIp(request); + return getIpLocation(ip); + } + } diff --git a/modules/core/src/main/java/com/bytedesk/core/message/Message.java b/modules/core/src/main/java/com/bytedesk/core/message/Message.java index 8fae05f535..7cf04e6534 100644 --- a/modules/core/src/main/java/com/bytedesk/core/message/Message.java +++ b/modules/core/src/main/java/com/bytedesk/core/message/Message.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-29 16:21:24 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-03-27 16:12:05 + * @LastEditTime: 2024-04-22 22:21:00 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -17,7 +17,10 @@ package com.bytedesk.core.message; import java.util.ArrayList; import java.util.List; -import com.bytedesk.core.rbac.user.User; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; + +import com.bytedesk.core.constant.BdConstants; import com.bytedesk.core.thread.Thread; import com.bytedesk.core.utils.AuditModel; import com.fasterxml.jackson.annotation.JsonIgnore; @@ -40,67 +43,54 @@ import lombok.experimental.Accessors; @Table(name = "core_message") public class Message extends AuditModel { + private static final long serialVersionUID = 6816837318L; + @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; - /** - * - */ @Column(unique = true, nullable = false) private String mid; - /** - * - * 消息类型 - */ @Column(name = "by_type") private String type; - /** - * - */ @Column(length = 512) private String content; - /** - * - */ - @Lob - private String extra; + // @Lob + // @Builder.Default + // @Column(columnDefinition = "json") + // @JdbcTypeCode(SqlTypes.JSON) + // private String extra = BdConstants.EMPTY_JSON_STRING; - /** - * - */ + /** send/stored/read */ private String status; - /** - * - */ private String client; - /** - * message belongs to - */ - // @JsonIgnore - // @ManyToOne(fetch = FetchType.LAZY) - // @JoinColumn(name = "thread_id", foreignKey = @ForeignKey(name = "none", value - // = ConstraintMode.NO_CONSTRAINT)) - // private Thread thread; - + /** message belongs to */ @JsonIgnore @Builder.Default @ManyToMany(fetch = FetchType.LAZY) - @JoinTable(name = "core_message_threads", - joinColumns = @JoinColumn(name = "message_id"), - inverseJoinColumns = @JoinColumn(name = "thread_id")) private List threads = new ArrayList<>(); /** * sender + * 考虑到访客信息不存储在user表中,在visitor表中,此处使用json存储,加快查询速度, + * 以空间换时间 */ - @ManyToOne(fetch = FetchType.EAGER) - @JoinColumn(name = "user_id", foreignKey = @ForeignKey(name = "none", value = ConstraintMode.NO_CONSTRAINT)) - private User user; + // @ManyToOne(fetch = FetchType.EAGER) + // private User user; + // + // h2 db 不能使用 user, 所以重定义为 by_user + @Builder.Default + @Column(name = "by_user", columnDefinition = "json") + @JdbcTypeCode(SqlTypes.JSON) + private String user = BdConstants.EMPTY_JSON_STRING; + + // TODO: + /** belong to org */ + private String orgOid; } diff --git a/modules/core/src/main/java/com/bytedesk/core/message/MessageController.java b/modules/core/src/main/java/com/bytedesk/core/message/MessageController.java index 2272aedd64..a82ef1ca5a 100644 --- a/modules/core/src/main/java/com/bytedesk/core/message/MessageController.java +++ b/modules/core/src/main/java/com/bytedesk/core/message/MessageController.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-29 16:21:24 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-03-01 17:26:34 + * @LastEditTime: 2024-04-27 16:42:05 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -14,25 +14,22 @@ */ package com.bytedesk.core.message; -import java.util.Map; - import org.springframework.data.domain.Page; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.bytedesk.core.utils.JsonResult; import lombok.AllArgsConstructor; -import lombok.extern.slf4j.Slf4j; +// import lombok.extern.slf4j.Slf4j; /** * * http://localhost:9003/swagger-ui/index.html */ -@Slf4j +// @Slf4j @RestController @AllArgsConstructor @RequestMapping("/api/v1/message") @@ -47,28 +44,12 @@ public class MessageController { * @return json */ @GetMapping("/query") - public JsonResult query(MessageRequest messageRequest) { + public ResponseEntity query(MessageRequest messageRequest) { Page messagePage = messageService.query(messageRequest); // - return new JsonResult<>("query message success", 200, messagePage); + return ResponseEntity.ok(JsonResult.success(messagePage)); } - /** - * send offline message - * - * @param map map - * @return json - */ - @PostMapping("/send") - public JsonResult sendOfflineMessage(@RequestBody Map map) { - - String json = (String) map.get("json"); - log.debug("json {}", json); - // stompMqService.sendMessageToMq(json); - // - return new JsonResult<>("send offline message success", 200, json); - } - } diff --git a/modules/core/src/main/java/com/bytedesk/core/message/MessageRepository.java b/modules/core/src/main/java/com/bytedesk/core/message/MessageRepository.java index 53324d9062..30e0353177 100644 --- a/modules/core/src/main/java/com/bytedesk/core/message/MessageRepository.java +++ b/modules/core/src/main/java/com/bytedesk/core/message/MessageRepository.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-29 16:21:24 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-03-01 16:07:01 + * @LastEditTime: 2024-04-17 09:43:34 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -25,7 +25,7 @@ import org.springframework.stereotype.Repository; import io.swagger.v3.oas.annotations.tags.Tag; /** - * + * QuerydslPredicateExecutor */ @Repository @Tag(name = "message - 消息") @@ -35,6 +35,10 @@ public interface MessageRepository extends JpaRepository, JpaSpec Long deleteByMid(String mid); - Page findByThreadsTidIn(String[] threadIds, Pageable pageable); + Page findByThreadsTidIn(String[] threadTids, Pageable pageable); + + Optional findFirstByThreadsTidInOrderByCreatedAtDesc(String[] threadTids); + + boolean existsByMid(String mid); } diff --git a/modules/core/src/main/java/com/bytedesk/core/message/MessageResponse.java b/modules/core/src/main/java/com/bytedesk/core/message/MessageResponse.java index 73fdba99ee..a324dd6025 100644 --- a/modules/core/src/main/java/com/bytedesk/core/message/MessageResponse.java +++ b/modules/core/src/main/java/com/bytedesk/core/message/MessageResponse.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-02-21 10:00:55 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-03-04 14:18:57 + * @LastEditTime: 2024-04-22 20:51:15 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -16,51 +16,48 @@ package com.bytedesk.core.message; import java.util.Date; -import org.springframework.beans.factory.annotation.Value; - import com.bytedesk.core.rbac.user.UserResponseSimple; -import com.fasterxml.jackson.annotation.JsonFormat; - +import com.bytedesk.core.thread.ThreadResponseSimple; +import com.bytedesk.core.utils.BaseResponse; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; +/** + * response for visitor init/request thread + * distinguish visitor message from agent view + * 区分 访客端拉取的消息格式 和 客服端拉取到的消息格式 + */ @Data -public class MessageResponse { +@Builder +@Accessors(chain = true) +@AllArgsConstructor +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class MessageResponse extends BaseResponse { - @Value("${bytedesk.timezone}") - private static final String timezone = "GMT+8"; + private static final long serialVersionUID = 9911390153L; - private String mid; + /** message */ + private String mid; - /** - * - */ - private String type; + private String type; - /** - * - */ - private String content; + private String content; - /** - * - */ - private String extra; + private String status; - /** - * - */ - private String status; + private String client; - /** - * - */ - private String client; + private Date createdAt; + /** */ + private ThreadResponseSimple thread; - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = timezone) - private Date createdAt; - - - private UserResponseSimple user; + /** */ + private UserResponseSimple user; } diff --git a/modules/core/src/main/java/com/bytedesk/core/message/MessageService.java b/modules/core/src/main/java/com/bytedesk/core/message/MessageService.java index acd77e74f2..030fc00f79 100644 --- a/modules/core/src/main/java/com/bytedesk/core/message/MessageService.java +++ b/modules/core/src/main/java/com/bytedesk/core/message/MessageService.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-29 16:21:24 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-03-11 13:54:35 + * @LastEditTime: 2024-04-22 21:11:23 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -16,6 +16,11 @@ package com.bytedesk.core.message; import java.util.Optional; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.cache.annotation.Caching; +import org.springframework.cache.annotation.CachePut; +// import org.modelmapper.ModelMapper; +import org.springframework.cache.annotation.CacheEvict; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; @@ -45,19 +50,47 @@ public class MessageService { return messagePage.map(BdConvertUtils::convertToMessageResponse); } + @Cacheable(value = "message", key = "#mid", unless="#result == null") public Optional findByMid(String mid) { return messageRepository.findByMid(mid); } + /** + * find the last message in the thread + * 找到当前会话中最新一条聊天记录 + */ + @Cacheable(value = "message", key = "#threadTid", unless="#result == null") + public Optional findByThreadsTidInOrderByCreatedAtDesc(String threadTid) { + return messageRepository.findFirstByThreadsTidInOrderByCreatedAtDesc(new String[]{threadTid}); + } + + @Caching(put = { + @CachePut(value = "message", key = "#message.mid"), + }) public Message save(@NonNull Message message) { return messageRepository.save(message); } + @Caching(evict = { + @CacheEvict(value = "message", key = "#message.mid"), + }) public void delete(@NonNull Message message) { messageRepository.delete(message); } + @Caching(evict = { + @CacheEvict(value = "message", key = "#mid"), + }) public void deleteByMid(String mid) { messageRepository.deleteByMid(mid); } + + public boolean existsByMid(String mid) { + return messageRepository.existsByMid(mid); + } + + // public MessageResponse convertToMessageResponse(Message message) { + // return modelMapper.map(message, MessageResponse.class); + // } + } diff --git a/modules/core/src/main/java/com/bytedesk/core/schedule/Schedule.java b/modules/core/src/main/java/com/bytedesk/core/openid/OpenId.java similarity index 79% rename from modules/core/src/main/java/com/bytedesk/core/schedule/Schedule.java rename to modules/core/src/main/java/com/bytedesk/core/openid/OpenId.java index b460393f16..83a0dda5d1 100644 --- a/modules/core/src/main/java/com/bytedesk/core/schedule/Schedule.java +++ b/modules/core/src/main/java/com/bytedesk/core/openid/OpenId.java @@ -1,8 +1,8 @@ /* * @Author: jackning 270580156@qq.com - * @Date: 2024-02-22 16:54:02 + * @Date: 2024-04-09 09:49:09 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-02-22 16:54:05 + * @LastEditTime: 2024-04-09 09:49:11 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -12,11 +12,11 @@ * 联系:270580156@qq.com * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. */ -package com.bytedesk.core.schedule; +package com.bytedesk.core.openid; /** - * schedule tasks - 定时任务 + * third party openid, including: wechat/github/google... */ -public class Schedule { - +public class OpenId { + } diff --git a/modules/core/src/main/java/com/bytedesk/core/push/Notifier.java b/modules/core/src/main/java/com/bytedesk/core/push/Notifier.java new file mode 100644 index 0000000000..147f40d7f7 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/push/Notifier.java @@ -0,0 +1,22 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-03-29 15:49:55 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-25 15:55:19 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.push; + +import com.bytedesk.core.message.Message; + +public abstract class Notifier { + abstract void notify(Message e); + abstract void send(String to, String content); +} diff --git a/modules/core/src/main/java/com/bytedesk/core/push/Push.java b/modules/core/src/main/java/com/bytedesk/core/push/Push.java index 8817880300..d6485ee28a 100644 --- a/modules/core/src/main/java/com/bytedesk/core/push/Push.java +++ b/modules/core/src/main/java/com/bytedesk/core/push/Push.java @@ -1,8 +1,8 @@ /* * @Author: jackning 270580156@qq.com - * @Date: 2024-03-29 15:49:55 + * @Date: 2024-04-25 15:30:11 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-03-29 15:49:58 + * @LastEditTime: 2024-04-25 20:23:47 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -14,6 +14,53 @@ */ package com.bytedesk.core.push; -public class Push { +import com.bytedesk.core.constant.StatusConsts; +import com.bytedesk.core.utils.AuditModel; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +/** + * + */ +@Data +@Entity +@Builder +@EqualsAndHashCode(callSuper=false) +@Accessors(chain = true) +@AllArgsConstructor +@NoArgsConstructor +@Table(name = "core_push") +public class Push extends AuditModel { + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private Long id; + + @Column(unique = true, nullable = false) + private String pid; + + private String sender; + + private String content; + + private String receiver; + + @Column(name = "by_type") + private String type; + + @Builder.Default + private String status = StatusConsts.CODE_STATUS_PENDING; + + private String client; } diff --git a/modules/core/src/main/java/com/bytedesk/core/push/PushConfig.java b/modules/core/src/main/java/com/bytedesk/core/push/PushConfig.java new file mode 100644 index 0000000000..6598cde118 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/push/PushConfig.java @@ -0,0 +1,40 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-17 10:35:11 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-17 10:54:09 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.push; + +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.AsyncConfigurer; +import org.springframework.scheduling.annotation.EnableAsync; + +/** + * async push + * https://www.baeldung.com/spring-async + * https://spring.io/guides/gs/async-method + */ +@EnableAsync +@Configuration +public class PushConfig implements AsyncConfigurer { + + // @Override + // public Executor getAsyncExecutor() { + // ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor(); + // threadPoolTaskExecutor.setCorePoolSize(2); + // threadPoolTaskExecutor.setMaxPoolSize(2); + // threadPoolTaskExecutor.setQueueCapacity(500); + // threadPoolTaskExecutor.setThreadNamePrefix("PushService-"); // default prefix :TaskExecutor- + // threadPoolTaskExecutor.initialize(); + // return threadPoolTaskExecutor; + // } +} diff --git a/modules/core/src/main/java/com/bytedesk/core/push/SmsService.java b/modules/core/src/main/java/com/bytedesk/core/push/PushController.java similarity index 88% rename from modules/core/src/main/java/com/bytedesk/core/push/SmsService.java rename to modules/core/src/main/java/com/bytedesk/core/push/PushController.java index 9bd9647d5a..0fa198be67 100644 --- a/modules/core/src/main/java/com/bytedesk/core/push/SmsService.java +++ b/modules/core/src/main/java/com/bytedesk/core/push/PushController.java @@ -1,8 +1,8 @@ /* * @Author: jackning 270580156@qq.com - * @Date: 2024-03-31 15:29:55 + * @Date: 2024-04-25 15:41:22 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-03-31 15:29:57 + * @LastEditTime: 2024-04-25 15:41:24 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -14,6 +14,6 @@ */ package com.bytedesk.core.push; -public class SmsService { +public class PushController { } diff --git a/modules/core/src/main/java/com/bytedesk/core/push/PushRepository.java b/modules/core/src/main/java/com/bytedesk/core/push/PushRepository.java new file mode 100644 index 0000000000..4951569107 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/push/PushRepository.java @@ -0,0 +1,31 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-25 15:42:24 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-25 17:36:36 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.push; + +import java.util.List; +import java.util.Optional; + +import org.springframework.data.jpa.repository.JpaRepository; + +public interface PushRepository extends JpaRepository { + + List findByStatus(String status); + + Optional findByStatusAndTypeAndReceiver(String status, String type, String receiver); + + Boolean existsByStatusAndTypeAndReceiver(String status, String type, String receiver); + + Boolean existsByStatusAndTypeAndReceiverAndContent(String status, String type, String receiver, String content); +} diff --git a/modules/core/src/main/java/com/bytedesk/core/push/PushRequest.java b/modules/core/src/main/java/com/bytedesk/core/push/PushRequest.java new file mode 100644 index 0000000000..407b02f7ad --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/push/PushRequest.java @@ -0,0 +1,48 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-25 15:42:01 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-25 20:28:33 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.push; + +import com.bytedesk.core.constant.StatusConsts; +import com.bytedesk.core.utils.BaseRequest; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +/** + * + */ +@Data +@Builder +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = false) +@AllArgsConstructor +@NoArgsConstructor +public class PushRequest extends BaseRequest { + + private static final long serialVersionUID = 6684752544L; + + private String pid; + + private String sender; + + private String receiver; + + @Builder.Default + private String status = StatusConsts.CODE_STATUS_PENDING; +} diff --git a/modules/core/src/main/java/com/bytedesk/core/push/PushResponse.java b/modules/core/src/main/java/com/bytedesk/core/push/PushResponse.java new file mode 100644 index 0000000000..91dab8e4ef --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/push/PushResponse.java @@ -0,0 +1,39 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-25 15:42:11 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-25 15:49:46 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.push; + +import com.bytedesk.core.utils.BaseResponse; + +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +@Data +@Builder +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = false) +public class PushResponse extends BaseResponse { + + private static final long serialVersionUID = -8586294033L; + + private String pid; + + private String content; + + private String type; + + private String status; +} diff --git a/modules/core/src/main/java/com/bytedesk/core/push/PushService.java b/modules/core/src/main/java/com/bytedesk/core/push/PushService.java new file mode 100644 index 0000000000..31acbe45fe --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/push/PushService.java @@ -0,0 +1,177 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-25 15:41:33 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-26 12:24:40 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.push; + +import java.util.Date; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.TimeUnit; + +import org.modelmapper.ModelMapper; +import org.springframework.cache.annotation.CachePut; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.cache.annotation.Caching; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import com.bytedesk.core.constant.StatusConsts; +import com.bytedesk.core.constant.TypeConsts; +import com.bytedesk.core.exception.EmailExistsException; +import com.bytedesk.core.exception.MobileExistsException; +import com.bytedesk.core.rbac.user.UserService; +import com.bytedesk.core.uid.UidUtils; +import com.bytedesk.core.utils.Utils; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Service +@AllArgsConstructor +public class PushService { + + private final PushRepository pushRepository; + + private final ModelMapper modelMapper; + + private final UidUtils uidUtils; + + private final PushServiceImplEmail pushServiceImplEmail; + + private final PushServiceImplSms pushServiceImplSms; + + private final UserService userService; + + public Boolean sendEmailCode(String email, String client, String authType) { + + return sendCode(email, TypeConsts.TYPE_EMAIL, client, authType); + } + + public Boolean sendSmsCode(String mobile, String client, String authType) { + + return sendCode(mobile, TypeConsts.TYPE_MOBILE, client, authType); + } + + public Boolean sendCode(String receiver, String type, String client, String authType) { + + // 注册验证码,如果账号已经存在,则直接抛出异常 + if (authType.equals(TypeConsts.SEND_MOBILE_CODE_TYPE_REGISTER)) { + + if (type.equals(TypeConsts.TYPE_MOBILE) && userService.existsByMobile(receiver)) { + throw new MobileExistsException("mobile already exists"); + } + + if (type.equals(TypeConsts.TYPE_EMAIL) && userService.existsByEmail(receiver)) { + throw new EmailExistsException("email already exists"); + } + } + + // check if has already send validate code within 15min + if (existsByStatusAndTypeAndReceiver(StatusConsts.CODE_STATUS_PENDING, type, receiver)) { + return false; + } + + String code = Utils.getRandomCode(receiver); + + if (type.equals(TypeConsts.TYPE_EMAIL)) { + pushServiceImplEmail.send(receiver, code); + } else if (type.equals(TypeConsts.TYPE_MOBILE)) { + pushServiceImplSms.send(receiver, code); + } else { + return false; + } + + // + PushRequest pushRequest = new PushRequest(); + pushRequest.setType(type); + pushRequest.setSender(TypeConsts.TYPE_SYSTEM); + pushRequest.setContent(code); + pushRequest.setReceiver(receiver); + pushRequest.setClient(client); + create(pushRequest); + + return true; + } + + public Push create(PushRequest pushRequest) { + log.info("pushRequest {}", pushRequest.toString()); + + Push push = modelMapper.map(pushRequest, Push.class); + push.setPid(uidUtils.getCacheSerialUid()); + push.setClient(pushRequest.getClient()); + + return save(push); + } + + public Boolean validateEmailCode(String email, String code) { + return validateCode(email, TypeConsts.TYPE_EMAIL, code); + } + + public Boolean validateSmsCode(String mobile, String code) { + return validateCode(mobile, TypeConsts.TYPE_MOBILE, code); + } + + public Boolean validateCode(String receiver, String type, String code) { + return pushRepository.existsByStatusAndTypeAndReceiverAndContent(StatusConsts.CODE_STATUS_PENDING, type, receiver, code); + } + + @Cacheable(value = "push", key = "#receiver-#status-#type", unless = "#result == null") + public Optional findByStatusAndTypeAndReceiver(String status, String type, String receiver) { + return pushRepository.findByStatusAndTypeAndReceiver(status, type, receiver); + } + + public Boolean existsByStatusAndTypeAndReceiver(String status, String type, String receiver) { + return pushRepository.existsByStatusAndTypeAndReceiver(status, type, receiver); + } + + @Caching(put = { + @CachePut(value = "push", key = "#push.receiver"), + // TODO: 根据status, 缓存或清空缓存,clear or cache according to status + }) + public Push save(Push push) { + return pushRepository.save(push); + } + + // TODO: 更新缓存 + @Cacheable(value = "pushPending") + public List findStatusPending() { + return pushRepository.findByStatus(StatusConsts.CODE_STATUS_PENDING); + } + + // 自动过期 + // TODO: 频繁查库,待优化 + @Async + public void autoOutdateCode() { + List pendingPushes = findStatusPending(); + pendingPushes.forEach(push -> { + // 计算两个日期之间的毫秒差 + long diffInMilliseconds = Math.abs(new Date().getTime() - push.getUpdatedAt().getTime()); + // 转换为分钟 + long diffInMinutes = TimeUnit.MILLISECONDS.toMinutes(diffInMilliseconds); + // 验证码有效时间15分钟 + if (diffInMinutes > 15) { + // TODO: 过期,清空缓存 + push.setStatus(StatusConsts.CODE_STATUS_EXPIRED); + save(push); + } + }); + } + + + public PushResponse convertToPushResponse(Push push) { + return modelMapper.map(push, PushResponse.class); + } + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/push/PushServiceImplAndroid.java b/modules/core/src/main/java/com/bytedesk/core/push/PushServiceImplAndroid.java new file mode 100644 index 0000000000..96622596a6 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/push/PushServiceImplAndroid.java @@ -0,0 +1,39 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-03-31 15:30:30 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-26 12:55:50 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.push; + +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import com.bytedesk.core.message.Message; + +@Service +public class PushServiceImplAndroid extends Notifier { + + + @Async + @Override + void notify(Message e) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'notify'"); + } + + @Override + void send(String to, String content) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'send'"); + } + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/push/PushServiceImplEmail.java b/modules/core/src/main/java/com/bytedesk/core/push/PushServiceImplEmail.java new file mode 100644 index 0000000000..71029f2e6f --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/push/PushServiceImplEmail.java @@ -0,0 +1,44 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-03-31 15:30:19 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-26 12:55:58 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.push; + +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import com.bytedesk.core.message.Message; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Service +public class PushServiceImplEmail extends Notifier { + + + @Async + @Override + void notify(Message e) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'notify'"); + } + + @Async + @Override + void send(String to, String content) { + log.info("TODO: send email to {}, content {}", to, content); + + + } + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/push/PushServiceImplIos.java b/modules/core/src/main/java/com/bytedesk/core/push/PushServiceImplIos.java new file mode 100644 index 0000000000..60126d0824 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/push/PushServiceImplIos.java @@ -0,0 +1,38 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-03-31 15:30:08 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-26 12:55:38 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.push; + +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import com.bytedesk.core.message.Message; + +@Service +public class PushServiceImplIos extends Notifier { + + @Async + @Override + void notify(Message e) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'notify'"); + } + + @Override + void send(String to, String content) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'send'"); + } + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/push/PushServiceImplSms.java b/modules/core/src/main/java/com/bytedesk/core/push/PushServiceImplSms.java new file mode 100644 index 0000000000..e775fd6eae --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/push/PushServiceImplSms.java @@ -0,0 +1,43 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-03-31 15:29:55 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-26 12:56:13 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.push; + +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import com.bytedesk.core.message.Message; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Service +public class PushServiceImplSms extends Notifier { + + @Async + @Override + void notify(Message e) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'notify'"); + } + + @Async + @Override + void send(String to, String content) { + // TODO Auto-generated method stub + log.info("TODO: send sms to {}, content: {}", to, content); + + } + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/rbac/action/ActionController.java b/modules/core/src/main/java/com/bytedesk/core/rbac/action/ActionController.java deleted file mode 100644 index 47a2747346..0000000000 --- a/modules/core/src/main/java/com/bytedesk/core/rbac/action/ActionController.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.bytedesk.core.rbac.action; - -import lombok.AllArgsConstructor; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -/** - * 操作:查询、插入、删除 - */ -// @Slf4j -@AllArgsConstructor -@RestController -@RequestMapping("/api/v1/action") -public class ActionController { - - // private final ActionService actionService; - - /** - * - * - * @return json - */ - // @GetMapping("/list") - // public JsonResult list(@RequestParam(value = "client") final String client) { - // // - // final List actionDTOS = actionService.findAllDTO(); - - // return new JsonResult<>("获取操作列表成功", 200, actionDTOS); - // } - -} diff --git a/modules/core/src/main/java/com/bytedesk/core/rbac/action/ActionRepository.java b/modules/core/src/main/java/com/bytedesk/core/rbac/action/ActionRepository.java deleted file mode 100644 index 01bae0d908..0000000000 --- a/modules/core/src/main/java/com/bytedesk/core/rbac/action/ActionRepository.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * @Author: jackning 270580156@qq.com - * @Date: 2024-01-29 16:21:24 - * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-01-31 11:26:39 - * @Description: bytedesk.com https://github.com/Bytedesk/bytedeskt - * Please be aware of the BSL license restrictions before installing Bytedesk IM – - * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. - * 仅支持企业内部员工自用,严禁用于销售、二次销售或者部署SaaS方式销售 - * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE - * contact: 270580156@qq.com - * 联系:270580156@qq.com - * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. - */ -package com.bytedesk.core.rbac.action; - -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -import io.swagger.v3.oas.annotations.tags.Tag; - -import java.util.Optional; - -/** - * action - */ -@Repository -@Tag(name = "actions - 操作") -public interface ActionRepository extends JpaRepository { - - Optional findByValue(String value); -} diff --git a/modules/core/src/main/java/com/bytedesk/core/auth/AuthController.java b/modules/core/src/main/java/com/bytedesk/core/rbac/auth/AuthController.java similarity index 55% rename from modules/core/src/main/java/com/bytedesk/core/auth/AuthController.java rename to modules/core/src/main/java/com/bytedesk/core/rbac/auth/AuthController.java index ef7391015f..a1b4aeb3b0 100644 --- a/modules/core/src/main/java/com/bytedesk/core/auth/AuthController.java +++ b/modules/core/src/main/java/com/bytedesk/core/rbac/auth/AuthController.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-29 16:21:24 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-04-01 15:58:08 + * @LastEditTime: 2024-04-26 12:11:26 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -12,7 +12,7 @@ * 联系:270580156@qq.com * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. */ -package com.bytedesk.core.auth; +package com.bytedesk.core.rbac.auth; import org.springframework.http.ResponseEntity; import org.springframework.security.authentication.AuthenticationManager; @@ -23,17 +23,16 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import com.bytedesk.core.annotation.ActionLog; +import com.bytedesk.core.push.PushService; import com.bytedesk.core.rbac.user.UserRequest; import com.bytedesk.core.rbac.user.UserResponse; import com.bytedesk.core.rbac.user.UserService; -import com.bytedesk.core.redis.RedisLoginService; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; -// import com.bytedesk.core.token.RefreshToken; -// import com.bytedesk.core.token.RefreshTokenService; import com.bytedesk.core.utils.JsonResult; /** @@ -50,10 +49,10 @@ public class AuthController { private AuthService authService; - private RedisLoginService redisLoginService; - private AuthenticationManager authenticationManager; + private PushService pushService; + /** * * @param userRequest @@ -61,15 +60,19 @@ public class AuthController { */ @PostMapping(value = "/register") public ResponseEntity register(@RequestBody UserRequest userRequest) { - try { - UserResponse userResponse = userService.register(userRequest); - return ResponseEntity.ok(JsonResult.success(userResponse)); - } catch (Exception e) { - throw new RuntimeException(e); + // validate sms code + // 验证手机验证码 + if (!pushService.validateSmsCode(userRequest.getMobile(), userRequest.getCode())) { + return ResponseEntity.ok().body(JsonResult.error("validate code failed", -1, false)); } + + UserResponse userResponse = userService.register(userRequest); + + return ResponseEntity.ok(JsonResult.success("register success", userResponse)); } + @ActionLog(title = "Auth", action = "loginWithUsernamePassword", description = "Login With Username & Password") @PostMapping("/login") public ResponseEntity loginWithUsernamePassword(@RequestBody AuthRequest authRequest) { log.debug("login {}", authRequest.toString()); @@ -77,23 +80,22 @@ public class AuthController { Authentication authentication = authenticationManager.authenticate( new UsernamePasswordAuthenticationToken(authRequest.getUsername(), authRequest.getPassword())); // - return authService.formatResponse(authentication); + AuthResponse authResponse = authService.formatResponse(authentication); + + return ResponseEntity.ok(JsonResult.success(authResponse)); } @PostMapping("/send/mobile") public ResponseEntity sendMobileCode(@RequestBody AuthRequest authRequest) { - log.debug("send mobile code {}", authRequest.toString()); + log.debug("send mobile code {}, client {}, type {}", authRequest.toString(), authRequest.getClient(), authRequest.getType()); - // check if has already send validate code within 15min - if (redisLoginService.hasValidateCode(authRequest.getMobile())) { - return ResponseEntity.ok() - .body(new JsonResult<>("validate code already sent", -1, false)); + // send mobile code + Boolean result = pushService.sendSmsCode(authRequest.getMobile(), authRequest.getClient(), authRequest.getType()); + if (!result) { + return ResponseEntity.ok().body(JsonResult.error("already send, dont repeat", -1, false)); } - int code = authService.getRandomCode(authRequest.getMobile()); - // TODO: send mobile code - - return ResponseEntity.ok().body(new JsonResult<>("validate code success", 200, code)); + return ResponseEntity.ok().body(JsonResult.success("send mobile code success")); } @PostMapping("/login/mobile") @@ -101,36 +103,67 @@ public class AuthController { log.debug("login mobile {}", authRequest.toString()); // validate mobile & code - if (!redisLoginService.validateCode(authRequest.getMobile(), authRequest.getCode())) { - return ResponseEntity.ok() - .body(new JsonResult<>("validate code failed", -1, false)); - + // 验证手机验证码 + if (!pushService.validateSmsCode(authRequest.getMobile(), authRequest.getCode())) { + return ResponseEntity.ok().body(JsonResult.error("validate code failed", -1, false)); } + + // if mobile already exists, if none, then registe + // 手机号是否已经注册,如果没有,则自动注册 + if (!userService.existsByMobile(authRequest.getMobile())) { + UserRequest userRequest = new UserRequest(); + userRequest.setUsername(authRequest.getMobile()); + userRequest.setMobile(authRequest.getMobile()); + userService.register(userRequest); + } + Authentication authentication = authService.authenticationWithMobile(authRequest.getMobile()); // - return authService.formatResponse(authentication); + AuthResponse authResponse = authService.formatResponse(authentication); + + return ResponseEntity.ok(JsonResult.success(authResponse)); } @PostMapping("/send/email") public ResponseEntity sendEmailCode(@RequestBody AuthRequest authRequest) { log.debug("send email code {}", authRequest.toString()); - // TODO: send email code + // send email code + Boolean result = pushService.sendEmailCode(authRequest.getEmail(), authRequest.getClient(), authRequest.getType()); + if (!result) { + return ResponseEntity.ok(JsonResult.error("already send, dont repeat", -1, false)); + } - return ResponseEntity.ok().body(null); + return ResponseEntity.ok(JsonResult.success("send email code success")); } @PostMapping("/login/email") public ResponseEntity loginWithEmailCode(@RequestBody AuthRequest authRequest) { log.debug("login email {}", authRequest.toString()); - // TODO: validate email & code + // validate email & code + if (!pushService.validateEmailCode(authRequest.getEmail(), authRequest.getCode())) { + return ResponseEntity.ok(JsonResult.error("validate code failed", -1, false)); + } + + // 邮箱是否已经注册,如果没有,则自动注册 + if (!userService.existsByEmail(authRequest.getEmail())) { + UserRequest userRequest = new UserRequest(); + userRequest.setUsername(authRequest.getEmail()); + userRequest.setEmail(authRequest.getEmail()); + userService.register(userRequest); + } Authentication authentication = authService.authenticationWithEmail(authRequest.getEmail()); // - return authService.formatResponse(authentication); + AuthResponse authResponse = authService.formatResponse(authentication); + + return ResponseEntity.ok(JsonResult.success(authResponse)); } + + + // @PostMapping("/refreshToken") // public JwtResponse refreshToken(@RequestBody RefreshTokenRequest // refreshTokenRequestDTO) { diff --git a/modules/core/src/main/java/com/bytedesk/core/auth/AuthEntryPoint.java b/modules/core/src/main/java/com/bytedesk/core/rbac/auth/AuthEntryPoint.java similarity index 98% rename from modules/core/src/main/java/com/bytedesk/core/auth/AuthEntryPoint.java rename to modules/core/src/main/java/com/bytedesk/core/rbac/auth/AuthEntryPoint.java index e3362a4d5e..10654520a0 100644 --- a/modules/core/src/main/java/com/bytedesk/core/auth/AuthEntryPoint.java +++ b/modules/core/src/main/java/com/bytedesk/core/rbac/auth/AuthEntryPoint.java @@ -12,7 +12,7 @@ * 联系:270580156@qq.com * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. */ -package com.bytedesk.core.auth; +package com.bytedesk.core.rbac.auth; import java.io.IOException; import java.util.HashMap; diff --git a/modules/core/src/main/java/com/bytedesk/core/auth/AuthJwtTokenFilter.java b/modules/core/src/main/java/com/bytedesk/core/rbac/auth/AuthJwtTokenFilter.java similarity index 72% rename from modules/core/src/main/java/com/bytedesk/core/auth/AuthJwtTokenFilter.java rename to modules/core/src/main/java/com/bytedesk/core/rbac/auth/AuthJwtTokenFilter.java index 5f2da94b44..4cfd1ade15 100644 --- a/modules/core/src/main/java/com/bytedesk/core/auth/AuthJwtTokenFilter.java +++ b/modules/core/src/main/java/com/bytedesk/core/rbac/auth/AuthJwtTokenFilter.java @@ -1,12 +1,18 @@ /* - * @Author: jack ning github@bytedesk.com - * @Date: 2024-01-29 11:48:06 + * @Author: jackning 270580156@qq.com + * @Date: 2024-01-29 16:17:36 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-02-26 11:35:54 - * @FilePath: /spring-boot-spring-security-jwt-authentication/src/main/java/com/bezkoder/springjwt/security/jwt/AuthTokenFilter.java - * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + * @LastEditTime: 2024-04-27 10:19:53 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. */ -package com.bytedesk.core.auth; +package com.bytedesk.core.rbac.auth; import java.io.IOException; diff --git a/modules/core/src/main/java/com/bytedesk/core/auth/AuthRequest.java b/modules/core/src/main/java/com/bytedesk/core/rbac/auth/AuthRequest.java similarity index 76% rename from modules/core/src/main/java/com/bytedesk/core/auth/AuthRequest.java rename to modules/core/src/main/java/com/bytedesk/core/rbac/auth/AuthRequest.java index 83baade34b..dd63a3032a 100644 --- a/modules/core/src/main/java/com/bytedesk/core/auth/AuthRequest.java +++ b/modules/core/src/main/java/com/bytedesk/core/rbac/auth/AuthRequest.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-23 07:53:01 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-02-03 10:41:05 + * @LastEditTime: 2024-04-25 20:28:15 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -12,16 +12,22 @@ * 联系:270580156@qq.com * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. */ -package com.bytedesk.core.auth; +package com.bytedesk.core.rbac.auth; + +import com.bytedesk.core.utils.BaseRequest; import lombok.Data; +import lombok.EqualsAndHashCode; /** * @author 20580156@qq.com * @project bytedesk-im */ @Data -public class AuthRequest { +@EqualsAndHashCode(callSuper=false) +public class AuthRequest extends BaseRequest { + + private static final long serialVersionUID = -9618212342L; private String username; private String password; diff --git a/modules/core/src/main/java/com/bytedesk/core/auth/AuthResponse.java b/modules/core/src/main/java/com/bytedesk/core/rbac/auth/AuthResponse.java similarity index 96% rename from modules/core/src/main/java/com/bytedesk/core/auth/AuthResponse.java rename to modules/core/src/main/java/com/bytedesk/core/rbac/auth/AuthResponse.java index 50d5253952..5ad22a1e00 100644 --- a/modules/core/src/main/java/com/bytedesk/core/auth/AuthResponse.java +++ b/modules/core/src/main/java/com/bytedesk/core/rbac/auth/AuthResponse.java @@ -12,7 +12,7 @@ * 联系:270580156@qq.com * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. */ -package com.bytedesk.core.auth; +package com.bytedesk.core.rbac.auth; import com.bytedesk.core.rbac.user.UserResponse; diff --git a/modules/core/src/main/java/com/bytedesk/core/auth/AuthService.java b/modules/core/src/main/java/com/bytedesk/core/rbac/auth/AuthService.java similarity index 72% rename from modules/core/src/main/java/com/bytedesk/core/auth/AuthService.java rename to modules/core/src/main/java/com/bytedesk/core/rbac/auth/AuthService.java index 039937bc0e..b911925ab1 100644 --- a/modules/core/src/main/java/com/bytedesk/core/auth/AuthService.java +++ b/modules/core/src/main/java/com/bytedesk/core/rbac/auth/AuthService.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-23 07:53:01 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-03-27 21:28:12 + * @LastEditTime: 2024-04-27 10:40:14 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -12,11 +12,9 @@ * 联系:270580156@qq.com * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. */ -package com.bytedesk.core.auth; +package com.bytedesk.core.rbac.auth; -import java.util.Random; import org.modelmapper.ModelMapper; -import org.springframework.http.ResponseEntity; import org.springframework.lang.NonNull; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; @@ -29,8 +27,6 @@ import com.bytedesk.core.rbac.user.User; import com.bytedesk.core.rbac.user.UserDetailsImpl; import com.bytedesk.core.rbac.user.UserDetailsServiceImpl; import com.bytedesk.core.rbac.user.UserResponse; -import com.bytedesk.core.redis.RedisLoginService; -import com.bytedesk.core.utils.JsonResult; import com.bytedesk.core.utils.JwtUtils; import jakarta.servlet.http.HttpServletRequest; @@ -47,8 +43,6 @@ public class AuthService { private JwtUtils jwtUtils; - private RedisLoginService redisLoginService; - private UserDetailsServiceImpl userDetailsService; private ModelMapper modelMapper; @@ -82,49 +76,28 @@ public class AuthService { return new AuthToken(userDetails); } - public ResponseEntity formatResponse(Authentication authentication) { + public AuthResponse formatResponse(Authentication authentication) { SecurityContextHolder.getContext().setAuthentication(authentication); UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal(); - // List roles = userDetails.getAuthorities().stream() - // .map(item -> item.getAuthority()) - // .collect(Collectors.toList()); - UserResponse userResponse = modelMapper.map(userDetails, UserResponse.class); + + UserResponse userResponse = convertToUserResponse(userDetails); + String jwt = jwtUtils.generateJwtToken(userDetails.getUsername()); - return ResponseEntity.ok(new JsonResult<>("login success", 200, AuthResponse.builder() + return AuthResponse.builder() .access_token(jwt) .user(userResponse) - .build())); - } - - /** - * for test - * - * @param mobile - * @return - */ - public boolean isTestMobile(String mobile) { - return mobile.startsWith("133111562") || mobile.startsWith("1888888"); - } - - /** - * - * @return - */ - @SuppressWarnings("null") - public int getRandomCode(String key) { - int code = 123456; - if (isTestMobile(key)) { - code = 123456; - } else { - int min = 100001; - int max = 999998; - code = new Random().nextInt(max) % (max - min + 1) + min; - } - redisLoginService.cacheValidateCode(key, String.valueOf(code)); - return code; + .build(); + } + + + public UserResponse convertToUserResponse(UserDetailsImpl userDetails) { + UserResponse userResponse = modelMapper.map(userDetails, UserResponse.class); + + return userResponse; } + } diff --git a/modules/core/src/main/java/com/bytedesk/core/auth/AuthToken.java b/modules/core/src/main/java/com/bytedesk/core/rbac/auth/AuthToken.java similarity index 98% rename from modules/core/src/main/java/com/bytedesk/core/auth/AuthToken.java rename to modules/core/src/main/java/com/bytedesk/core/rbac/auth/AuthToken.java index 632f22c57f..569085613a 100644 --- a/modules/core/src/main/java/com/bytedesk/core/auth/AuthToken.java +++ b/modules/core/src/main/java/com/bytedesk/core/rbac/auth/AuthToken.java @@ -12,7 +12,7 @@ * 联系:270580156@qq.com * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. */ -package com.bytedesk.core.auth; +package com.bytedesk.core.rbac.auth; import java.util.Collection; diff --git a/modules/core/src/main/java/com/bytedesk/core/rbac/authority/Authority.java b/modules/core/src/main/java/com/bytedesk/core/rbac/authority/Authority.java index f9581d2fd0..c88dfaa829 100755 --- a/modules/core/src/main/java/com/bytedesk/core/rbac/authority/Authority.java +++ b/modules/core/src/main/java/com/bytedesk/core/rbac/authority/Authority.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-29 16:21:24 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-03-29 14:01:47 + * @LastEditTime: 2024-04-24 11:13:15 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -14,28 +14,30 @@ */ package com.bytedesk.core.rbac.authority; -import com.bytedesk.core.rbac.action.Action; -import com.fasterxml.jackson.annotation.JsonIgnore; - +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; import lombok.experimental.Accessors; import jakarta.persistence.*; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; + +import com.bytedesk.core.utils.AuditModel; /** * @author im.bytedesk.com */ @Data +@Builder @Accessors(chain = true) +@EqualsAndHashCode(callSuper=false) @Entity +@AllArgsConstructor +@NoArgsConstructor @Table(name = "core_authority") -// @JsonIgnoreProperties(value = { "handler", "hibernateLazyInitializer", -// "fieldHandler" }) -public class Authority implements Serializable { +public class Authority extends AuditModel { - private static final long serialVersionUID = 8868352778004638978L; + private static final long serialVersionUID = -3232924689L; @Id @GeneratedValue(strategy = GenerationType.AUTO) @@ -46,25 +48,19 @@ public class Authority implements Serializable { private String name; + /** value is a keyword in h2 db */ + @Column(name = "by_value") private String value; - private Integer status = 1; + // private Integer status = 1; private String description; @Column(name = "by_type") private String type; - @JsonIgnore - @OneToMany - private List actions = new ArrayList<>(); - // @JsonIgnore - // @ManyToMany(cascade = CascadeType.DETACH, fetch = FetchType.LAZY) - // @JoinTable(name = "core_authority_actions", - // joinColumns = @JoinColumn(name = "authority_id", foreignKey = @ForeignKey(name = "none", value = ConstraintMode.NO_CONSTRAINT)), - // inverseJoinColumns = @JoinColumn(name = "action_id", foreignKey = @ForeignKey(name = "none", value = ConstraintMode.NO_CONSTRAINT)) - // ) - // private List actions; + // @OneToMany + // private List actions = new ArrayList<>(); } diff --git a/modules/core/src/main/java/com/bytedesk/core/rbac/authority/AuthorityController.java b/modules/core/src/main/java/com/bytedesk/core/rbac/authority/AuthorityController.java index 612633713e..1a0ff8849c 100644 --- a/modules/core/src/main/java/com/bytedesk/core/rbac/authority/AuthorityController.java +++ b/modules/core/src/main/java/com/bytedesk/core/rbac/authority/AuthorityController.java @@ -1,28 +1,9 @@ -/* - * bytedesk.com https://github.com/Bytedesk/bytedesk - * - * Copyright (C) 2013-2024 bytedesk.com - * - * License restrictions - * - * Please be aware of the BSL license restrictions before installing Bytedesk IM – - * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. - * 仅支持企业内部员工自用,严禁用于销售、二次销售或者部署SaaS方式销售 - * - * https://github.com/Bytedesk/bytedesk/blob/main/LICENSE - * - */ package com.bytedesk.core.rbac.authority; import lombok.AllArgsConstructor; -import java.util.List; - -import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; -import com.bytedesk.core.utils.JsonResult; - /** * 权限管理 */ @@ -32,38 +13,20 @@ import com.bytedesk.core.utils.JsonResult; @RequestMapping("/api/v1/authority") public class AuthorityController { - private final AuthorityService authorityService; - - /** - * 全部 - * - * @return json - */ - // @GetMapping("/list") - // public Callable> list() { - - // return () -> { - - // // 全部查询 - // List authorityDTOPage = authorityService.findByUser(); - - // return new JsonResult<>("获取全部权限成功", 200, authorityDTOPage); - // }; - // } + // private final AuthorityService authorityService; /** * 查询 * * @return json */ - @GetMapping("/query") - public ResponseEntity> query(AuthorityRequest authorityRequest) { + // @GetMapping("/query") + // public ResponseEntity> query(AuthorityRequest authorityRequest) { + // List authorityList = authorityService.findAll(); - List authorityList = authorityService.findAll(); - - return ResponseEntity.ok().body(new JsonResult<>("get authority success", 200, authorityList)); - } + // return ResponseEntity.ok().body(new JsonResult<>("get authority success", 200, authorityList)); + // } /** * 创建 diff --git a/modules/core/src/main/java/com/bytedesk/core/rbac/authority/AuthorityRepository.java b/modules/core/src/main/java/com/bytedesk/core/rbac/authority/AuthorityRepository.java index f482290bd2..e3804538af 100644 --- a/modules/core/src/main/java/com/bytedesk/core/rbac/authority/AuthorityRepository.java +++ b/modules/core/src/main/java/com/bytedesk/core/rbac/authority/AuthorityRepository.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-29 16:21:24 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-01-31 11:27:43 + * @LastEditTime: 2024-04-24 11:04:52 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk@ * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -31,13 +31,7 @@ import java.util.Optional; @Tag(name = "authoritys - 权限") public interface AuthorityRepository extends JpaRepository, JpaSpecificationExecutor { - // List findByUser(User user); - - // Page findByUser(User user, Pageable pageable); - - // Page findByNameContainingOrValueContainingAndUser(String name, - // String value, User user, - // Pageable pageable); + Optional findByAid(String aid); Optional findByValue(String value); diff --git a/modules/core/src/main/java/com/bytedesk/core/rbac/authority/AuthorityRequest.java b/modules/core/src/main/java/com/bytedesk/core/rbac/authority/AuthorityRequest.java index e2248d9fd6..0a0f602b8c 100644 --- a/modules/core/src/main/java/com/bytedesk/core/rbac/authority/AuthorityRequest.java +++ b/modules/core/src/main/java/com/bytedesk/core/rbac/authority/AuthorityRequest.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-29 16:21:24 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-03-29 14:02:47 + * @LastEditTime: 2024-04-24 10:41:37 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -14,14 +14,16 @@ */ package com.bytedesk.core.rbac.authority; +import lombok.Builder; import lombok.Data; import lombok.EqualsAndHashCode; - -import java.util.List; +import lombok.experimental.Accessors; import com.bytedesk.core.utils.BaseRequest; @Data +@Builder +@Accessors(chain = true) @EqualsAndHashCode(callSuper = true) public class AuthorityRequest extends BaseRequest { @@ -31,12 +33,10 @@ public class AuthorityRequest extends BaseRequest { private String value; - private int status; + // private int status; private String description; - private String type; - - private List actions; + // private List actions; } diff --git a/modules/core/src/main/java/com/bytedesk/core/rbac/authority/AuthorityResponse.java b/modules/core/src/main/java/com/bytedesk/core/rbac/authority/AuthorityResponse.java index d76d7f9898..13df5433dc 100644 --- a/modules/core/src/main/java/com/bytedesk/core/rbac/authority/AuthorityResponse.java +++ b/modules/core/src/main/java/com/bytedesk/core/rbac/authority/AuthorityResponse.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-29 16:21:24 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-03-29 14:02:57 + * @LastEditTime: 2024-04-24 11:19:54 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -17,9 +17,6 @@ package com.bytedesk.core.rbac.authority; import lombok.Data; import lombok.EqualsAndHashCode; -import java.util.List; - -import com.bytedesk.core.rbac.action.ActionResponse; import com.bytedesk.core.utils.BaseResponse; @Data @@ -32,12 +29,12 @@ public class AuthorityResponse extends BaseResponse { private String value; - private int status; + // private int status; private String description; private String type; - private List actions; + // private List actions; } diff --git a/modules/core/src/main/java/com/bytedesk/core/rbac/authority/AuthorityService.java b/modules/core/src/main/java/com/bytedesk/core/rbac/authority/AuthorityService.java index a3fd62e402..4e2a796d7b 100644 --- a/modules/core/src/main/java/com/bytedesk/core/rbac/authority/AuthorityService.java +++ b/modules/core/src/main/java/com/bytedesk/core/rbac/authority/AuthorityService.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-29 16:21:24 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-02-06 09:25:50 + * @LastEditTime: 2024-04-24 10:54:51 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -15,20 +15,77 @@ package com.bytedesk.core.rbac.authority; import lombok.AllArgsConstructor; + +import org.modelmapper.ModelMapper; +import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; -import java.util.List; +import com.bytedesk.core.constant.TypeConsts; +import com.bytedesk.core.uid.UidUtils; + +import java.util.Optional; @Service @AllArgsConstructor public class AuthorityService { - // private final ActionRepository actionRepository; - private final AuthorityRepository authorityRepository; - public List findAll() { - return authorityRepository.findAll(); + private final ModelMapper modelMapper; + + private final UidUtils uidUtils; + + public Authority create(AuthorityRequest authorityRequest) { + // + Authority authority = modelMapper.map(authorityRequest, Authority.class); + authority.setAid(uidUtils.getCacheSerialUid()); + + return save(authority); + } + + @Cacheable(value = "authority", key = "#aid", unless = "#result == null") + public Optional findByAid(String aid) { + return authorityRepository.findByAid(aid); + } + + @Cacheable(value = "authority", key = "#value", unless = "#result == null") + public Optional findByValue(String value) { + return authorityRepository.findByValue(value); + } + + public Authority save(Authority authority) { + return authorityRepository.save(authority); + } + + public void initData() { + + if (authorityRepository.count() > 0) { + return; + } + // + String[] authorities = { + TypeConsts.AUTHORITY_SUPER, + TypeConsts.AUTHORITY_ADMIN, + TypeConsts.AUTHORITY_HR, + TypeConsts.AUTHORITY_ORG, + TypeConsts.AUTHORITY_IT, + TypeConsts.AUTHORITY_MONEY, + TypeConsts.AUTHORITY_MARKETING, + TypeConsts.AUTHORITY_SALES, + TypeConsts.AUTHORITY_CUSTOMER_SERVICE, + }; + + for (String authority : authorities) { + AuthorityRequest authRequest = AuthorityRequest.builder() + .name(authority) + .value(authority) + .description(authority) + .build(); + authRequest.setType(TypeConsts.TYPE_SYSTEM); + // + create(authRequest); + } + } } diff --git a/modules/core/src/main/java/com/bytedesk/core/rbac/role/Role.java b/modules/core/src/main/java/com/bytedesk/core/rbac/role/Role.java index d6ba569f2a..f190cf880c 100755 --- a/modules/core/src/main/java/com/bytedesk/core/rbac/role/Role.java +++ b/modules/core/src/main/java/com/bytedesk/core/rbac/role/Role.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-29 16:21:24 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-03-29 18:12:28 + * @LastEditTime: 2024-04-24 11:06:52 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -14,21 +14,20 @@ */ package com.bytedesk.core.rbac.role; -import com.bytedesk.core.rbac.authority.Authority; -import com.bytedesk.core.rbac.user.User; -import com.fasterxml.jackson.annotation.JsonBackReference; -import com.fasterxml.jackson.annotation.JsonIgnore; - import jakarta.persistence.*; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; +import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; +import java.util.Set; +import java.util.HashSet; + +import com.bytedesk.core.rbac.authority.Authority; +import com.bytedesk.core.utils.AuditModel; +import com.fasterxml.jackson.annotation.JsonIgnore; /** * role table @@ -38,13 +37,14 @@ import java.util.List; @Data @Entity @Builder +@EqualsAndHashCode(callSuper=false) @Accessors(chain = true) @AllArgsConstructor @NoArgsConstructor @Table(name = "core_role") -public class Role implements Serializable { +public class Role extends AuditModel { - private static final long serialVersionUID = -2461905686314283608L; + private static final long serialVersionUID = -1470818087L; @Id @GeneratedValue(strategy = GenerationType.AUTO) @@ -53,47 +53,41 @@ public class Role implements Serializable { @Column(unique = true, nullable = false, length = 127) private String rid; - /** - * name - */ private String name; /** - * value + * value is a keyword in h2 db */ - @Column(unique = true, nullable = false) - private String value; + // @Column(name = "by_value", unique = true, nullable = false) + // private String value; - /** - * - */ private String description; - /** - * - */ @Column(name = "by_type") private String type; - /** - * - */ @JsonIgnore @Builder.Default - @OneToMany - private List authorities = new ArrayList<>(); - // @JsonIgnore - // @ManyToMany(cascade = CascadeType.DETACH, fetch = FetchType.LAZY) - // @JoinTable(name = "core_role_authorities", joinColumns = @JoinColumn(name = "role_id", foreignKey = @ForeignKey(name = "none", value = ConstraintMode.NO_CONSTRAINT)), inverseJoinColumns = @JoinColumn(name = "authority_id", foreignKey = @ForeignKey(name = "none", value = ConstraintMode.NO_CONSTRAINT))) - // private List authorities; + @ManyToMany + private Set authorities = new HashSet<>(); /** * 除系统自带角色之外, * 允许管理员-自己创建角色 */ - @JsonIgnore - @ManyToOne(fetch = FetchType.LAZY) - @JsonBackReference // 避免无限递归 - private User user; + // @JsonIgnore + // @ManyToOne(fetch = FetchType.LAZY) + // @JsonBackReference("user-roles") // 避免无限递归 + // private User user; + + private String orgOid; + + + public void addAuthority(Authority authority) { + this.authorities.add(authority); + } + public void removeAuthority(Authority authority) { + this.authorities.remove(authority); + } } diff --git a/modules/core/src/main/java/com/bytedesk/core/rbac/role/RoleController.java b/modules/core/src/main/java/com/bytedesk/core/rbac/role/RoleController.java index 93ee11e71d..300fff10a0 100644 --- a/modules/core/src/main/java/com/bytedesk/core/rbac/role/RoleController.java +++ b/modules/core/src/main/java/com/bytedesk/core/rbac/role/RoleController.java @@ -22,8 +22,6 @@ import org.springframework.data.domain.Page; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; -import com.bytedesk.core.auth.AuthService; -import com.bytedesk.core.rbac.user.User; import com.bytedesk.core.utils.JsonResult; /** @@ -37,7 +35,7 @@ public class RoleController { private final RoleService roleService; - private final AuthService authService; + // private final AuthService authService; /** * query my roles by page @@ -47,9 +45,7 @@ public class RoleController { @GetMapping("/query") public ResponseEntity> query(RoleRequest roleRequest) { - User user = authService.getCurrentUser(); - - Page rolePage = roleService.query(user, roleRequest); + Page rolePage = roleService.query(roleRequest); // return ResponseEntity.ok(JsonResult.success(rolePage)); } @@ -76,9 +72,7 @@ public class RoleController { */ // @PostMapping("/update") // public Callable> update(@RequestBody RoleParam roleParam) { - // return () -> { - // RoleDTO roleDTO = roleService.update(roleParam); // // // return new JsonResult<>("更新角色成功", 200, roleDTO); @@ -93,9 +87,7 @@ public class RoleController { */ // @PostMapping("/delete") // public Callable> delete(@RequestBody RoleParam roleParam) { - // return () -> { - // // // roleService.deleteById(roleParam.getId()); // return new JsonResult<>("删除角色成功", 200, roleParam.getId()); @@ -109,9 +101,7 @@ public class RoleController { */ // @GetMapping("/filter") // public Callable> filter(FilterParam filterParam) { - // return () -> { - // // // Page roleDTOPage = roleService.findByNameContainingOrValueContainingAndUser(filterParam); // // // return new JsonResult<>("搜索角色成功", 200, roleDTOPage); diff --git a/modules/core/src/main/java/com/bytedesk/core/rbac/role/RoleRepository.java b/modules/core/src/main/java/com/bytedesk/core/rbac/role/RoleRepository.java index 91f2d56a06..80be87eb7d 100644 --- a/modules/core/src/main/java/com/bytedesk/core/rbac/role/RoleRepository.java +++ b/modules/core/src/main/java/com/bytedesk/core/rbac/role/RoleRepository.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-29 16:21:24 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-03-29 15:46:34 + * @LastEditTime: 2024-04-24 10:14:30 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -22,8 +22,6 @@ import org.springframework.lang.NonNull; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; -import com.bytedesk.core.rbac.user.User; - import io.swagger.v3.oas.annotations.tags.Tag; import java.util.List; @@ -38,13 +36,14 @@ import java.util.Optional; @Tag(name = "roles - 角色") public interface RoleRepository extends JpaRepository, JpaSpecificationExecutor { - Optional findByValue(String value); + Optional findByName(String name); List findByType(String type); - Page findByUser(User user, Pageable pageable); + // Page findByUser(User user, Pageable pageable); + Page findByOrgOid(String orgOid, Pageable pageable); - Boolean existsByValue(String value); + Boolean existsByName(String name); @Transactional void deleteById(@NonNull Long id); diff --git a/modules/core/src/main/java/com/bytedesk/core/rbac/role/RoleRequest.java b/modules/core/src/main/java/com/bytedesk/core/rbac/role/RoleRequest.java index 8138c6e658..afad4d3c50 100644 --- a/modules/core/src/main/java/com/bytedesk/core/rbac/role/RoleRequest.java +++ b/modules/core/src/main/java/com/bytedesk/core/rbac/role/RoleRequest.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-29 16:21:24 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-03-29 14:00:05 + * @LastEditTime: 2024-04-24 11:10:01 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -14,14 +14,19 @@ */ package com.bytedesk.core.rbac.role; +import lombok.Builder; import lombok.Data; import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; +import java.util.HashSet; import java.util.Set; import com.bytedesk.core.utils.BaseRequest; @Data +@Builder +@Accessors(chain = true) @EqualsAndHashCode(callSuper = false) public class RoleRequest extends BaseRequest { @@ -29,12 +34,16 @@ public class RoleRequest extends BaseRequest { private String name; - private String value; + // private String value; private String description; - // private String type; + @Builder.Default + private Set authorityAids = new HashSet<>(); - private Set authorities; + // organization oid + private String orgOid; + + } diff --git a/modules/core/src/main/java/com/bytedesk/core/rbac/role/RoleResponse.java b/modules/core/src/main/java/com/bytedesk/core/rbac/role/RoleResponse.java index c0171847ba..faf0289e12 100644 --- a/modules/core/src/main/java/com/bytedesk/core/rbac/role/RoleResponse.java +++ b/modules/core/src/main/java/com/bytedesk/core/rbac/role/RoleResponse.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-29 16:21:24 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-04-02 14:45:38 + * @LastEditTime: 2024-04-24 11:16:29 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -21,7 +21,8 @@ import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; -import java.util.List; +import java.util.HashSet; +import java.util.Set; import com.bytedesk.core.rbac.authority.AuthorityResponse; import com.bytedesk.core.utils.BaseResponse; @@ -37,11 +38,13 @@ import com.bytedesk.core.utils.BaseResponse; @EqualsAndHashCode(callSuper = true) public class RoleResponse extends BaseResponse { + private static final long serialVersionUID = 4082434575L; + private String rid; private String name; - private String value; + // private String value; private String description; @@ -51,6 +54,7 @@ public class RoleResponse extends BaseResponse { */ private String type; - private List authorities; + @Builder.Default + private Set authorities = new HashSet<>(); } diff --git a/modules/core/src/main/java/com/bytedesk/core/rbac/role/RoleService.java b/modules/core/src/main/java/com/bytedesk/core/rbac/role/RoleService.java index 11d83e3c52..549fdc96be 100644 --- a/modules/core/src/main/java/com/bytedesk/core/rbac/role/RoleService.java +++ b/modules/core/src/main/java/com/bytedesk/core/rbac/role/RoleService.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-29 16:21:24 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-04-02 11:07:32 + * @LastEditTime: 2024-04-27 12:55:37 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -15,8 +15,12 @@ package com.bytedesk.core.rbac.role; import lombok.AllArgsConstructor; -import lombok.extern.slf4j.Slf4j; +// import lombok.extern.slf4j.Slf4j; +import org.modelmapper.ModelMapper; +import org.springframework.cache.annotation.CachePut; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.cache.annotation.Caching; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; @@ -25,16 +29,19 @@ import org.springframework.stereotype.Service; import com.bytedesk.core.config.BytedeskProperties; import com.bytedesk.core.constant.TypeConsts; +import com.bytedesk.core.rbac.authority.Authority; +import com.bytedesk.core.rbac.authority.AuthorityService; import com.bytedesk.core.rbac.user.User; import com.bytedesk.core.rbac.user.UserRepository; +import com.bytedesk.core.uid.UidUtils; import com.bytedesk.core.utils.BdConvertUtils; -import com.bytedesk.core.utils.Utils; import java.util.Arrays; +import java.util.Iterator; import java.util.Optional; @AllArgsConstructor -@Slf4j +// @Slf4j @Service public class RoleService { @@ -44,97 +51,119 @@ public class RoleService { private final BytedeskProperties properties; - public Page query(User user, RoleRequest roleRequest) { - - Pageable pageable = PageRequest.of(roleRequest.getPageNumber(), roleRequest.getPageSize(), Sort.Direction.DESC, + private final ModelMapper modelMapper; + + private final UidUtils uidUtils; + + private final AuthorityService authorityService; + + public Role create(RoleRequest rolerRequest) { + + if (existsByName(rolerRequest.getName())) { + throw new RuntimeException("角色已存在"); + } + + Role role = modelMapper.map(rolerRequest, Role.class); + role.setRid(uidUtils.getCacheSerialUid()); + // + Iterator iterator = rolerRequest.getAuthorityAids().iterator(); + while (iterator.hasNext()) { + String authorityAid = iterator.next(); + Optional authorityOptional = authorityService.findByAid(authorityAid); + if (authorityOptional.isPresent()) { + role.addAuthority(authorityOptional.get()); + } + } + // + return save(role); + } + + public Page query(RoleRequest roleRequest) { + + Pageable pageable = PageRequest.of(roleRequest.getPageNumber(), roleRequest.getPageSize(), + Sort.Direction.DESC, "id"); - - Page rolePage = roleRepository.findByUser(user, pageable); + + Page rolePage = roleRepository.findByOrgOid(roleRequest.getOrgOid(), pageable); return rolePage.map(BdConvertUtils::convertToRoleResponse); } - - public Optional findByValue(String value) { - return roleRepository.findByValue(value); + + @Cacheable(value = "roleExists", key = "#name", unless="#result == null") + public Boolean existsByName(String namString) { + return roleRepository.existsByName(namString); } - private static Role[] roles = new Role[] { - Role.builder().rid(Utils.getUid()).name( - TypeConsts.ROLE_ADMIN).value( - TypeConsts.ROLE_ADMIN) - .description( - TypeConsts.ROLE_ADMIN) - .type(TypeConsts.TYPE_SYSTEM).build(), - Role.builder().rid(Utils.getUid()).name( - TypeConsts.ROLE_ORG).value( - TypeConsts.ROLE_ORG) - .description( - TypeConsts.ROLE_ORG) - .type(TypeConsts.TYPE_SYSTEM).build(), - Role.builder().rid(Utils.getUid()).name( - TypeConsts.ROLE_IT).value( - TypeConsts.ROLE_IT) - .description( - TypeConsts.ROLE_ADMIN) - .type(TypeConsts.TYPE_SYSTEM).build(), - Role.builder().rid(Utils.getUid()).name( - TypeConsts.ROLE_MONEY).value( - TypeConsts.ROLE_MONEY) - .description( - TypeConsts.ROLE_MONEY) - .type(TypeConsts.TYPE_SYSTEM).build(), - Role.builder().rid(Utils.getUid()).name( - TypeConsts.ROLE_HR).value( - TypeConsts.ROLE_HR) - .description( - TypeConsts.ROLE_HR) - .type(TypeConsts.TYPE_SYSTEM).build(), - Role.builder().rid(Utils.getUid()).name( - TypeConsts.ROLE_MARKETING).value( - TypeConsts.ROLE_MARKETING) - .description( - TypeConsts.ROLE_MARKETING) - .type(TypeConsts.TYPE_SYSTEM).build(), - Role.builder().rid(Utils.getUid()).name( - TypeConsts.ROLE_SALES).value( - TypeConsts.ROLE_SALES) - .description(TypeConsts.ROLE_SALES).type(TypeConsts.TYPE_SYSTEM) - .build(), - Role.builder().rid(Utils.getUid()).name( - TypeConsts.ROLE_CUSTOMER_SERVICE).value( - TypeConsts.ROLE_CUSTOMER_SERVICE) - .description(TypeConsts.ROLE_CUSTOMER_SERVICE) - .type(TypeConsts.TYPE_SYSTEM).build(), + @Cacheable(value = "role", key = "#name", unless="#result == null") + public Optional findByName(String name) { + return roleRepository.findByName(name); + } + @Caching(put = { + @CachePut(value = "role", key = "#role.name"), + // TODO: 此处put的exists内容跟缓存时内容类型是否一致? + // @CachePut(value = "roleExists", key = "#role.name") + }) + public Role save(Role role) { + return roleRepository.save(role); + } + + // + // private static final String [] roles = { + // TypeConsts.ROLE_ADMIN, + // TypeConsts.ROLE_ORG, + // TypeConsts.ROLE_IT, + // TypeConsts.ROLE_MONEY, + // TypeConsts.ROLE_HR, + // TypeConsts.ROLE_MARKETING, + // TypeConsts.ROLE_SALES, + // TypeConsts.ROLE_CUSTOMER_SERVICE, + // }; + // + private static final String[] authorities = { + TypeConsts.AUTHORITY_SUPER, + TypeConsts.AUTHORITY_ADMIN, + TypeConsts.AUTHORITY_HR, + TypeConsts.AUTHORITY_ORG, + TypeConsts.AUTHORITY_IT, + TypeConsts.AUTHORITY_MONEY, + TypeConsts.AUTHORITY_MARKETING, + TypeConsts.AUTHORITY_SALES, + TypeConsts.AUTHORITY_CUSTOMER_SERVICE, }; public void initData() { if (roleRepository.count() > 0) { - log.debug("role already exists"); + // log.debug("role already exists"); return; } // - Arrays.stream(roles).forEach((role) -> { - if (!roleRepository.existsByValue(role.getValue())) { - roleRepository.save(role); + for (String authority : authorities) { + String role = TypeConsts.ROLE_ + authority; + RoleRequest roleRequest = RoleRequest.builder().name(role).description(role).build(); + roleRequest.setType(TypeConsts.TYPE_SYSTEM); + // + Optional authorityOptional = authorityService.findByValue(authority); + if (authorityOptional.isPresent()) { + roleRequest.getAuthorityAids().add(authorityOptional.get().getAid()); } - }); + // + create(roleRequest); + } } - @SuppressWarnings("null") public void updateInitData() { - - // Optional adminOptional = userRepository.findByEmail(properties.getEmail()); if (adminOptional.isPresent()) { // - Arrays.stream(roles).forEach((role) -> { - Optional roleOptional = roleRepository.findByValue(role.getValue()); - if (roleOptional.isPresent()) { - roleOptional.get().setUser(adminOptional.get()); - roleRepository.save(roleOptional.get()); - } + Arrays.stream(authorities).forEach((authority) -> { + String roleName = TypeConsts.ROLE_ + authority; + Optional roleOptional = findByName(roleName); + roleOptional.ifPresent(role -> { + role.setOrgOid(adminOptional.get().getOrgOid()); + roleRepository.save(role); + }); }); } diff --git a/modules/core/src/main/java/com/bytedesk/core/rbac/user/User.java b/modules/core/src/main/java/com/bytedesk/core/rbac/user/User.java index 9dcd0a6346..6c294931d6 100644 --- a/modules/core/src/main/java/com/bytedesk/core/rbac/user/User.java +++ b/modules/core/src/main/java/com/bytedesk/core/rbac/user/User.java @@ -1,27 +1,26 @@ package com.bytedesk.core.rbac.user; -import java.util.ArrayList; -import java.util.List; +import java.util.HashSet; +import java.util.Set; import com.bytedesk.core.constant.AvatarConsts; import com.bytedesk.core.constant.BdConstants; import com.bytedesk.core.rbac.role.Role; import com.bytedesk.core.utils.AuditModel; -import com.bytedesk.core.utils.StringListConverter; +import com.bytedesk.core.utils.StringSetConverter; import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonManagedReference; - import jakarta.persistence.Column; import jakarta.persistence.Convert; import jakarta.persistence.Entity; +import jakarta.persistence.EntityListeners; import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; -import jakarta.persistence.OneToMany; +import jakarta.persistence.ManyToMany; import jakarta.persistence.Table; -import jakarta.persistence.UniqueConstraint; -import jakarta.validation.constraints.Digits; +// import jakarta.persistence.UniqueConstraint; +// import jakarta.validation.constraints.Digits; import jakarta.validation.constraints.Email; import lombok.AllArgsConstructor; import lombok.Builder; @@ -37,45 +36,41 @@ import lombok.experimental.Accessors; @EqualsAndHashCode(callSuper = true) @AllArgsConstructor @NoArgsConstructor +@EntityListeners({ UserListener.class }) @Table(name = "core_user", uniqueConstraints = { - @UniqueConstraint(columnNames = "username"), - @UniqueConstraint(columnNames = "email") + // @UniqueConstraint(columnNames = "username"), + // @UniqueConstraint(columnNames = "email") }) public class User extends AuditModel { + private static final long serialVersionUID = 3817197261L; + @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; - /** - * uuid - */ - @Column(name = "uuid", unique = true, nullable = false, length = 127) + @Column(name = "uuid", unique = true, nullable = false) private String uid; - /** - * - */ @Column(unique = true) private String num; - /** - * - */ + // used in authjwtToken, should not be null @Column(unique = true, nullable = false) private String username; private String nickname; @JsonIgnore - @Column(nullable = false) private String password; @Email(message = "email format error") @Column(unique = true) private String email; - @Digits(message = "phone length error", fraction = 0, integer = 11) + // TODO: including country + // @Digits(message = "phone length error", fraction = 0, integer = 11) + @Column(unique = true) private String mobile; @Builder.Default @@ -84,22 +79,14 @@ public class User extends AuditModel { @Builder.Default private String description = BdConstants.DEFAULT_USER_DESCRIPTION; - /** - * - */ @Builder.Default @Column(name = "is_enabled") private boolean enabled = true; - /** - */ @Builder.Default @Column(name = "is_super") private boolean superUser = false; - /** - * - */ @Builder.Default @Column(name = "is_email_verified") private boolean emailVerified = false; @@ -108,19 +95,32 @@ public class User extends AuditModel { @Column(name = "is_mobile_verified") private boolean mobileVerified = false; - /** - * - */ @Builder.Default - @OneToMany(fetch = FetchType.EAGER) - @JsonManagedReference // 避免无限递归 - private List roles = new ArrayList<>(); + @ManyToMany(fetch = FetchType.EAGER) + private Set roles = new HashSet<>(); - /** - * - */ @Builder.Default - @Convert(converter = StringListConverter.class) - private List organizations = new ArrayList<>(); + @Convert(converter = StringSetConverter.class) + private Set organizations = new HashSet<>(); + // return the first organization oid + public String getOrgOid() { + return this.organizations.isEmpty() ? null : this.organizations.iterator().next(); + } + + /** */ + public void addRole(Role role) { + if (!this.roles.contains(role)) { + this.roles.add(role); + // role.getUsers().add(this); + } + } + + public void removeRole(Role role) { + if (this.roles.contains(role)) { + this.roles.remove(role); + // role.getUsers().remove(this); + } + } + } \ No newline at end of file diff --git a/modules/core/src/main/java/com/bytedesk/core/rbac/user/UserAspect.java b/modules/core/src/main/java/com/bytedesk/core/rbac/user/UserAspect.java new file mode 100644 index 0000000000..f313212661 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/rbac/user/UserAspect.java @@ -0,0 +1,49 @@ +/* + * @Visitoror: jackning 270580156@qq.com + * @Date: 2024-04-05 14:51:45 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-18 12:21:15 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.rbac.user; + +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.stereotype.Component; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Aspect +@Component +public class UserAspect { + + @Pointcut("execution(* com.bytedesk.core.rbac.user.UserService.save(..))") + public void userSave() {} + + @Before("userSave()") + public void beforeUserSave(JoinPoint joinPoint) { + //类名 + String clazzName = joinPoint.getTarget().getClass().getName(); + MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); + //方法名 + String methodName = methodSignature.getName(); + //参数名数组 + String[] parameters = methodSignature.getParameterNames(); + //参数值: FIXME: user/role toString 循环引用栈溢出 + // Object[] args = joinPoint.getArgs(); + log.info("beforeUserSave {}, {}, {}, {}", clazzName, methodName, parameters); + + } + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/rbac/user/UserController.java b/modules/core/src/main/java/com/bytedesk/core/rbac/user/UserController.java index a840cf5577..0d5d5e326c 100644 --- a/modules/core/src/main/java/com/bytedesk/core/rbac/user/UserController.java +++ b/modules/core/src/main/java/com/bytedesk/core/rbac/user/UserController.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-29 16:21:24 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-04-02 11:01:20 + * @LastEditTime: 2024-04-25 22:46:49 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -14,11 +14,11 @@ */ package com.bytedesk.core.rbac.user; -import org.modelmapper.ModelMapper; import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; -import com.bytedesk.core.auth.AuthService; +import com.bytedesk.core.rbac.auth.AuthService; import com.bytedesk.core.utils.JsonResult; import lombok.AllArgsConstructor; @@ -35,8 +35,6 @@ public class UserController { private final AuthService authService; - private final ModelMapper modelMapper; - /** * get user info * @@ -44,16 +42,12 @@ public class UserController { */ @GetMapping("/profile") public ResponseEntity getProfile() { - try { - // - User user = authService.getCurrentUser(); + // + User user = authService.getCurrentUser(); - UserResponse userResponse = modelMapper.map(user, UserResponse.class); + UserResponse userResponse = userService.convertToUserResponse(user); - return ResponseEntity.ok(JsonResult.success(userResponse)); - } catch (Exception e) { - throw new RuntimeException(e); - } + return ResponseEntity.ok(JsonResult.success(userResponse)); } /** @@ -64,56 +58,35 @@ public class UserController { */ @PostMapping("/update") public ResponseEntity update(@RequestBody UserRequest userRequest) { - try { - User user = authService.getCurrentUser(); + UserResponse userResponse = userService.update(userRequest); - UserResponse userResponse = userService.update(userRequest, user); - - return ResponseEntity.ok().body(new JsonResult<>("update user success", 200, userResponse)); - - } catch (Exception e) { - throw new RuntimeException(e); - } + return ResponseEntity.ok(JsonResult.success(userResponse)); } - /** - * - * @return - */ + /** */ @PostMapping("/logout") public ResponseEntity logout() { - try { - return ResponseEntity.ok().body("logout"); - } catch (Exception e) { - throw new RuntimeException(e); - } + // TODO: 清理token,使其过期 + return ResponseEntity.ok().body("logout"); + } + + /** for testing,client will return 403, if dont have authority/role */ + @PreAuthorize("hasAnyAuthority('ROLE_SUPER', 'ROLE_ADMIN')") + // @PreAuthorize("hasAuthority('ROLE_SUPER') or hasAuthority('ROLE_ADMIN')") + // @PreAuthorize("hasAuthority('ROLE_SUPER')") + @GetMapping("/test/super") + public ResponseEntity testSuperAuthority() { + return ResponseEntity.ok("you have super authority"); } - // @PreAuthorize("hasAuthority('ROLE_ADMIN')") - // @GetMapping("/test") - // public String test() { - // try { - // return "Welcome"; - // } catch (Exception e) { - // throw new RuntimeException(e); - // } - // } - - // @GetMapping("/me") - // @PreAuthorize("isAuthenticated()") - // public ResponseEntity authenticatedUser() { - // Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); - // User currentUser = (User) authentication.getPrincipal(); - // return ResponseEntity.ok(currentUser); - // } - - // @GetMapping - // @PreAuthorize("hasAnyRole('ADMIN', 'SUPER_ADMIN')") - // public ResponseEntity> allUsers() { - // // List users = userService.allUsers(); - // return ResponseEntity.ok(null); - // } + /** no need to add ROLE_ prefix, system will auto add */ + @GetMapping(value = "/test/cs") + @PreAuthorize("hasAnyRole('ADMIN', 'SUPER', 'CS')") + // @PreAuthorize("hasRole('CS')") + public ResponseEntity testCsRole() { + return ResponseEntity.ok("you have admin or cs role"); + } } diff --git a/modules/core/src/main/java/com/bytedesk/core/rbac/user/UserDetailsImpl.java b/modules/core/src/main/java/com/bytedesk/core/rbac/user/UserDetailsImpl.java index acebd6a36f..bdb4d0ecb1 100644 --- a/modules/core/src/main/java/com/bytedesk/core/rbac/user/UserDetailsImpl.java +++ b/modules/core/src/main/java/com/bytedesk/core/rbac/user/UserDetailsImpl.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-23 07:53:01 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-02-06 14:34:53 + * @LastEditTime: 2024-04-24 10:13:18 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -18,13 +18,14 @@ import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; +import com.bytedesk.core.constant.TypeConsts; import com.bytedesk.core.rbac.role.Role; import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Data; import java.util.Collection; -import java.util.List; +import java.util.Set; import java.util.stream.Collectors; @Data @@ -40,14 +41,16 @@ public class UserDetailsImpl implements UserDetails { private String description; @JsonIgnore private String password; - private List roles; - private List organizations; + private Set roles; + private Set organizations; + // + private boolean enabled; Collection authorities; - public UserDetailsImpl(Long id, String uid, String username, String nickname, String avatar, String mobile, + private UserDetailsImpl(Long id, String uid, String username, String nickname, String avatar, String mobile, String email, String password, - Collection authorities, List roles, List organizations, - String description) { + Collection authorities, Set roles, Set organizations, + String description, boolean enabled) { this.id = id; this.uid = uid; this.username = username; @@ -60,13 +63,19 @@ public class UserDetailsImpl implements UserDetails { this.roles = roles; this.organizations = organizations; this.description = description; + this.enabled = enabled; } // public static UserDetailsImpl build(User user) { - List authorities = user.getRoles().stream() - .map(role -> new SimpleGrantedAuthority(role.getValue())) - .collect(Collectors.toList()); + // + // Set authorities = user.getRoles().stream() + // .map(role -> new SimpleGrantedAuthority(role.getValue())) + // .collect(Collectors.toSet()); + Set authorities = user.getRoles().stream() + .flatMap(role -> role.getAuthorities().stream() + .map(authority -> new SimpleGrantedAuthority(TypeConsts.ROLE_ + authority.getValue()))) + .collect(Collectors.toSet()); return new UserDetailsImpl(user.getId(), user.getUid(), @@ -79,7 +88,8 @@ public class UserDetailsImpl implements UserDetails { authorities, user.getRoles(), user.getOrganizations(), - user.getDescription()); + user.getDescription(), + user.isEnabled()); } @Override @@ -99,21 +109,25 @@ public class UserDetailsImpl implements UserDetails { @Override public boolean isAccountNonExpired() { - return true; + // return true; + return enabled; } @Override public boolean isAccountNonLocked() { - return true; + // return true; + return enabled; } @Override public boolean isCredentialsNonExpired() { - return true; + // return true; + return enabled; } @Override public boolean isEnabled() { - return true; + // return true; + return enabled; } } diff --git a/modules/core/src/main/java/com/bytedesk/core/rbac/user/UserDetailsServiceImpl.java b/modules/core/src/main/java/com/bytedesk/core/rbac/user/UserDetailsServiceImpl.java index 7e0b773eb5..9e1dd076d6 100644 --- a/modules/core/src/main/java/com/bytedesk/core/rbac/user/UserDetailsServiceImpl.java +++ b/modules/core/src/main/java/com/bytedesk/core/rbac/user/UserDetailsServiceImpl.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-23 07:53:01 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-03-27 22:14:36 + * @LastEditTime: 2024-04-26 11:34:30 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -22,9 +22,9 @@ import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; -import com.bytedesk.core.utils.exception.EmailNotFoundException; -import com.bytedesk.core.utils.exception.ForbiddenException; -import com.bytedesk.core.utils.exception.MobileNotFoundException; +import com.bytedesk.core.exception.EmailNotFoundException; +import com.bytedesk.core.exception.MobileNotFoundException; +import com.bytedesk.core.exception.UserDisabledException; import lombok.extern.slf4j.Slf4j; @@ -47,7 +47,7 @@ public class UserDetailsServiceImpl implements UserDetailsService { throw new UsernameNotFoundException("username " + username + " is not found"); } if (!userOptional.get().isEnabled()) { - throw new ForbiddenException("username " + username + " is not enabled"); + throw new UserDisabledException("username " + username + " is not enabled"); } return UserDetailsImpl.build(userOptional.get()); } @@ -60,7 +60,7 @@ public class UserDetailsServiceImpl implements UserDetailsService { throw new EmailNotFoundException("email " + email + " is not found"); } if (!userOptional.get().isEnabled()) { - throw new ForbiddenException("email " + email + " is not enabled"); + throw new UserDisabledException("email " + email + " is not enabled"); } return UserDetailsImpl.build(userOptional.get()); } @@ -73,7 +73,7 @@ public class UserDetailsServiceImpl implements UserDetailsService { throw new MobileNotFoundException("mobile " + mobile + " is not found"); } if (!userOptional.get().isEnabled()) { - throw new ForbiddenException("mobile " + mobile + " is not enabled"); + throw new UserDisabledException("mobile " + mobile + " is not enabled"); } return UserDetailsImpl.build(userOptional.get()); } diff --git a/modules/core/src/main/java/com/bytedesk/core/rbac/user/UserListener.java b/modules/core/src/main/java/com/bytedesk/core/rbac/user/UserListener.java new file mode 100644 index 0000000000..f5eab557c6 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/rbac/user/UserListener.java @@ -0,0 +1,63 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-15 09:30:09 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-23 09:00:16 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.rbac.user; + +import org.springframework.stereotype.Component; + +import com.bytedesk.core.topic.TopicService; +import com.bytedesk.core.utils.ApplicationContextHolder; + +import jakarta.persistence.PostPersist; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Component +public class UserListener { + + // 无法注入bean,否则报错 + // private static TopicService topicService; + + @PostPersist + public void postPersist(User user) { + log.info("user postPersist {}", user.getUid()); + // 这里可以记录日志、发送通知等 + // create user topic + TopicService topicService = ApplicationContextHolder.getBean(TopicService.class); + // + topicService.create(user.getUid(), user.getUid()); + } + + // @PreUpdate + // public void preUpdate(User user) { + // log.info("preUpdate {}", user.getUid()); + // } + + // @PostUpdate + // public void postUpdate(User user) { + // log.info("postUpdate {}", user.getUid()); + // } + + // @PreRemove + // public void preRemove(User user) { + // log.info("preRemove {}", user.getUid()); + // } + + // @PostRemove + // public void postRemove(User user) { + // log.info("postRemove {}", user.getUid()); + // // topicService.deleteByTopicAndUid(user.getUid(), user.getUid()); + // } + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/rbac/user/UserRepository.java b/modules/core/src/main/java/com/bytedesk/core/rbac/user/UserRepository.java index e6c28e1369..0dac7f688b 100644 --- a/modules/core/src/main/java/com/bytedesk/core/rbac/user/UserRepository.java +++ b/modules/core/src/main/java/com/bytedesk/core/rbac/user/UserRepository.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-29 16:21:24 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-03-27 22:11:38 + * @LastEditTime: 2024-04-26 21:10:25 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -32,19 +32,14 @@ import org.springframework.stereotype.Repository; @Repository public interface UserRepository extends JpaRepository { - // @Cacheable(cacheNames = "users") Optional findByEmail(String email); - // @Cacheable(cacheNames = "users") Optional findByMobile(String mobile); - // @Cacheable(cacheNames = "users") Optional findByUsername(String username); - // @Cacheable(cacheNames = "users") Optional findByUid(String uid); - // Boolean existsByUsernameAndDeleted(String username, Boolean deleted); Boolean existsByMobileAndDeleted(String mobile, Boolean deleted); diff --git a/modules/core/src/main/java/com/bytedesk/core/rbac/user/UserRequest.java b/modules/core/src/main/java/com/bytedesk/core/rbac/user/UserRequest.java index c134b2463f..5e301404df 100644 --- a/modules/core/src/main/java/com/bytedesk/core/rbac/user/UserRequest.java +++ b/modules/core/src/main/java/com/bytedesk/core/rbac/user/UserRequest.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-29 16:21:24 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-04-01 15:58:57 + * @LastEditTime: 2024-04-26 10:53:19 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -14,14 +14,22 @@ */ package com.bytedesk.core.rbac.user; +import com.bytedesk.core.constant.AvatarConsts; +import com.bytedesk.core.constant.BdConstants; import com.bytedesk.core.utils.BaseRequest; -import jakarta.validation.constraints.Digits; +// import jakarta.validation.constraints.Digits; import jakarta.validation.constraints.Email; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; @Data +@Builder @EqualsAndHashCode(callSuper = false) +@NoArgsConstructor +@AllArgsConstructor public class UserRequest extends BaseRequest { private Long id; @@ -39,17 +47,23 @@ public class UserRequest extends BaseRequest { @Email(message = "email format error") private String email; - @Digits(message = "phone length error", fraction = 0, integer = 11) + // country prefix, e.g. +86 + // @Digits(message = "phone length error", fraction = 0, integer = 11) private String mobile; + private String code; - private String avatar; + @Builder.Default + private String avatar = AvatarConsts.DEFAULT_AVATAR_URL; - private String description; + @Builder.Default + private String description = BdConstants.DEFAULT_USER_DESCRIPTION; - private boolean enabled; + private Boolean enabled; + + // private boolean superUser; - private boolean superUser; + private Boolean emailVerified; - private boolean verified; + private Boolean mobileVerified; } diff --git a/modules/core/src/main/java/com/bytedesk/core/rbac/user/UserResponse.java b/modules/core/src/main/java/com/bytedesk/core/rbac/user/UserResponse.java index 59032d4368..113362f951 100644 --- a/modules/core/src/main/java/com/bytedesk/core/rbac/user/UserResponse.java +++ b/modules/core/src/main/java/com/bytedesk/core/rbac/user/UserResponse.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-29 16:21:24 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-04-02 14:46:03 + * @LastEditTime: 2024-04-25 22:52:53 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -21,10 +21,8 @@ import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; -// import java.util.Collection; -import java.util.List; - -// import org.springframework.security.core.GrantedAuthority; +import java.util.HashSet; +import java.util.Set; import com.bytedesk.core.rbac.role.RoleResponse; import com.bytedesk.core.utils.BaseResponse; @@ -37,6 +35,8 @@ import com.bytedesk.core.utils.BaseResponse; @EqualsAndHashCode(callSuper = true) public class UserResponse extends BaseResponse { + private static final long serialVersionUID = -2015147462L; + private String uid; private String username; private String nickname; @@ -44,7 +44,15 @@ public class UserResponse extends BaseResponse { private String mobile; private String avatar; private String description; + // + private Boolean enabled; + private boolean superUser; + private Boolean emailVerified; + private Boolean mobileVerified; // - private List roles; - private List organizations; + @Builder.Default + private Set roles = new HashSet<>(); + + @Builder.Default + private Set organizations = new HashSet<>(); } diff --git a/modules/core/src/main/java/com/bytedesk/core/rbac/user/UserResponseSimple.java b/modules/core/src/main/java/com/bytedesk/core/rbac/user/UserResponseSimple.java index 3eb905ed63..636b4f8e38 100644 --- a/modules/core/src/main/java/com/bytedesk/core/rbac/user/UserResponseSimple.java +++ b/modules/core/src/main/java/com/bytedesk/core/rbac/user/UserResponseSimple.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-29 16:21:24 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-04-02 14:46:40 + * @LastEditTime: 2024-04-16 17:04:38 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -31,11 +31,9 @@ import lombok.experimental.Accessors; @EqualsAndHashCode(callSuper = true) public class UserResponseSimple extends BaseResponse { + private static final long serialVersionUID = 4684010695L; + private String uid; private String nickname; - private String email; - private String mobile; private String avatar; - private String description; - } diff --git a/modules/core/src/main/java/com/bytedesk/core/rbac/user/UserService.java b/modules/core/src/main/java/com/bytedesk/core/rbac/user/UserService.java index 1c5784e216..9b725406f0 100644 --- a/modules/core/src/main/java/com/bytedesk/core/rbac/user/UserService.java +++ b/modules/core/src/main/java/com/bytedesk/core/rbac/user/UserService.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-29 16:21:24 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-04-02 16:32:26 + * @LastEditTime: 2024-04-27 12:24:01 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -15,34 +15,40 @@ package com.bytedesk.core.rbac.user; import java.util.Optional; +import java.util.Set; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.CachePut; import org.springframework.cache.annotation.Cacheable; -// import org.springframework.cache.annotation.Cacheable; import org.springframework.cache.annotation.Caching; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; import org.springframework.lang.NonNull; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; -// import com.bytedesk.core.auth.AuthService; import com.bytedesk.core.config.BytedeskProperties; import com.bytedesk.core.constant.AvatarConsts; import com.bytedesk.core.constant.TypeConsts; +import com.bytedesk.core.exception.EmailExistsException; +import com.bytedesk.core.exception.MobileExistsException; +import com.bytedesk.core.exception.NotFoundException; import com.bytedesk.core.rbac.role.Role; import com.bytedesk.core.rbac.role.RoleService; -import com.bytedesk.core.utils.Utils; +import com.bytedesk.core.uid.UidUtils; import lombok.AllArgsConstructor; -import lombok.extern.slf4j.Slf4j; +// import lombok.extern.slf4j.Slf4j; import org.modelmapper.ModelMapper; -import java.util.ArrayList; -import java.util.List; +import java.util.HashSet; -@Slf4j +// @Slf4j @Service @AllArgsConstructor public class UserService { @@ -60,38 +66,117 @@ public class UserService { private final BCryptPasswordEncoder passwordEncoder; + private final UidUtils uidUtils; + + public Page query(UserRequest userRequest) { + + Pageable pageable = PageRequest.of(userRequest.getPageNumber(), userRequest.getPageSize(), Sort.Direction.ASC, + "updatedAt"); + + return userRepository.findAll(pageable); + } + + @Transactional public UserResponse register(UserRequest userRequest) { - if (userRequest.getUsername() == null) { - throw new RuntimeException("Parameter username is not found in request..!!"); - } else if (userRequest.getPassword() == null) { - throw new RuntimeException("Parameter password is not found in request..!!"); + + if (existsByEmail(userRequest.getEmail())) { + throw new EmailExistsException("Email already exists..!!"); + } + if (existsByMobile(userRequest.getMobile())) { + throw new MobileExistsException("Mobile already exists..!!"); } - String rawPassword = userRequest.getPassword(); - String encodedPassword = passwordEncoder.encode(rawPassword); // User user = modelMapper.map(userRequest, User.class); - user.setPassword(encodedPassword); - // - User savedUser = userRepository.save(user); + user.setUid(uidUtils.getCacheSerialUid()); // - return modelMapper.map(savedUser, UserResponse.class); - } - - public UserResponse update(UserRequest userRequest, User user) { - + if (StringUtils.hasLength(userRequest.getNickname())) { + user.setNickname(userRequest.getNickname()); + } else { + user.setNickname(createNickname()); + } + // + if (StringUtils.hasLength(userRequest.getAvatar())) { + user.setAvatar(userRequest.getAvatar()); + } else { + user.setAvatar(AvatarConsts.DEFAULT_AVATAR_URL); + } + // + if (StringUtils.hasLength(userRequest.getPassword())) { + String rawPassword = userRequest.getPassword(); + String encodedPassword = passwordEncoder.encode(rawPassword); + user.setPassword(encodedPassword); + } + // 只有经过验证的邮箱,才真正执行注册 + if (StringUtils.hasLength(userRequest.getEmail())) { + user.setUsername(userRequest.getEmail()); + user.setNum(userRequest.getEmail()); + user.setEmailVerified(true); + user.setEnabled(true); + } + // 只有经过验证的手机号,才真正执行注册 + if (StringUtils.hasLength(userRequest.getMobile())) { + user.setNum(userRequest.getMobile()); + user.setMobileVerified(true); + user.setEnabled(true); + } + // TODO: 设置角色role + // - - return null; + // + return convertToUserResponse(save(user)); } - // + @Transactional + public UserResponse update(UserRequest userRequest) { + + Optional userOptional = findByUid(userRequest.getUid()); + if (userOptional.isPresent()) { + User user = userOptional.get(); + + if (StringUtils.hasLength(userRequest.getNickname())) { + user.setNickname(userRequest.getNickname()); + } + + if (StringUtils.hasLength(userRequest.getAvatar())) { + user.setAvatar(userRequest.getAvatar()); + } + + if (StringUtils.hasLength(userRequest.getPassword())) { + String rawPassword = userRequest.getPassword(); + String encodedPassword = passwordEncoder.encode(rawPassword); + user.setPassword(encodedPassword); + } + + if (StringUtils.hasLength(userRequest.getEmail())) { + user.setEmail(userRequest.getEmail()); + } + + if (StringUtils.hasLength(userRequest.getMobile())) { + user.setMobile(userRequest.getMobile()); + } + + if(StringUtils.hasLength(userRequest.getDescription())) { + user.setDescription(userRequest.getDescription()); + } + + // TODO: 设置角色role + + return convertToUserResponse(save(user)); + + } else { + throw new NotFoundException("User not found..!!"); + } + } + + @Transactional public User createUser(String nickname, String avatar, String password, String mobile, String email, boolean isVerified, - String organization_oid) { + String orgOid) { User user = User.builder() - .uid(Utils.getUid()) + .uid(uidUtils.getCacheSerialUid()) .avatar(avatar) - .username(mobile) + // use email as default username + .username(email) .nickname(nickname) .mobile(mobile) .num(mobile) @@ -107,10 +192,10 @@ public class UserService { user.setPassword(passwordEncoder.encode("123456")); } - user.getOrganizations().add(organization_oid); + user.getOrganizations().add(orgOid); - // return save(user); - return user; + return save(user); + // return user; } public User updateUser(User user, String password, String mobile, String email) { @@ -126,79 +211,100 @@ public class UserService { return save(user); } - // - @Cacheable(cacheNames = "users", unless="#result == null") + @Cacheable(value = "user", key = "#email", unless="#result == null") public Optional findByEmail(String email) { return userRepository.findByEmail(email); } - @Cacheable(cacheNames = "users", unless="#result == null") + @Cacheable(value = "user", key = "#mobile", unless="#result == null") public Optional findByMobile(String mobile) { return userRepository.findByMobile(mobile); } - @Cacheable(cacheNames = "users", unless="#result == null") + @Cacheable(value = "user", key = "#username", unless="#result == null") public Optional findByUsername(String username) { return userRepository.findByUsername(username); } - @Cacheable(cacheNames = "users", unless="#result == null") + @Cacheable(value = "user", key = "#uid", unless="#result == null") public Optional findByUid(String uid) { return userRepository.findByUid(uid); } - @Cacheable(cacheNames = "admin", unless="#result == null") + @Cacheable(value = "admin", unless="#result == null") public Optional getAdmin() { return userRepository.findByUsername(properties.getUsername()); } // + @Cacheable(value = "userExists", key = "#username", unless="#result == null") public Boolean existsByUsername(String username) { return userRepository.existsByUsernameAndDeleted(username, false); } + @Cacheable(value = "userExists", key = "#mobile", unless="#result == null") public Boolean existsByMobile(String mobile) { return userRepository.existsByMobileAndDeleted(mobile, false); } + @Cacheable(value = "userExists", key = "#email", unless="#result == null") public Boolean existsByEmail(String email) { return userRepository.existsByEmailAndDeleted(email, false); } - @Caching(put = { - @CachePut(cacheNames = "users", key = "#user.username"), - @CachePut(cacheNames = "users", key = "#user.mobile"), - @CachePut(cacheNames = "users", key = "#user.email"), - @CachePut(cacheNames = "users", key = "#user.uid") + @CachePut(value = "user", key = "#user.username"), + @CachePut(value = "user", key = "#user.mobile"), + @CachePut(value = "user", key = "#user.email"), + @CachePut(value = "user", key = "#user.uid"), + // TODO: 此处put的exists内容跟缓存时内容类型是否一致? + // @CachePut(value = "userExists", key = "#user.username"), + // @CachePut(value = "userExists", key = "#user.mobile"), + // @CachePut(value = "userExists", key = "#user.email"), }) public User save(@NonNull User user) { return userRepository.save(user); } @Caching(evict = { - @CacheEvict(cacheNames = "users", key = "#user.username"), - @CacheEvict(cacheNames = "users", key = "#user.mobile"), - @CacheEvict(cacheNames = "users", key = "#user.email"), - @CacheEvict(cacheNames = "users", key = "#user.uid") + @CacheEvict(value = "user", key = "#user.username"), + @CacheEvict(value = "user", key = "#user.mobile"), + @CacheEvict(value = "user", key = "#user.email"), + @CacheEvict(value = "user", key = "#user.uid"), + @CacheEvict(value = "userExists", key = "#user.username"), + @CacheEvict(value = "userExists", key = "#user.mobile"), + @CacheEvict(value = "userExists", key = "#user.email"), }) public void delete(@NonNull User user) { userRepository.delete(user); } + public UserResponse convertToUserResponse(User user) { + return modelMapper.map(user, UserResponse.class); + } + + public UserResponseSimple convertToUserResponseSimple(User user) { + return modelMapper.map(user, UserResponseSimple.class); + } + + // TODO: 待完善 + public String createNickname() { + String randomId = uidUtils.getCacheSerialUid().substring(11, 15); + return "User" + randomId; + } + public void initData() { if (userRepository.count() > 0) { - log.debug("user already exists"); return; } - // + User admin = User.builder() - .uid(Utils.getUid()) + .uid(uidUtils.getCacheSerialUid()) .email(properties.getEmail()) .username(properties.getUsername()) .password(new BCryptPasswordEncoder().encode(properties.getPassword())) - .nickname("Admin") + .nickname(properties.getNickname()) .avatar(AvatarConsts.DEFAULT_AVATAR_URL) .mobile(properties.getMobile()) .num(properties.getMobile()) @@ -207,14 +313,13 @@ public class UserService { .mobileVerified(true) .build(); // - Optional roleOptional = roleService.findByValue(TypeConsts.ROLE_ADMIN); - List roles = new ArrayList<>(); - if (roleOptional.isPresent()) { - roles.add(roleOptional.get()); - } - // + Optional roleOptional = roleService.findByName(TypeConsts.ROLE_SUPER); + Set roles = new HashSet<>(); + roleOptional.ifPresent(role -> { + roles.add(role); + }); admin.setRoles(roles); - userRepository.save(admin); + save(admin); } } diff --git a/modules/core/src/main/java/com/bytedesk/core/redis/RedisLoginService.java b/modules/core/src/main/java/com/bytedesk/core/redis/RedisLoginService.java deleted file mode 100644 index c6be33aa64..0000000000 --- a/modules/core/src/main/java/com/bytedesk/core/redis/RedisLoginService.java +++ /dev/null @@ -1,123 +0,0 @@ -package com.bytedesk.core.redis; - -import lombok.AllArgsConstructor; -import org.springframework.data.redis.core.StringRedisTemplate; -import org.springframework.lang.NonNull; -import org.springframework.stereotype.Service; -import org.springframework.util.StringUtils; - -import com.bytedesk.core.constant.RedisConsts; - -import java.util.concurrent.TimeUnit; - -// @Slf4j -@Service -@AllArgsConstructor -public class RedisLoginService { - - private final StringRedisTemplate stringRedisTemplate; - - /** - * cache validate code for 15min - * 缓存验证码, 缓存时间15分钟 - * - * @param keyNum email/mobile - * @param code code - */ - public void cacheValidateCode(String keyNum, @NonNull String code) { - String key = RedisConsts.VALIDATE_CODE + keyNum; - stringRedisTemplate.opsForValue().set(key, code, 60 * 15, TimeUnit.SECONDS); - } - - /** - * validate code - * 验证验证码是否正确 - * - * @param keyNum email/mobile - * @param code code - * @return boolean - */ - public boolean validateCode(String keyNum, String code) { - String key = RedisConsts.VALIDATE_CODE + keyNum; - String cacheCode = stringRedisTemplate.opsForValue().get(key); - if (code.equals(cacheCode)) { - return true; - } - return false; - } - - /** - * check validate code - * 是否缓存有验证码 - * - * @param keyNum - * @return - */ - public boolean hasValidateCode(String keyNum) { - String key = RedisConsts.VALIDATE_CODE + keyNum; - String cacheCode = stringRedisTemplate.opsForValue().get(key); - if (!StringUtils.hasLength(cacheCode)) { - return false; - } - return true; - } - - /** - * cache ip for 60min - * 缓存注册ip, 缓存时间60分钟 - * 不允许同一个ip短时间内重复注册 - * - * @param ip ip - */ - public void cacheRegisterIP(@NonNull String ip) { - String key = RedisConsts.REGISTE_IP + ip; - stringRedisTemplate.opsForValue().set(key, ip, 60 * 60, TimeUnit.SECONDS); - } - - /** - * check ip - * 是否缓存有ip - * - * @param ip - * @return - */ - public boolean hasRegisterIP(String ip) { - String key = RedisConsts.REGISTE_IP + ip; - String cacheIp = stringRedisTemplate.opsForValue().get(key); - if (!StringUtils.hasLength(cacheIp)) { - return false; - } - return true; - } - - /** - * cache visitor ip - * 限制访客端 - * 缓存注册ip, 缓存时间5分钟 - * 不允许同一个ip短时间内重复注册 - * - * @param ip ip - */ - public void cacheVisitorRegisterIP(@NonNull String ip) { - String key = RedisConsts.REGISTE_IP_VISITOR + ip; - stringRedisTemplate.opsForValue().set(key, ip, 60 * 5, TimeUnit.SECONDS); - } - - /** - * check visitor ip - * 限制访客端 - * 是否缓存有ip - * - * @param ip - * @return - */ - public boolean hasVisitorRegisterIP(String ip) { - String key = RedisConsts.REGISTE_IP_VISITOR + ip; - String cacheIp = stringRedisTemplate.opsForValue().get(key); - if (!StringUtils.hasLength(cacheIp)) { - return false; - } - return true; - } - -} diff --git a/modules/core/src/main/java/com/bytedesk/core/redis/RedisUserService.java b/modules/core/src/main/java/com/bytedesk/core/redis/RedisUserService.java deleted file mode 100644 index a2221ab7c7..0000000000 --- a/modules/core/src/main/java/com/bytedesk/core/redis/RedisUserService.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * @Author: jackning 270580156@qq.com - * @Date: 2024-01-27 10:54:35 - * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-02-26 13:20:36 - * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk - * Please be aware of the BSL license restrictions before installing Bytedesk IM – - * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. - * 仅支持企业内部员工自用,严禁用于销售、二次销售或者部署SaaS方式销售 - * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE - * contact: 270580156@qq.com - * 联系:270580156@qq.com - * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. - */ -package com.bytedesk.core.redis; - -import java.util.Set; -import org.springframework.data.redis.core.StringRedisTemplate; -import org.springframework.lang.NonNull; -import org.springframework.stereotype.Service; -import com.bytedesk.core.constant.RedisConsts; -import lombok.AllArgsConstructor; - -@Service -@AllArgsConstructor -public class RedisUserService { - - private final StringRedisTemplate stringRedisTemplate; - - // private final RedisThreadService redisThreadService; - - public void addAccessToken(String username, String accessToken) { - String key = RedisConsts.ACCESS_TOKEN_PREFIX + username; - stringRedisTemplate.opsForSet().add(key, accessToken); - } - - /** - * 存储客服订阅的topic - */ - - // 判断用户是否被缓存 - @SuppressWarnings("null") - public boolean hasTopics(@NonNull String uid) { - return stringRedisTemplate.opsForSet().isMember(RedisConsts.USER_TOPIC_PREFIX + uid, uid); - } - - // 存储用户topic - public void addTopic(@NonNull String uid, @NonNull String topic) { - stringRedisTemplate.opsForSet().add(RedisConsts.USER_TOPIC_PREFIX + uid, topic); - } - - public void removeTopic(@NonNull String uid, @NonNull String topic) { - stringRedisTemplate.opsForSet().remove(RedisConsts.USER_TOPIC_PREFIX + uid, topic); - } - - public Set getTopics(@NonNull String uid) { - return stringRedisTemplate.opsForSet().members(RedisConsts.USER_TOPIC_PREFIX + uid); - } - - // 判断客服账号是否被禁用 - // private static final String USER_DISABLED = "bytedeskim:user:disabled"; // - // "bytedeskim:user:enabled"; - - public void enable(@NonNull String uid) { - stringRedisTemplate.opsForSet().remove(RedisConsts.USER_DISABLED, uid); - } - - public void disable(@NonNull String uid) { - stringRedisTemplate.opsForSet().add(RedisConsts.USER_DISABLED, uid); - } - - // 判断用户是否被禁用 - @SuppressWarnings("null") - public boolean isDisabled(@NonNull String uid) { - return stringRedisTemplate.opsForSet().isMember(RedisConsts.USER_DISABLED, uid); - } - -} diff --git a/modules/core/src/main/java/com/bytedesk/core/session/HttpSessionConfig.java b/modules/core/src/main/java/com/bytedesk/core/session/HttpSessionConfig.java index 6b163bc75c..0fde925403 100644 --- a/modules/core/src/main/java/com/bytedesk/core/session/HttpSessionConfig.java +++ b/modules/core/src/main/java/com/bytedesk/core/session/HttpSessionConfig.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-04-05 00:04:38 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-04-05 10:40:10 + * @LastEditTime: 2024-04-13 14:25:20 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -12,42 +12,49 @@ * 联系:270580156@qq.com * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. */ -package com.bytedesk.core.session; +// package com.bytedesk.core.session; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; -import org.springframework.data.redis.serializer.RedisSerializer; -import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession; +// import org.springframework.context.annotation.Bean; +// import org.springframework.context.annotation.Configuration; +// import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; +// import org.springframework.data.redis.serializer.RedisSerializer; +// import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession; -/** - * https://docs.spring.io/spring-session/reference/guides/boot-redis.html - * - * @description - * @author jackning - * @date 2024-04-05 00:15:55 - */ -@Configuration -@EnableRedisHttpSession(redisNamespace = "bytedeskim") -public class HttpSessionConfig { +// /** +// * https://docs.spring.io/spring-session/reference/guides/boot-redis.html +// * +// * @description +// * @author jackning +// * @date 2024-04-05 00:15:55 +// */ +// @Configuration +// @EnableRedisHttpSession(redisNamespace = "bytedeskim") +// public class HttpSessionConfig { - @Bean - public RedisSerializer springSessionDefaultRedisSerializer() { - return new GenericJackson2JsonRedisSerializer(); - } +// @Bean +// public RedisSerializer springSessionDefaultRedisSerializer() { +// return new GenericJackson2JsonRedisSerializer(); +// } - /** - * Custom Cookie - * https://docs.spring.io/spring-session/reference/guides/java-custom-cookie.html#custom-cookie-sample - * @return - */ - // @Bean - // public CookieSerializer cookieSerializer() { - // DefaultCookieSerializer serializer = new DefaultCookieSerializer(); - // serializer.setCookieName("JSESSIONID"); - // serializer.setCookiePath("/"); - // serializer.setDomainNamePattern("^.+?\\.(\\w+\\.[a-z]+)$"); - // return serializer; - // } +// /** +// * Custom Cookie +// * https://docs.spring.io/spring-session/reference/guides/java-custom-cookie.html#custom-cookie-sample +// * @return +// */ +// // @Bean +// // public CookieSerializer cookieSerializer() { +// // DefaultCookieSerializer serializer = new DefaultCookieSerializer(); +// // serializer.setCookieName("JSESSIONID"); +// // serializer.setCookiePath("/"); +// // serializer.setDomainNamePattern("^.+?\\.(\\w+\\.[a-z]+)$"); +// // return serializer; +// // } -} +// } + + +// \ No newline at end of file diff --git a/modules/core/src/main/java/com/bytedesk/core/thread/Thread.java b/modules/core/src/main/java/com/bytedesk/core/thread/Thread.java index cbe3fefcab..f00b4f02e9 100644 --- a/modules/core/src/main/java/com/bytedesk/core/thread/Thread.java +++ b/modules/core/src/main/java/com/bytedesk/core/thread/Thread.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-29 16:21:24 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-03-01 15:20:24 + * @LastEditTime: 2024-04-23 09:55:39 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -14,7 +14,12 @@ */ package com.bytedesk.core.thread; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; + import com.bytedesk.core.constant.BdConstants; +import com.bytedesk.core.constant.StatusConsts; +import com.bytedesk.core.constant.ThreadTypeConsts; import com.bytedesk.core.rbac.user.User; import com.bytedesk.core.utils.AuditModel; import com.fasterxml.jackson.annotation.JsonIgnore; @@ -27,6 +32,10 @@ import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; +/** + * every visitor <-> agent thread should only be one, + * history records are stored in thread_log table + */ @Entity @Data @Builder @@ -34,6 +43,7 @@ import lombok.experimental.Accessors; @EqualsAndHashCode(callSuper = true) @AllArgsConstructor @NoArgsConstructor +@EntityListeners({ ThreadListener.class }) @Table(name = "core_thread") public class Thread extends AuditModel { @@ -44,37 +54,57 @@ public class Thread extends AuditModel { @Column(unique = true, nullable = false) private String tid; - private String nickname; - - private String avatar; - + /** + * used to push message + * topic format: + * workgroup_wid + '/' + visitor_vid + * agent_aid + '/' + visitor_vid + * such as: wid/vid or aid/vid + */ private String topic; @Builder.Default - private String content = BdConstants.EMPTY; + private String content = BdConstants.EMPTY_STRING; @Builder.Default private Integer unreadCount = 0; /** - * + * @{ThreadTypeConsts} */ - @Column(name = "by_type") - private String type; - - /** - * - */ - @Lob @Builder.Default - private String extra = BdConstants.EMPTY; + @Column(name = "by_type") + private String type = ThreadTypeConsts.WORKGROUP; + + /** closed/open, agent closed/auto closed */ + @Builder.Default + private String status = StatusConsts.THREAD_STATUS_OPEN; + + private String client; + + // @Lob + @Builder.Default + @Column(columnDefinition = "json") + // 用于兼容postgreSQL,否则会报错,[ERROR: column "extra" is of type json but expression is of type character varying + @JdbcTypeCode(SqlTypes.JSON) + private String extra = BdConstants.EMPTY_JSON_STRING; + + // + // h2 db 不能使用 user, 所以重定义为 by_user + @Builder.Default + @Column(name = "by_user", columnDefinition = "json") + @JdbcTypeCode(SqlTypes.JSON) + private String user = BdConstants.EMPTY_JSON_STRING; /** - * + * belongs to user */ @JsonIgnore @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "user_id", foreignKey = @ForeignKey(name = "none", value = ConstraintMode.NO_CONSTRAINT)) - private User user; + private User owner; + + // TODO: + /** belong to org */ + private String orgOid; } diff --git a/modules/core/src/main/java/com/bytedesk/core/thread/ThreadController.java b/modules/core/src/main/java/com/bytedesk/core/thread/ThreadController.java index c162f9d487..71c2885d5d 100644 --- a/modules/core/src/main/java/com/bytedesk/core/thread/ThreadController.java +++ b/modules/core/src/main/java/com/bytedesk/core/thread/ThreadController.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-29 16:21:24 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-02-22 11:30:17 + * @LastEditTime: 2024-04-23 10:07:32 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -15,7 +15,9 @@ package com.bytedesk.core.thread; import org.springframework.data.domain.Page; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -41,22 +43,43 @@ public class ThreadController { * @return json */ @GetMapping("/query") - public JsonResult query(BaseRequest pageParam) { + public ResponseEntity query(BaseRequest pageParam) { - Page threadPage = threadService.query(pageParam); + Page threadPage = threadService.query(pageParam); // - return new JsonResult<>("query thread success", 200, threadPage); + return ResponseEntity.ok(JsonResult.success(threadPage)); } - @RequestMapping("/create") - public JsonResult create(@RequestBody ThreadRequest threadRequest) { - - Thread thread = threadService.create(threadRequest); + /** + * user create member thread + * @param threadRequest + * @return + */ + @PostMapping("/create") + public ResponseEntity create(@RequestBody ThreadRequest threadRequest) { + // + ThreadResponse thread = threadService.createMemberThread(threadRequest); if (thread == null) { - return new JsonResult<>("create thread failed", -1, null); + return ResponseEntity.ok(JsonResult.error()); } - return new JsonResult<>("create thread success", 200, thread); + return ResponseEntity.ok(JsonResult.success(thread)); } + + + + // @PostMapping("/delete") + // public ResponseEntity delete(@RequestBody ThreadRequest threadRequest) { + // Thread thread = threadService.findByTid(threadRequest.getTid()).orElse(null); + // if (thread == null) { + // return ResponseEntity.ok(JsonResult.error()); + // } + // threadService.delete(thread); + // return ResponseEntity.ok(JsonResult.success()); + // } + + + + } diff --git a/modules/core/src/main/java/com/bytedesk/core/thread/ThreadEventHandler.java b/modules/core/src/main/java/com/bytedesk/core/thread/ThreadEventHandler.java index 36830cc154..754553627e 100644 --- a/modules/core/src/main/java/com/bytedesk/core/thread/ThreadEventHandler.java +++ b/modules/core/src/main/java/com/bytedesk/core/thread/ThreadEventHandler.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-02-22 10:40:06 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-02-22 11:11:52 + * @LastEditTime: 2024-04-15 09:32:18 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -25,13 +25,11 @@ import org.springframework.data.rest.core.annotation.HandleBeforeSave; import org.springframework.data.rest.core.annotation.RepositoryEventHandler; import org.springframework.stereotype.Component; -import com.bytedesk.core.auth.AuthService; -import com.bytedesk.core.utils.Utils; - import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; /** + * used for spring-data-rest api * https://spring.io/guides/tutorials/react-and-spring-data-rest/ * https://docs.spring.io/spring-data/rest/reference/events.html */ @@ -41,14 +39,14 @@ import lombok.extern.slf4j.Slf4j; @RepositoryEventHandler(Thread.class) public class ThreadEventHandler { - private AuthService authService; + // private AuthService authService; @HandleBeforeCreate public void beforeCreate(Thread thread) { log.debug("beforeCreate"); // - thread.setTid(Utils.getUid()); - thread.setUser(authService.getCurrentUser()); + // thread.setTid(Utils.getUid()); + // thread.setOwner(authService.getCurrentUser()); return; } diff --git a/modules/core/src/main/java/com/bytedesk/core/thread/ThreadListener.java b/modules/core/src/main/java/com/bytedesk/core/thread/ThreadListener.java new file mode 100644 index 0000000000..adda5ea2bd --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/thread/ThreadListener.java @@ -0,0 +1,72 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-15 09:30:56 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-27 12:12:59 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.thread; + +import org.springframework.stereotype.Component; + +import com.bytedesk.core.event.BytedeskEventPublisher; +import com.bytedesk.core.topic.TopicService; +import com.bytedesk.core.utils.ApplicationContextHolder; + +import jakarta.persistence.PostPersist; +import jakarta.persistence.PostUpdate; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Component +public class ThreadListener { + + // @PrePersist + // public void prePersist(Thread thread) { + // log.info("prePersist {}", thread.getTid()); + // } + + @PostPersist + public void postPersist(Thread thread) { + log.info("thread postPersist {}", thread.getTid()); + // 这里可以记录日志 + // create thread topic + TopicService topicService = ApplicationContextHolder.getBean(TopicService.class); + topicService.create(thread.getTopic(), thread.getOwner().getUid()); + // send notifications + BytedeskEventPublisher bytedeskEventPublisher = ApplicationContextHolder.getBean(BytedeskEventPublisher.class); + bytedeskEventPublisher.publishThreadCreateEvent(thread); + } + + // @PreUpdate + // public void preUpdate(Thread thread) { + // log.info("preUpdate {}", thread.getTid()); + // } + + @PostUpdate + public void postUpdate(Thread thread) { + log.info("postUpdate {}", thread.getTid()); + // + BytedeskEventPublisher bytedeskEventPublisher = ApplicationContextHolder.getBean(BytedeskEventPublisher.class); + bytedeskEventPublisher.publishThreadUpdateEvent(thread); + } + + // @PreRemove + // public void preRemove(Thread thread) { + // log.info("preRemove {}", thread.getTid()); + // } + + // @PostRemove + // public void postRemove(Thread thread) { + // log.info("postRemove {}", thread.getTid()); + // // topicService.deleteByTopicAndUid(thread.getTopic(), thread.getOwner().getUid()); + // } + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/thread/ThreadRepository.java b/modules/core/src/main/java/com/bytedesk/core/thread/ThreadRepository.java index 120d714c05..be76f3af97 100644 --- a/modules/core/src/main/java/com/bytedesk/core/thread/ThreadRepository.java +++ b/modules/core/src/main/java/com/bytedesk/core/thread/ThreadRepository.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-29 16:21:24 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-02-28 15:04:11 + * @LastEditTime: 2024-04-22 22:30:34 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -14,12 +14,14 @@ */ package com.bytedesk.core.thread; +import java.util.List; import java.util.Optional; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +// import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; import com.bytedesk.core.rbac.user.User; @@ -31,12 +33,23 @@ import io.swagger.v3.oas.annotations.tags.Tag; */ @Repository @Tag(name = "thread - 会话") -public interface ThreadRepository - extends JpaRepository, JpaSpecificationExecutor { - +public interface ThreadRepository extends JpaRepository, JpaSpecificationExecutor { Optional findByTid(String tid); + /** used for member thread type */ + Optional findFirstByTopicAndOwner(String topic, User owner); - Optional findByTopicAndUser(String topic, User user); + Optional findFirstByTopic(String topic); - Page findByUser(User user, Pageable pageable); + Page findByOwner(User owner, Pageable pageable); + + // @Query(value="select * from core_thread where extra like %?1% ", nativeQuery = true) + // public Boolean existByExtra(String vid); + + // FIXME: h2不兼容 JSON_EXTRACT + // FIXME: PostgreSQL ERROR: function json_extract(json, unknown) does not exist + // @Query(value = "SELECT * FROM core_thread WHERE JSON_EXTRACT(extra, '$.closed') = false", nativeQuery = true) + // List findByExtraClosed(); + List findByStatus(String status); + + // List findByUpdatedAtAfter(Date updatedAt); } diff --git a/modules/core/src/main/java/com/bytedesk/core/thread/ThreadRequest.java b/modules/core/src/main/java/com/bytedesk/core/thread/ThreadRequest.java index 2ba609795d..2f922c6dfc 100644 --- a/modules/core/src/main/java/com/bytedesk/core/thread/ThreadRequest.java +++ b/modules/core/src/main/java/com/bytedesk/core/thread/ThreadRequest.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-02-21 10:01:12 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-03-01 15:21:22 + * @LastEditTime: 2024-04-13 16:25:54 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -14,22 +14,27 @@ */ package com.bytedesk.core.thread; +import com.bytedesk.core.rbac.user.UserResponseSimple; import com.bytedesk.core.utils.BaseRequest; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; @Data -@EqualsAndHashCode(callSuper=false) +@Builder +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = false) +@NoArgsConstructor +@AllArgsConstructor public class ThreadRequest extends BaseRequest { private String tid; private String topic; - private String nickname; - - private String avatar; - - private String extra; + private UserResponseSimple user; } diff --git a/modules/core/src/main/java/com/bytedesk/core/thread/ThreadResponse.java b/modules/core/src/main/java/com/bytedesk/core/thread/ThreadResponse.java index b3a60c81fb..0359cec0cc 100644 --- a/modules/core/src/main/java/com/bytedesk/core/thread/ThreadResponse.java +++ b/modules/core/src/main/java/com/bytedesk/core/thread/ThreadResponse.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-02-21 10:01:27 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-02-21 10:01:33 + * @LastEditTime: 2024-04-18 12:38:40 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -14,9 +14,43 @@ */ package com.bytedesk.core.thread; +import java.util.Date; + +import com.bytedesk.core.rbac.user.UserResponseSimple; +import com.bytedesk.core.utils.BaseResponse; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; +/** + * for agent client + */ @Data -public class ThreadResponse { +@Builder +@Accessors(chain = true) +@AllArgsConstructor +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class ThreadResponse extends BaseResponse { + private static final long serialVersionUID = -9969282117L; + + private String tid; + + private String topic; + + private String content; + + private Integer unreadCount; + + private String type; + + private String extra; + + private Date createdAt; + + private UserResponseSimple user; } diff --git a/modules/core/src/main/java/com/bytedesk/core/thread/ThreadResponseSimple.java b/modules/core/src/main/java/com/bytedesk/core/thread/ThreadResponseSimple.java new file mode 100644 index 0000000000..18bc666d12 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/thread/ThreadResponseSimple.java @@ -0,0 +1,44 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-02-21 10:01:27 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-16 17:04:09 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.thread; + +import com.bytedesk.core.utils.BaseResponse; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +/** + * for visitor client + */ +@Data +@Builder +@Accessors(chain = true) +@AllArgsConstructor +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class ThreadResponseSimple extends BaseResponse { + + private static final long serialVersionUID = -2417833247L; + + private String tid; + + private String topic; + + private String type; +} diff --git a/modules/core/src/main/java/com/bytedesk/core/thread/ThreadService.java b/modules/core/src/main/java/com/bytedesk/core/thread/ThreadService.java index 70e1e2cb93..38b0aa6132 100644 --- a/modules/core/src/main/java/com/bytedesk/core/thread/ThreadService.java +++ b/modules/core/src/main/java/com/bytedesk/core/thread/ThreadService.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-29 16:21:24 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-03-11 15:03:14 + * @LastEditTime: 2024-04-27 12:29:48 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -14,26 +14,34 @@ */ package com.bytedesk.core.thread; +import java.util.List; import java.util.Optional; import org.modelmapper.ModelMapper; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.CachePut; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.cache.annotation.Caching; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.lang.NonNull; import org.springframework.stereotype.Service; -import org.springframework.util.StringUtils; -import com.bytedesk.core.auth.AuthService; +import com.alibaba.fastjson2.JSON; +import com.bytedesk.core.constant.StatusConsts; +import com.bytedesk.core.rbac.auth.AuthService; import com.bytedesk.core.rbac.user.User; +import com.bytedesk.core.rbac.user.UserResponseSimple; import com.bytedesk.core.rbac.user.UserService; +import com.bytedesk.core.uid.UidUtils; import com.bytedesk.core.utils.BaseRequest; -import com.bytedesk.core.utils.Utils; import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; -// @Slf4j +@Slf4j @Service @AllArgsConstructor public class ThreadService { @@ -46,7 +54,10 @@ public class ThreadService { private ThreadRepository threadRepository; - public Page query(BaseRequest pageParam) { + private UidUtils uidUtils; + + /** */ + public Page query(BaseRequest pageParam) { User user = authService.getCurrentUser(); @@ -54,30 +65,43 @@ public class ThreadService { Pageable pageable = PageRequest.of(pageParam.getPageNumber(), pageParam.getPageSize(), Sort.Direction.DESC, "updatedAt"); - return threadRepository.findByUser(user, pageable); + Page threadPage = findByOwner(user, pageable); + + return threadPage.map(this::convertToThreadResponse); } - public Thread create(ThreadRequest threadRequest) { + /** + * create member thread + * + * @param threadRequest + * @return + */ + public ThreadResponse createMemberThread(ThreadRequest threadRequest) { - User user = authService.getCurrentUser(); - - Optional threadOptional = threadRepository.findByTopicAndUser(threadRequest.getTopic(), user); + User owner = authService.getCurrentUser(); + // + Optional threadOptional = findByTopicAndOwner(threadRequest.getTopic(), owner); if (threadOptional.isPresent()) { - return threadOptional.get(); - } - - Thread thread = modelMapper.map(threadRequest, Thread.class); - if (!StringUtils.hasText(thread.getTid())) { - thread.setTid(Utils.getUid()); + return convertToThreadResponse(threadOptional.get()); } // + Thread thread = modelMapper.map(threadRequest, Thread.class); + thread.setTid(uidUtils.getCacheSerialUid()); + thread.setStatus(StatusConsts.THREAD_STATUS_INIT); + // + String user = JSON.toJSONString(threadRequest.getUser()); + log.info("request {}, user {}", threadRequest.toString(), user); thread.setUser(user); - return threadRepository.save(thread); + // + thread.setOwner(owner); + Thread result = save(thread); + // + return convertToThreadResponse(result); } - - @SuppressWarnings("null") + + /** */ public Thread getReverse(Thread thread) { - + String reverseTid = new StringBuffer(thread.getTid()).reverse().toString(); Optional reverseThreadOptional = findByTid(reverseTid); if (reverseThreadOptional.isPresent()) { @@ -90,29 +114,117 @@ public class ThreadService { } Thread reverseThread = new Thread(); reverseThread.setTid(reverseTid); - reverseThread.setTopic(thread.getUser().getUid()); - reverseThread.setAvatar(thread.getUser().getAvatar()); - reverseThread.setNickname(thread.getUser().getNickname()); + reverseThread.setTopic(thread.getOwner().getUid()); + // + UserResponseSimple user = userService.convertToUserResponseSimple(thread.getOwner()); + reverseThread.setUser(JSON.toJSONString(user)); + // reverseThread.setAvatar(thread.getOwner().getAvatar()); + // reverseThread.setNickname(thread.getOwner().getNickname()); + // reverseThread.setContent(thread.getContent()); // reverseThread.setExtra(thread.getExtra()); reverseThread.setType(thread.getType()); - reverseThread.setUser(userOptional.get()); + reverseThread.setOwner(userOptional.get()); // return save(reverseThread); } } + /** */ + public Thread createAsistantThread(ThreadRequest threadRequest) { + + + + return null; + } + + + @Cacheable(value = "thread", key = "#tid", unless = "#result == null") public Optional findByTid(String tid) { return threadRepository.findByTid(tid); } + // TODO: how to cacheput or cacheevict? + @Cacheable(value = "thread", key = "#topic-#user.uid", unless = "#result == null") + public Optional findByTopicAndOwner(String topic, User user) { + return threadRepository.findFirstByTopicAndOwner(topic, user); + } + + @Cacheable(value = "thread", key = "#topic", unless = "#result == null") + public Optional findByTopic(String topic) { + return threadRepository.findFirstByTopic(topic); + } + + // TODO: how to cacheput or cacheevict? + @Cacheable(value = "thread", key = "#user.uid-#pageable.getPageNumber()", unless = "#result == null") + public Page findByOwner(User user, Pageable pageable) { + return threadRepository.findByOwner(user, pageable); + } + + // TODO: 更新缓存 + @Cacheable(value = "threadOpen") + public List findStatusOpen() { + return threadRepository.findByStatus(StatusConsts.THREAD_STATUS_OPEN); + } + + public Boolean isClosed(Thread thread) { + return !StatusConsts.THREAD_STATUS_OPEN.equals(thread.getStatus()); + } + + public Thread reopen(Thread thread) { + thread.setStatus(StatusConsts.THREAD_STATUS_OPEN); + return save(thread); + } + + public Thread autoClose(Thread thread) { + thread.setStatus(StatusConsts.THREAD_STATUS_CLOSED_AUTO); + return save(thread); + } + + public Thread agentClose(Thread thread) { + thread.setStatus(StatusConsts.THREAD_STATUS_CLOSED_AGENT); + return save(thread); + } + + @Caching(put = { + @CachePut(value = "thread", key = "#thread.tid"), + @CachePut(value = "thread", key = "#thread.topic") + }) public Thread save(@NonNull Thread thread) { return threadRepository.save(thread); } + @Caching(evict = { + @CacheEvict(value = "thread", key = "#thread.tid"), + @CacheEvict(value = "thread", key = "#thread.topic") + }) public void delete(@NonNull Thread thread) { threadRepository.delete(thread); } + public ThreadResponse convertToThreadResponse(Thread thread) { + ThreadResponse threadResponse = modelMapper.map(thread, ThreadResponse.class); + // + UserResponseSimple user = JSON.parseObject(thread.getUser(), UserResponseSimple.class); + threadResponse.setUser(user); + + return threadResponse; + } + + public ThreadResponseSimple convertToThreadResponseSimple(Thread thread) { + return modelMapper.map(thread, ThreadResponseSimple.class); + } + + // + public void initData() { + + if(threadRepository.count() > 0) { + return; + } + + + + + } } diff --git a/modules/core/src/main/java/com/bytedesk/core/topic/Topic.java b/modules/core/src/main/java/com/bytedesk/core/topic/Topic.java new file mode 100644 index 0000000000..770bdac7c4 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/topic/Topic.java @@ -0,0 +1,95 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-13 16:03:44 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-23 16:09:01 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.topic; + +import java.util.Set; +import java.util.HashSet; + +import com.bytedesk.core.utils.AuditModel; +import com.bytedesk.core.utils.StringSetConverter; + +import jakarta.persistence.Column; +import jakarta.persistence.Convert; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +@Entity +@Data +@Builder +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = true) +@AllArgsConstructor +@NoArgsConstructor +@Table(name = "core_topic", uniqueConstraints = { + // @UniqueConstraint(columnNames = {"topic", "uuid"}), +}) +public class Topic extends AuditModel { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private Long id; + + @Column(unique = true, nullable = false) + private String tid; + + // @Column(nullable = false) + // private String topic; + /** 为防止后添加的记录,clientIds缺失,所以用数组代替,这样每个用户在topic中只有一条记录,cliendIds可共用 */ + @Builder.Default + @Column(length = 512) + @Convert(converter = StringSetConverter.class) + private Set topics = new HashSet<>(); + // private String topic; + + // user, no need map, just uid + @Column(name = "uuid", nullable = false) + private String uid; + + /** AT_MOST_ONCE(0),AT_LEAST_ONCE(1), EXACTLY_ONCE(2), */ + // @Builder.Default + // private int qos = 1; + + // @Builder.Default + // @Column(name = "is_subscribed") + // private boolean subscribed = false; + + /** + * topic通配符说明: + * 单层通配符"+":只能匹配一层主题。例如,"aaa/+"可以匹配"aaa/bbb",但不能匹配"aaa/bbb/ccc"。 + * 多层通配符"#":可以匹配多层主题。例如,"aaa/#"不但可以匹配"aaa/bbb",还可以匹配"aaa/bbb/ccc/ddd"。它必须作为主题的最后一个级别使用,并且只能出现在最后 + */ + // @Builder.Default + // @Column(name = "is_wildcard") + // private boolean wildcard = false; + + /** + * current online clientIds + */ + @Builder.Default + @Convert(converter = StringSetConverter.class) + private Set clientIds = new HashSet<>(); + + /** 描述 */ + // private String description; +} diff --git a/modules/core/src/main/java/com/bytedesk/core/push/AndroidService.java b/modules/core/src/main/java/com/bytedesk/core/topic/TopicController.java similarity index 84% rename from modules/core/src/main/java/com/bytedesk/core/push/AndroidService.java rename to modules/core/src/main/java/com/bytedesk/core/topic/TopicController.java index 29d369b708..1494599b77 100644 --- a/modules/core/src/main/java/com/bytedesk/core/push/AndroidService.java +++ b/modules/core/src/main/java/com/bytedesk/core/topic/TopicController.java @@ -1,8 +1,8 @@ /* * @Author: jackning 270580156@qq.com - * @Date: 2024-03-31 15:30:30 + * @Date: 2024-04-13 16:14:26 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-03-31 15:30:57 + * @LastEditTime: 2024-04-13 16:14:28 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -12,8 +12,8 @@ * 联系:270580156@qq.com * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. */ -package com.bytedesk.core.push; +package com.bytedesk.core.topic; -public class AndroidService { +public class TopicController { } diff --git a/modules/core/src/main/java/com/bytedesk/core/topic/TopicRepository.java b/modules/core/src/main/java/com/bytedesk/core/topic/TopicRepository.java new file mode 100644 index 0000000000..5338158af8 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/topic/TopicRepository.java @@ -0,0 +1,50 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-13 16:14:47 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-23 16:16:14 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.topic; + +import java.util.Optional; +import java.util.Set; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +@Repository +public interface TopicRepository extends JpaRepository { + + Optional findByTid(String tid); + + Optional findFirstByUid(String uid); + + // boolean existsByTopicAndUid(String topic, String uid); + + // exact match 精确匹配 + // List findByTopicAndUid(String topic, String uid); + + /** + * TODO: wildcard match 通配符匹配 topic + * topic通配符说明: + * 单层通配符"+":只能匹配一层主题。例如,"aaa/+"可以匹配"aaa/bbb",但不能匹配"aaa/bbb/ccc"。 + * 多层通配符"#":可以匹配多层主题。例如,"aaa/#"不但可以匹配"aaa/bbb",还可以匹配"aaa/bbb/ccc/ddd"。它必须作为主题的最后一个级别使用,并且只能出现在最后 + */ + // List findByTopicStartsWith(String topic); + // List findByTopic(String topic); + // + @Query(value="select * from core_topic where topics like %:topic% ", nativeQuery = true) + Set findByTopicsContains(@Param("topic") String topic); + + // void deleteByTopicAndUid(String topic, String uid); +} diff --git a/modules/core/src/main/java/com/bytedesk/core/topic/TopicRequest.java b/modules/core/src/main/java/com/bytedesk/core/topic/TopicRequest.java new file mode 100644 index 0000000000..05bf3cab08 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/topic/TopicRequest.java @@ -0,0 +1,59 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-13 16:15:11 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-22 14:23:43 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.topic; + +import java.util.ArrayList; +import java.util.List; + +import com.bytedesk.core.utils.BaseRequest; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +@Data +@Builder +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = false) +@NoArgsConstructor +@AllArgsConstructor +public class TopicRequest extends BaseRequest { + + private String tid; + + private String topic; + + private String uid; + + /** AT_MOST_ONCE(0),AT_LEAST_ONCE(1), EXACTLY_ONCE(2), */ + // @Builder.Default + // private int qos = 1; + + // private boolean subscribed; + + // private boolean wildcard; + + /** + * current online clientIds + */ + @Builder.Default + private List clientIds = new ArrayList<>(); + + /** 描述 */ + // private String description; +} diff --git a/modules/core/src/main/java/com/bytedesk/core/topic/TopicResponse.java b/modules/core/src/main/java/com/bytedesk/core/topic/TopicResponse.java new file mode 100644 index 0000000000..34a964dd40 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/topic/TopicResponse.java @@ -0,0 +1,56 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-13 16:15:22 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-16 09:41:32 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.topic; + +import java.util.ArrayList; +import java.util.List; + +import com.bytedesk.core.utils.BaseResponse; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + + +@Data +@Builder +@Accessors(chain = true) +@AllArgsConstructor +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class TopicResponse extends BaseResponse { + + private String tid; + + private String topic; + + private String uid; + + /** AT_MOST_ONCE(0),AT_LEAST_ONCE(1), EXACTLY_ONCE(2), */ + private int qos; + + // private boolean subscribed; + + private boolean wildcard; + + /** + * current online clientIds + */ + @Builder.Default + private List clientIds = new ArrayList<>(); +} diff --git a/modules/core/src/main/java/com/bytedesk/core/topic/TopicService.java b/modules/core/src/main/java/com/bytedesk/core/topic/TopicService.java new file mode 100644 index 0000000000..5fe4fa455a --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/topic/TopicService.java @@ -0,0 +1,209 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-13 16:14:36 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-27 12:06:52 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.topic; + +import java.util.Optional; +import java.util.Set; + +import org.modelmapper.ModelMapper; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.cache.annotation.Caching; +import org.springframework.scheduling.annotation.Async; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.CachePut; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.bytedesk.core.uid.UidUtils; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Service +@AllArgsConstructor +public class TopicService { + + private final TopicRepository topicRepository; + + private final ModelMapper modelMapper; + + private final UidUtils uidUtils; + + @Async + public void create(String topic, String uid) { + TopicRequest topicRequest = TopicRequest.builder() + .topic(topic) + .uid(uid) + // .qos(1) + .build(); + create(topicRequest); + } + + @Transactional + private void create(TopicRequest topicRequest) { + + // if (existsByTopicAndUid(topicRequest.getTopic(), topicRequest.getUid())) { + // return; + // } + + Optional topicOptional = findByUid(topicRequest.getUid()); + if (topicOptional.isPresent()) { + Topic topicElement = topicOptional.get(); + if (topicElement.getTopics().contains(topicRequest.getTopic())) { + log.info("create: {}", topicRequest.getTopic()); + return; + } + topicElement.getTopics().add(topicRequest.getTopic()); + // + save(topicElement); + // + return; + } + // + topicRequest.setTid(uidUtils.getCacheSerialUid()); + // + Topic topic = modelMapper.map(topicRequest, Topic.class); + topic.getTopics().add(topicRequest.getTopic()); + // Topics topicsObject = new Topics(); + // topicsObject.getTopics().add(topicRequest.getTopic()); + // topic.setTopic(JSON.toJSONString(topicsObject)); + // + save(topic); + } + + + @Async + public void subscribe(String topic, String clientId) { + // 用户clientId格式: uid/client + Optional topicOptional = findByClientId(clientId); + if (topicOptional.isPresent()) { + Topic topicElement = topicOptional.get(); + if (topicElement.getTopics().contains(topic)) { + log.info("create: {}", topic); + return; + } + topicElement.getTopics().add(topic); + // + save(topicElement); + } else { + // create + final String uid = clientId.split("/")[0]; + TopicRequest topicRequest = TopicRequest.builder() + .topic(topic) + .uid(uid) + // .qos(qos) + .build(); + topicRequest.getClientIds().add(clientId); + create(topicRequest); + } + } + + @Async + public void unsubscribe(String topic, String clientId) { + // 用户clientId格式: uid/client + Optional topicOptional = findByClientId(clientId); + if (topicOptional.isPresent()) { + Topic topicElement = topicOptional.get(); + if (topicElement.getTopics().contains(topic)) { + log.info("create: {}", topic); + return; + } + topicElement.getTopics().add(topic); + } + // final String uid = clientId.split("/")[0]; + // deleteByTopicAndUid(topic, uid); + } + + @Async + public void addClientId(String clientId) { + // 用户clientId格式: uid/client + Optional topicOptional = findByClientId(clientId); + if (topicOptional.isPresent()) { + Topic topic = topicOptional.get(); + if (!topic.getClientIds().contains(clientId)) { + log.info("addClientId: {}", clientId); + topic.getClientIds().add(clientId); + save(topic); + } + } + } + + @Async + public void removeClientId(String clientId) { + // 用户clientId格式: uid/client + Optional topicOptional = findByClientId(clientId); + if (topicOptional.isPresent()) { + Topic topic = topicOptional.get(); + if (topic.getClientIds().contains(clientId)) { + log.info("removeClientId: {}", clientId); + topic.getClientIds().remove(clientId); + save(topic); + } + } + } + + @Cacheable(value = "topic", key = "#tid") + public Optional findByTid(String tid) { + return topicRepository.findByTid(tid); + } + + @Cacheable(value = "topic", key = "#clientId", unless = "#result == null") + public Optional findByClientId(String clientId) { + // 用户clientId格式: uid/client + final String uid = clientId.split("/")[0]; + return findByUid(uid); + } + + @Cacheable(value = "topic", key = "#uid", unless = "#result == null") + public Optional findByUid(String uid) { + return topicRepository.findFirstByUid(uid); + } + + @Cacheable(value = "topic", key = "#topic", unless="#result == null") + public Set findByTopic(String topic) { + // List topics = topicRepository.findByTopicStartsWith(topic); + Set topics = topicRepository.findByTopicsContains(topic); + return topics; + // return topics.stream().map(this::convertToTopicResponse).toList(); + } + + @Caching(put = { + @CachePut(value = "topic", key = "#topic.uid") + }) + public Topic save(Topic topic) { + return topicRepository.save(topic); + } + + // TODO: 需要从原先uid的缓存列表中删除,然后添加到新的uid的换成列表中 + // @CachePut(value = "topic", key = "#uid") + public void update(String tid, String uid) { + Optional optionalTopic = findByTid(tid); + optionalTopic.ifPresent(topic -> { + topic.setUid(uid); + topicRepository.save(topic); + }); + } + + @CacheEvict(value = "topic", key = "#topic.uid") + public void delete(Topic topic) { + topicRepository.delete(topic); + } + + public TopicResponse convertToTopicResponse(Topic topic) { + return modelMapper.map(topic, TopicResponse.class); + } + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/uid/UidAutoConfigure.java b/modules/core/src/main/java/com/bytedesk/core/uid/UidAutoConfigure.java new file mode 100644 index 0000000000..5b34c35c82 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/uid/UidAutoConfigure.java @@ -0,0 +1,64 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2021-02-24 15:52:39 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-07 15:11:16 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.uid; + +import com.bytedesk.core.uid.impl.CachedUidGenerator; +import com.bytedesk.core.uid.impl.UidProperties; +import com.bytedesk.core.uid.worker.DisposableWorkerIdAssigner; +import com.bytedesk.core.uid.worker.WorkerIdAssigner; +import com.bytedesk.core.uid.impl.DefaultUidGenerator; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +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.context.annotation.Lazy; + +/** + * https://github.com/wujun234/uid-generator-spring-boot-starter + * UID 的自动配置 + * + * @author wujun + * @date 2019.02.20 10:57 + */ +@Configuration +@ConditionalOnClass({ DefaultUidGenerator.class, CachedUidGenerator.class }) +@EnableConfigurationProperties(UidProperties.class) +public class UidAutoConfigure { + + @Autowired + private UidProperties uidProperties; + + @Bean + @ConditionalOnMissingBean + @Lazy + DefaultUidGenerator defaultUidGenerator() { + return new DefaultUidGenerator(uidProperties); + } + + @Bean + @ConditionalOnMissingBean + @Lazy + CachedUidGenerator cachedUidGenerator() { + return new CachedUidGenerator(uidProperties); + } + + @Bean + @ConditionalOnMissingBean + WorkerIdAssigner workerIdAssigner() { + return new DisposableWorkerIdAssigner(); + } +} diff --git a/modules/core/src/main/java/com/bytedesk/core/uid/UidGenerator.java b/modules/core/src/main/java/com/bytedesk/core/uid/UidGenerator.java new file mode 100644 index 0000000000..97d24a2e0e --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/uid/UidGenerator.java @@ -0,0 +1,78 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2021-02-24 15:52:39 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-13 11:37:17 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.uid; + +import java.util.Date; + +import com.bytedesk.core.uid.worker.WorkerNodeType; +import com.bytedesk.core.utils.AuditModel; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +/** + * Entity for M_WORKER_NODE + * + * @author yutianbao + */ +@Entity +@Data +@Builder +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = true) +@AllArgsConstructor +@NoArgsConstructor +@Table(name = "core_uid_generator") +public class UidGenerator extends AuditModel { + + /** + * Entity unique id (table unique) + */ + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private Long id; + + /** + * Type of CONTAINER: HostName, ACTUAL : IP. + */ + private String host; + + /** + * Type of CONTAINER: Port, ACTUAL : Timestamp + Random(0-10000) + */ + private String port; + + /** + * type of {@link WorkerNodeType} + */ + private int type; + + /** + * Worker launch date, default now + */ + @Builder.Default + private Date launchDate = new Date(); + + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/uid/UidGeneratorService.java b/modules/core/src/main/java/com/bytedesk/core/uid/UidGeneratorService.java new file mode 100644 index 0000000000..a8b245b125 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/uid/UidGeneratorService.java @@ -0,0 +1,44 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2021-02-24 15:52:39 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-15 16:38:40 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.uid; + +import com.bytedesk.core.uid.exception.UidGenerateException; + +/** + * https://github.com/wujun234/uid-generator-spring-boot-starter + * Represents a unique id generator. + * + * @author yutianbao + */ +public interface UidGeneratorService { + + /** + * Get a unique ID + * + * @return UID + * @throws UidGenerateException + */ + long getUID() throws UidGenerateException; + + /** + * Parse the UID into elements which are used to generate the UID.
+ * Such as timestamp & workerId & sequence... + * + * @param uid + * @return Parsed info + */ + String parseUID(long uid); + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/uid/UidGereratorRepository.java b/modules/core/src/main/java/com/bytedesk/core/uid/UidGereratorRepository.java new file mode 100644 index 0000000000..8455732dd4 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/uid/UidGereratorRepository.java @@ -0,0 +1,54 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2021-02-24 15:52:39 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-07 15:48:40 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +/* + * Copyright (c) 2017 Baidu, Inc. All Rights Reserve. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.bytedesk.core.uid; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.stereotype.Repository; + +/** + * DAO for M_WORKER_NODE + * + * @author yutianbao + * @author wujun + */ +@Repository +public interface UidGereratorRepository extends JpaRepository, JpaSpecificationExecutor { + + /** + * Get {@link UidGenerator} by node host + * + * @param host + * @param port + * @return + */ + UidGenerator findByHostAndPort(String host, String port); + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/uid/UidUtils.java b/modules/core/src/main/java/com/bytedesk/core/uid/UidUtils.java new file mode 100644 index 0000000000..c4caf0b1d6 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/uid/UidUtils.java @@ -0,0 +1,70 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-07 15:39:15 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-09 17:49:09 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.uid; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.bytedesk.core.uid.impl.CachedUidGenerator; +import com.bytedesk.core.uid.impl.DefaultUidGenerator; + +// import lombok.extern.slf4j.Slf4j; + +/** + * https://github.com/wujun234/uid-generator-spring-boot-starter/blob/master/README.md + * UidGenerator接口提供了 UID 生成和解析的方法,提供了两种实现: + */ +// @Slf4j +@Component +public class UidUtils { + + @Autowired + private DefaultUidGenerator defaultUidGenerator; + + @Autowired + private CachedUidGenerator cachedUidGenerator; + + /** + * 实时生成 + * 性能有损耗 + * + * @return string + */ + public String getDefaultSerialUid() { + // Generate UID + long uid = defaultUidGenerator.getUID(); + // Parse UID into [Timestamp, WorkerId, Sequence] + // {"UID":"1165810429067392","timestamp":"2023-07-17 12:17:13","workerId":"1","sequence":"0"} + // log.info(defaultUidGenerator.parseUID(uid)); + return String.valueOf(uid); + } + + + /** + * 生成一次id之后,按序列号+1生成一批id,缓存,供之后请求 + * 如对UID生成性能有要求, 请使用CachedUidGenerator + * + * @return string + */ + public String getCacheSerialUid() { + // Generate UID + long uid = cachedUidGenerator.getUID(); + // Parse UID into [Timestamp, WorkerId, Sequence] + // {"UID":"1165809330159873","timestamp":"2023-07-17 12:15:02","workerId":"2","sequence":"1"} + // log.info(cachedUidGenerator.parseUID(uid)); + return String.valueOf(uid); + } + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/uid/buffer/BufferPaddingExecutor.java b/modules/core/src/main/java/com/bytedesk/core/uid/buffer/BufferPaddingExecutor.java new file mode 100644 index 0000000000..8039957986 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/uid/buffer/BufferPaddingExecutor.java @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2017 Baidu, Inc. All Rights Reserve. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.bytedesk.core.uid.buffer; + +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import com.bytedesk.core.uid.utils.NamingThreadFactory; +import com.bytedesk.core.uid.utils.PaddedAtomicLong; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.Assert; + +/** + * Represents an executor for padding {@link RingBuffer}
+ * There are two kinds of executors: one for scheduled padding, the other for padding immediately. + * + * @author yutianbao + */ +public class BufferPaddingExecutor { + private static final Logger LOGGER = LoggerFactory.getLogger(RingBuffer.class); + + /** Constants */ + private static final String WORKER_NAME = "RingBuffer-Padding-Worker"; + private static final String SCHEDULE_NAME = "RingBuffer-Padding-Schedule"; + /** 5 minutes */ + private static final long DEFAULT_SCHEDULE_INTERVAL = 5 * 60L; + + /** Whether buffer padding is running */ + private final AtomicBoolean running; + + /** We can borrow UIDs from the future, here store the last second we have consumed */ + private final PaddedAtomicLong lastSecond; + + /** RingBuffer & BufferUidProvider */ + private final RingBuffer ringBuffer; + private final BufferedUidProvider uidProvider; + + /** Padding immediately by the thread pool */ + private final ExecutorService bufferPadExecutors; + /** Padding schedule thread */ + private final ScheduledExecutorService bufferPadSchedule; + + /** Schedule interval Unit as seconds */ + private long scheduleInterval = DEFAULT_SCHEDULE_INTERVAL; + + /** + * Constructor with {@link RingBuffer} and {@link BufferedUidProvider}, default use schedule + * + * @param ringBuffer {@link RingBuffer} + * @param uidProvider {@link BufferedUidProvider} + */ + public BufferPaddingExecutor(RingBuffer ringBuffer, BufferedUidProvider uidProvider) { + this(ringBuffer, uidProvider, true); + } + + /** + * Constructor with {@link RingBuffer}, {@link BufferedUidProvider}, and whether use schedule padding + * + * @param ringBuffer {@link RingBuffer} + * @param uidProvider {@link BufferedUidProvider} + * @param usingSchedule + */ + public BufferPaddingExecutor(RingBuffer ringBuffer, BufferedUidProvider uidProvider, boolean usingSchedule) { + this.running = new AtomicBoolean(false); + this.lastSecond = new PaddedAtomicLong(TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis())); + this.ringBuffer = ringBuffer; + this.uidProvider = uidProvider; + + // initialize thread pool + int cores = Runtime.getRuntime().availableProcessors(); + bufferPadExecutors = Executors.newFixedThreadPool(cores * 2, new NamingThreadFactory(WORKER_NAME)); + + // initialize schedule thread + if (usingSchedule) { + bufferPadSchedule = Executors.newSingleThreadScheduledExecutor(new NamingThreadFactory(SCHEDULE_NAME)); + } else { + bufferPadSchedule = null; + } + } + + /** + * Start executors such as schedule + */ + public void start() { + if (bufferPadSchedule != null) { + bufferPadSchedule.scheduleWithFixedDelay(() -> paddingBuffer(), scheduleInterval, scheduleInterval, TimeUnit.SECONDS); + } + } + + /** + * Shutdown executors + */ + public void shutdown() { + if (!bufferPadExecutors.isShutdown()) { + bufferPadExecutors.shutdownNow(); + } + + if (bufferPadSchedule != null && !bufferPadSchedule.isShutdown()) { + bufferPadSchedule.shutdownNow(); + } + } + + /** + * Whether is padding + * + * @return + */ + public boolean isRunning() { + return running.get(); + } + + /** + * Padding buffer in the thread pool + */ + public void asyncPadding() { + bufferPadExecutors.submit(this::paddingBuffer); + } + + /** + * Padding buffer fill the slots until to catch the cursor + */ + public void paddingBuffer() { + LOGGER.info("Ready to padding buffer lastSecond:{}. {}", lastSecond.get(), ringBuffer); + + // is still running + if (!running.compareAndSet(false, true)) { + LOGGER.info("Padding buffer is still running. {}", ringBuffer); + return; + } + + // fill the rest slots until to catch the cursor + boolean isFullRingBuffer = false; + while (!isFullRingBuffer) { + List uidList = uidProvider.provide(lastSecond.incrementAndGet()); + for (Long uid : uidList) { + isFullRingBuffer = !ringBuffer.put(uid); + if (isFullRingBuffer) { + break; + } + } + } + + // not running now + running.compareAndSet(true, false); + LOGGER.info("End to padding buffer lastSecond:{}. {}", lastSecond.get(), ringBuffer); + } + + /** + * Setters + */ + public void setScheduleInterval(long scheduleInterval) { + Assert.isTrue(scheduleInterval > 0, "Schedule interval must positive!"); + this.scheduleInterval = scheduleInterval; + } + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/uid/buffer/BufferedUidProvider.java b/modules/core/src/main/java/com/bytedesk/core/uid/buffer/BufferedUidProvider.java new file mode 100644 index 0000000000..8e1602ad81 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/uid/buffer/BufferedUidProvider.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2017 Baidu, Inc. All Rights Reserve. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.bytedesk.core.uid.buffer; + +import java.util.List; + +/** + * Buffered UID provider(Lambda supported), which provides UID in the same one second + * + * @author yutianbao + */ +@FunctionalInterface +public interface BufferedUidProvider { + + /** + * Provides UID in one second + * + * @param momentInSecond + * @return + */ + List provide(long momentInSecond); +} diff --git a/modules/core/src/main/java/com/bytedesk/core/uid/buffer/RejectedPutBufferHandler.java b/modules/core/src/main/java/com/bytedesk/core/uid/buffer/RejectedPutBufferHandler.java new file mode 100644 index 0000000000..c6b2e4f9fd --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/uid/buffer/RejectedPutBufferHandler.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2017 Baidu, Inc. All Rights Reserve. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.bytedesk.core.uid.buffer; + +/** + * If tail catches the cursor it means that the ring buffer is full, any more buffer put request will be rejected. + * Specify the policy to handle the reject. This is a Lambda supported interface + * + * @author yutianbao + */ +@FunctionalInterface +public interface RejectedPutBufferHandler { + + /** + * Reject put buffer request + * + * @param ringBuffer + * @param uid + */ + void rejectPutBuffer(RingBuffer ringBuffer, long uid); +} diff --git a/modules/core/src/main/java/com/bytedesk/core/uid/buffer/RejectedTakeBufferHandler.java b/modules/core/src/main/java/com/bytedesk/core/uid/buffer/RejectedTakeBufferHandler.java new file mode 100644 index 0000000000..7ca9a33c1d --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/uid/buffer/RejectedTakeBufferHandler.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2017 Baidu, Inc. All Rights Reserve. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.bytedesk.core.uid.buffer; + +/** + * If cursor catches the tail it means that the ring buffer is empty, any more buffer take request will be rejected. + * Specify the policy to handle the reject. This is a Lambda supported interface + * + * @author yutianbao + */ +@FunctionalInterface +public interface RejectedTakeBufferHandler { + + /** + * Reject take buffer request + * + * @param ringBuffer + */ + void rejectTakeBuffer(RingBuffer ringBuffer); +} diff --git a/modules/core/src/main/java/com/bytedesk/core/uid/buffer/RingBuffer.java b/modules/core/src/main/java/com/bytedesk/core/uid/buffer/RingBuffer.java new file mode 100644 index 0000000000..3fc4342aa8 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/uid/buffer/RingBuffer.java @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2017 Baidu, Inc. All Rights Reserve. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.bytedesk.core.uid.buffer; + +import java.util.concurrent.atomic.AtomicLong; + +import com.bytedesk.core.uid.utils.PaddedAtomicLong; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.Assert; + +/** + * Represents a ring buffer based on array.
+ * Using array could improve read element performance due to the CUP cache line. To prevent + * the side effect of False Sharing, {@link PaddedAtomicLong} is using on 'tail' and 'cursor'

+ * + * A ring buffer is consisted of: + *

  • slots: each element of the array is a slot, which is be set with a UID + *
  • flags: flag array corresponding the same index with the slots, indicates whether can take or put slot + *
  • tail: a sequence of the max slot position to produce + *
  • cursor: a sequence of the min slot position to consume + * + * @author yutianbao + */ +public class RingBuffer { + private static final Logger LOGGER = LoggerFactory.getLogger(RingBuffer.class); + + /** Constants */ + private static final int START_POINT = -1; + private static final long CAN_PUT_FLAG = 0L; + private static final long CAN_TAKE_FLAG = 1L; + public static final int DEFAULT_PADDING_PERCENT = 50; + + /** The size of RingBuffer's slots, each slot hold a UID */ + private final int bufferSize; + private final long indexMask; + private final long[] slots; + private final PaddedAtomicLong[] flags; + + /** Tail: last position sequence to produce */ + private final AtomicLong tail = new PaddedAtomicLong(START_POINT); + + /** Cursor: current position sequence to consume */ + private final AtomicLong cursor = new PaddedAtomicLong(START_POINT); + + /** Threshold for trigger padding buffer*/ + private final int paddingThreshold; + + /** Reject put/take buffer handle policy */ + private RejectedPutBufferHandler rejectedPutHandler = this::discardPutBuffer; + private RejectedTakeBufferHandler rejectedTakeHandler = this::exceptionRejectedTakeBuffer; + + /** Executor of padding buffer */ + private BufferPaddingExecutor bufferPaddingExecutor; + + /** + * Constructor with buffer size, paddingFactor default as {@value #DEFAULT_PADDING_PERCENT} + * + * @param bufferSize must be positive & a power of 2 + */ + public RingBuffer(int bufferSize) { + this(bufferSize, DEFAULT_PADDING_PERCENT); + } + + /** + * Constructor with buffer size & padding factor + * + * @param bufferSize must be positive & a power of 2 + * @param paddingFactor percent in (0 - 100). When the count of rest available UIDs reach the threshold, it will trigger padding buffer
    + * Sample: paddingFactor=20, bufferSize=1000 -> threshold=1000 * 20 /100, + * padding buffer will be triggered when tail-cursor 0L, "RingBuffer size must be positive"); + Assert.isTrue(Integer.bitCount(bufferSize) == 1, "RingBuffer size must be a power of 2"); + Assert.isTrue(paddingFactor > 0 && paddingFactor < 100, "RingBuffer size must be positive"); + + this.bufferSize = bufferSize; + this.indexMask = bufferSize - 1; + this.slots = new long[bufferSize]; + this.flags = initFlags(bufferSize); + + this.paddingThreshold = bufferSize * paddingFactor / 100; + } + + /** + * Put an UID in the ring & tail moved
    + * We use 'synchronized' to guarantee the UID fill in slot & publish new tail sequence as atomic operations
    + * + * Note that: It is recommended to put UID in a serialize way, cause we once batch generate a series UIDs and put + * the one by one into the buffer, so it is unnecessary put in multi-threads + * + * @param uid + * @return false means that the buffer is full, apply {@link RejectedPutBufferHandler} + */ + public synchronized boolean put(long uid) { + long currentTail = tail.get(); + long currentCursor = cursor.get(); + + // tail catches the cursor, means that you can't put any cause of RingBuffer is full + long distance = currentTail - (currentCursor == START_POINT ? 0 : currentCursor); + if (distance == bufferSize - 1) { + rejectedPutHandler.rejectPutBuffer(this, uid); + return false; + } + + // 1. pre-check whether the flag is CAN_PUT_FLAG + int nextTailIndex = calSlotIndex(currentTail + 1); + if (flags[nextTailIndex].get() != CAN_PUT_FLAG) { + rejectedPutHandler.rejectPutBuffer(this, uid); + return false; + } + + // 2. put UID in the next slot + // 3. update next slot' flag to CAN_TAKE_FLAG + // 4. publish tail with sequence increase by one + slots[nextTailIndex] = uid; + flags[nextTailIndex].set(CAN_TAKE_FLAG); + tail.incrementAndGet(); + + // The atomicity of operations above, guarantees by 'synchronized'. In another word, + // the take operation can't consume the UID we just put, until the tail is published(tail.incrementAndGet()) + return true; + } + + /** + * Take an UID of the ring at the next cursor, this is a lock free operation by using atomic cursor

    + * + * Before getting the UID, we also check whether reach the padding threshold, + * the padding buffer operation will be triggered in another thread
    + * If there is no more available UID to be taken, the specified {@link RejectedTakeBufferHandler} will be applied
    + * + * @return UID + * @throws IllegalStateException if the cursor moved back + */ + public long take() { + // spin get next available cursor + long currentCursor = cursor.get(); + long nextCursor = cursor.updateAndGet(old -> old == tail.get() ? old : old + 1); + + // check for safety consideration, it never occurs + Assert.isTrue(nextCursor >= currentCursor, "Curosr can't move back"); + + // trigger padding in an async-mode if reach the threshold + long currentTail = tail.get(); + if (currentTail - nextCursor < paddingThreshold) { + LOGGER.info("Reach the padding threshold:{}. tail:{}, cursor:{}, rest:{}", paddingThreshold, currentTail, + nextCursor, currentTail - nextCursor); + bufferPaddingExecutor.asyncPadding(); + } + + // cursor catch the tail, means that there is no more available UID to take + if (nextCursor == currentCursor) { + rejectedTakeHandler.rejectTakeBuffer(this); + } + + // 1. check next slot flag is CAN_TAKE_FLAG + int nextCursorIndex = calSlotIndex(nextCursor); + Assert.isTrue(flags[nextCursorIndex].get() == CAN_TAKE_FLAG, "Curosr not in can take status"); + + // 2. get UID from next slot + // 3. set next slot flag as CAN_PUT_FLAG. + long uid = slots[nextCursorIndex]; + flags[nextCursorIndex].set(CAN_PUT_FLAG); + + // Note that: Step 2,3 can not swap. If we set flag before get value of slot, the producer may overwrite the + // slot with a new UID, and this may cause the consumer take the UID twice after walk a round the ring + return uid; + } + + /** + * Calculate slot index with the slot sequence (sequence % bufferSize) + */ + protected int calSlotIndex(long sequence) { + return (int) (sequence & indexMask); + } + + /** + * Discard policy for {@link RejectedPutBufferHandler}, we just do logging + */ + protected void discardPutBuffer(RingBuffer ringBuffer, long uid) { + LOGGER.warn("Rejected putting buffer for uid:{}. {}", uid, ringBuffer); + } + + /** + * Policy for {@link RejectedTakeBufferHandler}, throws {@link RuntimeException} after logging + */ + protected void exceptionRejectedTakeBuffer(RingBuffer ringBuffer) { + LOGGER.warn("Rejected take buffer. {}", ringBuffer); + throw new RuntimeException("Rejected take buffer. " + ringBuffer); + } + + /** + * Initialize flags as CAN_PUT_FLAG + */ + private PaddedAtomicLong[] initFlags(int bufferSize) { + PaddedAtomicLong[] flags = new PaddedAtomicLong[bufferSize]; + for (int i = 0; i < bufferSize; i++) { + flags[i] = new PaddedAtomicLong(CAN_PUT_FLAG); + } + + return flags; + } + + /** + * Getters + */ + public long getTail() { + return tail.get(); + } + + public long getCursor() { + return cursor.get(); + } + + public int getBufferSize() { + return bufferSize; + } + + /** + * Setters + */ + public void setBufferPaddingExecutor(BufferPaddingExecutor bufferPaddingExecutor) { + this.bufferPaddingExecutor = bufferPaddingExecutor; + } + + public void setRejectedPutHandler(RejectedPutBufferHandler rejectedPutHandler) { + this.rejectedPutHandler = rejectedPutHandler; + } + + public void setRejectedTakeHandler(RejectedTakeBufferHandler rejectedTakeHandler) { + this.rejectedTakeHandler = rejectedTakeHandler; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("RingBuffer [bufferSize=").append(bufferSize) + .append(", tail=").append(tail) + .append(", cursor=").append(cursor) + .append(", paddingThreshold=").append(paddingThreshold).append("]"); + + return builder.toString(); + } + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/uid/exception/UidGenerateException.java b/modules/core/src/main/java/com/bytedesk/core/uid/exception/UidGenerateException.java new file mode 100644 index 0000000000..1878b608c5 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/uid/exception/UidGenerateException.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2017 Baidu, Inc. All Rights Reserve. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.bytedesk.core.uid.exception; + +/** + * UidGenerateException + * + * @author yutianbao + */ +public class UidGenerateException extends RuntimeException { + + /** + * Serial Version UID + */ + private static final long serialVersionUID = -27048199131316992L; + + /** + * Default constructor + */ + public UidGenerateException() { + super(); + } + + /** + * Constructor with message & cause + * + * @param message + * @param cause + */ + public UidGenerateException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Constructor with message + * + * @param message + */ + public UidGenerateException(String message) { + super(message); + } + + /** + * Constructor with message format + * + * @param msgFormat + * @param args + */ + public UidGenerateException(String msgFormat, Object... args) { + super(String.format(msgFormat, args)); + } + + /** + * Constructor with cause + * + * @param cause + */ + public UidGenerateException(Throwable cause) { + super(cause); + } + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/uid/impl/BitsAllocator.java b/modules/core/src/main/java/com/bytedesk/core/uid/impl/BitsAllocator.java new file mode 100644 index 0000000000..a1c964a0f2 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/uid/impl/BitsAllocator.java @@ -0,0 +1,110 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2021-02-24 15:52:39 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-07 15:37:54 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +/* + * Copyright (c) 2017 Baidu, Inc. All Rights Reserve. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.bytedesk.core.uid.impl; + +import org.springframework.util.Assert; + +import lombok.Data; +import lombok.ToString; + +/** + * Allocate 64 bits for the UID(long)
    + * sign (fixed 1bit) -> deltaSecond -> workerId -> sequence(within the same second) + * + * @author yutianbao + */ +@ToString +@Data +public class BitsAllocator { + /** + * Total 64 bits + */ + public static final int TOTAL_BITS = 1 << 6; + + /** + * Bits for [sign-> second-> workId-> sequence] + */ + private int signBits = 1; + private final int timestampBits; + private final int workerIdBits; + private final int sequenceBits; + + /** + * Max value for workId & sequence + */ + private final long maxDeltaSeconds; + private final long maxWorkerId; + private final long maxSequence; + + /** + * Shift for timestamp & workerId + */ + private final int timestampShift; + private final int workerIdShift; + + /** + * Constructor with timestampBits, workerIdBits, sequenceBits
    + * The highest bit used for sign, so 63 bits for timestampBits, workerIdBits, sequenceBits + */ + public BitsAllocator(int timestampBits, int workerIdBits, int sequenceBits) { + // make sure allocated 64 bits + int allocateTotalBits = signBits + timestampBits + workerIdBits + sequenceBits; + Assert.isTrue(allocateTotalBits <= TOTAL_BITS, "allocate larger than 64 bits"); + + // initialize bits + this.timestampBits = timestampBits; + this.workerIdBits = workerIdBits; + this.sequenceBits = sequenceBits; + + // initialize max value + this.maxDeltaSeconds = ~(-1L << timestampBits); + this.maxWorkerId = ~(-1L << workerIdBits); + this.maxSequence = ~(-1L << sequenceBits); + + // initialize shift + this.timestampShift = workerIdBits + sequenceBits; + this.workerIdShift = sequenceBits; + } + + /** + * Allocate bits for UID according to delta seconds & workerId & sequence
    + * Note that: The highest bit will always be 0 for sign + * + * @param deltaSeconds + * @param workerId + * @param sequence + * @return + */ + public long allocate(long deltaSeconds, long workerId, long sequence) { + return (deltaSeconds << timestampShift) | (workerId << workerIdShift) | sequence; + } + + +} \ No newline at end of file diff --git a/modules/core/src/main/java/com/bytedesk/core/uid/impl/CachedUidGenerator.java b/modules/core/src/main/java/com/bytedesk/core/uid/impl/CachedUidGenerator.java new file mode 100644 index 0000000000..eb194ec317 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/uid/impl/CachedUidGenerator.java @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2017 Baidu, Inc. All Rights Reserve. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.bytedesk.core.uid.impl; + +import java.util.ArrayList; +import java.util.List; + +import com.bytedesk.core.uid.UidGeneratorService; +import com.bytedesk.core.uid.exception.UidGenerateException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.util.Assert; + +import com.bytedesk.core.uid.buffer.BufferPaddingExecutor; +import com.bytedesk.core.uid.buffer.RejectedPutBufferHandler; +import com.bytedesk.core.uid.buffer.RejectedTakeBufferHandler; +import com.bytedesk.core.uid.buffer.RingBuffer; + +/** + * Represents a cached implementation of {@link UidGeneratorService} extends + * from {@link DefaultUidGenerator}, based on a lock free {@link RingBuffer}

    + *

    + * The spring properties you can specified as below:
    + *

  • boostPower: RingBuffer size boost for a power of 2, Sample: boostPower is 3, it means the buffer size + * will be ({@link BitsAllocator#getMaxSequence()} + 1) << + * {@link #boostPower}, Default as {@value #DEFAULT_BOOST_POWER} + *
  • paddingFactor: Represents a percent value of (0 - 100). When the count of rest available UIDs reach the + * threshold, it will trigger padding buffer. Default as{@link RingBuffer#DEFAULT_PADDING_PERCENT} + * Sample: paddingFactor=20, bufferSize=1000 -> threshold=1000 * 20 /100, padding buffer will be triggered when tail-cursorscheduleInterval: Padding buffer in a schedule, specify padding buffer interval, Unit as second + *
  • rejectedPutBufferHandler: Policy for rejected put buffer. Default as discard put request, just do logging + *
  • rejectedTakeBufferHandler: Policy for rejected take buffer. Default as throwing up an exception + * + * @author yutianbao + * @author wujun + */ +@ConfigurationProperties(prefix = "bytedesk.uid.cached-uid-generator") +public class CachedUidGenerator extends DefaultUidGenerator implements DisposableBean { + private static final Logger LOGGER = LoggerFactory.getLogger(CachedUidGenerator.class); + private static final int DEFAULT_BOOST_POWER = 3; + + // --------------------- 配置属性 begin --------------------- + /** + * RingBuffer size扩容参数, 可提高UID生成的吞吐量. + * 默认:3, 原bufferSize=8192, 扩容后bufferSize= 8192 << 3 = 65536 + */ + private int boostPower = DEFAULT_BOOST_POWER; + /** + * 指定何时向RingBuffer中填充UID, 取值为百分比(0, 100), 默认为50 + * 举例: bufferSize=1024, paddingFactor=50 -> threshold=1024 * 50 / 100 = 512. + * 当环上可用UID数量 < 512时, 将自动对RingBuffer进行填充补全 + */ + private int paddingFactor = RingBuffer.DEFAULT_PADDING_PERCENT; + /** + * 另外一种RingBuffer填充时机, 在Schedule线程中, 周期性检查填充 + * 默认:不配置此项, 即不使用Schedule线程. 如需使用, 请指定Schedule线程时间间隔, 单位:秒 + */ + private Long scheduleInterval; + // --------------------- 配置属性 end ----------------------- + + /** 拒绝策略: 当环已满, 无法继续填充时 + 默认无需指定, 将丢弃Put操作, 仅日志记录. 如有特殊需求, 请实现RejectedPutBufferHandler接口(支持Lambda表达式)并以@Autowired方式注入 */ + @Autowired(required = false) + private RejectedPutBufferHandler rejectedPutBufferHandler; + + /** 拒绝策略: 当环已空, 无法继续获取时 + 默认无需指定, 将记录日志, 并抛出UidGenerateException异常. 如有特殊需求, 请实现RejectedTakeBufferHandler接口(支持Lambda表达式)并以@Autowired方式注入 */ + @Autowired(required = false) + private RejectedTakeBufferHandler rejectedTakeBufferHandler; + + /** + * RingBuffer + */ + private RingBuffer ringBuffer; + private BufferPaddingExecutor bufferPaddingExecutor; + + public CachedUidGenerator(UidProperties uidProperties) { + super(uidProperties); + } + + @Override + public void afterPropertiesSet() throws Exception { + // initialize workerId & bitsAllocator + super.afterPropertiesSet(); + + // initialize RingBuffer & RingBufferPaddingExecutor + this.initRingBuffer(); + LOGGER.info("Initialized RingBuffer successfully."); + } + + @Override + public long getUID() { + try { + return ringBuffer.take(); + } catch (Exception e) { + LOGGER.error("Generate unique id exception. ", e); + throw new UidGenerateException(e); + } + } + + @Override + public String parseUID(long uid) { + return super.parseUID(uid); + } + + @Override + public void destroy() throws Exception { + bufferPaddingExecutor.shutdown(); + } + + /** + * Get the UIDs in the same specified second under the max sequence + * + * @param currentSecond + * @return UID list, size of {@link BitsAllocator#getMaxSequence()} + 1 + */ + protected List nextIdsForOneSecond(long currentSecond) { + // Initialize result list size of (max sequence + 1) + int listSize = (int) bitsAllocator.getMaxSequence() + 1; + List uidList = new ArrayList<>(listSize); + + // Allocate the first sequence of the second, the others can be calculated with the offset + long firstSeqUid = bitsAllocator.allocate(currentSecond - uidProperties.getEpochSeconds(), workerId, 0L); + for (int offset = 0; offset < listSize; offset++) { + uidList.add(firstSeqUid + offset); + } + + return uidList; + } + + /** + * Initialize RingBuffer & RingBufferPaddingExecutor + */ + private void initRingBuffer() { + // initialize RingBuffer + int bufferSize = ((int) bitsAllocator.getMaxSequence() + 1) << boostPower; + this.ringBuffer = new RingBuffer(bufferSize, paddingFactor); + LOGGER.info("Initialized ring buffer size:{}, paddingFactor:{}", bufferSize, paddingFactor); + + // initialize RingBufferPaddingExecutor + boolean usingSchedule = (scheduleInterval != null); + this.bufferPaddingExecutor = new BufferPaddingExecutor(ringBuffer, this::nextIdsForOneSecond, usingSchedule); + if (usingSchedule) { + bufferPaddingExecutor.setScheduleInterval(scheduleInterval); + } + + LOGGER.info("Initialized BufferPaddingExecutor. Using schdule:{}, interval:{}", usingSchedule, scheduleInterval); + + // set rejected put/take handle policy + this.ringBuffer.setBufferPaddingExecutor(bufferPaddingExecutor); + if (rejectedPutBufferHandler != null) { + this.ringBuffer.setRejectedPutHandler(rejectedPutBufferHandler); + } + if (rejectedTakeBufferHandler != null) { + this.ringBuffer.setRejectedTakeHandler(rejectedTakeBufferHandler); + } + + // fill in all slots of the RingBuffer + bufferPaddingExecutor.paddingBuffer(); + + // start buffer padding threads + bufferPaddingExecutor.start(); + } + + /** + * Setters for spring property + */ + public void setBoostPower(int boostPower) { + Assert.isTrue(boostPower > 0, "Boost power must be positive!"); + this.boostPower = boostPower; + } + + public void setPaddingFactor(int paddingFactor) { + Assert.isTrue(paddingFactor > 0 && paddingFactor < 100, "padding factor must be in (0, 100)!"); + this.paddingFactor = paddingFactor; + } + + public void setRejectedPutBufferHandler(RejectedPutBufferHandler rejectedPutBufferHandler) { + Assert.notNull(rejectedPutBufferHandler, "RejectedPutBufferHandler can't be null!"); + this.rejectedPutBufferHandler = rejectedPutBufferHandler; + } + + public void setRejectedTakeBufferHandler(RejectedTakeBufferHandler rejectedTakeBufferHandler) { + Assert.notNull(rejectedTakeBufferHandler, "RejectedTakeBufferHandler can't be null!"); + this.rejectedTakeBufferHandler = rejectedTakeBufferHandler; + } + + public void setScheduleInterval(long scheduleInterval) { + Assert.isTrue(scheduleInterval > 0, "Schedule interval must positive!"); + this.scheduleInterval = scheduleInterval; + } + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/uid/impl/DefaultUidGenerator.java b/modules/core/src/main/java/com/bytedesk/core/uid/impl/DefaultUidGenerator.java new file mode 100644 index 0000000000..d8ae2a040d --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/uid/impl/DefaultUidGenerator.java @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2017 Baidu, Inc. All Rights Reserve. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.bytedesk.core.uid.impl; + +import java.util.concurrent.TimeUnit; + +import com.bytedesk.core.uid.UidGeneratorService; +import com.bytedesk.core.uid.exception.UidGenerateException; +import com.bytedesk.core.uid.worker.WorkerIdAssigner; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.InitializingBean; + +import org.springframework.beans.factory.annotation.Autowired; + +/** + * Represents an implementation of {@link UidGeneratorService} + *

    + * The unique id has 64bits (long), default allocated as blow:
    + *

  • sign: The highest bit is 0 + *
  • delta seconds: The next 28 bits, represents delta seconds since a customer epoch(2016-05-20 00:00:00.000). + * Supports about 8.7 years until to 2024-11-20 21:24:16 + *
  • worker id: The next 22 bits, represents the worker's id which assigns based on database, max id is about 420W + *
  • sequence: The next 13 bits, represents a sequence within the same second, max for 8192/s

    + *

    + * The {@link DefaultUidGenerator#parseUID(long)} is a tool method to parse the bits + *

    + *

    {@code
    + * +------+----------------------+----------------+-----------+
    + * | sign |     delta seconds    | worker node id | sequence  |
    + * +------+----------------------+----------------+-----------+
    + *   1bit          28bits              22bits         13bits
    + * }
    + *

    + * You can also specified the bits by Spring property setting. + *

  • timeBits: default as 28 + *
  • workerBits: default as 22 + *
  • seqBits: default as 13 + *
  • epochStr: Epoch date string format 'yyyy-MM-dd'. Default as '2016-05-20'

    + *

    + * Note that: The total bits must be 64 -1 + * + * @author yutianbao + * @author wujun + */ +@Slf4j +public class DefaultUidGenerator implements UidGeneratorService, InitializingBean { + // private static final Logger log = LoggerFactory.getLogger(DefaultUidGenerator.class); + + protected UidProperties uidProperties; + + /** + * Bit分配器,Stable fields after spring bean initializing + */ + protected BitsAllocator bitsAllocator; + protected long workerId; + + /** + * Volatile fields caused by nextId() + */ + protected long sequence = 0L; + protected long lastSecond = -1L; + + /** + * Spring property + */ + @Autowired + protected WorkerIdAssigner workerIdAssigner; + + public DefaultUidGenerator(UidProperties uidProperties) { + this.uidProperties = uidProperties; + } + + @Override + public void afterPropertiesSet() throws Exception { + // initialize bits allocator + bitsAllocator = new BitsAllocator(uidProperties.getTimeBits(), uidProperties.getWorkerBits(), uidProperties.getSeqBits()); + + // initialize worker id + workerId = workerIdAssigner.assignWorkerId(); + if (workerId > bitsAllocator.getMaxWorkerId()) { + log.error("Worker id " + workerId + " exceeds the max " + bitsAllocator.getMaxWorkerId()); + workerId = workerId % bitsAllocator.getMaxWorkerId(); + log.info("new Worker id = " + workerId); + } + + log.info("Initialized bits(1, {}, {}, {}) for workerID:{}", uidProperties.getTimeBits(), uidProperties.getWorkerBits(), uidProperties.getSeqBits(), workerId); + } + + @Override + public long getUID() throws UidGenerateException { + try { + return nextId(); + } catch (Exception e) { + log.error("Generate unique id exception. ", e); + throw new UidGenerateException(e); + } + } + + @Override + public String parseUID(long uid) { + long totalBits = BitsAllocator.TOTAL_BITS; + long workerIdBits = bitsAllocator.getWorkerIdBits(); + long sequenceBits = bitsAllocator.getSequenceBits(); + + // parse UID + long sequence = (uid << (totalBits - sequenceBits)) >>> (totalBits - sequenceBits); + long workerId = (uid << (totalBits - workerIdBits - sequenceBits)) >>> (totalBits - workerIdBits); + // long deltaSeconds = uid >>> (workerIdBits + sequenceBits); + + // Date thatTime = new Date(TimeUnit.SECONDS.toMillis(uidProperties.getEpochSeconds() + deltaSeconds)); + // String thatTimeStr = DateUtils.formatByDateTimePattern(thatTime); + + // format as string + return String.format("{\"UID\":\"%d\",\"timestamp\":\"%s\",\"workerId\":\"%d\",\"sequence\":\"%d\"}", + uid, + "", // thatTimeStr, + workerId, + sequence); + } + + /** + * Get UID + * + * @return UID + * @throws UidGenerateException in the case: Clock moved backwards; Exceeds the max timestamp + */ + protected synchronized long nextId() { + long currentSecond = getCurrentSecond(); + + // Clock moved backwards, refuse to generate uid + if (currentSecond < lastSecond) { + long refusedSeconds = lastSecond - currentSecond; + if (uidProperties.isEnableBackward()) { + if (refusedSeconds <= uidProperties.getMaxBackwardSeconds()) { + log.error("Clock moved backwards. wait for %d seconds", refusedSeconds); + while (currentSecond < lastSecond) { + currentSecond = getCurrentSecond(); + } + } else { + workerId = workerIdAssigner.assignFakeWorkerId(); + log.error("Clock moved backwards. Assigned New WorkerId %d", workerId); + if (workerId > bitsAllocator.getMaxWorkerId()) { + log.error("Worker id " + workerId + " exceeds the max " + bitsAllocator.getMaxWorkerId()); + workerId = workerId % bitsAllocator.getMaxWorkerId(); + log.info("new Worker id = " + workerId); + } + } + } else { + throw new UidGenerateException("Clock moved backwards. Refusing for %d seconds", refusedSeconds); + } + } + + // At the same second, increase sequence + if (currentSecond == lastSecond) { + sequence = (sequence + 1) & bitsAllocator.getMaxSequence(); + // Exceed the max sequence, we wait the next second to generate uid + if (sequence == 0) { + currentSecond = getNextSecond(lastSecond); + } + + // At the different second, sequence restart from zero + } else { + sequence = 0L; + } + + lastSecond = currentSecond; + + // Allocate bits for UID + return bitsAllocator.allocate(currentSecond - uidProperties.getEpochSeconds(), workerId, sequence); + } + + /** + * Get next second + */ + private long getNextSecond(long lastTimestamp) { + long timestamp = getCurrentSecond(); + while (timestamp <= lastTimestamp) { + timestamp = getCurrentSecond(); + } + + return timestamp; + } + + /** + * Get current second + */ + private long getCurrentSecond() { + long currentSecond = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()); + if (currentSecond - uidProperties.getEpochSeconds() > bitsAllocator.getMaxDeltaSeconds()) { + throw new UidGenerateException("Timestamp bits is exhausted. Refusing UID generate. Now: " + currentSecond); + } + + return currentSecond; + } + + /** + * Setters for spring property + */ + public void setWorkerIdAssigner(WorkerIdAssigner workerIdAssigner) { + this.workerIdAssigner = workerIdAssigner; + } +} diff --git a/modules/core/src/main/java/com/bytedesk/core/uid/impl/UidProperties.java b/modules/core/src/main/java/com/bytedesk/core/uid/impl/UidProperties.java new file mode 100644 index 0000000000..eca659652b --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/uid/impl/UidProperties.java @@ -0,0 +1,75 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2021-02-24 15:52:39 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-07 15:40:50 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.uid.impl; + +import lombok.Data; + +import java.util.concurrent.TimeUnit; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * UID 的配置 + * + * @author wujun + * @date 2019.02.20 10:31 + */ +@Data +@ConfigurationProperties(prefix = "bytedesk.uid") +public class UidProperties { + + /** + * 时间增量值占用位数。当前时间相对于时间基点的增量值,单位为秒 + */ + private int timeBits = 30; + + /** + * 工作机器ID占用的位数 + */ + private int workerBits = 16; + + /** + * 序列号占用的位数 + */ + private int seqBits = 7; + + /** + * 时间基点. 例如 2019-02-20 (毫秒: 1550592000000) + */ + private String epochStr = "2019-02-20"; + + /** + * 时间基点对应的毫秒数 + */ + private long epochSeconds = TimeUnit.MILLISECONDS.toSeconds(1550592000000L); + + /** + * 是否容忍时钟回拨, 默认:true + */ + private boolean enableBackward = true; + + /** + * 时钟回拨最长容忍时间(秒) + */ + private long maxBackwardSeconds = 1L; + + // public void setEpochStr(String epochStr) { + // if (StringUtils.hasText(epochStr)) { + // this.epochStr = epochStr; + // this.epochSeconds = TimeUnit.MILLISECONDS.toSeconds(DateUtils.parseByDayPattern(epochStr).getTime()); + // } + // } + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/uid/readme.md b/modules/core/src/main/java/com/bytedesk/core/uid/readme.md new file mode 100644 index 0000000000..55daa45f10 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/uid/readme.md @@ -0,0 +1,17 @@ + +# uidgenerator-spring-boot-starter + +- adapted to spring boot3 [uid-generator-spring-boot-starter](https://github.com/wujun234/uid-generator-spring-boot-starter) diff --git a/modules/core/src/main/java/com/bytedesk/core/uid/utils/DateUtils.java b/modules/core/src/main/java/com/bytedesk/core/uid/utils/DateUtils.java new file mode 100644 index 0000000000..58d645af38 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/uid/utils/DateUtils.java @@ -0,0 +1,122 @@ +// /* +// * Copyright (c) 2017 Baidu, Inc. All Rights Reserve. +// * +// * Licensed under the Apache License, Version 2.0 (the "License"); +// * you may not use this file except in compliance with the License. +// * You may obtain a copy of the License at +// * +// * http://www.apache.org/licenses/LICENSE-2.0 +// * +// * Unless required by applicable law or agreed to in writing, software +// * distributed under the License is distributed on an "AS IS" BASIS, +// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// * See the License for the specific language governing permissions and +// * limitations under the License. +// */ +// package com.bytedesk.core.uid.utils; + +// import java.text.ParseException; +// import java.util.Calendar; +// import java.util.Date; + +// import org.apache.commons.lang3.time.DateFormatUtils; + + +// /** +// * DateUtils provides date formatting, parsing +// * +// * @author yutianbao +// */ +// public abstract class DateUtils { +// /** +// * Patterns +// */ +// public static final String DAY_PATTERN = "yyyy-MM-dd"; +// public static final String DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss"; +// public static final String DATETIME_MS_PATTERN = "yyyy-MM-dd HH:mm:ss.SSS"; + +// public static final Date DEFAULT_DATE = DateUtils.parseByDayPattern("1970-01-01"); + +// /** +// * Parse date by 'yyyy-MM-dd' pattern +// * +// * @param str +// * @return +// */ +// public static Date parseByDayPattern(String str) { +// return parseDate(str, DAY_PATTERN); +// } + +// /** +// * Parse date by 'yyyy-MM-dd HH:mm:ss' pattern +// * +// * @param str +// * @return +// */ +// public static Date parseByDateTimePattern(String str) { +// return parseDate(str, DATETIME_PATTERN); +// } + +// /** +// * Parse date without Checked exception +// * +// * @param str +// * @param pattern +// * @return +// * @throws RuntimeException when ParseException occurred +// */ +// public static Date parseDate(String str, String pattern) { +// try { +// return parseDate(str, new String[]{pattern}); +// } catch (ParseException e) { +// throw new RuntimeException(e); +// } +// } + +// /** +// * Format date into string +// * +// * @param date +// * @param pattern +// * @return +// */ +// public static String formatDate(Date date, String pattern) { +// return DateFormatUtils.format(date, pattern); +// } + +// /** +// * Format date by 'yyyy-MM-dd' pattern +// * +// * @param date +// * @return +// */ +// public static String formatByDayPattern(Date date) { +// if (date != null) { +// return DateFormatUtils.format(date, DAY_PATTERN); +// } else { +// return null; +// } +// } + +// /** +// * Format date by 'yyyy-MM-dd HH:mm:ss' pattern +// * +// * @param date +// * @return +// */ +// public static String formatByDateTimePattern(Date date) { +// return DateFormatUtils.format(date, DATETIME_PATTERN); +// } + +// /** +// * Get current day using format date by 'yyyy-MM-dd HH:mm:ss' pattern +// * +// * @return +// * @author yebo +// */ +// public static String getCurrentDayByDayPattern() { +// Calendar cal = Calendar.getInstance(); +// return formatByDayPattern(cal.getTime()); +// } + +// } diff --git a/modules/core/src/main/java/com/bytedesk/core/uid/utils/DockerUtils.java b/modules/core/src/main/java/com/bytedesk/core/uid/utils/DockerUtils.java new file mode 100644 index 0000000000..560a97bdcb --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/uid/utils/DockerUtils.java @@ -0,0 +1,104 @@ +// /* +// * Copyright (c) 2017 Baidu, Inc. All Rights Reserve. +// * +// * Licensed under the Apache License, Version 2.0 (the "License"); +// * you may not use this file except in compliance with the License. +// * You may obtain a copy of the License at +// * +// * http://www.apache.org/licenses/LICENSE-2.0 +// * +// * Unless required by applicable law or agreed to in writing, software +// * distributed under the License is distributed on an "AS IS" BASIS, +// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// * See the License for the specific language governing permissions and +// * limitations under the License. +// */ +// package com.bytedesk.core.uid.utils; + +// import org.apache.commons.lang.StringUtils; +// import org.slf4j.Logger; +// import org.slf4j.LoggerFactory; + +// /** +// * DockerUtils +// * +// * @author yutianbao +// */ +// public abstract class DockerUtils { +// private static final Logger LOGGER = LoggerFactory.getLogger(DockerUtils.class); + +// /** Environment param keys */ +// private static final String ENV_KEY_HOST = "JPAAS_HOST"; +// private static final String ENV_KEY_PORT = "JPAAS_HTTP_PORT"; +// private static final String ENV_KEY_PORT_ORIGINAL = "JPAAS_HOST_PORT_8080"; + +// /** Docker host & port */ +// private static String DOCKER_HOST = ""; +// private static String DOCKER_PORT = ""; + +// /** Whether is docker */ +// private static boolean IS_DOCKER; + +// static { +// retrieveFromEnv(); +// } + +// /** +// * Retrieve docker host +// * +// * @return empty string if not a docker +// */ +// public static String getDockerHost() { +// return DOCKER_HOST; +// } + +// /** +// * Retrieve docker port +// * +// * @return empty string if not a docker +// */ +// public static String getDockerPort() { +// return DOCKER_PORT; +// } + +// /** +// * Whether a docker +// * +// * @return +// */ +// public static boolean isDocker() { +// return IS_DOCKER; +// } + +// /** +// * Retrieve host & port from environment +// */ +// private static void retrieveFromEnv() { +// // retrieve host & port from environment +// DOCKER_HOST = System.getenv(ENV_KEY_HOST); +// DOCKER_PORT = System.getenv(ENV_KEY_PORT); + +// // not found from 'JPAAS_HTTP_PORT', then try to find from 'JPAAS_HOST_PORT_8080' +// if (StringUtils.isBlank(DOCKER_PORT)) { +// DOCKER_PORT = System.getenv(ENV_KEY_PORT_ORIGINAL); +// } + +// boolean hasEnvHost = StringUtils.isNotBlank(DOCKER_HOST); +// boolean hasEnvPort = StringUtils.isNotBlank(DOCKER_PORT); + +// // docker can find both host & port from environment +// if (hasEnvHost && hasEnvPort) { +// IS_DOCKER = true; + +// // found nothing means not a docker, maybe an actual machine +// } else if (!hasEnvHost && !hasEnvPort) { +// IS_DOCKER = false; + +// } else { +// LOGGER.error("Missing host or port from env for Docker. host:{}, port:{}", DOCKER_HOST, DOCKER_PORT); +// throw new RuntimeException( +// "Missing host or port from env for Docker. host:" + DOCKER_HOST + ", port:" + DOCKER_PORT); +// } +// } + +// } diff --git a/modules/core/src/main/java/com/bytedesk/core/uid/utils/EnumUtils.java b/modules/core/src/main/java/com/bytedesk/core/uid/utils/EnumUtils.java new file mode 100644 index 0000000000..4174c062f3 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/uid/utils/EnumUtils.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2017 Baidu, Inc. All Rights Reserve. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.bytedesk.core.uid.utils; + +import org.springframework.util.Assert; + +/** + * EnumUtils provides the operations for {@link ValuedEnum} such as Parse, value of... + * + * @author yutianbao + */ +public abstract class EnumUtils { + + /** + * Parse the bounded value into ValuedEnum + * + * @param clz + * @param value + * @return + */ + public static , V> T parse(Class clz, V value) { + Assert.notNull(clz, "clz can not be null"); + if (value == null) { + return null; + } + + for (T t : clz.getEnumConstants()) { + if (value.equals(t.value())) { + return t; + } + } + return null; + } + + /** + * Null-safe valueOf function + * + * @param + * @param enumType + * @param name + * @return + */ + public static > T valueOf(Class enumType, String name) { + if (name == null) { + return null; + } + + return Enum.valueOf(enumType, name); + } + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/uid/utils/NamingThreadFactory.java b/modules/core/src/main/java/com/bytedesk/core/uid/utils/NamingThreadFactory.java new file mode 100644 index 0000000000..b6833019be --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/uid/utils/NamingThreadFactory.java @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2017 Baidu, Inc. All Rights Reserve. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.bytedesk.core.uid.utils; + +import java.lang.Thread.UncaughtExceptionHandler; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicLong; + +// import org.apache.commons.lang.ClassUtils; +import org.springframework.util.StringUtils; + +import lombok.extern.slf4j.Slf4j; + +/** + * Named thread in ThreadFactory. If there is no specified name for thread, it + * will auto detect using the invoker classname instead. + * + * @author yutianbao + */ +@Slf4j +public class NamingThreadFactory implements ThreadFactory { + + /** + * Thread name pre + */ + private String name; + /** + * Is daemon thread + */ + private boolean daemon; + /** + * UncaughtExceptionHandler + */ + private UncaughtExceptionHandler uncaughtExceptionHandler; + /** + * Sequences for multi thread name prefix + */ + private final ConcurrentHashMap sequences; + + /** + * Constructors + */ + public NamingThreadFactory() { + this(null, false, null); + } + + public NamingThreadFactory(String name) { + this(name, false, null); + } + + public NamingThreadFactory(String name, boolean daemon) { + this(name, daemon, null); + } + + public NamingThreadFactory(String name, boolean daemon, UncaughtExceptionHandler handler) { + this.name = name; + this.daemon = daemon; + this.uncaughtExceptionHandler = handler; + this.sequences = new ConcurrentHashMap(); + } + + @Override + public Thread newThread(Runnable r) { + Thread thread = new Thread(r); + thread.setDaemon(this.daemon); + + // If there is no specified name for thread, it will auto detect using the invoker classname instead. + // Notice that auto detect may cause some performance overhead + String prefix = this.name; + if (!StringUtils.hasText(prefix)) { + prefix = getInvoker(2); + } + thread.setName(prefix + "-" + getSequence(prefix)); + + // no specified uncaughtExceptionHandler, just do logging. + if (this.uncaughtExceptionHandler != null) { + thread.setUncaughtExceptionHandler(this.uncaughtExceptionHandler); + } else { + thread.setUncaughtExceptionHandler(new UncaughtExceptionHandler() { + @Override + public void uncaughtException(Thread t, Throwable e) { + log.error("unhandled exception in thread: " + t.getId() + ":" + t.getName(), e); + } + }); + } + + return thread; + } + + /** + * Get the method invoker's class name + * + * @param depth + * @return + */ + private String getInvoker(int depth) { + // Exception e = new Exception(); + // StackTraceElement[] stes = e.getStackTrace(); + // if (stes.length > depth) { + // return ClassUtils.getShortClassName(stes[depth].getClassName()); + // } + return getClass().getSimpleName(); + } + + /** + * Get sequence for different naming prefix + * + * @param invoker + * @return + */ + private long getSequence(String invoker) { + AtomicLong r = this.sequences.get(invoker); + if (r == null) { + r = new AtomicLong(0); + AtomicLong previous = this.sequences.putIfAbsent(invoker, r); + if (previous != null) { + r = previous; + } + } + + return r.incrementAndGet(); + } + + /** + * Getters & Setters + */ + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public boolean isDaemon() { + return daemon; + } + + public void setDaemon(boolean daemon) { + this.daemon = daemon; + } + + public UncaughtExceptionHandler getUncaughtExceptionHandler() { + return uncaughtExceptionHandler; + } + + public void setUncaughtExceptionHandler(UncaughtExceptionHandler handler) { + this.uncaughtExceptionHandler = handler; + } + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/uid/utils/NetUtils.java b/modules/core/src/main/java/com/bytedesk/core/uid/utils/NetUtils.java new file mode 100644 index 0000000000..bf00e4e251 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/uid/utils/NetUtils.java @@ -0,0 +1,115 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2021-02-24 15:52:39 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-15 16:48:18 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +/* + * Copyright (c) 2017 Baidu, Inc. All Rights Reserve. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.bytedesk.core.uid.utils; + +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.net.UnknownHostException; +import java.util.Enumeration; + +/** + * NetUtils + * + * @author yutianbao + */ +public abstract class NetUtils { + + /** + * Pre-loaded local address + */ + public static InetAddress localAddress; + + static { + try { + localAddress = getLocalInetAddress(); + } catch (SocketException e) { + // throw new RuntimeException("fail to get local ip."); + } + } + + /** + * Retrieve the first validated local ip address(the Public and LAN ip addresses are validated). + * + * @return the local address + * @throws SocketException the socket exception + */ + public static InetAddress getLocalInetAddress() throws SocketException { + // enumerates all network interfaces + Enumeration enu = NetworkInterface.getNetworkInterfaces(); + + while (enu.hasMoreElements()) { + NetworkInterface ni = enu.nextElement(); + if (ni.isLoopback()) { + continue; + } + + Enumeration addressEnumeration = ni.getInetAddresses(); + while (addressEnumeration.hasMoreElements()) { + InetAddress address = addressEnumeration.nextElement(); + + // ignores all invalidated addresses + if (address.isLinkLocalAddress() || address.isLoopbackAddress() || address.isAnyLocalAddress()) { + continue; + } + + return address; + } + } + + // throw new RuntimeException("No validated local address!"); + try { + return InetAddress.getByName("127.0.0.1"); + } catch (UnknownHostException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + return null; + } + + + public static InetAddress getLocalAddressInstance() { + return localAddress; + } + /** + * Retrieve local address + * + * @return the string local address + */ + public static String getLocalAddress() { + return localAddress.getHostAddress(); + } + + public static String getHostname() { + return localAddress.getHostAddress(); + } + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/uid/utils/PaddedAtomicLong.java b/modules/core/src/main/java/com/bytedesk/core/uid/utils/PaddedAtomicLong.java new file mode 100644 index 0000000000..7ef63aea2c --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/uid/utils/PaddedAtomicLong.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2017 Baidu, Inc. All Rights Reserve. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.bytedesk.core.uid.utils; + +import java.util.concurrent.atomic.AtomicLong; + +/** + * Represents a padded {@link AtomicLong} to prevent the FalseSharing problem

    + * + * The CPU cache line commonly be 64 bytes, here is a sample of cache line after padding:
    + * 64 bytes = 8 bytes (object reference) + 6 * 8 bytes (padded long) + 8 bytes (a long value) + * + * @author yutianbao + */ +public class PaddedAtomicLong extends AtomicLong { + private static final long serialVersionUID = -3415778863941386253L; + + /** Padded 6 long (48 bytes) */ + public volatile long p1, p2, p3, p4, p5, p6 = 7L; + + /** + * Constructors from {@link AtomicLong} + */ + public PaddedAtomicLong() { + super(); + } + + public PaddedAtomicLong(long initialValue) { + super(initialValue); + } + + /** + * To prevent GC optimizations for cleaning unused padded references + */ + public long sumPaddingToPreventOptimization() { + return p1 + p2 + p3 + p4 + p5 + p6; + } + +} \ No newline at end of file diff --git a/modules/core/src/main/java/com/bytedesk/core/uid/utils/ValuedEnum.java b/modules/core/src/main/java/com/bytedesk/core/uid/utils/ValuedEnum.java new file mode 100644 index 0000000000..c7f160442b --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/uid/utils/ValuedEnum.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2017 Baidu, Inc. All Rights Reserve. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.bytedesk.core.uid.utils; + +/** + * {@code ValuedEnum} defines an enumeration which is bounded to a value, you + * may implements this interface when you defines such kind of enumeration, that + * you can use {@link EnumUtils} to simplify parse and valueOf operation. + * + * @author yutianbao + */ +public interface ValuedEnum { + /** + * get value + * + * @return T + */ + T value(); +} diff --git a/modules/core/src/main/java/com/bytedesk/core/uid/worker/DisposableWorkerIdAssigner.java b/modules/core/src/main/java/com/bytedesk/core/uid/worker/DisposableWorkerIdAssigner.java new file mode 100644 index 0000000000..d295c64253 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/uid/worker/DisposableWorkerIdAssigner.java @@ -0,0 +1,120 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2021-02-24 15:52:39 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-09 16:59:02 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +/* + * Copyright (c) 2017 Baidu, Inc. All Rights Reserve. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.bytedesk.core.uid.worker; + +import com.bytedesk.core.uid.UidGenerator; +import com.bytedesk.core.uid.UidGereratorRepository; +// import com.bytedesk.core.uid.utils.DockerUtils; +import com.bytedesk.core.uid.utils.NetUtils; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +// import org.apache.commons.lang.math.RandomUtils; +// import org.slf4j.Logger; +// import org.slf4j.LoggerFactory; +import org.springframework.transaction.annotation.Transactional; + +/** + * Represents an implementation of {@link WorkerIdAssigner}, + * the worker id will be discarded after assigned to the UidGenerator + * + * @author yutianbao + */ +public class DisposableWorkerIdAssigner implements WorkerIdAssigner { + + // @Value("${server.host}") + // private String host; + + @Value("${server.port}") + private String port; + + // @Resource + @Autowired + private UidGereratorRepository workerNodeDAO; + + /** + * Assign worker id base on database.

    + * If there is host name & port in the environment, we considered that the node runs in Docker container
    + * Otherwise, the node runs on an actual machine. + * + * @return assigned worker id + */ + @Transactional(rollbackFor = Exception.class) + @Override + public long assignWorkerId() { + // build worker node entity + UidGenerator workerNodeEntity = buildWorkerNode(); + + UidGenerator oldWorkerNode = workerNodeDAO + .findByHostAndPort(workerNodeEntity.getHost(), workerNodeEntity.getPort()); + if (null != oldWorkerNode) { + return oldWorkerNode.getId(); + } + + // add worker node for new (ignore the same IP + PORT) + workerNodeDAO.save(workerNodeEntity); + // LOGGER.info("Add worker node:" + workerNodeEntity); + + return workerNodeEntity.getId(); + } + + @Transactional(rollbackFor = Exception.class) + @Override + public long assignFakeWorkerId() { + return buildFakeWorkerNode().getId(); + } + + /** + * Build worker node entity by IP and PORT + */ + private UidGenerator buildWorkerNode() { + UidGenerator workerNodeEntity = new UidGenerator(); + + workerNodeEntity.setType(WorkerNodeType.ACTUAL.value()); + workerNodeEntity.setHost(NetUtils.getLocalAddress()); + // workerNodeEntity.setPort(System.currentTimeMillis() + "-" + new Random().nextInt(100000)); + // workerNodeEntity.setHost(host); + workerNodeEntity.setPort(port); + + return workerNodeEntity; + } + + private UidGenerator buildFakeWorkerNode() { + UidGenerator workerNodeEntity = new UidGenerator(); + workerNodeEntity.setType(WorkerNodeType.FAKE.value()); + workerNodeEntity.setHost(NetUtils.getLocalAddress()); + // workerNodeEntity.setPort(System.currentTimeMillis() + "-" + new Random().nextInt(100000)); + // workerNodeEntity.setHost(host); + workerNodeEntity.setPort(port); + + return workerNodeEntity; + } +} diff --git a/modules/core/src/main/java/com/bytedesk/core/uid/worker/WorkerIdAssigner.java b/modules/core/src/main/java/com/bytedesk/core/uid/worker/WorkerIdAssigner.java new file mode 100644 index 0000000000..1af46c991b --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/uid/worker/WorkerIdAssigner.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2017 Baidu, Inc. All Rights Reserve. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.bytedesk.core.uid.worker; + +import com.bytedesk.core.uid.impl.DefaultUidGenerator; + +/** + * Represents a worker id assigner for {@link DefaultUidGenerator} + * + * @author yutianbao + */ +public interface WorkerIdAssigner { + + /** + * Assign worker id for {@link DefaultUidGenerator} + * + * @return assigned worker id + */ + long assignWorkerId(); + + /** + * Assign fake worker id + * + * @return assigned fake worker id + */ + long assignFakeWorkerId(); + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/uid/worker/WorkerNodeType.java b/modules/core/src/main/java/com/bytedesk/core/uid/worker/WorkerNodeType.java new file mode 100644 index 0000000000..84eba87b22 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/uid/worker/WorkerNodeType.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2017 Baidu, Inc. All Rights Reserve. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.bytedesk.core.uid.worker; + +import com.bytedesk.core.uid.utils.ValuedEnum; + +/** + * WorkerNodeType + *

  • CONTAINER: Such as Docker + *
  • ACTUAL: Actual machine + * + * @author yutianbao + */ +public enum WorkerNodeType implements ValuedEnum { + + /** + * 容器 + */ + CONTAINER(1), + /** + * 物理机 + */ + ACTUAL(2), + /** + * 虚拟 + */ + FAKE(3); + + /** + * Lock type + */ + private final Integer type; + + /** + * Constructor with field of type + */ + private WorkerNodeType(Integer type) { + this.type = type; + } + + @Override + public Integer value() { + return type; + } + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/upload/UploadService.java b/modules/core/src/main/java/com/bytedesk/core/upload/UploadService.java index 8457309c8b..a381f6a9b5 100755 --- a/modules/core/src/main/java/com/bytedesk/core/upload/UploadService.java +++ b/modules/core/src/main/java/com/bytedesk/core/upload/UploadService.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-03-15 11:35:53 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-03-23 13:39:01 + * @LastEditTime: 2024-04-17 11:33:34 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -94,7 +94,7 @@ public class UploadService { return rootLocation.resolve(filename); } - @SuppressWarnings("null") + // @SuppressWarnings("null") public Resource loadAsResource(String filename) { try { Path file = load(filename); diff --git a/modules/core/src/main/java/com/bytedesk/core/utils/ApplicationContextHolder.java b/modules/core/src/main/java/com/bytedesk/core/utils/ApplicationContextHolder.java new file mode 100644 index 0000000000..654aad1793 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/utils/ApplicationContextHolder.java @@ -0,0 +1,32 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-22 23:32:19 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-22 23:32:22 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.utils; + +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; + +public class ApplicationContextHolder implements ApplicationContextAware { + private static ApplicationContext context; + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + context = applicationContext; + } + + public static T getBean(Class beanClass) { + return context.getBean(beanClass); + } +} diff --git a/modules/core/src/main/java/com/bytedesk/core/utils/AuditModel.java b/modules/core/src/main/java/com/bytedesk/core/utils/AuditModel.java index 5b756d8f7d..61a811a287 100644 --- a/modules/core/src/main/java/com/bytedesk/core/utils/AuditModel.java +++ b/modules/core/src/main/java/com/bytedesk/core/utils/AuditModel.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-29 16:21:24 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-03-25 12:46:27 + * @LastEditTime: 2024-04-18 12:35:49 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesa * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -14,29 +14,31 @@ */ package com.bytedesk.core.utils; -import com.fasterxml.jackson.annotation.JsonFormat; - import jakarta.persistence.Column; import jakarta.persistence.EntityListeners; import jakarta.persistence.MappedSuperclass; import jakarta.persistence.Temporal; import jakarta.persistence.TemporalType; -import org.springframework.beans.factory.annotation.Value; +// import org.springframework.beans.factory.annotation.Value; import org.springframework.data.annotation.CreatedDate; import org.springframework.data.annotation.LastModifiedDate; import org.springframework.data.jpa.domain.support.AuditingEntityListener; +// import com.fasterxml.jackson.annotation.JsonFormat; + import lombok.Data; -// import lombok.Builder; -// import lombok.Getter; -// import lombok.Setter; import java.io.Serializable; +// import java.time.ZonedDateTime; import java.util.Date; /** + * Date -> ZonedDateTime ? + * spring.jackson.date-format=yyyy-MM-dd HH:mm:ss + * spring.jackson.time-zone=GMT+8 * + * @see https://docs.spring.io/spring-data/jpa/reference/auditing.html * @author im.bytedesk.com */ @Data @@ -44,22 +46,22 @@ import java.util.Date; @EntityListeners(AuditingEntityListener.class) public class AuditModel implements Serializable { - private static final long serialVersionUID = 6798032420558915191L; - - @Value("${bytedesk.timezone}") - private static final String timezone = "GMT+8"; + // @Value("${bytedesk.timezone}") + // private static final String timezone = "GMT+8"; @Temporal(TemporalType.TIMESTAMP) @Column(name = "created_at", updatable = false) @CreatedDate - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = timezone) + // @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = timezone) // config in properties private Date createdAt; + // private ZonedDateTime createdAt; @Temporal(TemporalType.TIMESTAMP) @Column(name = "updated_at") @LastModifiedDate - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = timezone) + // @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = timezone) // config in properties private Date updatedAt; + // private ZonedDateTime updatedAt; /** * soft delete diff --git a/modules/core/src/main/java/com/bytedesk/core/utils/BaseRequest.java b/modules/core/src/main/java/com/bytedesk/core/utils/BaseRequest.java index ba3b5ad0e2..5dad808b6f 100644 --- a/modules/core/src/main/java/com/bytedesk/core/utils/BaseRequest.java +++ b/modules/core/src/main/java/com/bytedesk/core/utils/BaseRequest.java @@ -23,16 +23,16 @@ import lombok.EqualsAndHashCode; @EqualsAndHashCode(callSuper = false) public class BaseRequest implements Serializable { - Long id; + public Long id; - int pageNumber; + public int pageNumber; - int pageSize; + public int pageSize; - String type; + public String type; - String content; + public String content; - String client; + public String client; } diff --git a/modules/core/src/main/java/com/bytedesk/core/utils/BaseResponse.java b/modules/core/src/main/java/com/bytedesk/core/utils/BaseResponse.java index c1ad04b001..676875ec1e 100644 --- a/modules/core/src/main/java/com/bytedesk/core/utils/BaseResponse.java +++ b/modules/core/src/main/java/com/bytedesk/core/utils/BaseResponse.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-29 16:21:24 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-04-02 14:45:48 + * @LastEditTime: 2024-04-11 16:32:08 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -16,6 +16,7 @@ package com.bytedesk.core.utils; import java.io.Serializable; + public class BaseResponse implements Serializable { } diff --git a/modules/core/src/main/java/com/bytedesk/core/utils/BdConvertUtils.java b/modules/core/src/main/java/com/bytedesk/core/utils/BdConvertUtils.java index a3cb6e32dd..7d07dc9e25 100644 --- a/modules/core/src/main/java/com/bytedesk/core/utils/BdConvertUtils.java +++ b/modules/core/src/main/java/com/bytedesk/core/utils/BdConvertUtils.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-03-01 17:20:46 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-04-02 11:06:19 + * @LastEditTime: 2024-04-11 11:53:16 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -16,6 +16,7 @@ package com.bytedesk.core.utils; import org.modelmapper.ModelMapper; +import com.alibaba.fastjson2.JSON; import com.bytedesk.core.message.Message; import com.bytedesk.core.message.MessageResponse; import com.bytedesk.core.rbac.role.Role; @@ -39,7 +40,9 @@ public class BdConvertUtils { MessageResponse messageResponse = new ModelMapper().map(message, MessageResponse.class); - messageResponse.setUser(convertTUserResponseSimple(message.getUser())); + UserResponseSimple user = JSON.parseObject(message.getUser(), UserResponseSimple.class); + messageResponse.setUser(user); + // messageResponse.setUser(convertTUserResponseSimple(message.getUser())); return messageResponse; } diff --git a/modules/core/src/main/java/com/bytedesk/core/utils/BdDateUtils.java b/modules/core/src/main/java/com/bytedesk/core/utils/BdDateUtils.java index 29060cc4aa..b937247902 100644 --- a/modules/core/src/main/java/com/bytedesk/core/utils/BdDateUtils.java +++ b/modules/core/src/main/java/com/bytedesk/core/utils/BdDateUtils.java @@ -15,7 +15,6 @@ import org.springframework.util.StringUtils; public class BdDateUtils { private BdDateUtils() { - } private static final String datetimeFormat = "yyyy-MM-dd HH:mm:ss"; diff --git a/modules/core/src/main/java/com/bytedesk/core/utils/JsonResult.java b/modules/core/src/main/java/com/bytedesk/core/utils/JsonResult.java index 5a809003cc..fbb4e05a9c 100644 --- a/modules/core/src/main/java/com/bytedesk/core/utils/JsonResult.java +++ b/modules/core/src/main/java/com/bytedesk/core/utils/JsonResult.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-29 16:21:24 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-04-05 09:45:50 + * @LastEditTime: 2024-04-22 21:08:37 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -52,8 +52,12 @@ public class JsonResult implements Serializable { return new JsonResult().setCode(200).setMessage("success").setData(data); } - public static JsonResult success(String message, int statusCode, T data) { - return new JsonResult().setCode(statusCode).setMessage(message).setData(data); + public static JsonResult success(String message, T data) { + return new JsonResult().setCode(200).setMessage(message).setData(data); + } + + public static JsonResult success(String message, int code, T data) { + return new JsonResult().setCode(code).setMessage(message).setData(data); } public static JsonResult error() { @@ -64,7 +68,11 @@ public class JsonResult implements Serializable { return new JsonResult().setCode(500).setMessage(message).setData(false); } - public static JsonResult error(String message, int statusCode, T data) { - return new JsonResult().setCode(statusCode).setMessage(message).setData(data); + public static JsonResult error(String message, int code) { + return new JsonResult().setCode(code).setMessage(message).setData(false); + } + + public static JsonResult error(String message, int code, T data) { + return new JsonResult().setCode(code).setMessage(message).setData(data); } } diff --git a/modules/core/src/main/java/com/bytedesk/core/utils/JwtUtils.java b/modules/core/src/main/java/com/bytedesk/core/utils/JwtUtils.java index f5d42bd809..48c30cd59a 100644 --- a/modules/core/src/main/java/com/bytedesk/core/utils/JwtUtils.java +++ b/modules/core/src/main/java/com/bytedesk/core/utils/JwtUtils.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-29 16:21:24 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-03-07 22:42:26 + * @LastEditTime: 2024-04-27 11:55:28 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -14,10 +14,10 @@ */ package com.bytedesk.core.utils; -// import javax.crypto.SecretKey; -import java.security.Key; import java.util.Date; +import javax.crypto.SecretKey; + import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @@ -26,6 +26,9 @@ import io.jsonwebtoken.io.Decoders; import io.jsonwebtoken.security.Keys; import lombok.extern.slf4j.Slf4j; +/** + * https://github.com/jwtk/jjwt#jws-create-key + */ @Slf4j @Component // @AllArgsConstructor @@ -37,56 +40,30 @@ public class JwtUtils { @Value("${bytedesk.jwt-expiration}") private long jwtExpirationMs; - // @Autowired - // private BytedeskProperties bytedeskProperties; - - @SuppressWarnings("deprecation") + // @SuppressWarnings("deprecation") + /** + * https://github.com/jwtk/jjwt?tab=readme-ov-file#creating-a-jwt + * @param username + * @return + */ public String generateJwtToken(String username) { - // log.info("generateJwtToken: {}, key {}, expiration {}", - // username, - // bytedeskProperties.getJwtSecretKey(), - // bytedeskProperties.getJwtExpiration() - // ); - return Jwts.builder() .subject((username)) .issuedAt(new Date()) .expiration(new Date((new Date()).getTime() + jwtExpirationMs)) - .signWith(key(), - SignatureAlgorithm.HS256) + // .signWith(key(), SignatureAlgorithm.HS256) + .signWith(secretKey()) .compact(); } - // public String generateJwtToken(Authentication authentication) { - // UserDetailsImpl userPrincipal = (UserDetailsImpl) - // authentication.getPrincipal(); - // return Jwts.builder() - // .subject((userPrincipal.getUsername())) - // .issuedAt(new Date()) - // .expiration(new Date((new Date()).getTime() + jwtExpirationMs)) - // .signWith(key(), - // SignatureAlgorithm.HS256) // SignatureAlgorithm.HS256 - // .compact(); - // } - - // private SecretKey key() { - // return Keys.hmacShaKeyFor(Decoders.BASE64.decode(jwtSecret)); - // } - - private Key key() { - return Keys.hmacShaKeyFor(Decoders.BASE64.decode(jwtSecret)); - } - - @SuppressWarnings("deprecation") - public String getUserNameFromJwtToken(String token) { - return Jwts.parser().setSigningKey(key()).build() - .parseSignedClaims(token).getPayload().getSubject(); - } - - @SuppressWarnings("deprecation") + // @SuppressWarnings("deprecation") public boolean validateJwtToken(String authToken) { try { - Jwts.parser().setSigningKey(key()).build().parse(authToken); + Jwts.parser() + // .setSigningKey(key()) + .verifyWith(secretKey()) + .build() + .parse(authToken); return true; } catch (MalformedJwtException e) { log.error("Invalid JWT token: {}", e.getMessage()); @@ -100,4 +77,23 @@ public class JwtUtils { return false; } + + // @SuppressWarnings("deprecation") + public String getUserNameFromJwtToken(String token) { + return Jwts.parser() + // .setSigningKey(key()) + .verifyWith(secretKey()) + .build() + .parseSignedClaims(token) + .getPayload() + .getSubject(); + } + + // private Key key() { + // return Keys.hmacShaKeyFor(Decoders.BASE64.decode(jwtSecret)); + // } + + private SecretKey secretKey() { + return Keys.hmacShaKeyFor(Decoders.BASE64.decode(jwtSecret)); + } } diff --git a/modules/core/src/main/java/com/bytedesk/core/utils/StringSetConverter.java b/modules/core/src/main/java/com/bytedesk/core/utils/StringSetConverter.java new file mode 100644 index 0000000000..db5c2d1d22 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/utils/StringSetConverter.java @@ -0,0 +1,47 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-15 16:14:33 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-15 16:14:51 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.utils; + +import com.google.common.base.Strings; + +import jakarta.persistence.AttributeConverter; +import jakarta.persistence.Converter; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +@Converter +public class StringSetConverter implements AttributeConverter, String> { + + @Override + public String convertToDatabaseColumn(Set set) { + Iterator iterator = set.iterator(); + while(iterator.hasNext()){ + String str = iterator.next(); + if(Strings.isNullOrEmpty(str)){ + iterator.remove(); // 正确 + } + } + return String.join(",", set); + } + + @Override + public Set convertToEntityAttribute(String joined) { + return joined == null ? new HashSet<>() : new HashSet<>(Arrays.asList(joined.split(","))); + } + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/utils/Utils.java b/modules/core/src/main/java/com/bytedesk/core/utils/Utils.java index a0b29d345f..5b55af2037 100644 --- a/modules/core/src/main/java/com/bytedesk/core/utils/Utils.java +++ b/modules/core/src/main/java/com/bytedesk/core/utils/Utils.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-02-01 10:22:19 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-02-01 10:22:30 + * @LastEditTime: 2024-04-25 15:58:28 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -14,6 +14,10 @@ */ package com.bytedesk.core.utils; +import com.bytedesk.core.utils.id.DefaultIdGenerator; +import com.bytedesk.core.utils.id.IdGenerator; + +import java.util.Random; import java.util.UUID; public class Utils { @@ -21,7 +25,69 @@ public class Utils { private Utils() { } + /** + * ID 生成器 + */ + private static final IdGenerator ID_GENERATOR = new DefaultIdGenerator(); + + /** + * 根据时间戳,生成随机唯一id 如:202009151044291 + * 必须只能返回数字串,不能包含字母标点符号等 + * + * @return 随机 + */ + public static String timeSerialId() { + return ID_GENERATOR.next(); + } + + /** + * UUID + * + * @return UUID + */ + public static String uuid() { + return UUID.randomUUID().toString(); + } + + /** + * 带有时间戳的uuid + * UUID.randomUUID().toString()长度为36,我们去掉‘-’之后,截取前半段 + * + * @return uuid + */ + public static String timeUuid() { + return ID_GENERATOR.next() + UUID.randomUUID().toString().replace("-", "");// .substring(0, 18); + } + public static String getUid() { return UUID.randomUUID().toString().replaceAll("-", ""); } + + + /** + * for test + * + * @param mobile + * @return + */ + public static boolean isTestMobile(String mobile) { + return mobile.startsWith("1888888"); + } + + /** + * + * @return + */ + public static String getRandomCode(String key) { + int code = 123456; + if (isTestMobile(key)) { + code = 123456; + } else { + int min = 100001; + int max = 999998; + code = new Random().nextInt(max) % (max - min + 1) + min; + } + return String.valueOf(code); + } + } diff --git a/modules/core/src/main/java/com/bytedesk/core/utils/exception/AlreadyExistsException.java b/modules/core/src/main/java/com/bytedesk/core/utils/exception/AlreadyExistsException.java deleted file mode 100755 index 283ab9134f..0000000000 --- a/modules/core/src/main/java/com/bytedesk/core/utils/exception/AlreadyExistsException.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * bytedesk.com https://github.com/Bytedesk/bytedesk - * - * Copyright (C) 2013-2024 bytedesk.com - * - * License restrictions - * - * Please be aware of the BSL license restrictions before installing Bytedesk IM – - * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. - * 仅支持企业内部员工自用,严禁用于销售、二次销售或者部署SaaS方式销售 - * - * Business Source License 1.1: - * https://github.com/Bytedesk/bytedesk/blob/main/LICENSE - * - * contact: 270580156@qq.com - * 联系:270580156@qq.com - */ -package com.bytedesk.core.utils.exception; - -/** - * Exception caused by entity existence already. - * - * @author johnniang - */ -public class AlreadyExistsException extends BadRequestException { - - /** - * - */ - private static final long serialVersionUID = 185895443794683426L; - - public AlreadyExistsException(String message) { - super(message); - } - - public AlreadyExistsException(String message, Throwable cause) { - super(message, cause); - } - -} diff --git a/modules/core/src/main/java/com/bytedesk/core/utils/exception/ApiErrorResponse.java b/modules/core/src/main/java/com/bytedesk/core/utils/exception/ApiErrorResponse.java deleted file mode 100644 index 63040fafa3..0000000000 --- a/modules/core/src/main/java/com/bytedesk/core/utils/exception/ApiErrorResponse.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * bytedesk.com https://github.com/Bytedesk/bytedesk - * - * Copyright (C) 2013-2024 bytedesk.com - * - * License restrictions - * - * Please be aware of the BSL license restrictions before installing Bytedesk IM – - * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. - * 仅支持企业内部员工自用,严禁用于销售、二次销售或者部署SaaS方式销售 - * - * Business Source License 1.1: - * https://github.com/Bytedesk/bytedesk/blob/main/LICENSE - * - * contact: 270580156@qq.com - * 联系:270580156@qq.com - */ -package com.bytedesk.core.utils.exception; - -import lombok.Getter; -import lombok.Setter; -import org.springframework.http.HttpStatus; - -@Getter -@Setter -public class ApiErrorResponse { - - private HttpStatus status; - private String error_code; - private String message; - private String detail; - - // getter and setters - // Builder - public static final class ApiErrorResponseBuilder { - private HttpStatus status; - private String error_code; - private String message; - private String detail; - - public ApiErrorResponseBuilder() { - } - - public static ApiErrorResponseBuilder anApiErrorResponse() { - return new ApiErrorResponseBuilder(); - } - - public ApiErrorResponseBuilder withStatus(HttpStatus status) { - this.status = status; - return this; - } - - public ApiErrorResponseBuilder withError_code(String error_code) { - this.error_code = error_code; - return this; - } - - public ApiErrorResponseBuilder withMessage(String message) { - this.message = message; - return this; - } - - public ApiErrorResponseBuilder withDetail(String detail) { - this.detail = detail; - return this; - } - - public ApiErrorResponse build() { - ApiErrorResponse apiErrorResponse = new ApiErrorResponse(); - apiErrorResponse.status = this.status; - apiErrorResponse.error_code = this.error_code; - apiErrorResponse.detail = this.detail; - apiErrorResponse.message = this.message; - return apiErrorResponse; - } - } - -} diff --git a/modules/core/src/main/java/com/bytedesk/core/utils/exception/AppNotFoundException.java b/modules/core/src/main/java/com/bytedesk/core/utils/exception/AppNotFoundException.java deleted file mode 100644 index 24baaed7f8..0000000000 --- a/modules/core/src/main/java/com/bytedesk/core/utils/exception/AppNotFoundException.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * bytedesk.com https://github.com/Bytedesk/bytedesk - * - * Copyright (C) 2013-2024 bytedesk.com - * - * License restrictions - * - * Please be aware of the BSL license restrictions before installing Bytedesk IM – - * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. - * 仅支持企业内部员工自用,严禁用于销售、二次销售或者部署SaaS方式销售 - * - * Business Source License 1.1: - * https://github.com/Bytedesk/bytedesk/blob/main/LICENSE - * - * contact: 270580156@qq.com - * 联系:270580156@qq.com - */ -package com.bytedesk.core.utils.exception; - -import lombok.extern.slf4j.Slf4j; - -@Slf4j -public class AppNotFoundException extends RuntimeException { - - /** - * - */ - private static final long serialVersionUID = -3987082031613316940L; - - public AppNotFoundException(String aid) { - super("app not found"); - log.error("app {} not fount", aid); - } -} diff --git a/modules/core/src/main/java/com/bytedesk/core/utils/exception/AuthorityNotFoundException.java b/modules/core/src/main/java/com/bytedesk/core/utils/exception/AuthorityNotFoundException.java deleted file mode 100644 index afaa771d4f..0000000000 --- a/modules/core/src/main/java/com/bytedesk/core/utils/exception/AuthorityNotFoundException.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * bytedesk.com https://github.com/Bytedesk/bytedesk - * - * Copyright (C) 2013-2024 bytedesk.com - * - * License restrictions - * - * Please be aware of the BSL license restrictions before installing Bytedesk IM – - * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. - * 仅支持企业内部员工自用,严禁用于销售、二次销售或者部署SaaS方式销售 - * - * Business Source License 1.1: - * https://github.com/Bytedesk/bytedesk/blob/main/LICENSE - * - * contact: 270580156@qq.com - * 联系:270580156@qq.com - */ -package com.bytedesk.core.utils.exception; - -import lombok.extern.slf4j.Slf4j; - -@Slf4j -public class AuthorityNotFoundException extends RuntimeException { - - /** - * - */ - private static final long serialVersionUID = -5856696470241765976L; - - public AuthorityNotFoundException(Long id) { - super("role not found"); - log.error("role {} not fount", id); - } -} diff --git a/modules/core/src/main/java/com/bytedesk/core/utils/exception/BadRequestException.java b/modules/core/src/main/java/com/bytedesk/core/utils/exception/BadRequestException.java deleted file mode 100755 index dc14da6724..0000000000 --- a/modules/core/src/main/java/com/bytedesk/core/utils/exception/BadRequestException.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * bytedesk.com https://github.com/Bytedesk/bytedesk - * - * Copyright (C) 2013-2024 bytedesk.com - * - * License restrictions - * - * Please be aware of the BSL license restrictions before installing Bytedesk IM – - * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. - * 仅支持企业内部员工自用,严禁用于销售、二次销售或者部署SaaS方式销售 - * - * Business Source License 1.1: - * https://github.com/Bytedesk/bytedesk/blob/main/LICENSE - * - * contact: 270580156@qq.com - * 联系:270580156@qq.com - */ -package com.bytedesk.core.utils.exception; - -import org.springframework.http.HttpStatus; -import org.springframework.lang.NonNull; - -/** - * Exception caused by bad request. - * - * @author johnniang - */ -public class BadRequestException extends BytedeskException { - - /** - * - */ - private static final long serialVersionUID = 8146006124058491585L; - - public BadRequestException(String message) { - super(message); - } - - public BadRequestException(String message, Throwable cause) { - super(message, cause); - } - - @Override - public @NonNull HttpStatus getStatus() { - return HttpStatus.BAD_REQUEST; - } -} diff --git a/modules/core/src/main/java/com/bytedesk/core/utils/exception/BeanUtilsException.java b/modules/core/src/main/java/com/bytedesk/core/utils/exception/BeanUtilsException.java deleted file mode 100755 index ed830c6289..0000000000 --- a/modules/core/src/main/java/com/bytedesk/core/utils/exception/BeanUtilsException.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * bytedesk.com https://github.com/Bytedesk/bytedesk - * - * Copyright (C) 2013-2024 bytedesk.com - * - * License restrictions - * - * Please be aware of the BSL license restrictions before installing Bytedesk IM – - * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. - * 仅支持企业内部员工自用,严禁用于销售、二次销售或者部署SaaS方式销售 - * - * Business Source License 1.1: - * https://github.com/Bytedesk/bytedesk/blob/main/LICENSE - * - * contact: 270580156@qq.com - * 联系:270580156@qq.com - */ -package com.bytedesk.core.utils.exception; - -import org.springframework.http.HttpStatus; -import org.springframework.lang.NonNull; - -/** - * BeanUtils exception. - * - * @author johnniang - */ -public class BeanUtilsException extends BytedeskException { - - private static final long serialVersionUID = -2693716689479955009L; - - public BeanUtilsException(String message) { - super(message); - } - - public BeanUtilsException(String message, Throwable cause) { - super(message, cause); - } - - @Override - public @NonNull HttpStatus getStatus() { - return HttpStatus.INTERNAL_SERVER_ERROR; - } -} diff --git a/modules/core/src/main/java/com/bytedesk/core/utils/exception/BytedeskException.java b/modules/core/src/main/java/com/bytedesk/core/utils/exception/BytedeskException.java deleted file mode 100755 index a5c4b7aa8b..0000000000 --- a/modules/core/src/main/java/com/bytedesk/core/utils/exception/BytedeskException.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * bytedesk.com https://github.com/Bytedesk/bytedesk - * - * Copyright (C) 2013-2024 bytedesk.com - * - * License restrictions - * - * Please be aware of the BSL license restrictions before installing Bytedesk IM – - * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. - * 仅支持企业内部员工自用,严禁用于销售、二次销售或者部署SaaS方式销售 - * - * Business Source License 1.1: - * https://github.com/Bytedesk/bytedesk/blob/main/LICENSE - * - * contact: 270580156@qq.com - * 联系:270580156@qq.com - */ -package com.bytedesk.core.utils.exception; - -import org.springframework.http.HttpStatus; -import org.springframework.lang.NonNull; -import org.springframework.lang.Nullable; - -/** - * Base exception of the project. - * - * @author johnniang - */ -public abstract class BytedeskException extends RuntimeException { - - /** - * - */ - private static final long serialVersionUID = -3730280146845163419L; - /** - * Error errorData. - */ - private Object errorData; - - public BytedeskException(String message) { - super(message); - } - - public BytedeskException(String message, Throwable cause) { - super(message, cause); - } - - @NonNull - public abstract HttpStatus getStatus(); - - @Nullable - public Object getErrorData() { - return errorData; - } - - /** - * Sets error errorData. - * - * @param errorData error data - * @return current exception. - */ - @NonNull - public BytedeskException setErrorData(@Nullable Object errorData) { - this.errorData = errorData; - return this; - } - -} diff --git a/modules/core/src/main/java/com/bytedesk/core/utils/exception/DepartmentNotFoundException.java b/modules/core/src/main/java/com/bytedesk/core/utils/exception/DepartmentNotFoundException.java deleted file mode 100644 index 1512d5d0cf..0000000000 --- a/modules/core/src/main/java/com/bytedesk/core/utils/exception/DepartmentNotFoundException.java +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - *

    - * http://www.apache.org/licenses/LICENSE-2.0 - *

    - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * bytedesk.com https://github.com/Bytedesk/bytedesk - * - * Copyright (C) 2013-2024 bytedesk.com - * - * License restrictions - * - * Please be aware of the BSL license restrictions before installing Bytedesk IM – - * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. - * 仅支持企业内部员工自用,严禁用于销售、二次销售或者部署SaaS方式销售 - * - * Business Source License 1.1: - * https://github.com/Bytedesk/bytedesk/blob/main/LICENSE - * - * contact: 270580156@qq.com - * 联系:270580156@qq.com - */ -package com.bytedesk.core.utils.exception; - -import lombok.extern.slf4j.Slf4j; - -@Slf4j -public class DepartmentNotFoundException extends RuntimeException { - - private static final long serialVersionUID = -8502840684293721269L; - - public DepartmentNotFoundException(String did) { - super("department not found"); - log.error("department {} not fount", did); - } -} diff --git a/modules/core/src/main/java/com/bytedesk/core/utils/exception/ForbiddenException.java b/modules/core/src/main/java/com/bytedesk/core/utils/exception/ForbiddenException.java deleted file mode 100755 index 8f28c148b6..0000000000 --- a/modules/core/src/main/java/com/bytedesk/core/utils/exception/ForbiddenException.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * bytedesk.com https://github.com/Bytedesk/bytedesk - * - * Copyright (C) 2013-2024 bytedesk.com - * - * License restrictions - * - * Please be aware of the BSL license restrictions before installing Bytedesk IM – - * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. - * 仅支持企业内部员工自用,严禁用于销售、二次销售或者部署SaaS方式销售 - * - * Business Source License 1.1: - * https://github.com/Bytedesk/bytedesk/blob/main/LICENSE - * - * contact: 270580156@qq.com - * 联系:270580156@qq.com - */ -package com.bytedesk.core.utils.exception; - -import org.springframework.http.HttpStatus; -import org.springframework.lang.NonNull; - -/** - * Exception caused by accessing forbidden resources. - * - * @author johnniang - */ -public class ForbiddenException extends BytedeskException { - - /** - * - */ - private static final long serialVersionUID = -6029126336570526306L; - - public ForbiddenException(String message) { - super(message); - } - - public ForbiddenException(String message, Throwable cause) { - super(message, cause); - } - - @Override - public @NonNull HttpStatus getStatus() { - return HttpStatus.FORBIDDEN; - } -} diff --git a/modules/core/src/main/java/com/bytedesk/core/utils/exception/ImageFormatException.java b/modules/core/src/main/java/com/bytedesk/core/utils/exception/ImageFormatException.java deleted file mode 100644 index d9c69b800f..0000000000 --- a/modules/core/src/main/java/com/bytedesk/core/utils/exception/ImageFormatException.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * bytedesk.com https://github.com/Bytedesk/bytedesk - * - * Copyright (C) 2013-2024 bytedesk.com - * - * License restrictions - * - * Please be aware of the BSL license restrictions before installing Bytedesk IM – - * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. - * 仅支持企业内部员工自用,严禁用于销售、二次销售或者部署SaaS方式销售 - * - * Business Source License 1.1: - * https://github.com/Bytedesk/bytedesk/blob/main/LICENSE - * - * contact: 270580156@qq.com - * 联系:270580156@qq.com - */ -package com.bytedesk.core.utils.exception; - -/** - * Image format exception. - * - * @author ZhiXiang Yuan - * @date 2020/08/10 02:11 - */ -public class ImageFormatException extends BadRequestException { - - public ImageFormatException(String message) { - super(message); - } - - public ImageFormatException(String message, Throwable cause) { - super(message, cause); - } -} diff --git a/modules/core/src/main/java/com/bytedesk/core/utils/exception/MenuNotFoundException.java b/modules/core/src/main/java/com/bytedesk/core/utils/exception/MenuNotFoundException.java deleted file mode 100644 index c242190288..0000000000 --- a/modules/core/src/main/java/com/bytedesk/core/utils/exception/MenuNotFoundException.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * bytedesk.com https://github.com/Bytedesk/bytedesk - * - * Copyright (C) 2013-2024 bytedesk.com - * - * License restrictions - * - * Please be aware of the BSL license restrictions before installing Bytedesk IM – - * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. - * 仅支持企业内部员工自用,严禁用于销售、二次销售或者部署SaaS方式销售 - * - * Business Source License 1.1: - * https://github.com/Bytedesk/bytedesk/blob/main/LICENSE - * - * contact: 270580156@qq.com - * 联系:270580156@qq.com - */ -package com.bytedesk.core.utils.exception; - -import lombok.extern.slf4j.Slf4j; - -@Slf4j -public class MenuNotFoundException extends RuntimeException { - - /** - * - */ - private static final long serialVersionUID = 2945447432978388479L; - - public MenuNotFoundException(String mid) { - super("menu not found"); - log.error("menu {} not fount", mid); - } -} diff --git a/modules/core/src/main/java/com/bytedesk/core/utils/exception/PrincipalNullException.java b/modules/core/src/main/java/com/bytedesk/core/utils/exception/PrincipalNullException.java deleted file mode 100644 index bde6416e30..0000000000 --- a/modules/core/src/main/java/com/bytedesk/core/utils/exception/PrincipalNullException.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * bytedesk.com https://github.com/Bytedesk/bytedesk - * - * Copyright (C) 2013-2024 bytedesk.com - * - * License restrictions - * - * Please be aware of the BSL license restrictions before installing Bytedesk IM – - * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. - * 仅支持企业内部员工自用,严禁用于销售、二次销售或者部署SaaS方式销售 - * - * Business Source License 1.1: - * https://github.com/Bytedesk/bytedesk/blob/main/LICENSE - * - * contact: 270580156@qq.com - * 联系:270580156@qq.com - */ -package com.bytedesk.core.utils.exception; - -import lombok.extern.slf4j.Slf4j; - -@Slf4j -public class PrincipalNullException extends RuntimeException { - - /** - * - */ - private static final long serialVersionUID = -6426450230129602873L; - - public PrincipalNullException() { - log.error("principal is null"); - } -} diff --git a/modules/core/src/main/java/com/bytedesk/core/utils/exception/RoleNotFoundException.java b/modules/core/src/main/java/com/bytedesk/core/utils/exception/RoleNotFoundException.java deleted file mode 100644 index e1956a76ae..0000000000 --- a/modules/core/src/main/java/com/bytedesk/core/utils/exception/RoleNotFoundException.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * bytedesk.com https://github.com/Bytedesk/bytedesk - * - * Copyright (C) 2013-2024 bytedesk.com - * - * License restrictions - * - * Please be aware of the BSL license restrictions before installing Bytedesk IM – - * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. - * 仅支持企业内部员工自用,严禁用于销售、二次销售或者部署SaaS方式销售 - * - * Business Source License 1.1: - * https://github.com/Bytedesk/bytedesk/blob/main/LICENSE - * - * contact: 270580156@qq.com - * 联系:270580156@qq.com - */ -package com.bytedesk.core.utils.exception; - -import lombok.extern.slf4j.Slf4j; - -@Slf4j -public class RoleNotFoundException extends RuntimeException { - - /** - * - */ - private static final long serialVersionUID = 5646024396772307621L; - - public RoleNotFoundException(Long id) { - super("role not found"); - log.error("role {} not fount", id); - } -} diff --git a/modules/core/src/main/java/com/bytedesk/core/utils/exception/UserNotFoundException.java b/modules/core/src/main/java/com/bytedesk/core/utils/exception/UserNotFoundException.java deleted file mode 100644 index f3eb31a89b..0000000000 --- a/modules/core/src/main/java/com/bytedesk/core/utils/exception/UserNotFoundException.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * bytedesk.com https://github.com/Bytedesk/bytedesk - * - * Copyright (C) 2013-2024 bytedesk.com - * - * License restrictions - * - * Please be aware of the BSL license restrictions before installing Bytedesk IM – - * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. - * 仅支持企业内部员工自用,严禁用于销售、二次销售或者部署SaaS方式销售 - * - * Business Source License 1.1: - * https://github.com/Bytedesk/bytedesk/blob/main/LICENSE - * - * contact: 270580156@qq.com - * 联系:270580156@qq.com - */ -package com.bytedesk.core.utils.exception; - -import lombok.extern.slf4j.Slf4j; - -@Slf4j -public class UserNotFoundException extends RuntimeException { - - /** - * - */ - private static final long serialVersionUID = -6690095132444054097L; - - public UserNotFoundException(String username) { - super("username not found"); - log.error("username {} not fount", username); - } -} diff --git a/modules/core/src/main/java/com/bytedesk/core/utils/id/DefaultIdGenerator.java b/modules/core/src/main/java/com/bytedesk/core/utils/id/DefaultIdGenerator.java new file mode 100644 index 0000000000..7e00ac982b --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/utils/id/DefaultIdGenerator.java @@ -0,0 +1,78 @@ +package com.bytedesk.core.utils.id; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +/** + * 默认的ID生成器, 采用前缀+时间+原子数的形式实现 + * 建议相同的配置采用同一个实例 + * @see IdGeneratorConfig + * @author Ivan.Ma + */ +public class DefaultIdGenerator implements IdGenerator, Runnable{ + + private String time; + + private AtomicInteger value; + + private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyyMMddHHmmss"); + + private IdGeneratorConfig config; + + private Thread thread; + + private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); + + public DefaultIdGenerator(){ + config = new DefaultIdGeneratorConfig(); + time = LocalDateTime.now().format(FORMATTER); + value = new AtomicInteger(config.getInitial()); + + thread = new Thread(this); + thread.setDaemon(true); + thread.start(); + } + + public DefaultIdGenerator(IdGeneratorConfig config){ + this.config = config; + time = LocalDateTime.now().format(FORMATTER); + value = new AtomicInteger(config.getInitial()); + + thread = new Thread(this); + thread.setDaemon(true); + thread.start(); + } + + @Override + public String next() { + lock.readLock().lock(); + StringBuffer sb = new StringBuffer(config.getPrefix()) + .append(config.getSplitString()) + .append(time) + .append(config.getSplitString()) + .append(value.getAndIncrement()); + lock.readLock().unlock(); + return sb.toString(); + } + + @Override + public void run() { + while (true){ + try { + Thread.sleep(1000 * config.getRollingInterval()); + } catch (InterruptedException e) { + e.printStackTrace(); + } + String now = LocalDateTime.now().format(FORMATTER); + if (!now.equals(time)){ + lock.writeLock().lock(); + time = now; + value.set(config.getInitial()); + lock.writeLock().unlock(); + } + } + } + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/redis/RedisThreadService.java b/modules/core/src/main/java/com/bytedesk/core/utils/id/DefaultIdGeneratorConfig.java similarity index 61% rename from modules/core/src/main/java/com/bytedesk/core/redis/RedisThreadService.java rename to modules/core/src/main/java/com/bytedesk/core/utils/id/DefaultIdGeneratorConfig.java index 0f7cb77b84..ced307b8e3 100644 --- a/modules/core/src/main/java/com/bytedesk/core/redis/RedisThreadService.java +++ b/modules/core/src/main/java/com/bytedesk/core/utils/id/DefaultIdGeneratorConfig.java @@ -1,8 +1,8 @@ /* * @Author: jackning 270580156@qq.com - * @Date: 2024-02-26 13:01:41 + * @Date: 2024-04-08 12:13:12 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-02-26 13:12:23 + * @LastEditTime: 2024-04-08 12:13:20 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -12,25 +12,32 @@ * 联系:270580156@qq.com * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. */ -package com.bytedesk.core.redis; - -import org.springframework.stereotype.Service; -import lombok.AllArgsConstructor; - -// import io.xiaper.core.publisher.EventPublisher; +package com.bytedesk.core.utils.id; /** - * 会话 redis 操作 * * @author xiaper.io */ -// @Slf4j -@Service -@AllArgsConstructor -public class RedisThreadService { +public class DefaultIdGeneratorConfig implements IdGeneratorConfig { - // private final StringRedisTemplate stringRedisTemplate; + @Override + public String getSplitString() { + return ""; + } - // private final EventPublisher eventPublisher; + @Override + public int getInitial() { + return 1; + } + + @Override + public String getPrefix() { + return ""; + } + + @Override + public int getRollingInterval() { + return 1; + } } diff --git a/modules/core/src/main/java/com/bytedesk/core/utils/id/IdGenerator.java b/modules/core/src/main/java/com/bytedesk/core/utils/id/IdGenerator.java new file mode 100644 index 0000000000..073364fc1a --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/utils/id/IdGenerator.java @@ -0,0 +1,17 @@ +package com.bytedesk.core.utils.id; + +/** + * + * ID生成器接口, 用于生成全局唯一的ID流水号 + * + * @author Ivan.Ma + */ +public interface IdGenerator { + + /** + * 生成下一个不重复的流水号 + * @return string + */ + String next(); + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/utils/id/IdGeneratorConfig.java b/modules/core/src/main/java/com/bytedesk/core/utils/id/IdGeneratorConfig.java new file mode 100644 index 0000000000..2ab98e879a --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/utils/id/IdGeneratorConfig.java @@ -0,0 +1,47 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-08 12:13:12 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-08 12:13:31 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.utils.id; + +/** + * ID生成器的配置接口 + * @author Ivan.Ma + */ +public interface IdGeneratorConfig { + + /** + * 获取分隔符 + * @return string + */ + String getSplitString(); + + /** + * 获取初始值 + * @return int + */ + int getInitial(); + + /** + * 获取ID前缀 + * @return string + */ + String getPrefix(); + + /** + * 获取滚动间隔, 单位: 秒 + * @return int + */ + int getRollingInterval(); + +} diff --git a/modules/local/.DS_Store b/modules/local/.DS_Store index ebe6301f9b3982dd908100578d6fdb0ff165b75e..257957d8f2af75ea6ca3134f679a5e12978e8c93 100644 GIT binary patch delta 88 zcmZoMXffEJ!pvl>F9%MSp}x*9;YG!$+^ybNPm}S@&q-@)H_4ed_%yQ}w=21rm1_m~U m5{5*EB8GH^RECm*48!2${M-VdI1n7zEXcvavYDOZFFybq!W*jq diff --git a/modules/local/pom.xml b/modules/local/pom.xml index debd81bab0..0bf1566f18 100644 --- a/modules/local/pom.xml +++ b/modules/local/pom.xml @@ -11,7 +11,7 @@ 0.0.1-SNAPSHOT - weiyu-local + im-local local Demo project for Spring Boot @@ -20,14 +20,21 @@ com.bytedesk - weiyu-core + im-core ${im.version} provided com.bytedesk - weiyu-socket + im-service + ${im.version} + provided + + + + com.bytedesk + im-socket ${im.version} provided @@ -51,6 +58,7 @@ + 0.0.1-SNAPSHOT @@ -18,10 +17,12 @@ ai + blog core local - oa + service social + socket team @@ -57,18 +58,13 @@ provided + org.springframework.boot spring-boot-starter-data-jpa provided - - com.mysql - mysql-connector-j - provided - - org.springframework.boot spring-boot-starter-validation @@ -87,18 +83,7 @@ provided - - org.springframework.boot - spring-boot-starter-data-redis - provided - - - - org.springframework.session - spring-session-data-redis - provided - - + org.springframework.boot spring-boot-starter-actuator @@ -126,22 +111,39 @@ true + + + + + - + + - + + + com.alibaba.fastjson2 fastjson2 - 2.0.45 + 2.0.48 + provided @@ -175,6 +177,32 @@ provided + + + + + com.google.guava + guava + 33.1.0-jre + provided + + + + + + + + + com.github.javafaker + javafaker + 1.0.2 + + org.springframework.boot @@ -202,12 +230,12 @@ - + + com.querydsl querydsl-apt @@ -224,11 +252,10 @@ target/generated-sources/queries com.querydsl.apt.jpa.JPAAnnotationProcessor - - + --> diff --git a/modules/readme.md b/modules/readme.md new file mode 100644 index 0000000000..d588a21b74 --- /dev/null +++ b/modules/readme.md @@ -0,0 +1,15 @@ + +# open source modules - 开源模块 diff --git a/modules/service/.DS_Store b/modules/service/.DS_Store index d52c55efb6f60a45ccafc677647ba90008222107..85b88949c7dab234b76b78d1595cead8c69b4178 100644 GIT binary patch delta 142 zcmZoMXffEJ%xcRV_=$mmftjJ0p@<$z$T-$PIZZl!b7k&Hii<0M4++h45Dr~;a HrYi^lw(lof diff --git a/modules/service/pom.xml b/modules/service/pom.xml index 7761f3d179..49699c5ee4 100644 --- a/modules/service/pom.xml +++ b/modules/service/pom.xml @@ -11,25 +11,30 @@ 0.0.1-SNAPSHOT - weiyu-service + im-service service Demo project for Spring Boot + + 7.4.2 + 2.6.1 + + com.bytedesk - weiyu-core + im-core ${im.version} provided com.bytedesk - weiyu-team + im-team ${im.version} provided @@ -38,6 +43,28 @@ + +-keepnames interface ** { *; } +# 此选项将保存所有软件包中的所有原始接口文件(不进行混淆) +-keep interface * extends * { *; } +# 保留参数名,因为控制器,或者Mybatis等接口的参数如果混淆会导致无法接受参数,xml文件找不到参数 +-keepparameternames +# 保留枚举成员及方法 +-keepclassmembers enum * { *; } +# 不混淆所有类,保存原始定义的注释- +-keepclassmembers class * { + @org.springframework.context.annotation.Bean *; + @org.springframework.beans.factory.annotation.Autowired *; + @org.springframework.beans.factory.annotation.Value *; + @org.springframework.stereotype.Service *; + @org.springframework.stereotype.Component *; + @org.springframework.web.bind.annotation.GetMapping *; + @org.springframework.web.bind.annotation.PostMapping *; + @org.springframework.web.bind.annotation.RequestBody *; + @org.springframework.web.bind.annotation.RequestMapping *; + @org.springframework.web.bind.annotation.RestController *; +} +# 忽略warn消息 +-ignorewarnings +# 打印配置信息 +-printconfiguration \ No newline at end of file diff --git a/modules/service/src/.DS_Store b/modules/service/src/.DS_Store index d9bdf88b7a0624eb6cb39f406198bad0b25cefe3..8e720825f751ec04d68fc03f3e309592b50adac1 100644 GIT binary patch delta 107 zcmZoMXffEJ${5F_u$zH_frTNLA(0`IAul)I#U&{xKM5$t@#VkdQiX>{9Z}^|@X8lt W7zQWj=N16aL*C>yjFMbXc5Z&k3jbZ?P)Dm3) diff --git a/modules/service/src/main/.DS_Store b/modules/service/src/main/.DS_Store index 8aebf79e626ab2d8575a92e052c70e52d3c896a6..229838d1f6341e331421f1b761d43cff6fd1dc63 100644 GIT binary patch delta 112 zcmZoMXffEJ$`sGUv5kR&frTN9A(5esAu%`K#U&{xKM5$t@$SWuNL*nEEOyZVsUT%JhOHxjL5>N#P14Dz=iOokH fkyRID7zQWj=N16P7#LU&Fiif(B(`}LQCJ*F;Q%yo}wrV0|Nsi1A_pAVQ_MOZUK-7)Dc-W1&?e&29l|40zhrZV6yo>ph^A(LqVrb#Sni=bO=8ww@`w5qmPAATW(FX&;K+V9! zhBK-Em-v-NFZp#yjDmq+;EyrDO}lItcqy-~UtUjYZ9-e2iO9Sn3Iw{AVxX2{3}hcU dQK$Kn=)!KtKQh diff --git a/modules/ai/src/.DS_Store b/modules/service/src/main/java/com/.DS_Store similarity index 94% rename from modules/ai/src/.DS_Store rename to modules/service/src/main/java/com/.DS_Store index a477d201128d8ba10ef2e1931e35c6986f7b6a4c..5c3e827b80fc6b9acebe8806864cadf0f97f6623 100644 GIT binary patch delta 198 zcmZoMXfc@JFUrEez`)4BAi%(o!jQ^P%#fXvZWuf+R9T?!s`k_bx+G7N*^ma=}>%*e#XHnAXX JGdss$egIqvGE)Em delta 294 zcmZoMXfc@JFUY~bz`)4BAi$85ZWx@LpIb0_Bjf6NkSGg7E<++iCPN-f1}Fvu7kYsN zTrM}?#U&{xKM5!X(vxqu?WiNFd%#g}Z#8AeN$&k#Dnwy{El9ZF5 V1eD=`sG3~CsKmHn^K8aUF#sX$7Qz4k diff --git a/modules/service/src/main/java/com/bytedesk/service/.DS_Store b/modules/service/src/main/java/com/bytedesk/service/.DS_Store index f5ae764c234fe8e22bd77b357cdd8f518c1936da..98fa724ea3085d5b75b70266c7218d121870b9fa 100644 GIT binary patch delta 41 xcmZn(XbG6$&ls>VU^hQwz-AtSrHq>ug`V+FY$({wuJDUxva_i2<|(2Nm;g9~4(I>? delta 162 zcmZn(XbG6$&ls{XU^hQw$YvgarHu6{4EYSnIq8PM$@#ej3}C<<1*Di6z%se{E-pzq z`AI+#4i!<0^>Ys&bwrj;!6RFcfo!S($ZTeYG=@ZmLWF&r4+vi8-OR4=i)Hgf5oTrp DUMDGW diff --git a/modules/service/src/main/java/com/bytedesk/service/agent/Agent.java b/modules/service/src/main/java/com/bytedesk/service/agent/Agent.java index 50a0736f39..47c85e8d7d 100644 --- a/modules/service/src/main/java/com/bytedesk/service/agent/Agent.java +++ b/modules/service/src/main/java/com/bytedesk/service/agent/Agent.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-29 16:19:51 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-04-02 16:35:50 + * @LastEditTime: 2024-04-24 15:14:35 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -14,6 +14,10 @@ */ package com.bytedesk.service.agent; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; + +import com.bytedesk.core.constant.BdConstants; import com.bytedesk.core.rbac.user.User; import com.bytedesk.core.utils.AuditModel; import com.fasterxml.jackson.annotation.JsonIgnore; @@ -25,10 +29,12 @@ import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; +// import lombok.extern.slf4j.Slf4j; /** * 客服账号-关联信息 */ +// @Slf4j @Entity @Data @Builder @@ -36,6 +42,7 @@ import lombok.experimental.Accessors; @EqualsAndHashCode(callSuper = true) @AllArgsConstructor @NoArgsConstructor +@EntityListeners({ AgentListener.class }) @Table(name = "service_agent") public class Agent extends AuditModel { @@ -43,12 +50,12 @@ public class Agent extends AuditModel { @GeneratedValue(strategy = GenerationType.AUTO) private Long id; - /** - * - */ - @Column(unique = true, nullable = false) - private String aid; + @Column(name = "uuid", unique = true, nullable = false) + private String uid; + /** + * visible to visitors + */ private String nickname; private String avatar; @@ -57,20 +64,71 @@ public class Agent extends AuditModel { private String email; + /** agent description */ private String description; /** - * + * @{AgentConsts} */ - // private String acceptStatus; + @Builder.Default + private String acceptStatus = AgentConsts.ACCEPT_STATUS_ACCEPTING; - // private String connectStatus; + @Builder.Default + @Column(name = "is_connected") + private boolean connected = false; + + // max concurrent chatting thread count + @Builder.Default + private Integer maxThreadCount = 10; /** - * + * tips + * TODO: set different tips for different lang + */ + @Builder.Default + private String welcomeTip = BdConstants.DEFAULT_WORK_GROUP_ACCEPT_TIP; + + /** auto close time in min - 默认自动关闭时间,单位分钟 */ + @Builder.Default + private Double autoCloseMin = Double.valueOf(25); + + /** 存储当前接待数量等 */ + @Builder.Default + @Column(columnDefinition = "json") + // 用于兼容postgreSQL,否则会报错,[ERROR: column "extra" is of type json but expression is of type character varying + @JdbcTypeCode(SqlTypes.JSON) + private String extra = BdConstants.EMPTY_JSON_STRING; + + /** + * login user info */ @JsonIgnore - @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL) + @ManyToOne(fetch = FetchType.LAZY) private User user; + /** belong to org */ + // @JsonIgnore + // @ManyToOne(fetch = FetchType.LAZY) + // private Organization organization; + private String orgOid; + + /** + * belongs to user + */ + // @JsonIgnore + // @ManyToOne(fetch = FetchType.LAZY) + // private User owner; + + + // @PostPersist + // public void onPostPersist() { + // // log.debug("onPostPersist: {}", this); + // // 这里可以记录日志、发送通知等 + // // create agent topic + // TopicService topicService = ApplicationContextHolder.getBean(TopicService.class); + // // + // topicService.create(this.getUid(), this.getUser().getUid()); + // } + } + diff --git a/modules/service/src/main/java/com/bytedesk/service/agent/AgentConsts.java b/modules/service/src/main/java/com/bytedesk/service/agent/AgentConsts.java new file mode 100644 index 0000000000..897ec6f158 --- /dev/null +++ b/modules/service/src/main/java/com/bytedesk/service/agent/AgentConsts.java @@ -0,0 +1,30 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-10 10:45:35 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-16 14:26:41 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.service.agent; + +public class AgentConsts { + + private AgentConsts() { + } + + public static final String ACCEPT_STATUS_ACCEPTING = "accepting"; + public static final String ACCEPT_STATUS_OFFLINE = "offline"; + public static final String ACCEPT_STATUS_BUSY = "busy"; + public static final String ACCEPT_STATUS_REST = "rest"; + public static final String ACCEPT_STATUS_REJECT = "reject"; + public static final String ACCEPT_STATUS_RESTRICT = "restrict"; + public static final String ACCEPT_STATUS_OTHER = "other"; + +} diff --git a/modules/service/src/main/java/com/bytedesk/service/agent/AgentController.java b/modules/service/src/main/java/com/bytedesk/service/agent/AgentController.java index ac9ee74b96..2730a31a88 100644 --- a/modules/service/src/main/java/com/bytedesk/service/agent/AgentController.java +++ b/modules/service/src/main/java/com/bytedesk/service/agent/AgentController.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-29 16:19:51 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-04-02 15:06:30 + * @LastEditTime: 2024-04-15 13:16:52 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -59,7 +59,12 @@ public class AgentController { @PostMapping("/create") public ResponseEntity create(@RequestBody AgentRequest agentRequest) { - return ResponseEntity.ok(agentService.create(agentRequest)); + Agent agent = agentService.create(agentRequest); + if (agent == null) { + return ResponseEntity.ok(JsonResult.error("department not exist")); + } + + return ResponseEntity.ok(JsonResult.success(agentService.convertToAgentResponse(agent))); } /** diff --git a/modules/service/src/main/java/com/bytedesk/service/agent/AgentListener.java b/modules/service/src/main/java/com/bytedesk/service/agent/AgentListener.java new file mode 100644 index 0000000000..325f42216c --- /dev/null +++ b/modules/service/src/main/java/com/bytedesk/service/agent/AgentListener.java @@ -0,0 +1,71 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-15 09:30:30 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-23 08:39:50 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.service.agent; + +import org.springframework.stereotype.Component; + +import com.bytedesk.core.topic.TopicService; +import com.bytedesk.core.utils.ApplicationContextHolder; + +import jakarta.persistence.PostPersist; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Component +public class AgentListener { + + // 无法注入bean,否则报错 + // private final TopicService topicService; + + // @PrePersist + // public void prePersist(Agent agent) { + // log.info("prePersist {}", agent.getUid()); + // } + + @PostPersist + public void postPersist(Agent agent) { + log.info("postPersist {}", agent.getUid()); + // topicService.create(agent.getUid(), agent.getUser().getUid()); + // 这里可以记录日志、发送通知等 + // create agent topic + TopicService topicService = ApplicationContextHolder.getBean(TopicService.class); + // + topicService.create(agent.getUid(), agent.getUser().getUid()); + } + + // @PreUpdate + // public void preUpdate(Agent agent) { + // log.info("preUpdate {}", agent.getUid()); + // } + + // @PostUpdate + // public void postUpdate(Agent agent) { + // log.info("postUpdate {}", agent.getUid()); + // // TODO: 切换agent对应的user时,需要更新topic:从原user缓存中删除,然后添加到新user缓存中 + // // topicService.update(agent.getUid(), agent.getUser().getUid()); + // } + + // @PreRemove + // public void preRemove(Agent agent) { + // log.info("preRemove {}", agent.getUid()); + // } + + // @PostRemove + // public void postRemove(Agent agent) { + // log.info("postRemove {}", agent.getUid()); + // // topicService.deleteByTopicAndUid(agent.getUid(), agent.getUser().getUid()); + // } + +} diff --git a/modules/service/src/main/java/com/bytedesk/service/agent/AgentRepository.java b/modules/service/src/main/java/com/bytedesk/service/agent/AgentRepository.java index 2130b70f70..2396537545 100644 --- a/modules/service/src/main/java/com/bytedesk/service/agent/AgentRepository.java +++ b/modules/service/src/main/java/com/bytedesk/service/agent/AgentRepository.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-29 16:19:51 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-02-06 10:38:09 + * @LastEditTime: 2024-04-22 12:17:20 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -14,9 +14,13 @@ */ package com.bytedesk.service.agent; +import java.util.Optional; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; -import org.springframework.security.access.prepost.PreAuthorize; +// import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Repository; import io.swagger.v3.oas.annotations.tags.Tag; @@ -26,8 +30,17 @@ import io.swagger.v3.oas.annotations.tags.Tag; */ @Repository @Tag(name = "agent account info - 客服账号信息") -@PreAuthorize("hasRole('ROLE_ADMIN')") +// @PreAuthorize("hasRole('ROLE_ADMIN')") public interface AgentRepository extends JpaRepository, JpaSpecificationExecutor { - // Page findAll(Pageable pageable); + Optional findByUid(String uid); + + Optional findByEmail(String email); + + Optional findByMobile(String mobile); + + Optional findByUser_Uid(String uid); + + // Page findByOrganization_Oid(String oid, Pageable pageable); + Page findByOrgOid(String oid, Pageable pageable); } diff --git a/modules/service/src/main/java/com/bytedesk/service/agent/AgentRequest.java b/modules/service/src/main/java/com/bytedesk/service/agent/AgentRequest.java index 9f249d885f..69d5f1e274 100644 --- a/modules/service/src/main/java/com/bytedesk/service/agent/AgentRequest.java +++ b/modules/service/src/main/java/com/bytedesk/service/agent/AgentRequest.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-02-06 10:16:30 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-04-02 16:41:42 + * @LastEditTime: 2024-04-13 22:29:10 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -18,25 +18,34 @@ import com.bytedesk.core.constant.AvatarConsts; import com.bytedesk.core.constant.BdConstants; import com.bytedesk.core.utils.BaseRequest; +import lombok.Builder; import lombok.Data; import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; @Data +@Builder +@Accessors(chain = true) @EqualsAndHashCode(callSuper = false) public class AgentRequest extends BaseRequest { - private String aid; + private String uid; private String nickname; private String password; + @Builder.Default private String avatar = AvatarConsts.DEFAULT_AGENT_AVATAR_URL; private String mobile; private String email; + @Builder.Default private String description = BdConstants.DEFAULT_AGENT_DESCRIPTION; + // organization oid + private String orgOid; + } diff --git a/modules/service/src/main/java/com/bytedesk/service/agent/AgentResponse.java b/modules/service/src/main/java/com/bytedesk/service/agent/AgentResponse.java index fbf7f19c9b..61122add8a 100644 --- a/modules/service/src/main/java/com/bytedesk/service/agent/AgentResponse.java +++ b/modules/service/src/main/java/com/bytedesk/service/agent/AgentResponse.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-02-06 10:17:01 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-04-02 14:49:30 + * @LastEditTime: 2024-04-16 17:07:56 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -31,7 +31,9 @@ import lombok.experimental.Accessors; @EqualsAndHashCode(callSuper = true) public class AgentResponse extends BaseResponse { - private String aid; + private static final long serialVersionUID = 94072119L; + + private String uid; private String nickname; @@ -43,5 +45,11 @@ public class AgentResponse extends BaseResponse { private String description; + private String acceptStatus; + + private boolean connected; + private Integer maxThreadCount; + + private String welcomeTip; } diff --git a/modules/socket/src/main/java/com/bytedesk/socket/mqtt/model/MqttRetainMessage.java b/modules/service/src/main/java/com/bytedesk/service/agent/AgentResponseSimple.java old mode 100755 new mode 100644 similarity index 66% rename from modules/socket/src/main/java/com/bytedesk/socket/mqtt/model/MqttRetainMessage.java rename to modules/service/src/main/java/com/bytedesk/service/agent/AgentResponseSimple.java index 49ea89e98e..176f8be87c --- a/modules/socket/src/main/java/com/bytedesk/socket/mqtt/model/MqttRetainMessage.java +++ b/modules/service/src/main/java/com/bytedesk/service/agent/AgentResponseSimple.java @@ -1,8 +1,8 @@ /* * @Author: jackning 270580156@qq.com - * @Date: 2024-01-29 16:21:46 + * @Date: 2024-02-06 10:17:01 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-02-29 10:41:38 + * @LastEditTime: 2024-04-16 17:07:43 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -12,29 +12,30 @@ * 联系:270580156@qq.com * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. */ -package com.bytedesk.socket.mqtt.model; +package com.bytedesk.service.agent; -import java.io.Serializable; +import com.bytedesk.core.utils.BaseResponse; import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; +import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; -/** - * Retain标志消息存储 - */ @Data +@Builder @Accessors(chain = true) @AllArgsConstructor @NoArgsConstructor -public class MqttRetainMessage implements Serializable { +@EqualsAndHashCode(callSuper = true) +public class AgentResponseSimple extends BaseResponse { - private static final long serialVersionUID = -7548204047370972779L; + private static final long serialVersionUID = 1219497968L; - private String topic; + private String uid; - private byte[] messageBytes; + private String nickname; - private int mqttQoS; + private String avatar; } diff --git a/modules/service/src/main/java/com/bytedesk/service/agent/AgentService.java b/modules/service/src/main/java/com/bytedesk/service/agent/AgentService.java index 06ab76bdb7..59cbb013a3 100644 --- a/modules/service/src/main/java/com/bytedesk/service/agent/AgentService.java +++ b/modules/service/src/main/java/com/bytedesk/service/agent/AgentService.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-29 16:19:51 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-04-02 16:50:31 + * @LastEditTime: 2024-04-25 15:21:19 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -17,21 +17,25 @@ package com.bytedesk.service.agent; import java.util.Optional; import org.modelmapper.ModelMapper; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.cache.annotation.Caching; +import org.springframework.cache.annotation.CachePut; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; -import com.bytedesk.core.constant.TypeConsts; +import com.bytedesk.core.config.BytedeskProperties; import com.bytedesk.core.rbac.user.User; import com.bytedesk.core.rbac.user.UserService; -import com.bytedesk.core.utils.JsonResult; -import com.bytedesk.core.utils.Utils; -import com.bytedesk.team.department.Department; -import com.bytedesk.team.department.DepartmentRepository; +import com.bytedesk.core.uid.UidUtils; +import com.bytedesk.team.organization.Organization; +import com.bytedesk.team.organization.OrganizationService; import lombok.AllArgsConstructor; +// import lombok.extern.slf4j.Slf4j; // @Slf4j @Service @@ -40,24 +44,33 @@ public class AgentService { private final AgentRepository agentRepository; - private final DepartmentRepository departmentRepository; - private final ModelMapper modelMapper; private final UserService userService; - public Page query(AgentRequest pageParam) { + private final UidUtils uidUtils; - Pageable pageable = PageRequest.of(pageParam.getPageNumber(), - pageParam.getPageSize(), Sort.Direction.DESC, + // private final TopicService topicService; + + // private final AuthService authService; + + private final BytedeskProperties properties; + + private final OrganizationService organizationService; + + public Page query(AgentRequest agentRequest) { + + Pageable pageable = PageRequest.of(agentRequest.getPageNumber(), + agentRequest.getPageSize(), Sort.Direction.DESC, "id"); - Page agentPage = agentRepository.findAll(pageable); + Page agentPage = agentRepository.findByOrgOid(agentRequest.getOrgOid(), pageable); return agentPage.map(this::convertToAgentResponse); } - - public JsonResult create(AgentRequest agentRequest) { + + @Transactional + public Agent create(AgentRequest agentRequest) { // // if (userService.existsByMobile(agentRequest.getMobile())) { // return JsonResult.error("mobile already exist"); @@ -67,15 +80,10 @@ public class AgentService { // } // Agent agent = modelMapper.map(agentRequest, Agent.class); - agent.setAid(Utils.getUid()); - // - Optional depOptional = departmentRepository.findByName(TypeConsts.DEPT_CUSTOMER_SERVICE); - if (!depOptional.isPresent()) { - return JsonResult.error("department not exist"); - } + agent.setUid(uidUtils.getCacheSerialUid()); // User user; - Optional userOptional = userService.findByMobile(agentRequest.getMobile()); + Optional userOptional = userService.findByEmail(agentRequest.getEmail()); if (!userOptional.isPresent()) { user = userService.createUser( agentRequest.getNickname(), @@ -83,40 +91,107 @@ public class AgentService { agentRequest.getPassword(), agentRequest.getMobile(), agentRequest.getEmail(), - true, - depOptional.get().getOrganization().getOid() + true, + agentRequest.getOrgOid() ); } else { + // just return user user = userOptional.get(); - // user = userService.updateUser( - // userOptional.get(), - // agentRequest.getPassword(), - // agentRequest.getMobile(), - // agentRequest.getEmail() - // ); } agent.setUser(user); + + agent = save(agent); // - return JsonResult.success(save(agent)); + return agent; } public AgentResponse update(AgentRequest agentRequest) { Agent agent = modelMapper.map(agentRequest, Agent.class); - return save(agent); + agent = save(agent); + + return convertToAgentResponse(agent); } - @SuppressWarnings("null") - public AgentResponse save(Agent agent) { - return convertToAgentResponse(agentRepository.save(agent)); + public void updateConnect(String uid, boolean isConnect) { + Optional agentOptional = findByUser_Uid(uid); + agentOptional.ifPresent(agent -> { + agent.setConnected(isConnect); + save(agent); + }); + } + + + @Cacheable(value = "agent", key = "#uid", unless="#result == null") + public Optional findByUid(String uid) { + return agentRepository.findByUid(uid); + } + + @Cacheable(value = "agent", key = "#mobile", unless="#result == null") + public Optional findByMobile(String mobile) { + return agentRepository.findByMobile(mobile); + } + + @Cacheable(value = "agent", key = "#email", unless="#result == null") + public Optional findByEmail(String email) { + return agentRepository.findByEmail(email); + } + + @Cacheable(value = "agent", key = "#userUid", unless="#result == null") + public Optional findByUser_Uid(String userUid) { + return agentRepository.findByUser_Uid(userUid); } - private AgentResponse convertToAgentResponse(Agent agent) { - return new ModelMapper().map(agent, AgentResponse.class); + @Caching(put = { + @CachePut(value = "agent", key = "#agent.uid"), + @CachePut(value = "agent", key = "#agent.mobile"), + @CachePut(value = "agent", key = "#agent.email"), + }) + public Agent save(Agent agent) { + return agentRepository.save(agent); + } + + public AgentResponse convertToAgentResponse(Agent agent) { + return modelMapper.map(agent, AgentResponse.class); + } + + public AgentResponseSimple convertToAgentResponseSimple(Agent agent) { + return modelMapper.map(agent, AgentResponseSimple.class); } + public void initData() { + + if (agentRepository.count() > 0) { + return; + } + + Optional orgOptional = organizationService.findByName(properties.getCompany()); + if (orgOptional.isPresent()) { + // add agent + AgentRequest agent1Request = AgentRequest.builder() + .nickname("Agent1") + .email("agent1@email.com") + .mobile("18888888008") + .password("123456") + .orgOid(orgOptional.get().getOid()) + .build(); + create(agent1Request); + // + AgentRequest agent2Request = AgentRequest.builder() + .nickname("Agent2") + .email("agent2@email.com") + .mobile("18888888009") + .password("123456") + .orgOid(orgOptional.get().getOid()) + .build(); + create(agent2Request); + + } + + + } } diff --git a/modules/service/src/main/java/com/bytedesk/service/customer/Customer.java b/modules/service/src/main/java/com/bytedesk/service/customer/Customer.java index 13eb53a17b..dedba330b1 100644 --- a/modules/service/src/main/java/com/bytedesk/service/customer/Customer.java +++ b/modules/service/src/main/java/com/bytedesk/service/customer/Customer.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-02-22 16:52:52 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-03-22 23:12:17 + * @LastEditTime: 2024-04-26 22:53:21 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -16,7 +16,8 @@ package com.bytedesk.service.customer; import com.bytedesk.core.utils.AuditModel; -import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import jakarta.persistence.Embedded; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; @@ -44,7 +45,20 @@ public class Customer extends AuditModel { @Id @GeneratedValue(strategy = GenerationType.AUTO) - @Column(name = "id") private Long id; + private String name; + + + /** + * https://docs.spring.io/spring-data/jpa/reference/repositories/projections.html + */ + @Embedded + Address address; + + @Embeddable + public static class Address { + String zipCode, city, street; + } + } diff --git a/modules/socket/src/main/java/com/bytedesk/socket/mqtt/service/MqttPublishMessageService.java b/modules/service/src/main/java/com/bytedesk/service/customer/CustomerNameOnly.java similarity index 71% rename from modules/socket/src/main/java/com/bytedesk/socket/mqtt/service/MqttPublishMessageService.java rename to modules/service/src/main/java/com/bytedesk/service/customer/CustomerNameOnly.java index 401bc80337..517d6d3fdf 100644 --- a/modules/socket/src/main/java/com/bytedesk/socket/mqtt/service/MqttPublishMessageService.java +++ b/modules/service/src/main/java/com/bytedesk/service/customer/CustomerNameOnly.java @@ -1,8 +1,8 @@ /* * @Author: jackning 270580156@qq.com - * @Date: 2024-01-29 16:21:46 + * @Date: 2024-04-12 12:55:55 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-02-22 15:06:27 + * @LastEditTime: 2024-04-12 15:11:08 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -12,14 +12,14 @@ * 联系:270580156@qq.com * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. */ -package com.bytedesk.socket.mqtt.service; - -import org.springframework.stereotype.Service; +package com.bytedesk.service.customer; /** - * @author bytedesk.com on 2019-07-18 + * https://docs.spring.io/spring-data/jpa/reference/repositories/projections.html */ -@Service -public class MqttPublishMessageService { +public interface CustomerNameOnly { + + String getName(); + // Optional getName(); } diff --git a/modules/service/src/main/java/com/bytedesk/service/customer/CustomerRepository.java b/modules/service/src/main/java/com/bytedesk/service/customer/CustomerRepository.java index 63825e498b..3f07f5a1a9 100644 --- a/modules/service/src/main/java/com/bytedesk/service/customer/CustomerRepository.java +++ b/modules/service/src/main/java/com/bytedesk/service/customer/CustomerRepository.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-03-22 23:06:25 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-03-22 23:06:26 + * @LastEditTime: 2024-04-12 15:12:15 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -14,6 +14,16 @@ */ package com.bytedesk.service.customer; -public class CustomerRepository { +import java.util.Collection; +import org.springframework.data.repository.Repository; + +/** + * https://docs.spring.io/spring-data/jpa/reference/repositories/projections.html + */ +public interface CustomerRepository extends Repository{ + + Collection findByName(String name); + // using a dynamic projection parameter + Collection findByName(String name, Class type); } diff --git a/modules/service/src/main/java/com/bytedesk/service/doc/Doc.java b/modules/service/src/main/java/com/bytedesk/service/customer/CustomerSummary.java similarity index 67% rename from modules/service/src/main/java/com/bytedesk/service/doc/Doc.java rename to modules/service/src/main/java/com/bytedesk/service/customer/CustomerSummary.java index ae8b4f8f52..f8bffacbe9 100644 --- a/modules/service/src/main/java/com/bytedesk/service/doc/Doc.java +++ b/modules/service/src/main/java/com/bytedesk/service/customer/CustomerSummary.java @@ -1,8 +1,8 @@ /* * @Author: jackning 270580156@qq.com - * @Date: 2024-02-22 16:18:37 + * @Date: 2024-04-12 15:06:27 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-02-22 16:20:48 + * @LastEditTime: 2024-04-12 15:09:56 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -12,11 +12,16 @@ * 联系:270580156@qq.com * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. */ -package com.bytedesk.service.doc; +package com.bytedesk.service.customer; /** - * 帮助文档 + * https://docs.spring.io/spring-data/jpa/reference/repositories/projections.html */ -public class Doc { +public interface CustomerSummary { + String getName(); + AddressSummary getAddress(); + interface AddressSummary { + String getCity(); + } } diff --git a/modules/service/src/main/java/com/bytedesk/service/leavemsg/LeaveMessage.java b/modules/service/src/main/java/com/bytedesk/service/leave_msg/LeaveMessage.java similarity index 97% rename from modules/service/src/main/java/com/bytedesk/service/leavemsg/LeaveMessage.java rename to modules/service/src/main/java/com/bytedesk/service/leave_msg/LeaveMessage.java index 70ed28a733..f16d23ea6b 100644 --- a/modules/service/src/main/java/com/bytedesk/service/leavemsg/LeaveMessage.java +++ b/modules/service/src/main/java/com/bytedesk/service/leave_msg/LeaveMessage.java @@ -12,7 +12,7 @@ * 联系:270580156@qq.com * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. */ -package com.bytedesk.service.leavemsg; +package com.bytedesk.service.leave_msg; import com.bytedesk.core.utils.AuditModel; diff --git a/modules/service/src/main/java/com/bytedesk/service/leavemsg/LeaveMessageController.java b/modules/service/src/main/java/com/bytedesk/service/leave_msg/LeaveMessageController.java similarity index 95% rename from modules/service/src/main/java/com/bytedesk/service/leavemsg/LeaveMessageController.java rename to modules/service/src/main/java/com/bytedesk/service/leave_msg/LeaveMessageController.java index 95fe2bf63b..3aceeb2fbc 100644 --- a/modules/service/src/main/java/com/bytedesk/service/leavemsg/LeaveMessageController.java +++ b/modules/service/src/main/java/com/bytedesk/service/leave_msg/LeaveMessageController.java @@ -12,7 +12,7 @@ * 联系:270580156@qq.com * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. */ -package com.bytedesk.service.leavemsg; +package com.bytedesk.service.leave_msg; public class LeaveMessageController { diff --git a/modules/service/src/main/java/com/bytedesk/service/leavemsg/LeaveMessageRepository.java b/modules/service/src/main/java/com/bytedesk/service/leave_msg/LeaveMessageRepository.java similarity index 95% rename from modules/service/src/main/java/com/bytedesk/service/leavemsg/LeaveMessageRepository.java rename to modules/service/src/main/java/com/bytedesk/service/leave_msg/LeaveMessageRepository.java index 4dbc84ec8c..07cae3a561 100644 --- a/modules/service/src/main/java/com/bytedesk/service/leavemsg/LeaveMessageRepository.java +++ b/modules/service/src/main/java/com/bytedesk/service/leave_msg/LeaveMessageRepository.java @@ -12,7 +12,7 @@ * 联系:270580156@qq.com * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. */ -package com.bytedesk.service.leavemsg; +package com.bytedesk.service.leave_msg; public class LeaveMessageRepository { diff --git a/modules/service/src/main/java/com/bytedesk/service/leavemsg/LeaveMessageRequest.java b/modules/service/src/main/java/com/bytedesk/service/leave_msg/LeaveMessageRequest.java similarity index 95% rename from modules/service/src/main/java/com/bytedesk/service/leavemsg/LeaveMessageRequest.java rename to modules/service/src/main/java/com/bytedesk/service/leave_msg/LeaveMessageRequest.java index 141b1fe0f4..b18f3724b4 100644 --- a/modules/service/src/main/java/com/bytedesk/service/leavemsg/LeaveMessageRequest.java +++ b/modules/service/src/main/java/com/bytedesk/service/leave_msg/LeaveMessageRequest.java @@ -12,7 +12,7 @@ * 联系:270580156@qq.com * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. */ -package com.bytedesk.service.leavemsg; +package com.bytedesk.service.leave_msg; public class LeaveMessageRequest { diff --git a/modules/service/src/main/java/com/bytedesk/service/leavemsg/LeaveMessageResponse.java b/modules/service/src/main/java/com/bytedesk/service/leave_msg/LeaveMessageResponse.java similarity index 95% rename from modules/service/src/main/java/com/bytedesk/service/leavemsg/LeaveMessageResponse.java rename to modules/service/src/main/java/com/bytedesk/service/leave_msg/LeaveMessageResponse.java index 67cc2b1ff5..6534461c20 100644 --- a/modules/service/src/main/java/com/bytedesk/service/leavemsg/LeaveMessageResponse.java +++ b/modules/service/src/main/java/com/bytedesk/service/leave_msg/LeaveMessageResponse.java @@ -12,7 +12,7 @@ * 联系:270580156@qq.com * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. */ -package com.bytedesk.service.leavemsg; +package com.bytedesk.service.leave_msg; public class LeaveMessageResponse { diff --git a/modules/service/src/main/java/com/bytedesk/service/leavemsg/LeaveMessageService.java b/modules/service/src/main/java/com/bytedesk/service/leave_msg/LeaveMessageService.java similarity index 95% rename from modules/service/src/main/java/com/bytedesk/service/leavemsg/LeaveMessageService.java rename to modules/service/src/main/java/com/bytedesk/service/leave_msg/LeaveMessageService.java index 94d5739e3a..6555f47a95 100644 --- a/modules/service/src/main/java/com/bytedesk/service/leavemsg/LeaveMessageService.java +++ b/modules/service/src/main/java/com/bytedesk/service/leave_msg/LeaveMessageService.java @@ -12,7 +12,7 @@ * 联系:270580156@qq.com * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. */ -package com.bytedesk.service.leavemsg; +package com.bytedesk.service.leave_msg; public class LeaveMessageService { diff --git a/modules/service/src/main/java/com/bytedesk/service/listener/ServiceEventListener.java b/modules/service/src/main/java/com/bytedesk/service/listener/ServiceEventListener.java new file mode 100644 index 0000000000..f0b32598fc --- /dev/null +++ b/modules/service/src/main/java/com/bytedesk/service/listener/ServiceEventListener.java @@ -0,0 +1,53 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-12 17:58:50 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-16 13:48:59 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.service.listener; + +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Component; + +import com.bytedesk.core.event.MqttConnectedEvent; +import com.bytedesk.service.agent.AgentService; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Component +@AllArgsConstructor +public class ServiceEventListener { + + private AgentService agentService; + + @EventListener + public void onMqttConnectedEvent(MqttConnectedEvent event) { + String clientId = event.getClientId(); + // 用户clientId格式: uid/client + final String uid = clientId.split("/")[0]; + log.info("Service onMqttConnectedEvent uid {}, clientId {}", uid, clientId); + // + agentService.updateConnect(uid, true); + } + + @EventListener + public void onMqttDisconnectedEvent(MqttConnectedEvent event) { + String clientId = event.getClientId(); + // 用户clientId格式: uid/client + final String uid = clientId.split("/")[0]; + log.info("Service onMqttDisconnectedEvent uid {}, clientId {}", uid, clientId); + // + agentService.updateConnect(uid, false); + } + +} diff --git a/modules/service/src/main/java/com/bytedesk/service/qualitycheck/QualityCheck.java b/modules/service/src/main/java/com/bytedesk/service/quality_check/QualityCheck.java similarity index 94% rename from modules/service/src/main/java/com/bytedesk/service/qualitycheck/QualityCheck.java rename to modules/service/src/main/java/com/bytedesk/service/quality_check/QualityCheck.java index bfcaad2da5..4ac70aba0a 100644 --- a/modules/service/src/main/java/com/bytedesk/service/qualitycheck/QualityCheck.java +++ b/modules/service/src/main/java/com/bytedesk/service/quality_check/QualityCheck.java @@ -12,7 +12,7 @@ * 联系:270580156@qq.com * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. */ -package com.bytedesk.service.qualitycheck; +package com.bytedesk.service.quality_check; /** * 质检记录 diff --git a/modules/service/src/main/java/com/bytedesk/service/qualitycheck/QualityCheckAppeal.java b/modules/service/src/main/java/com/bytedesk/service/quality_check/QualityCheckAppeal.java similarity index 95% rename from modules/service/src/main/java/com/bytedesk/service/qualitycheck/QualityCheckAppeal.java rename to modules/service/src/main/java/com/bytedesk/service/quality_check/QualityCheckAppeal.java index 67c823eed6..b3f16b9e6e 100644 --- a/modules/service/src/main/java/com/bytedesk/service/qualitycheck/QualityCheckAppeal.java +++ b/modules/service/src/main/java/com/bytedesk/service/quality_check/QualityCheckAppeal.java @@ -12,7 +12,7 @@ * 联系:270580156@qq.com * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. */ -package com.bytedesk.service.qualitycheck; +package com.bytedesk.service.quality_check; /** * 质检申诉 diff --git a/modules/service/src/main/java/com/bytedesk/service/qualitycheck/QualityCheckPlan.java b/modules/service/src/main/java/com/bytedesk/service/quality_check/QualityCheckPlan.java similarity index 95% rename from modules/service/src/main/java/com/bytedesk/service/qualitycheck/QualityCheckPlan.java rename to modules/service/src/main/java/com/bytedesk/service/quality_check/QualityCheckPlan.java index 82e7e87040..a274f3e409 100644 --- a/modules/service/src/main/java/com/bytedesk/service/qualitycheck/QualityCheckPlan.java +++ b/modules/service/src/main/java/com/bytedesk/service/quality_check/QualityCheckPlan.java @@ -12,7 +12,7 @@ * 联系:270580156@qq.com * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. */ -package com.bytedesk.service.qualitycheck; +package com.bytedesk.service.quality_check; /** * 质检方案 diff --git a/modules/service/src/main/java/com/bytedesk/service/qualitycheck/QualityCheckSetting.java b/modules/service/src/main/java/com/bytedesk/service/quality_check/QualityCheckSetting.java similarity index 95% rename from modules/service/src/main/java/com/bytedesk/service/qualitycheck/QualityCheckSetting.java rename to modules/service/src/main/java/com/bytedesk/service/quality_check/QualityCheckSetting.java index e725f3ff02..ad92807890 100644 --- a/modules/service/src/main/java/com/bytedesk/service/qualitycheck/QualityCheckSetting.java +++ b/modules/service/src/main/java/com/bytedesk/service/quality_check/QualityCheckSetting.java @@ -12,7 +12,7 @@ * 联系:270580156@qq.com * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. */ -package com.bytedesk.service.qualitycheck; +package com.bytedesk.service.quality_check; /** * 质检方案-细分项 diff --git a/modules/service/src/main/java/com/bytedesk/service/qualitycheck/QualityCheckSettingScore.java b/modules/service/src/main/java/com/bytedesk/service/quality_check/QualityCheckSettingScore.java similarity index 95% rename from modules/service/src/main/java/com/bytedesk/service/qualitycheck/QualityCheckSettingScore.java rename to modules/service/src/main/java/com/bytedesk/service/quality_check/QualityCheckSettingScore.java index 7aa6f202b3..c6ba19a24d 100644 --- a/modules/service/src/main/java/com/bytedesk/service/qualitycheck/QualityCheckSettingScore.java +++ b/modules/service/src/main/java/com/bytedesk/service/quality_check/QualityCheckSettingScore.java @@ -12,7 +12,7 @@ * 联系:270580156@qq.com * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. */ -package com.bytedesk.service.qualitycheck; +package com.bytedesk.service.quality_check; /** * 质检方案-细分项-评分 diff --git a/modules/service/src/main/java/com/bytedesk/service/qualitycheck/QualityCheckStatistic.java b/modules/service/src/main/java/com/bytedesk/service/quality_check/QualityCheckStatistic.java similarity index 95% rename from modules/service/src/main/java/com/bytedesk/service/qualitycheck/QualityCheckStatistic.java rename to modules/service/src/main/java/com/bytedesk/service/quality_check/QualityCheckStatistic.java index e53b1249e6..41a90b26dc 100644 --- a/modules/service/src/main/java/com/bytedesk/service/qualitycheck/QualityCheckStatistic.java +++ b/modules/service/src/main/java/com/bytedesk/service/quality_check/QualityCheckStatistic.java @@ -12,7 +12,7 @@ * 联系:270580156@qq.com * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. */ -package com.bytedesk.service.qualitycheck; +package com.bytedesk.service.quality_check; /** * 质检统计 diff --git a/modules/service/src/main/java/com/bytedesk/service/quickbutton/QuickButton.java b/modules/service/src/main/java/com/bytedesk/service/quick_button/QuickButton.java similarity index 97% rename from modules/service/src/main/java/com/bytedesk/service/quickbutton/QuickButton.java rename to modules/service/src/main/java/com/bytedesk/service/quick_button/QuickButton.java index 91089525b4..c8769b9311 100644 --- a/modules/service/src/main/java/com/bytedesk/service/quickbutton/QuickButton.java +++ b/modules/service/src/main/java/com/bytedesk/service/quick_button/QuickButton.java @@ -12,7 +12,7 @@ * 联系:270580156@qq.com * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. */ -package com.bytedesk.service.quickbutton; +package com.bytedesk.service.quick_button; import com.bytedesk.core.utils.AuditModel; diff --git a/modules/service/src/main/java/com/bytedesk/service/quickbutton/QuickButtonController.java b/modules/service/src/main/java/com/bytedesk/service/quick_button/QuickButtonController.java similarity index 95% rename from modules/service/src/main/java/com/bytedesk/service/quickbutton/QuickButtonController.java rename to modules/service/src/main/java/com/bytedesk/service/quick_button/QuickButtonController.java index d1ebf468ad..97be3d270e 100644 --- a/modules/service/src/main/java/com/bytedesk/service/quickbutton/QuickButtonController.java +++ b/modules/service/src/main/java/com/bytedesk/service/quick_button/QuickButtonController.java @@ -12,7 +12,7 @@ * 联系:270580156@qq.com * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. */ -package com.bytedesk.service.quickbutton; +package com.bytedesk.service.quick_button; public class QuickButtonController { diff --git a/modules/service/src/main/java/com/bytedesk/service/quickbutton/QuickButtonRepository.java b/modules/service/src/main/java/com/bytedesk/service/quick_button/QuickButtonRepository.java similarity index 95% rename from modules/service/src/main/java/com/bytedesk/service/quickbutton/QuickButtonRepository.java rename to modules/service/src/main/java/com/bytedesk/service/quick_button/QuickButtonRepository.java index be3a3d699b..b40ef811e5 100644 --- a/modules/service/src/main/java/com/bytedesk/service/quickbutton/QuickButtonRepository.java +++ b/modules/service/src/main/java/com/bytedesk/service/quick_button/QuickButtonRepository.java @@ -12,7 +12,7 @@ * 联系:270580156@qq.com * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. */ -package com.bytedesk.service.quickbutton; +package com.bytedesk.service.quick_button; public class QuickButtonRepository { diff --git a/modules/service/src/main/java/com/bytedesk/service/quickbutton/QuickButtonRequest.java b/modules/service/src/main/java/com/bytedesk/service/quick_button/QuickButtonRequest.java similarity index 94% rename from modules/service/src/main/java/com/bytedesk/service/quickbutton/QuickButtonRequest.java rename to modules/service/src/main/java/com/bytedesk/service/quick_button/QuickButtonRequest.java index 77396cba63..c101e24633 100644 --- a/modules/service/src/main/java/com/bytedesk/service/quickbutton/QuickButtonRequest.java +++ b/modules/service/src/main/java/com/bytedesk/service/quick_button/QuickButtonRequest.java @@ -12,7 +12,7 @@ * 联系:270580156@qq.com * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. */ -package com.bytedesk.service.quickbutton; +package com.bytedesk.service.quick_button; public class QuickButtonRequest { diff --git a/modules/service/src/main/java/com/bytedesk/service/quickbutton/QuickButtonResponse.java b/modules/service/src/main/java/com/bytedesk/service/quick_button/QuickButtonResponse.java similarity index 94% rename from modules/service/src/main/java/com/bytedesk/service/quickbutton/QuickButtonResponse.java rename to modules/service/src/main/java/com/bytedesk/service/quick_button/QuickButtonResponse.java index f55b0ba833..cee51fe320 100644 --- a/modules/service/src/main/java/com/bytedesk/service/quickbutton/QuickButtonResponse.java +++ b/modules/service/src/main/java/com/bytedesk/service/quick_button/QuickButtonResponse.java @@ -12,7 +12,7 @@ * 联系:270580156@qq.com * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. */ -package com.bytedesk.service.quickbutton; +package com.bytedesk.service.quick_button; public class QuickButtonResponse { diff --git a/modules/service/src/main/java/com/bytedesk/service/quickbutton/QuickButtonService.java b/modules/service/src/main/java/com/bytedesk/service/quick_button/QuickButtonService.java similarity index 94% rename from modules/service/src/main/java/com/bytedesk/service/quickbutton/QuickButtonService.java rename to modules/service/src/main/java/com/bytedesk/service/quick_button/QuickButtonService.java index b6feaa5205..7c7594ca2c 100644 --- a/modules/service/src/main/java/com/bytedesk/service/quickbutton/QuickButtonService.java +++ b/modules/service/src/main/java/com/bytedesk/service/quick_button/QuickButtonService.java @@ -12,7 +12,7 @@ * 联系:270580156@qq.com * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. */ -package com.bytedesk.service.quickbutton; +package com.bytedesk.service.quick_button; public class QuickButtonService { diff --git a/modules/service/src/main/java/com/bytedesk/service/quickreply/QuickReply.java b/modules/service/src/main/java/com/bytedesk/service/quick_reply/QuickReply.java similarity index 97% rename from modules/service/src/main/java/com/bytedesk/service/quickreply/QuickReply.java rename to modules/service/src/main/java/com/bytedesk/service/quick_reply/QuickReply.java index 290bcb617c..4df8700d19 100644 --- a/modules/service/src/main/java/com/bytedesk/service/quickreply/QuickReply.java +++ b/modules/service/src/main/java/com/bytedesk/service/quick_reply/QuickReply.java @@ -12,7 +12,7 @@ * 联系:270580156@qq.com * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. */ -package com.bytedesk.service.quickreply; +package com.bytedesk.service.quick_reply; import com.bytedesk.core.utils.AuditModel; diff --git a/modules/service/src/main/java/com/bytedesk/service/quickreply/QuickReplyController.java b/modules/service/src/main/java/com/bytedesk/service/quick_reply/QuickReplyController.java similarity index 95% rename from modules/service/src/main/java/com/bytedesk/service/quickreply/QuickReplyController.java rename to modules/service/src/main/java/com/bytedesk/service/quick_reply/QuickReplyController.java index 914a583aa4..091e9fc944 100644 --- a/modules/service/src/main/java/com/bytedesk/service/quickreply/QuickReplyController.java +++ b/modules/service/src/main/java/com/bytedesk/service/quick_reply/QuickReplyController.java @@ -12,7 +12,7 @@ * 联系:270580156@qq.com * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. */ -package com.bytedesk.service.quickreply; +package com.bytedesk.service.quick_reply; public class QuickReplyController { diff --git a/modules/service/src/main/java/com/bytedesk/service/quickreply/QuickReplyRepository.java b/modules/service/src/main/java/com/bytedesk/service/quick_reply/QuickReplyRepository.java similarity index 95% rename from modules/service/src/main/java/com/bytedesk/service/quickreply/QuickReplyRepository.java rename to modules/service/src/main/java/com/bytedesk/service/quick_reply/QuickReplyRepository.java index 2394979dbf..c3ab28e852 100644 --- a/modules/service/src/main/java/com/bytedesk/service/quickreply/QuickReplyRepository.java +++ b/modules/service/src/main/java/com/bytedesk/service/quick_reply/QuickReplyRepository.java @@ -12,7 +12,7 @@ * 联系:270580156@qq.com * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. */ -package com.bytedesk.service.quickreply; +package com.bytedesk.service.quick_reply; public interface QuickReplyRepository { diff --git a/modules/service/src/main/java/com/bytedesk/service/quickreply/QuickReplyRequest.java b/modules/service/src/main/java/com/bytedesk/service/quick_reply/QuickReplyRequest.java similarity index 95% rename from modules/service/src/main/java/com/bytedesk/service/quickreply/QuickReplyRequest.java rename to modules/service/src/main/java/com/bytedesk/service/quick_reply/QuickReplyRequest.java index 64d48a2b7f..395433f09c 100644 --- a/modules/service/src/main/java/com/bytedesk/service/quickreply/QuickReplyRequest.java +++ b/modules/service/src/main/java/com/bytedesk/service/quick_reply/QuickReplyRequest.java @@ -12,7 +12,7 @@ * 联系:270580156@qq.com * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. */ -package com.bytedesk.service.quickreply; +package com.bytedesk.service.quick_reply; public class QuickReplyRequest { diff --git a/modules/service/src/main/java/com/bytedesk/service/quickreply/QuickReplyResponse.java b/modules/service/src/main/java/com/bytedesk/service/quick_reply/QuickReplyResponse.java similarity index 95% rename from modules/service/src/main/java/com/bytedesk/service/quickreply/QuickReplyResponse.java rename to modules/service/src/main/java/com/bytedesk/service/quick_reply/QuickReplyResponse.java index d9545f5df9..a81f939ca7 100644 --- a/modules/service/src/main/java/com/bytedesk/service/quickreply/QuickReplyResponse.java +++ b/modules/service/src/main/java/com/bytedesk/service/quick_reply/QuickReplyResponse.java @@ -12,7 +12,7 @@ * 联系:270580156@qq.com * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. */ -package com.bytedesk.service.quickreply; +package com.bytedesk.service.quick_reply; public class QuickReplyResponse { diff --git a/modules/service/src/main/java/com/bytedesk/service/quickreply/QuickReplyService.java b/modules/service/src/main/java/com/bytedesk/service/quick_reply/QuickReplyService.java similarity index 95% rename from modules/service/src/main/java/com/bytedesk/service/quickreply/QuickReplyService.java rename to modules/service/src/main/java/com/bytedesk/service/quick_reply/QuickReplyService.java index a03acd74ff..71541bddc2 100644 --- a/modules/service/src/main/java/com/bytedesk/service/quickreply/QuickReplyService.java +++ b/modules/service/src/main/java/com/bytedesk/service/quick_reply/QuickReplyService.java @@ -12,7 +12,7 @@ * 联系:270580156@qq.com * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. */ -package com.bytedesk.service.quickreply; +package com.bytedesk.service.quick_reply; public class QuickReplyService { diff --git a/modules/service/src/main/java/com/bytedesk/service/route/AbstractStrategyRouter.java b/modules/service/src/main/java/com/bytedesk/service/route/AbstractStrategyRouter.java new file mode 100644 index 0000000000..13f3d14e7d --- /dev/null +++ b/modules/service/src/main/java/com/bytedesk/service/route/AbstractStrategyRouter.java @@ -0,0 +1,113 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-09 14:56:40 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-09 15:01:57 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.service.route; + +import java.util.Objects; + +import org.springframework.stereotype.Component; + +import jakarta.annotation.PostConstruct; +import lombok.Getter; +import lombok.Setter; + +/** + * https://mp.weixin.qq.com/s/Wib0Ly45te00HMUnIG-tbg + * https://edu.aliyun.com/course/313614 + * + * 通用的“策略树“框架,通过树形结构实现分发与委托,每层通过指定的参数进行向下分发委托,直到达到最终的执行者。 + * 该框架包含两个类:{@code StrategyHandler} 和 {@code AbstractStrategyRouter} + * 其中:通过实现 {@code AbstractStrategyRouter} 抽象类完成对策略的分发, + * 实现 {@code StrategyHandler} 接口来对策略进行实现。 + * 像是第二层 A、B 这样的节点,既是 Root 节点的策略实现者也是策略A1、A2、B1、B2 的分发者,这样的节点只需要 + * 同时继承 {@code StrategyHandler} 和实现 {@code AbstractStrategyRouter} 接口就可以了。 + * + *

    + *           +---------+
    + *           |  Root   |   ----------- 第 1 层策略入口
    + *           +---------+
    + *            /       \  ------------- 根据入参 P1 进行策略分发
    + *           /         \
    + *     +------+      +------+
    + *     |  A   |      |  B   |  ------- 第 2 层不同策略的实现
    + *     +------+      +------+
    + *       /  \          /  \  --------- 根据入参 P2 进行策略分发
    + *      /    \        /    \
    + *   +---+  +---+  +---+  +---+
    + *   |A1 |  |A2 |  |B1 |  |B2 |  ----- 第 3 层不同策略的实现
    + *   +---+  +---+  +---+  +---+
    + * 
    + * + * @author + * @date + * @see StrategyHandler + */ +@Component +public abstract class AbstractStrategyRouter { + + /** + * 策略映射器,根据指定的入参路由到对应的策略处理者。 + * + * @param 策略的入参类型 + * @param 策略的返回值类型 + */ + public interface StrategyMapper { + /** + * 根据入参获取到对应的策略处理者。可通过 if-else 实现,也可通过 Map 实现。 + * + * @param param 入参 + * @return 策略处理者 + */ + StrategyHandler get(T param); + } + + private StrategyMapper strategyMapper; + + /** + * 类初始化时注册分发策略 Mapper + */ + @PostConstruct + private void abstractInit() { + strategyMapper = registerStrategyMapper(); + Objects.requireNonNull(strategyMapper, "strategyMapper cannot be null"); + } + + @Getter + @Setter + @SuppressWarnings("unchecked") + private StrategyHandler defaultStrategyHandler = StrategyHandler.DEFAULT; + + /** + * 执行策略,框架会自动根据策略分发至下游的 Handler 进行处理 + * + * @param param 入参 + * @return 下游执行者给出的返回值 + */ + public R applyStrategy(T param) { + final StrategyHandler strategyHandler = strategyMapper.get(param); + if (strategyHandler != null) { + return strategyHandler.apply(param); + } + + return defaultStrategyHandler.apply(param); + } + + /** + * 抽象方法,需要子类实现策略的分发逻辑 + * + * @return 分发逻辑 Mapper 对象 + */ + protected abstract StrategyMapper registerStrategyMapper(); + +} diff --git a/modules/service/src/main/java/com/bytedesk/service/route/IRouteService.java b/modules/service/src/main/java/com/bytedesk/service/route/IRouteService.java new file mode 100644 index 0000000000..eebdfba996 --- /dev/null +++ b/modules/service/src/main/java/com/bytedesk/service/route/IRouteService.java @@ -0,0 +1,19 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-08 13:03:35 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-09 13:08:44 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.service.route; + +public interface IRouteService { + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/push/EmailService.java b/modules/service/src/main/java/com/bytedesk/service/route/Route.java similarity index 84% rename from modules/core/src/main/java/com/bytedesk/core/push/EmailService.java rename to modules/service/src/main/java/com/bytedesk/service/route/Route.java index 677135250f..7f4126f1f2 100644 --- a/modules/core/src/main/java/com/bytedesk/core/push/EmailService.java +++ b/modules/service/src/main/java/com/bytedesk/service/route/Route.java @@ -1,8 +1,8 @@ /* * @Author: jackning 270580156@qq.com - * @Date: 2024-03-31 15:30:19 + * @Date: 2024-04-08 13:03:09 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-03-31 15:30:22 + * @LastEditTime: 2024-04-08 13:03:12 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -12,8 +12,8 @@ * 联系:270580156@qq.com * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. */ -package com.bytedesk.core.push; +package com.bytedesk.service.route; -public class EmailService { +public class Route { } diff --git a/modules/service/src/main/java/com/bytedesk/service/route/RouteFactory.java b/modules/service/src/main/java/com/bytedesk/service/route/RouteFactory.java new file mode 100644 index 0000000000..35d6051abb --- /dev/null +++ b/modules/service/src/main/java/com/bytedesk/service/route/RouteFactory.java @@ -0,0 +1,19 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-09 14:05:05 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-09 14:05:08 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.service.route; + +public class RouteFactory { + +} diff --git a/modules/service/src/main/java/com/bytedesk/service/route/RouteRepository.java b/modules/service/src/main/java/com/bytedesk/service/route/RouteRepository.java new file mode 100644 index 0000000000..3d85fc3586 --- /dev/null +++ b/modules/service/src/main/java/com/bytedesk/service/route/RouteRepository.java @@ -0,0 +1,19 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-08 13:04:04 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-08 13:04:06 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.service.route; + +public interface RouteRepository { + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/rbac/action/ActionService.java b/modules/service/src/main/java/com/bytedesk/service/route/StrategyHandler.java similarity index 66% rename from modules/core/src/main/java/com/bytedesk/core/rbac/action/ActionService.java rename to modules/service/src/main/java/com/bytedesk/service/route/StrategyHandler.java index 7842410b18..476ebdffc1 100644 --- a/modules/core/src/main/java/com/bytedesk/core/rbac/action/ActionService.java +++ b/modules/service/src/main/java/com/bytedesk/service/route/StrategyHandler.java @@ -1,8 +1,8 @@ /* * @Author: jackning 270580156@qq.com - * @Date: 2024-01-29 16:21:24 + * @Date: 2024-04-09 15:01:26 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-03-29 14:03:51 + * @LastEditTime: 2024-04-09 15:01:28 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -12,24 +12,24 @@ * 联系:270580156@qq.com * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. */ -package com.bytedesk.core.rbac.action; +package com.bytedesk.service.route; -import lombok.AllArgsConstructor; - -import org.springframework.stereotype.Service; - -import java.util.List; - -// @Slf4j -@Service -@AllArgsConstructor -public class ActionService { - - private final ActionRepository actionRepository; - - public List findAll() { - return actionRepository.findAll(); - } +/** + * https://mp.weixin.qq.com/s/Wib0Ly45te00HMUnIG-tbg + * + * @author + * @date + */ +public interface StrategyHandler { + @SuppressWarnings("rawtypes") + StrategyHandler DEFAULT = t -> null; + /** + * apply strategy + * + * @param param + * @return + */ + R apply(T param); } diff --git a/modules/service/src/main/java/com/bytedesk/service/thread_log/ThreadLog.java b/modules/service/src/main/java/com/bytedesk/service/thread_log/ThreadLog.java new file mode 100644 index 0000000000..29bb66f817 --- /dev/null +++ b/modules/service/src/main/java/com/bytedesk/service/thread_log/ThreadLog.java @@ -0,0 +1,115 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-09 16:34:13 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-22 21:38:50 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.service.thread_log; + +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; + +import com.bytedesk.core.constant.BdConstants; +import com.bytedesk.core.constant.StatusConsts; +import com.bytedesk.core.constant.ThreadTypeConsts; +import com.bytedesk.core.rbac.user.User; +import com.bytedesk.core.utils.AuditModel; +import com.fasterxml.jackson.annotation.JsonIgnore; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +/** + * only for customer service thread history, 只记录客服对话历史,不记录同事和群组对话历史 + * visitor service history, used for admin backend query + * thread table in core module is used for agent client query to avoid duplication + */ +@Entity +@Data +@Builder +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = true) +@AllArgsConstructor +@NoArgsConstructor +@Table(name = "service_thread_log") +public class ThreadLog extends AuditModel { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private Long id; + + @Column(unique = true, nullable = false) + private String tid; + + /** + * used to push message + * topic format: + * workgroup_wid + '/' + visitor_vid + * agent_aid + '/' + visitor_vid + * such as: wid/vid or aid/vid + */ + private String topic; + + @Builder.Default + private String content = BdConstants.EMPTY_STRING; + + @Builder.Default + private Integer unreadCount = 0; + + /** + * @{ThreadTypeConsts} + */ + @Builder.Default + @Column(name = "by_type") + private String type = ThreadTypeConsts.WORKGROUP; + + // closed/open + @Builder.Default + private String status = StatusConsts.THREAD_STATUS_OPEN; + + private String client; + + // @Lob + @Builder.Default + @Column(columnDefinition = "json") + // 用于兼容postgreSQL,否则会报错,[ERROR: column "extra" is of type json but expression is of type character varying + @JdbcTypeCode(SqlTypes.JSON) + private String extra = BdConstants.EMPTY_JSON_STRING; + + // + // h2 db 不能使用 user, 所以重定义为 by_user + @Builder.Default + @Column(name = "by_user", columnDefinition = "json") + @JdbcTypeCode(SqlTypes.JSON) + private String user = BdConstants.EMPTY_JSON_STRING; + + /** belongs to user */ + @JsonIgnore + @ManyToOne(fetch = FetchType.LAZY) + private User owner; + + + /** belong to org */ + private String orgOid; + +} diff --git a/modules/service/src/main/java/com/bytedesk/service/thread_log/ThreadLogController.java b/modules/service/src/main/java/com/bytedesk/service/thread_log/ThreadLogController.java new file mode 100644 index 0000000000..89050837d3 --- /dev/null +++ b/modules/service/src/main/java/com/bytedesk/service/thread_log/ThreadLogController.java @@ -0,0 +1,19 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-18 10:48:52 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-18 10:48:54 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.service.thread_log; + +public class ThreadLogController { + +} diff --git a/modules/service/src/main/java/com/bytedesk/service/thread_log/ThreadLogRepository.java b/modules/service/src/main/java/com/bytedesk/service/thread_log/ThreadLogRepository.java new file mode 100644 index 0000000000..f2903c7a64 --- /dev/null +++ b/modules/service/src/main/java/com/bytedesk/service/thread_log/ThreadLogRepository.java @@ -0,0 +1,26 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-18 10:48:16 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-22 16:21:55 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.service.thread_log; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface ThreadLogRepository extends JpaRepository { + + Page findByOrgOid(String orgOid, Pageable pageable); + + Boolean existsByTid(String tid); +} diff --git a/modules/core/src/main/java/com/bytedesk/core/rbac/action/ActionRequest.java b/modules/service/src/main/java/com/bytedesk/service/thread_log/ThreadLogRequest.java similarity index 69% rename from modules/core/src/main/java/com/bytedesk/core/rbac/action/ActionRequest.java rename to modules/service/src/main/java/com/bytedesk/service/thread_log/ThreadLogRequest.java index 9aa185ef8e..c9257799ab 100644 --- a/modules/core/src/main/java/com/bytedesk/core/rbac/action/ActionRequest.java +++ b/modules/service/src/main/java/com/bytedesk/service/thread_log/ThreadLogRequest.java @@ -1,8 +1,8 @@ /* * @Author: jackning 270580156@qq.com - * @Date: 2024-02-26 11:28:15 + * @Date: 2024-04-18 10:48:52 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-03-29 14:03:29 + * @LastEditTime: 2024-04-22 16:19:53 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -12,22 +12,23 @@ * 联系:270580156@qq.com * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. */ -package com.bytedesk.core.rbac.action; +package com.bytedesk.service.thread_log; import com.bytedesk.core.utils.BaseRequest; +import lombok.Builder; import lombok.Data; import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; @Data -@EqualsAndHashCode(callSuper = true) -public class ActionRequest extends BaseRequest { +@Builder +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = false) +public class ThreadLogRequest extends BaseRequest { + + - private String aid; - - private String name; - - private String value; - - private String description; + // organization oid + private String orgOid; } diff --git a/modules/service/src/main/java/com/bytedesk/service/thread_log/ThreadLogResponse.java b/modules/service/src/main/java/com/bytedesk/service/thread_log/ThreadLogResponse.java new file mode 100644 index 0000000000..97c73534f6 --- /dev/null +++ b/modules/service/src/main/java/com/bytedesk/service/thread_log/ThreadLogResponse.java @@ -0,0 +1,55 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-18 10:49:12 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-22 16:24:06 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.service.thread_log; + +import java.util.Date; + +import com.bytedesk.core.rbac.user.UserResponseSimple; +import com.bytedesk.core.utils.BaseResponse; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + + +@Data +@Builder +@Accessors(chain = true) +@AllArgsConstructor +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class ThreadLogResponse extends BaseResponse { + + private static final long serialVersionUID = 7910814181L; + + private String tid; + + private String topic; + + private String content; + + private Integer unreadCount; + + private String type; + + private String extra; + + private Date createdAt; + + private UserResponseSimple user; +} diff --git a/modules/service/src/main/java/com/bytedesk/service/thread_log/ThreadLogService.java b/modules/service/src/main/java/com/bytedesk/service/thread_log/ThreadLogService.java new file mode 100644 index 0000000000..7cb019b219 --- /dev/null +++ b/modules/service/src/main/java/com/bytedesk/service/thread_log/ThreadLogService.java @@ -0,0 +1,125 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-18 10:47:38 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-25 20:43:01 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.service.thread_log; + +import java.util.Date; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.modelmapper.ModelMapper; +import org.springframework.data.domain.Sort; +import org.springframework.scheduling.annotation.Async; +import org.springframework.context.event.EventListener; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; + +import com.alibaba.fastjson2.JSON; +import com.bytedesk.core.event.ThreadCreateEvent; +import com.bytedesk.core.event.ThreadUpdateEvent; +import com.bytedesk.core.thread.Thread; +import com.bytedesk.core.thread.ThreadService; +import com.bytedesk.service.visitor.VisitorExtra; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Service +@AllArgsConstructor +public class ThreadLogService { + + private final ThreadLogRepository threadLogRepository; + + private final ModelMapper modelMapper; + + private final ThreadService threadService; + + public Page query(ThreadLogRequest threadLogRequest) { + + Pageable pageable = PageRequest.of(threadLogRequest.getPageNumber(), + threadLogRequest.getPageSize(), Sort.Direction.DESC, + "updatedAt"); + + Page threadLogPage = threadLogRepository.findByOrgOid(threadLogRequest.getOrgOid(), pageable); + + return threadLogPage.map(this::convertThreadLogResponse); + } + + @Async + public ThreadLog create(Thread thread) { + + if (threadLogRepository.existsByTid(thread.getTid())) { + return null; + } + + ThreadLog threadLog = modelMapper.map(thread, ThreadLog.class); + + return save(threadLog); + } + + /** + * + * TODO: 座席端25分钟不回复则自动断开,推送满意度 + * TODO: 客户端2分钟没有回复坐席则自动推送1分钟计时提醒: + * 温馨提示:您已经有2分钟未有操作了,如再有1分钟未有操作,系统将自动结束本次对话,感谢您的支持与谅解 + * 如果1分钟之内无回复,则推送满意度: + */ + // TODO: 频繁查库,待优化 + @Async + public void autoCloseThread() { + // List threads = threadService.findByExtraClosed(); + List threads = threadService.findStatusOpen(); + // log.info("autoCloseThread size {}", threads.size()); + threads.forEach(thread -> { + // + VisitorExtra extra = JSON.parseObject(thread.getExtra(), VisitorExtra.class); + // 计算两个日期之间的毫秒差 + long diffInMilliseconds = Math.abs(new Date().getTime() - thread.getUpdatedAt().getTime()); + // 转换为分钟 + long diffInMinutes = TimeUnit.MILLISECONDS.toMinutes(diffInMilliseconds); + if (diffInMinutes > extra.getAutoCloseMin()) { + // 关闭线程 + threadService.autoClose(thread); + } else { + // log.debug("autoCloseThread: {}, min: {}", thread.getTid(), diffInMinutes); + } + }); + } + + public ThreadLog save(ThreadLog threadLog) { + return threadLogRepository.save(threadLog); + } + + public ThreadLogResponse convertThreadLogResponse(ThreadLog threadLog) { + return modelMapper.map(threadLog, ThreadLogResponse.class); + } + + + @EventListener + public void onThreadCreateEvent(ThreadCreateEvent event) { + Thread thread = event.getThread(); + log.info("onThreadCreateEvent: {}", thread.getTid()); + // create(thread); + } + + @EventListener + public void onThreadUpdateEvent(ThreadUpdateEvent event) { + Thread thread = event.getThread(); + log.info("onThreadUpdateEvent: {}", thread.getTid()); + } + +} diff --git a/modules/service/src/main/java/com/bytedesk/service/visitor/Visitor.java b/modules/service/src/main/java/com/bytedesk/service/visitor/Visitor.java index b2dd214e60..c8729b8880 100644 --- a/modules/service/src/main/java/com/bytedesk/service/visitor/Visitor.java +++ b/modules/service/src/main/java/com/bytedesk/service/visitor/Visitor.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-29 16:21:24 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-04-04 17:01:14 + * @LastEditTime: 2024-04-12 12:50:01 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -14,6 +14,7 @@ */ package com.bytedesk.service.visitor; +import com.bytedesk.core.constant.AvatarConsts; import com.bytedesk.core.utils.AuditModel; import jakarta.persistence.Column; @@ -22,15 +23,23 @@ import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; /** * visitor no need to login, without login can reduce the press of the database */ @Entity @Data +@Builder +@Accessors(chain = true) @EqualsAndHashCode(callSuper = false) +@AllArgsConstructor +@NoArgsConstructor @Table(name = "service_visitor") public class Visitor extends AuditModel { @@ -40,30 +49,36 @@ public class Visitor extends AuditModel { /** */ - @Column(unique = true, length = 127) - private String vid; + @Column(name = "uuid", unique = true, nullable = false) + private String uid; /** * developers can set basic visitor info */ private String nickname; - private String avatar; - - private String mobile; - - private String email; + @Builder.Default + private String avatar = AvatarConsts.DEFAULT_VISITOR_AVATAR_URL; + // location info private String ip; private String ipLocation; + // device info private String browser; private String os; private String device; + private String referrer; + + // used for agent notation + private String mobile; + + private String email; + private String note; } \ No newline at end of file diff --git a/modules/service/src/main/java/com/bytedesk/service/visitor/VisitorAspect.java b/modules/service/src/main/java/com/bytedesk/service/visitor/VisitorAspect.java index 224807ac24..c43db95840 100644 --- a/modules/service/src/main/java/com/bytedesk/service/visitor/VisitorAspect.java +++ b/modules/service/src/main/java/com/bytedesk/service/visitor/VisitorAspect.java @@ -1,8 +1,8 @@ /* - * @Visitoror: jackning 270580156@qq.com + * @Author: jackning 270580156@qq.com * @Date: 2024-04-05 14:51:45 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-04-05 14:54:48 + * @LastEditTime: 2024-04-17 17:17:12 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -14,7 +14,6 @@ */ package com.bytedesk.service.visitor; -import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; @@ -31,18 +30,37 @@ import lombok.extern.slf4j.Slf4j; public class VisitorAspect { @Pointcut("execution(* com.bytedesk.service.visitor.VisitorController.*(..))") - public void visitorLog() { - log.debug("ActionAspect visitorLog"); - }; + public void visitorLog() {}; @Before("visitorLog()") public void beforeVisitorLog() { - log.debug("ActionAspect beforeVisitorLog"); + // TODO: 拦截骚扰用户 + 被禁ip/ip段 + log.debug("VisitorAspect TODO: 拦截骚扰用户 + 被禁ip/ip段"); } - @After("visitorLog()") - public void afterVisitorLog() { - log.debug("ActionAspect afterVisitorLog"); - // TODO: action log save to db - } + // @After("visitorLog()") + // public void afterVisitorLog() { + // log.debug("VisitorAspect afterVisitorLog"); + // // TODO: action log save to db + // } + + // @Around("visitorLog()") + // public Object aroundVisitorLog(ProceedingJoinPoint joinPoint) throws Throwable { + // log.debug("VisitorAspect aroundVisitorLog before"); + + // long start = System.currentTimeMillis(); + + // // body + // Object result = joinPoint.proceed(); + + // long executionTime = System.currentTimeMillis() - start; + + // log.debug("{} executed in {} ms", joinPoint.getSignature(), executionTime); + + // log.debug("VisitorAspect aroundVisitorLog after"); + + // return result; + // } + + } diff --git a/modules/service/src/main/java/com/bytedesk/service/visitor/VisitorController.java b/modules/service/src/main/java/com/bytedesk/service/visitor/VisitorController.java index a00fb5fddb..66fd5a50a9 100644 --- a/modules/service/src/main/java/com/bytedesk/service/visitor/VisitorController.java +++ b/modules/service/src/main/java/com/bytedesk/service/visitor/VisitorController.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-29 16:21:24 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-04-05 15:25:09 + * @LastEditTime: 2024-04-11 16:50:29 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -21,17 +21,19 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import com.bytedesk.core.annotation.ApiRateLimiter; +import com.bytedesk.core.message.MessageResponse; import com.bytedesk.core.utils.BaseRequest; import com.bytedesk.core.utils.JsonResult; - +import jakarta.servlet.http.HttpServletRequest; import lombok.AllArgsConstructor; -import lombok.extern.slf4j.Slf4j; +// import lombok.extern.slf4j.Slf4j; /** * anonymous api, no need to login * http://localhost:9003/swagger-ui/index.html */ -@Slf4j +// @Slf4j @RestController @AllArgsConstructor @RequestMapping("/visitor/api/v1/") @@ -41,41 +43,43 @@ public class VisitorController { /** * init visitor cookies in browser & generate visitor in db + * + * considering multi request from different clients, including ios/android/web, + * apis should not use cookies which is specific to web browsers * http://localhost:9003/visitor/api/v1/init * * @param visitorRequest * @return */ + @ApiRateLimiter(value = 10.0, timeout = 1) @GetMapping("/init") - public ResponseEntity init(VisitorRequest visitorRequest) { + public ResponseEntity init(VisitorRequest visitorRequest, HttpServletRequest request) { + // + Visitor visitor = visitorService.create(visitorRequest, request); + if (visitor == null) { + return ResponseEntity.ok(JsonResult.error("init visitor failed", -401)); + } - log.info("visitor init"); - - return ResponseEntity.ok(JsonResult.success()); + return ResponseEntity.ok(JsonResult.success(visitorService.convertToVisitorResponseSimple(visitor))); } /** - * query + * request thread * * @param visitorRequest * @return */ - @GetMapping("/query") - public ResponseEntity query(VisitorRequest visitorRequest) { - - return ResponseEntity.ok(JsonResult.success()); - } - - /** - * create - * - * @param visitorRequest visitor - * @return json - */ - @PostMapping("/create") - public ResponseEntity create(@RequestBody VisitorRequest visitorRequest) { - - return ResponseEntity.ok(JsonResult.success()); + @GetMapping("/thread") + public ResponseEntity requestThread(VisitorRequest visitorRequest, HttpServletRequest request) { + // TODO: check if visitor is banned + // TODO: check if visitor ip is banned + // + MessageResponse messageResponse = visitorService.createCustomerServiceThread(visitorRequest); + if (messageResponse == null) { + return ResponseEntity.ok(JsonResult.error("sid not exist", -402)); + } + // + return ResponseEntity.ok(JsonResult.success(messageResponse)); } /** diff --git a/modules/service/src/main/java/com/bytedesk/service/visitor/VisitorExtra.java b/modules/service/src/main/java/com/bytedesk/service/visitor/VisitorExtra.java new file mode 100644 index 0000000000..e9595b01cd --- /dev/null +++ b/modules/service/src/main/java/com/bytedesk/service/visitor/VisitorExtra.java @@ -0,0 +1,55 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-08 12:03:27 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-23 10:01:27 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.service.visitor; + +import com.bytedesk.service.agent.AgentResponseSimple; +import com.bytedesk.core.constant.BdConstants; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +/** + * used for visitor thread extra info + */ +@Data +@Builder +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = false) +@AllArgsConstructor +@NoArgsConstructor +public class VisitorExtra { + + @Builder.Default + private String welcomeTip = BdConstants.DEFAULT_WORK_GROUP_ACCEPT_TIP; + + // visitor_vid + // private String uid; + private VisitorResponseSimple visitor; + + private AgentResponseSimple agent; + + // whether thread is closed + // @Builder.Default + // private boolean isClosed = false; + + /** auto close time in min - 默认自动关闭时间,单位分钟 */ + @Builder.Default + private Double autoCloseMin = Double.valueOf(25); + +} diff --git a/modules/service/src/main/java/com/bytedesk/service/visitor/VisitorRepository.java b/modules/service/src/main/java/com/bytedesk/service/visitor/VisitorRepository.java index 6b44597bda..9c68c49f53 100644 --- a/modules/service/src/main/java/com/bytedesk/service/visitor/VisitorRepository.java +++ b/modules/service/src/main/java/com/bytedesk/service/visitor/VisitorRepository.java @@ -1,3 +1,17 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-01-29 16:21:24 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-11 11:38:34 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ package com.bytedesk.service.visitor; import java.util.Optional; @@ -12,5 +26,5 @@ import org.springframework.stereotype.Repository; @Repository public interface VisitorRepository extends JpaRepository, JpaSpecificationExecutor { - Optional findByVid(String vid); + Optional findByUid(String uid); } diff --git a/modules/service/src/main/java/com/bytedesk/service/visitor/VisitorRequest.java b/modules/service/src/main/java/com/bytedesk/service/visitor/VisitorRequest.java index 22b67a7ae7..b9a98ff2f7 100644 --- a/modules/service/src/main/java/com/bytedesk/service/visitor/VisitorRequest.java +++ b/modules/service/src/main/java/com/bytedesk/service/visitor/VisitorRequest.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-04-04 17:05:48 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-04-04 17:07:22 + * @LastEditTime: 2024-04-16 14:57:23 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -14,6 +14,8 @@ */ package com.bytedesk.service.visitor; +import com.bytedesk.core.constant.AvatarConsts; +import com.bytedesk.core.constant.ThreadTypeConsts; import com.bytedesk.core.utils.BaseRequest; import lombok.Data; @@ -23,29 +25,56 @@ import lombok.EqualsAndHashCode; @EqualsAndHashCode(callSuper = false) public class VisitorRequest extends BaseRequest { - private String vid; + private String uid; /** * developers can set basic visitor info */ private String nickname; - private String avatar; - - private String mobile; - - private String email; + private String avatar = AvatarConsts.DEFAULT_VISITOR_AVATAR_URL; + // location info private String ip; private String ipLocation; + // device info private String browser; private String os; private String device; + private String referrer; + + // used for agent notation + private String mobile; + + private String email; + private String note; + // from source + private String client; + + // for thread request + // private String type; // use super.type + private String sid; + + + public String formatTopic(String uid) { + return this.sid + "/" + uid; + // return formatType() + "/" + this.sid + "/" + uid; + } + + public String formatType() { + if (type.equals("1")) { + return ThreadTypeConsts.APPOINTED; + } else if (type.equals("2")) { + return ThreadTypeConsts.WORKGROUP; + } else { + return type; + } + } } diff --git a/modules/service/src/main/java/com/bytedesk/service/visitor/VisitorResponse.java b/modules/service/src/main/java/com/bytedesk/service/visitor/VisitorResponse.java index 76823e0f17..a7ee1c757a 100644 --- a/modules/service/src/main/java/com/bytedesk/service/visitor/VisitorResponse.java +++ b/modules/service/src/main/java/com/bytedesk/service/visitor/VisitorResponse.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-04-04 17:05:59 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-04-04 17:07:01 + * @LastEditTime: 2024-04-16 17:07:29 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -24,6 +24,10 @@ import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; + +/** + * used for agent client + */ @Data @Builder @Accessors(chain = true) @@ -31,8 +35,10 @@ import lombok.experimental.Accessors; @NoArgsConstructor @EqualsAndHashCode(callSuper = true) public class VisitorResponse extends BaseResponse { + + private static final long serialVersionUID = 50026477L; - private String vid; + private String uid; /** * developers can set basic visitor info @@ -41,20 +47,29 @@ public class VisitorResponse extends BaseResponse { private String avatar; - private String mobile; - - private String email; - + // location info private String ip; private String ipLocation; + // device info private String browser; private String os; private String device; + private String referrer; + + // used for agent notation + private String mobile; + + private String email; + private String note; + + // from source + private String client; + } diff --git a/modules/socket/src/main/java/com/bytedesk/socket/mqtt/model/MqttWillMessage.java b/modules/service/src/main/java/com/bytedesk/service/visitor/VisitorResponseSimple.java old mode 100755 new mode 100644 similarity index 62% rename from modules/socket/src/main/java/com/bytedesk/socket/mqtt/model/MqttWillMessage.java rename to modules/service/src/main/java/com/bytedesk/service/visitor/VisitorResponseSimple.java index 60a509c37e..635f14beca --- a/modules/socket/src/main/java/com/bytedesk/socket/mqtt/model/MqttWillMessage.java +++ b/modules/service/src/main/java/com/bytedesk/service/visitor/VisitorResponseSimple.java @@ -1,8 +1,8 @@ /* * @Author: jackning 270580156@qq.com - * @Date: 2024-01-29 16:21:46 + * @Date: 2024-04-04 17:05:59 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-02-29 10:42:01 + * @LastEditTime: 2024-04-16 17:07:17 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -12,33 +12,35 @@ * 联系:270580156@qq.com * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. */ -package com.bytedesk.socket.mqtt.model; +package com.bytedesk.service.visitor; -import java.io.Serializable; +import com.bytedesk.core.utils.BaseResponse; + +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; +import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; + /** - * PUBLISH重发消息存储 + * used for agent client */ @Data +@Builder @Accessors(chain = true) +@AllArgsConstructor @NoArgsConstructor -public class MqttWillMessage implements Serializable { +@EqualsAndHashCode(callSuper = true) +public class VisitorResponseSimple extends BaseResponse { - private static final long serialVersionUID = -8112511377194421600L; - - private int messageId; - - private String clientId; - - private String willTopic; - - private boolean willRetain; - - private int willQoS; + private static final long serialVersionUID = 6459370944L; - private byte[] willMessageBytes; + private String uid; + + private String nickname; + + private String avatar; } diff --git a/modules/service/src/main/java/com/bytedesk/service/visitor/VisitorService.java b/modules/service/src/main/java/com/bytedesk/service/visitor/VisitorService.java index 8b5378d3f8..69409283ec 100644 --- a/modules/service/src/main/java/com/bytedesk/service/visitor/VisitorService.java +++ b/modules/service/src/main/java/com/bytedesk/service/visitor/VisitorService.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-29 16:21:24 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-04-04 17:09:07 + * @LastEditTime: 2024-04-23 16:06:38 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -16,22 +16,338 @@ package com.bytedesk.service.visitor; import java.util.Optional; +import org.modelmapper.ModelMapper; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.cache.annotation.Caching; +import org.springframework.cache.annotation.CachePut; import org.springframework.stereotype.Service; +import org.springframework.util.SerializationUtils; +import org.springframework.util.StringUtils; +import com.alibaba.fastjson2.JSON; +import com.bytedesk.core.constant.AvatarConsts; +import com.bytedesk.core.constant.ClientConsts; +import com.bytedesk.core.constant.MessageTypeConsts; +import com.bytedesk.core.constant.StatusConsts; +import com.bytedesk.core.constant.ThreadTypeConsts; +import com.bytedesk.core.event.BytedeskEventPublisher; +import com.bytedesk.core.ip.IpService; +import com.bytedesk.core.message.Message; +import com.bytedesk.core.message.MessageResponse; +import com.bytedesk.core.message.MessageService; +import com.bytedesk.core.rbac.user.UserResponseSimple; +import com.bytedesk.core.thread.Thread; +import com.bytedesk.core.thread.ThreadService; +import com.bytedesk.core.uid.UidUtils; +import com.bytedesk.service.agent.Agent; +import com.bytedesk.service.agent.AgentResponseSimple; +import com.bytedesk.service.agent.AgentService; +import com.bytedesk.service.workgroup.Workgroup; +import com.bytedesk.service.workgroup.WorkgroupService; + +import jakarta.servlet.http.HttpServletRequest; import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; -// @Slf4j +@Slf4j @Service @AllArgsConstructor public class VisitorService { private final VisitorRepository visitorRepository; - public Optional findByVid(String vid) { - return visitorRepository.findByVid(vid); + private final ModelMapper modelMapper; + + private final UidUtils uidUtils; + + private final IpService ipService; + + private final ThreadService threadService; + + private final AgentService agentService; + + private final WorkgroupService workgroupService; + + private final MessageService messageService; + + private final BytedeskEventPublisher bytedeskEventPublisher; + + @Cacheable(value = "visitor", key = "#uid", unless="#result == null") + public Optional findByUid(String uid) { + return visitorRepository.findByUid(uid); } + /** + * create visitor record + * + * @param visitorRequest + * @return + */ + public Visitor create(VisitorRequest visitorRequest, HttpServletRequest request) { + + String uid = visitorRequest.getUid(); + log.info("visitor init, uid: {}", uid); + // + Visitor visitor = findByUid(uid).orElse(null); + if (visitor != null) { + return visitor; + } + // + if (!StringUtils.hasText(visitorRequest.getNickname())) { + visitorRequest.setNickname(createNickname(request)); + } + if (!StringUtils.hasText(visitorRequest.getAvatar())) { + visitorRequest.setAvatar(AvatarConsts.DEFAULT_VISITOR_AVATAR_URL); + } + // + String ip = ipService.getIp(request); + if (ip != null) { + visitorRequest.setIp(ip); + visitorRequest.setIpLocation(ipService.getIpLocation(ip)); + } + + visitor = modelMapper.map(visitorRequest, Visitor.class); + if (visitor != null) { + visitor.setUid(uidUtils.getCacheSerialUid()); + return save(visitor); + } + + return null; + } + /** */ + public MessageResponse createCustomerServiceThread(VisitorRequest visitorRequest) { + // + String topic = visitorRequest.formatTopic(visitorRequest.getUid()); + // + Thread thread = getThread(visitorRequest, topic); + // + if (thread == null) { + return null; + } + + // TODO: check is agent is online + + // TODO: check push token, if offline & has token, push offline message + + // + Message lastMessage = findOrCreateThreadMessage(visitorRequest, thread); + // + MessageResponse messageResponse = convertToMessageResponse(lastMessage, thread); + + // notify agent - 通知客服 + notifyAgent(thread, messageResponse); + + return messageResponse; + } + + private Thread getThread(VisitorRequest visitorRequest, String topic) { + if (visitorRequest == null) { + throw new IllegalArgumentException("visitorRequest cannot be null"); + } + + Optional threadOptional = threadService.findByTopic(topic); + Thread thread = threadOptional.orElseGet(() -> { + // + String type = visitorRequest.formatType(); + // + Thread newThread = new Thread(); + newThread.setTid(uidUtils.getCacheSerialUid()); + newThread.setTopic(topic); + newThread.setType(type); + newThread.setClient(visitorRequest.getClient()); + // + VisitorResponseSimple visitor = convertToVisitorResponseSimple(visitorRequest); + newThread.setUser(JSON.toJSONString(visitor)); + // + VisitorExtra extra = new VisitorExtra(); + extra.setVisitor(visitor); + // + if (type.equals(ThreadTypeConsts.APPOINTED)) { + // 一对一 + String aid = visitorRequest.getSid(); + Optional agentOptional = agentService.findByUid(aid); + if (agentOptional.isPresent()) { + // + Agent agent = agentOptional.get(); + extra.setWelcomeTip(agent.getWelcomeTip()); + extra.setAgent(agentService.convertToAgentResponseSimple(agent)); + extra.setAutoCloseMin(agent.getAutoCloseMin()); + // + newThread.setOwner(agent.getUser()); + newThread.setContent(agent.getWelcomeTip()); + newThread.setOrgOid(agent.getOrgOid()); + } else { + log.error("agent aid {} not exist", aid); + return null; + } + } else { + // 技能组 + log.debug("workgroup {}", topic); + String aid = visitorRequest.getSid(); + Optional workgroupOptional = workgroupService.findByWid(aid); + if (workgroupOptional.isPresent()) { + Workgroup workgroup = workgroupOptional.get(); + if (!workgroup.getAgents().isEmpty()) { + // 获取workgroup的第一个agent + // TODO: 根据算法选择一个agent + Agent agent = workgroup.getAgents().iterator().next(); + extra.setWelcomeTip(workgroup.getWelcomeTip()); + extra.setAgent(agentService.convertToAgentResponseSimple(agent)); + extra.setAutoCloseMin(agent.getAutoCloseMin()); + // + newThread.setOwner(agent.getUser()); + newThread.setContent(workgroup.getWelcomeTip()); + newThread.setOrgOid(agent.getOrgOid()); + } else { + log.error("No agents found in workgroup with wid {}", aid); + return null; + } + } else { + log.error("workgroup wid {} not exist", aid); + return null; + } + } + // + newThread.setExtra(JSON.toJSONString(extra)); + return threadService.save(newThread); + }); + // + return thread; + } + private Message findOrCreateThreadMessage(VisitorRequest visitorRequest, Thread thread) { + if (thread == null) { + throw new IllegalArgumentException("Thread cannot be null"); + } + + // if thread is closed, reopen it and then create a new message + if (threadService.isClosed(thread)) { + VisitorExtra extra = JSON.parseObject(thread.getExtra(), VisitorExtra.class); + thread.setContent(extra.getWelcomeTip()); + thread = threadService.reopen(thread); + // + Message newMessage = createDefaultMessageForThread(thread); + return messageService.save(newMessage); + } + + // find the last message + Optional messageOptional = messageService.findByThreadsTidInOrderByCreatedAtDesc(thread.getTid()); + if (messageOptional.isPresent()) { + return messageOptional.get(); + } + + // create new message + Message newMessage = createDefaultMessageForThread(thread); + return messageService.save(newMessage); + } + + private Message createDefaultMessageForThread(Thread thread) { + VisitorExtra extra = JSON.parseObject(thread.getExtra(), VisitorExtra.class); + UserResponseSimple user = convertToUserResponseSimple(extra.getAgent()); + + Message message = Message.builder() + .mid(uidUtils.getCacheSerialUid()) + .type(MessageTypeConsts.NOTIFICATION_THREAD) + .content(extra.getWelcomeTip()) + .status(StatusConsts.MESSAGE_STATUS_READ) + .client(ClientConsts.CLIENT_SYSTEM) + .user(JSON.toJSONString(user)) + .orgOid(thread.getOrgOid()) + .build(); + + message.getThreads().add(thread); + return message; + } + + @Caching(put = { + @CachePut(value = "visitor", key = "#visitor.uid"), + }) + private Visitor save(Visitor visitor) { + return visitorRepository.save(visitor); + } + + public String createNickname(HttpServletRequest request) { + + String location = ipService.getIpLocation(request); + // TODO: 修改昵称后缀数字为从1~递增 + String randomId = uidUtils.getCacheSerialUid().substring(11, 15); + + // location: "国家|区域|省份|城市|ISP" + // location: "中国|0|湖北省|武汉市|联通" + // 0|0|0|内网IP|内网IP + String[] locals = location.split("|"); + // log.info("locals {}", location); + if (locals.length > 2) { + if (locals[2].equals("0")) { + return "LOCAL" + randomId; + } + return locals[2] + randomId; + } + + return "Visitor"; + } + + public void notifyAgent(Thread thread, MessageResponse messageResponse) { + try { + // 克隆MessageResponse对象 + MessageResponse agentMessageResponse = SerializationUtils.clone(messageResponse); + + // 验证并解析extra为VisitorExtra对象 + String extraJson = thread.getExtra(); + if (StringUtils.hasText(extraJson) && JSON.isValid(extraJson)) { + VisitorExtra extra = JSON.parseObject(extraJson, VisitorExtra.class); + + // 验证Visitor对象并转换 + VisitorResponseSimple visitor = extra.getVisitor(); + if (visitor != null) { + // user替换成访客,否则客服端会显示客服自己的头像 + UserResponseSimple user = convertToUserResponseSimple(visitor); + agentMessageResponse.setUser(user); + + // 发布消息事件 + String json = JSON.toJSONString(agentMessageResponse); + bytedeskEventPublisher.publishMessageJsonEvent(json); + } else { + // 处理visitor为空的情况 + } + } else { + // 处理extraJson为空或无效的情况 + } + } catch (Exception e) { + // 处理其他异常 + } + } + + public VisitorResponse convertToVisitorResponse(Visitor visitor) { + return modelMapper.map(visitor, VisitorResponse.class); + } + + public VisitorResponseSimple convertToVisitorResponseSimple(Visitor visitor) { + return modelMapper.map(visitor, VisitorResponseSimple.class); + } + + public VisitorResponseSimple convertToVisitorResponseSimple(VisitorRequest visitorRequest) { + return modelMapper.map(visitorRequest, VisitorResponseSimple.class); + } + + public UserResponseSimple convertToUserResponseSimple(AgentResponseSimple agentResponseSimple) { + return modelMapper.map(agentResponseSimple, UserResponseSimple.class); + } + + public UserResponseSimple convertToUserResponseSimple(VisitorResponseSimple visitorResponseSimple) { + return modelMapper.map(visitorResponseSimple, UserResponseSimple.class); + } + + public MessageResponse convertToMessageResponse(Message lastMessage, Thread thread) { + // + MessageResponse messageResponse = modelMapper.map(lastMessage, MessageResponse.class); + messageResponse.setThread(threadService.convertToThreadResponseSimple(thread)); + // + UserResponseSimple user = JSON.parseObject(lastMessage.getUser(), UserResponseSimple.class); + messageResponse.setUser(user); + + return messageResponse; + } } diff --git a/modules/service/src/main/java/com/bytedesk/service/workgroup/Workgroup.java b/modules/service/src/main/java/com/bytedesk/service/workgroup/Workgroup.java index 9748f09d1a..43d1e83799 100644 --- a/modules/service/src/main/java/com/bytedesk/service/workgroup/Workgroup.java +++ b/modules/service/src/main/java/com/bytedesk/service/workgroup/Workgroup.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-29 16:19:51 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-04-05 22:51:38 + * @LastEditTime: 2024-04-23 16:04:38 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -16,12 +16,18 @@ package com.bytedesk.service.workgroup; import java.util.ArrayList; import java.util.List; +import java.util.Set; +import java.util.HashSet; + +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; import com.bytedesk.core.constant.AvatarConsts; import com.bytedesk.core.constant.BdConstants; import com.bytedesk.core.constant.RouteConsts; import com.bytedesk.core.utils.AuditModel; import com.bytedesk.service.agent.Agent; +import com.bytedesk.service.worktime.Worktime; import com.fasterxml.jackson.annotation.JsonIgnore; import jakarta.persistence.*; @@ -45,13 +51,12 @@ import lombok.experimental.Accessors; @Table(name = "service_workgroup") public class Workgroup extends AuditModel { + private static final long serialVersionUID = 680083751L; + @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; - /** - * - */ @Column(unique = true, nullable = false) private String wid; @@ -64,48 +69,87 @@ public class Workgroup extends AuditModel { private String description = BdConstants.DEFAULT_WORK_GROUP_DESCRIPTION; /** - * - */ - - - /** - * + * route type */ @Builder.Default private String routeType = RouteConsts.ROUTE_TYPE_ROBIN; /** - * + * 熟客优先 */ @Builder.Default @Column(name = "is_recent") - private Boolean recent = false; + private boolean recent = false; - /** - * - */ @Builder.Default @Column(name = "is_auto_pop") - private Boolean autoPop = false; + private boolean autoPop = false; /** - * + * tips + * TODO: set different tips for different lang */ @Builder.Default - private Boolean showTopTip = false; + private boolean showTopTip = false; @Builder.Default @Column(length = 512) private String topTip = BdConstants.DEFAULT_WORK_GROUP_DEFAULT_TOP_TIP; + @Builder.Default + private String welcomeTip = BdConstants.DEFAULT_WORK_GROUP_WELCOME_TIP; + /** - * + * robot + * 是否默认机器人接待 + */ + @Builder.Default + private boolean defaultRobot = false; + + /** 无客服在线时,是否启用机器人接待 */ + @Builder.Default + private boolean offlineRobot = false; + + /** 非工作时间段,是否启用机器人接待 */ + @Builder.Default + private boolean nonWorktimeRobot = false; + + /** auto close time in min - 默认自动关闭时间,单位分钟 */ + @Builder.Default + private Double autoCloseMin = Double.valueOf(25); + + /** work time */ + @Builder.Default + @OneToMany(fetch = FetchType.LAZY) + private List workTimes = new ArrayList<>(); + + /** + * one wg can have many agents, one agent can belong to many wgs */ @JsonIgnore @Builder.Default - @OneToMany - private List agents = new ArrayList<>(); - + @ManyToMany(fetch = FetchType.LAZY) + private Set agents = new HashSet<>(); + /** 存储下一个待分配的客服等信息 */ + @Builder.Default + @Column(columnDefinition = "json") + // 用于兼容postgreSQL,否则会报错,[ERROR: column "extra" is of type json but expression is of type character varying + @JdbcTypeCode(SqlTypes.JSON) + private String extra = BdConstants.EMPTY_JSON_STRING; + /** + * belong to org + */ + // @JsonIgnore + // @ManyToOne(fetch = FetchType.LAZY) + // private Organization organization; + private String orgOid; + + /** + * belongs to user + */ + // @JsonIgnore + // @ManyToOne(fetch = FetchType.LAZY) + // private User owner; } diff --git a/modules/service/src/main/java/com/bytedesk/service/workgroup/WorkgroupAspect.java b/modules/service/src/main/java/com/bytedesk/service/workgroup/WorkgroupAspect.java index f357232a84..daf4383e30 100644 --- a/modules/service/src/main/java/com/bytedesk/service/workgroup/WorkgroupAspect.java +++ b/modules/service/src/main/java/com/bytedesk/service/workgroup/WorkgroupAspect.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-04-05 15:08:10 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-04-05 15:17:20 + * @LastEditTime: 2024-04-17 17:10:52 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -14,33 +14,28 @@ */ package com.bytedesk.service.workgroup; -import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; -import org.aspectj.lang.annotation.Before; -import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; -import lombok.extern.slf4j.Slf4j; - -@Slf4j +// @Slf4j @Aspect @Component public class WorkgroupAspect { - @Pointcut("execution(* com.bytedesk.service.workgroup.WorkgroupController.*(..))") - public void workgroupLog() { - log.debug("ActionAspect workgroupLog"); - }; + // @Pointcut("execution(* com.bytedesk.service.workgroup.WorkgroupController.*(..))") + // public void workgroupLog() { + // log.debug("ActionAspect workgroupLog"); + // }; - @Before("workgroupLog()") - public void beforeWorkgroupLog() { - log.debug("ActionAspect beforeWorkgroupLog"); - } + // @Before("workgroupLog()") + // public void beforeWorkgroupLog() { + // log.debug("ActionAspect beforeWorkgroupLog"); + // } - @After("workgroupLog()") - public void afterWorkgroupLog() { - log.debug("ActionAspect afterWorkgroupLog"); - // TODO: action log save to db - } + // @After("workgroupLog()") + // public void afterWorkgroupLog() { + // log.debug("ActionAspect afterWorkgroupLog"); + // // TODO: action log save to db + // } } diff --git a/modules/service/src/main/java/com/bytedesk/service/workgroup/WorkgroupController.java b/modules/service/src/main/java/com/bytedesk/service/workgroup/WorkgroupController.java index d03ebaa9de..fa9f5468cf 100644 --- a/modules/service/src/main/java/com/bytedesk/service/workgroup/WorkgroupController.java +++ b/modules/service/src/main/java/com/bytedesk/service/workgroup/WorkgroupController.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-29 16:19:51 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-04-03 14:51:01 + * @LastEditTime: 2024-04-22 10:37:22 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -21,6 +21,7 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import com.bytedesk.core.annotation.ActionLog; import com.bytedesk.core.utils.BaseRequest; import com.bytedesk.core.utils.JsonResult; @@ -43,9 +44,10 @@ public class WorkgroupController { * @param workgroupRequest * @return */ + @ActionLog(title = "workgroup", action = "query") @GetMapping("/query") public ResponseEntity query(WorkgroupRequest workgroupRequest) { - + return ResponseEntity.ok(JsonResult.success(workgroupService.query(workgroupRequest))); } @@ -58,7 +60,12 @@ public class WorkgroupController { @PostMapping("/create") public ResponseEntity create(@RequestBody WorkgroupRequest workgroupRequest) { - return ResponseEntity.ok(workgroupService.create(workgroupRequest)); + Workgroup workgroup = workgroupService.create(workgroupRequest); + if (workgroup == null) { + return ResponseEntity.ok(JsonResult.error("create failed")); + } + + return ResponseEntity.ok(JsonResult.success(workgroupService.convertToWorkgroupResponse(workgroup))); } /** @@ -70,8 +77,12 @@ public class WorkgroupController { @PostMapping("/update") public ResponseEntity update(@RequestBody WorkgroupRequest workgroupRequest) { + Workgroup workgroup = workgroupService.update(workgroupRequest); + if (workgroup == null) { + return ResponseEntity.ok(JsonResult.error("update failed")); + } // - return ResponseEntity.ok(JsonResult.success("update success")); + return ResponseEntity.ok(JsonResult.success(workgroupService.convertToWorkgroupResponse(workgroup))); } /** diff --git a/modules/service/src/main/java/com/bytedesk/service/workgroup/WorkgroupRepository.java b/modules/service/src/main/java/com/bytedesk/service/workgroup/WorkgroupRepository.java index 8188302fd2..8aaff63069 100644 --- a/modules/service/src/main/java/com/bytedesk/service/workgroup/WorkgroupRepository.java +++ b/modules/service/src/main/java/com/bytedesk/service/workgroup/WorkgroupRepository.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-29 16:19:51 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-03-28 22:32:02 + * @LastEditTime: 2024-04-22 12:16:54 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -14,8 +14,13 @@ */ package com.bytedesk.service.workgroup; +import java.util.Optional; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.lang.NonNull; // import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Repository; @@ -31,4 +36,11 @@ public interface WorkgroupRepository extends JpaRepository, Jpa // Page findAll(@NonNull Pageable pageable); + Optional findByWid(@NonNull String wid); + + Optional findByNickname(@NonNull String nickname); + + // Page findByOrganization_Oid(String oid, Pageable pageable); + Page findByOrgOid(String oid, Pageable pageable); + } diff --git a/modules/service/src/main/java/com/bytedesk/service/workgroup/WorkgroupRequest.java b/modules/service/src/main/java/com/bytedesk/service/workgroup/WorkgroupRequest.java index 478bfdffcb..70e36383b5 100644 --- a/modules/service/src/main/java/com/bytedesk/service/workgroup/WorkgroupRequest.java +++ b/modules/service/src/main/java/com/bytedesk/service/workgroup/WorkgroupRequest.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-02-06 10:17:32 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-04-03 14:58:09 + * @LastEditTime: 2024-04-22 12:38:20 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -14,14 +14,22 @@ */ package com.bytedesk.service.workgroup; +import java.util.ArrayList; +import java.util.List; + import com.bytedesk.core.constant.AvatarConsts; import com.bytedesk.core.constant.BdConstants; +import com.bytedesk.core.constant.RouteConsts; import com.bytedesk.core.utils.BaseRequest; +import lombok.Builder; import lombok.Data; import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; @Data +@Builder +@Accessors(chain = true) @EqualsAndHashCode(callSuper = false) public class WorkgroupRequest extends BaseRequest { @@ -29,8 +37,40 @@ public class WorkgroupRequest extends BaseRequest { private String nickname; + @Builder.Default private String avatar = AvatarConsts.DEFAULT_WORK_GROUP_AVATAR_URL; + @Builder.Default private String description = BdConstants.DEFAULT_WORK_GROUP_DESCRIPTION; + @Builder.Default + private String routeType = RouteConsts.ROUTE_TYPE_ROBIN; + + @Builder.Default + private Boolean recent = false; + + @Builder.Default + private Boolean autoPop = false; + + @Builder.Default + private Boolean showTopTip = false; + + @Builder.Default + private String topTip = BdConstants.DEFAULT_WORK_GROUP_DEFAULT_TOP_TIP; + + @Builder.Default + private String welcomeTip = BdConstants.DEFAULT_WORK_GROUP_WELCOME_TIP; + + @Builder.Default + private Boolean defaultRobot = false; + + @Builder.Default + private Double autoCloseMin = Double.valueOf(5); + + // 注意:此处不能命名为agents,因与agent中agents类型不同, 否则会报错 + @Builder.Default + private List agentAids = new ArrayList(); + + // organization oid + private String orgOid; } diff --git a/modules/service/src/main/java/com/bytedesk/service/workgroup/WorkgroupResponse.java b/modules/service/src/main/java/com/bytedesk/service/workgroup/WorkgroupResponse.java index e33c0b00a3..047478e51c 100644 --- a/modules/service/src/main/java/com/bytedesk/service/workgroup/WorkgroupResponse.java +++ b/modules/service/src/main/java/com/bytedesk/service/workgroup/WorkgroupResponse.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-02-06 10:18:02 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-04-03 15:16:02 + * @LastEditTime: 2024-04-17 13:54:40 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -34,6 +34,8 @@ import lombok.experimental.Accessors; @EqualsAndHashCode(callSuper = true) public class WorkgroupResponse extends BaseResponse { + private static final long serialVersionUID = -5451766294L; + private String wid; private String nickname; @@ -42,34 +44,22 @@ public class WorkgroupResponse extends BaseResponse { private String description; - /** - * - */ - - - - /** - * - */ private String routeType; - /** - * - */ private boolean recent; - /** - * - */ private boolean autoPop; - /** - * - */ private boolean showTopTip; private String topTip; + private String welcomeTip; + + private boolean defaultRobot; + + private Double autoCloseMin; + // private List agents; } diff --git a/modules/service/src/main/java/com/bytedesk/service/workgroup/WorkgroupService.java b/modules/service/src/main/java/com/bytedesk/service/workgroup/WorkgroupService.java index 8daf68c859..0278dc8251 100644 --- a/modules/service/src/main/java/com/bytedesk/service/workgroup/WorkgroupService.java +++ b/modules/service/src/main/java/com/bytedesk/service/workgroup/WorkgroupService.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-29 16:19:51 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-04-03 14:50:35 + * @LastEditTime: 2024-04-25 15:21:30 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. @@ -14,19 +14,28 @@ */ package com.bytedesk.service.workgroup; +import java.util.ArrayList; +import java.util.Iterator; import java.util.List; +import java.util.Optional; import org.modelmapper.ModelMapper; +import org.springframework.cache.annotation.Cacheable; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; -import com.bytedesk.core.utils.JsonResult; -import com.bytedesk.core.utils.Utils; +import com.bytedesk.core.config.BytedeskProperties; +import com.bytedesk.core.uid.UidUtils; +import com.bytedesk.service.agent.Agent; +import com.bytedesk.service.agent.AgentService; +import com.bytedesk.team.organization.Organization; +import com.bytedesk.team.organization.OrganizationService; import lombok.AllArgsConstructor; +import static java.util.Arrays.asList; // @Slf4j @Service @@ -35,41 +44,141 @@ public class WorkgroupService { private final WorkgroupRepository workgroupRepository; + private final AgentService agentService; + private final ModelMapper modelMapper; - public List findAll() { - return workgroupRepository.findAll(); - } + private final UidUtils uidUtils; - public Page query(WorkgroupRequest pageParam) { + private final BytedeskProperties properties; - Pageable pageable = PageRequest.of(pageParam.getPageNumber(), - pageParam.getPageSize(), Sort.Direction.DESC, + private final OrganizationService organizationService; + + public Page query(WorkgroupRequest workgroupRequest) { + + Pageable pageable = PageRequest.of(workgroupRequest.getPageNumber(), + workgroupRequest.getPageSize(), Sort.Direction.DESC, "id"); - Page workgroupPage = workgroupRepository.findAll(pageable); + Page workgroupPage = workgroupRepository.findByOrgOid(workgroupRequest.getOrgOid(), + pageable); return workgroupPage.map(this::convertToWorkgroupResponse); } - - public JsonResult create(WorkgroupRequest workgroupRequest) { - + public Workgroup create(WorkgroupRequest workgroupRequest) { + // Workgroup workgroup = modelMapper.map(workgroupRequest, Workgroup.class); - workgroup.setWid(Utils.getUid()); - - return JsonResult.success(save(workgroup)); + workgroup.setWid(uidUtils.getCacheSerialUid()); + // + Iterator iterator = workgroupRequest.getAgentAids().iterator(); + while (iterator.hasNext()) { + String agentAid = iterator.next(); + Optional agentOptional = agentService.findByUid(agentAid); + if (agentOptional.isPresent()) { + Agent agentEntity = agentOptional.get(); + workgroup.getAgents().add(agentEntity); + } else { + return null; + } + } + // + return save(workgroup); } + Workgroup update(WorkgroupRequest workgroupRequest) { - @SuppressWarnings("null") - private WorkgroupResponse save(Workgroup workgroup) { - return convertToWorkgroupResponse(workgroupRepository.save(workgroup)); + Optional workgroupOptional = findByWid(workgroupRequest.getWid()); + if (!workgroupOptional.isPresent()) { + return null; + } + // + Workgroup workgroup = workgroupOptional.get(); + workgroup = modelMapper.map(workgroupRequest, Workgroup.class); + // workgroupOptional.get().setNickname(workgroupRequest.getNickname()); + // workgroupOptional.get().setAvatar(workgroupRequest.getAvatar()); + // workgroupOptional.get().setDescription(workgroupRequest.getDescription()); + // workgroupOptional.get().setRouteType(workgroupRequest.getRouteType()); + // workgroupOptional.get().setRecent(workgroupRequest.getRecent()); + // workgroupOptional.get().setAutoPop(workgroupRequest.getAutoPop()); + // + // + Iterator iterator = workgroupRequest.getAgentAids().iterator(); + while (iterator.hasNext()) { + String agentAid = iterator.next(); + Optional agentOptional = agentService.findByUid(agentAid); + if (agentOptional.isPresent()) { + Agent agentEntity = agentOptional.get(); + workgroup.getAgents().add(agentEntity); + } else { + return null; + } + } + // + return save(workgroup); + } + + + + @Cacheable(value = "workgroup", key = "#wid", unless="#result == null") + public Optional findByWid(String wid) { + return workgroupRepository.findByWid(wid); } - private WorkgroupResponse convertToWorkgroupResponse(Workgroup workgroup) { + @Cacheable(value = "workgroup", key = "#nickname", unless="#result == null") + public Optional findByNickname(String nickname) { + return workgroupRepository.findByNickname(nickname); + } + + // @SuppressWarnings("null") + private Workgroup save(Workgroup workgroup) { + return workgroupRepository.save(workgroup); + } + + public WorkgroupResponse convertToWorkgroupResponse(Workgroup workgroup) { return modelMapper.map(workgroup, WorkgroupResponse.class); } + public void initData() { + + if (workgroupRepository.count() > 0) { + return; + } + + Optional orgOptional = organizationService.findByName(properties.getCompany()); + if (orgOptional.isPresent()) { + + List agents = new ArrayList<>(); + Optional agent1Optional = agentService.findByMobile("18888888008"); + agent1Optional.ifPresent(agent -> { + agents.add(agent.getUid()); + }); + Optional agent2Optional = agentService.findByMobile("18888888009"); + agent2Optional.ifPresent(agent -> { + agents.add(agent.getUid()); + }); + + // add workgroups + WorkgroupRequest workgroup1Request = WorkgroupRequest.builder() + .nickname("客服组1") + .agentAids(agents) + .orgOid(orgOptional.get().getOid()) + .build(); + create(workgroup1Request); + + // + WorkgroupRequest workgroup2Request = WorkgroupRequest.builder() + .nickname("客服组2") + .agentAids(asList(agent1Optional.get().getUid())) + .orgOid(orgOptional.get().getOid()) + .build(); + create(workgroup2Request); + + } + + + + } + } diff --git a/modules/service/src/main/java/com/bytedesk/service/worktime/Worktime.java b/modules/service/src/main/java/com/bytedesk/service/worktime/Worktime.java new file mode 100644 index 0000000000..22a8035263 --- /dev/null +++ b/modules/service/src/main/java/com/bytedesk/service/worktime/Worktime.java @@ -0,0 +1,114 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-18 14:43:29 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-18 14:50:05 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.service.worktime; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; + +import com.bytedesk.core.utils.AuditModel; +import com.fasterxml.jackson.annotation.JsonFormat; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import jakarta.persistence.Temporal; +import jakarta.persistence.TemporalType; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +/** + * + */ +@Entity +@Data +@Builder +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = true) +@AllArgsConstructor +@NoArgsConstructor +@Table(name = "service_worktime") +public class Worktime extends AuditModel { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private Long id; + + /** + * + */ + @Column(name = "start_time") + @JsonFormat(pattern = "HH:mm:ss") + @Temporal(TemporalType.TIME) + private Date startTime; + + /** + * + */ + @Column(name = "end_time") + @JsonFormat(pattern = "HH:mm:ss") + @Temporal(TemporalType.TIME) + private Date endTime; + + /** + * 是否工作时间 + * + * @return 是否工作时间 + */ + public boolean isWorkTime() { + + SimpleDateFormat formatter = new SimpleDateFormat("HH:mm:ss"); + String timeString = formatter.format(new Date()); + + Date now = null; + try { + now = formatter.parse(timeString); + } catch (ParseException e) { + e.printStackTrace(); + } + + Calendar calendarNow = Calendar.getInstance(); + calendarNow.setTime(now); + calendarNow.set(0, 0, 0); + + Calendar calendarStart = Calendar.getInstance(); + calendarStart.setTime(startTime); + calendarStart.set(0, 0, 0); + + Calendar calendarEnd = Calendar.getInstance(); + calendarEnd.setTime(endTime); + calendarEnd.set(0, 0, 0); + + boolean result1 = calendarNow.getTime().after(calendarStart.getTime()); + boolean result2 = calendarNow.getTime().before(calendarEnd.getTime()); + + // logger.info("startTime {}, nowTime {}, endTime {}, result1 {}, result2 {}", + // calendarStart.getTime().toString(), calendarNow.getTime().toString(), + // calendarEnd.getTime().toString(), + // result1 ? "before true" : "before false", + // result2 ? "end true" : "end false"); + + return result1 && result2; + } + +} diff --git a/modules/service/src/main/java/com/bytedesk/service/worktime/WorktimeController.java b/modules/service/src/main/java/com/bytedesk/service/worktime/WorktimeController.java new file mode 100644 index 0000000000..57019062b0 --- /dev/null +++ b/modules/service/src/main/java/com/bytedesk/service/worktime/WorktimeController.java @@ -0,0 +1,19 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-18 14:46:55 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-18 14:46:57 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.service.worktime; + +public class WorktimeController { + +} diff --git a/modules/service/src/main/java/com/bytedesk/service/worktime/WorktimeRepository.java b/modules/service/src/main/java/com/bytedesk/service/worktime/WorktimeRepository.java new file mode 100644 index 0000000000..caa07764d9 --- /dev/null +++ b/modules/service/src/main/java/com/bytedesk/service/worktime/WorktimeRepository.java @@ -0,0 +1,19 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-18 14:46:25 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-18 14:46:26 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.service.worktime; + +public interface WorktimeRepository { + +} diff --git a/modules/service/src/main/java/com/bytedesk/service/worktime/WorktimeRequest.java b/modules/service/src/main/java/com/bytedesk/service/worktime/WorktimeRequest.java new file mode 100644 index 0000000000..2ea3b9b8d3 --- /dev/null +++ b/modules/service/src/main/java/com/bytedesk/service/worktime/WorktimeRequest.java @@ -0,0 +1,19 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-18 14:46:34 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-18 14:46:36 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.service.worktime; + +public class WorktimeRequest { + +} diff --git a/modules/service/src/main/java/com/bytedesk/service/worktime/WorktimeResponse.java b/modules/service/src/main/java/com/bytedesk/service/worktime/WorktimeResponse.java new file mode 100644 index 0000000000..10e2f3691f --- /dev/null +++ b/modules/service/src/main/java/com/bytedesk/service/worktime/WorktimeResponse.java @@ -0,0 +1,19 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-18 14:46:44 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-18 14:46:47 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.service.worktime; + +public class WorktimeResponse { + +} diff --git a/modules/service/src/main/java/com/bytedesk/service/worktime/WorktimeService.java b/modules/service/src/main/java/com/bytedesk/service/worktime/WorktimeService.java new file mode 100644 index 0000000000..cba2fd2800 --- /dev/null +++ b/modules/service/src/main/java/com/bytedesk/service/worktime/WorktimeService.java @@ -0,0 +1,19 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-04-18 14:46:05 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2024-04-18 14:46:08 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售 + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.service.worktime; + +public class WorktimeService { + +} diff --git a/modules/social/.DS_Store b/modules/social/.DS_Store index 5bb368debb804595966e6b649ee9a62ebae0f246..f3b5d1376b540eb14b24fb17e2a7ae9ee68cdd3f 100644 GIT binary patch delta 148 zcmZoMXffEJ!feCD!@$76%uviw#E_hu@8Xh_lb-|>;Q(U44X2JeBFmxvG&oxG1(P94Go8^Oj;dno1+s>=Ek2)gDrl84APGFW| z447QaEX%@Pexr8s9A+7|es_?*$@`e))FDi;5o`=442eK1(iu`2N(wRzgOl@f3xGy5 Suva*27UW=I+04%ImmdJDye|j< diff --git a/modules/social/pom.xml b/modules/social/pom.xml index 607156d5e0..27067172fe 100644 --- a/modules/social/pom.xml +++ b/modules/social/pom.xml @@ -11,7 +11,7 @@ 0.0.1-SNAPSHOT - weiyu-social + im-social social Demo project for Spring Boot @@ -20,7 +20,7 @@ com.bytedesk - weiyu-core + im-core ${im.version} provided @@ -29,10 +29,10 @@ - + diff --git a/modules/socket/.DS_Store b/modules/socket/.DS_Store index 676a195d39302991bdda8588cbd26e45e944553a..a6814fed60ddaf816a00e142d529b3e7b9659d30 100644 GIT binary patch delta 91 zcmZoMXffEJ%*-4(yJ4~#b1+lrg~`>-a?F|96DQAMmSIb+xLSDV?c{yTa_SJ~QAY*_ r1~!HghD3%UhIEEhhLVB|!{Frn+ybCD14HhI&4L^(ESuRm{_+C=mIEDW delta 91 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

    XaPP}{TS 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%0Af$b}wWuu4t7p*iWGiUNywxx^#uOV7Sjrg>8T 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