From 1cf452b498cfac338f10cf84529fa039f3bd34e4 Mon Sep 17 00:00:00 2001 From: Kris <2893855659@qq.com> Date: Sat, 7 Dec 2024 13:00:12 +0800 Subject: [PATCH] =?UTF-8?q?[feat]=20=E5=BE=AE=E4=BF=A1=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=E5=88=9D=E5=A7=8B=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/wechat/ArticleController.java | 82 +++ .../wechat/CzsjWxAccountController.java | 104 ++++ .../wechat/CzsjWxMessageController.java | 104 ++++ .../wechat/CzsjWxQrCodeController.java | 104 ++++ .../wechat/CzsjWxReplyRuleController.java | 104 ++++ .../wechat/CzsjWxTemplateController.java | 104 ++++ .../wechat/CzsjWxTemplateLogController.java | 104 ++++ .../controller/wechat/WxAuthController.java | 130 +++++ .../wechat/WxMpPortalController.java | 106 ++++ .../controller/wechat/WxUserController.java | 38 ++ .../wechat/WxUserTagsController.java | 72 +++ czsj-common/pom.xml | 12 + czsj-system/pom.xml | 25 + .../service/ICzsjMemberWxFansService.java | 16 + .../impl/CzsjMemberWxFansServiceImpl.java | 57 ++ .../EventMessageListenerContainerConfig.java | 52 ++ .../com/czsj/wechat/config/TaskExcutor.java | 60 ++ .../WxMpMessageRouterConfiguration.java | 52 ++ .../config/WxMpServiceConfiguration.java | 29 + .../com/czsj/wechat/domain/CzsjWxAccount.java | 164 ++++++ .../com/czsj/wechat/domain/CzsjWxMessage.java | 150 +++++ .../com/czsj/wechat/domain/CzsjWxQrCode.java | 167 ++++++ .../czsj/wechat/domain/CzsjWxReplyRule.java | 196 +++++++ .../czsj/wechat/domain/CzsjWxTemplate.java | 178 ++++++ .../czsj/wechat/domain/CzsjWxTemplateLog.java | 178 ++++++ .../com/czsj/wechat/dto/PageSizeConstant.java | 9 + .../com/czsj/wechat/dto/RegexConstant.java | 44 ++ .../java/com/czsj/wechat/entity/Article.java | 39 ++ .../com/czsj/wechat/entity/MsgReplyRule.java | 48 ++ .../com/czsj/wechat/entity/MsgTemplate.java | 56 ++ .../czsj/wechat/entity/TemplateMsgLog.java | 56 ++ .../com/czsj/wechat/entity/WxAccount.java | 65 +++ .../java/com/czsj/wechat/entity/WxMsg.java | 103 ++++ .../java/com/czsj/wechat/entity/WxQrCode.java | 63 ++ .../java/com/czsj/wechat/entity/WxUser.java | 85 +++ .../czsj/wechat/enums/ArticleTypeEnum.java | 35 ++ .../czsj/wechat/exception/RRException.java | 52 ++ .../wechat/exception/RRExceptionHandler.java | 67 +++ .../com/czsj/wechat/form/AccountBindForm.java | 15 + .../wechat/form/MaterialFileDeleteForm.java | 14 + .../wechat/form/TemplateMsgBatchForm.java | 33 ++ .../com/czsj/wechat/form/TemplateMsgForm.java | 24 + .../czsj/wechat/form/WxH5OuthrizeForm.java | 16 + .../com/czsj/wechat/form/WxMsgReplyForm.java | 15 + .../com/czsj/wechat/form/WxQrCodeForm.java | 17 + .../wechat/form/WxUserBatchTaggingForm.java | 14 + .../com/czsj/wechat/form/WxUserTagForm.java | 14 + .../czsj/wechat/form/WxUserTaggingForm.java | 11 + .../czsj/wechat/handler/AbstractHandler.java | 14 + .../czsj/wechat/handler/KfSessionHandler.java | 25 + .../czsj/wechat/handler/LocationHandler.java | 40 ++ .../com/czsj/wechat/handler/LogHandler.java | 37 ++ .../com/czsj/wechat/handler/MenuHandler.java | 37 ++ .../com/czsj/wechat/handler/MsgHandler.java | 52 ++ .../com/czsj/wechat/handler/NullHandler.java | 24 + .../com/czsj/wechat/handler/ScanHandler.java | 32 ++ .../handler/StoreCheckNotifyHandler.java | 27 + .../czsj/wechat/handler/SubscribeHandler.java | 61 ++ .../wechat/handler/UnsubscribeHandler.java | 34 ++ .../WxAccountChangedMessageListener.java | 34 ++ .../com/czsj/wechat/mapper/ArticleMapper.java | 14 + .../wechat/mapper/CzsjWxAccountMapper.java | 61 ++ .../wechat/mapper/CzsjWxMessageMapper.java | 61 ++ .../wechat/mapper/CzsjWxQrCodeMapper.java | 61 ++ .../wechat/mapper/CzsjWxReplyRuleMapper.java | 61 ++ .../mapper/CzsjWxTemplateLogMapper.java | 61 ++ .../wechat/mapper/CzsjWxTemplateMapper.java | 61 ++ .../wechat/mapper/MsgReplyRuleMapper.java | 11 + .../czsj/wechat/mapper/MsgTemplateMapper.java | 11 + .../wechat/mapper/TemplateMsgLogMapper.java | 9 + .../czsj/wechat/mapper/WxAccountMapper.java | 18 + .../com/czsj/wechat/mapper/WxMsgMapper.java | 18 + .../czsj/wechat/mapper/WxQrCodeMapper.java | 19 + .../com/czsj/wechat/mapper/WxUserMapper.java | 13 + .../czsj/wechat/service/ArticleService.java | 62 ++ .../wechat/service/ICzsjWxAccountService.java | 61 ++ .../wechat/service/ICzsjWxMessageService.java | 61 ++ .../wechat/service/ICzsjWxQrCodeService.java | 61 ++ .../service/ICzsjWxReplyRuleService.java | 61 ++ .../service/ICzsjWxTemplateLogService.java | 61 ++ .../service/ICzsjWxTemplateService.java | 61 ++ .../wechat/service/MsgReplyRuleService.java | 51 ++ .../czsj/wechat/service/MsgReplyService.java | 107 ++++ .../wechat/service/MsgTemplateService.java | 41 ++ .../wechat/service/TemplateMsgLogService.java | 23 + .../wechat/service/TemplateMsgService.java | 18 + .../czsj/wechat/service/WxAccountService.java | 31 + .../czsj/wechat/service/WxAssetsService.java | 89 +++ .../com/czsj/wechat/service/WxMsgService.java | 29 + .../czsj/wechat/service/WxQrCodeService.java | 37 ++ .../czsj/wechat/service/WxUserService.java | 56 ++ .../wechat/service/WxUserTagsService.java | 79 +++ .../service/impl/ArticleServiceImpl.java | 153 +++++ .../impl/CzsjWxAccountServiceImpl.java | 96 ++++ .../impl/CzsjWxMessageServiceImpl.java | 96 ++++ .../service/impl/CzsjWxQrCodeServiceImpl.java | 96 ++++ .../impl/CzsjWxReplyRuleServiceImpl.java | 96 ++++ .../impl/CzsjWxTemplateLogServiceImpl.java | 96 ++++ .../impl/CzsjWxTemplateServiceImpl.java | 96 ++++ .../service/impl/MsgReplyRuleServiceImpl.java | 127 ++++ .../service/impl/MsgReplyServiceImpl.java | 189 ++++++ .../service/impl/MsgTemplateServiceImpl.java | 71 +++ .../impl/TemplateMsgLogServiceImpl.java | 42 ++ .../service/impl/TemplateMsgServiceImpl.java | 91 +++ .../service/impl/WxAccountServiceImpl.java | 113 ++++ .../service/impl/WxAssetsServiceImpl.java | 122 ++++ .../wechat/service/impl/WxMsgServiceImpl.java | 50 ++ .../service/impl/WxQrCodeServiceImpl.java | 68 +++ .../service/impl/WxUserServiceImpl.java | 190 ++++++ .../service/impl/WxUserTagsServiceImpl.java | 88 +++ .../com/czsj/wechat/utils/ConfigConstant.java | 12 + .../java/com/czsj/wechat/utils/Constant.java | 122 ++++ .../com/czsj/wechat/utils/CookieUtil.java | 64 +++ .../java/com/czsj/wechat/utils/DateUtils.java | 88 +++ .../java/com/czsj/wechat/utils/IPUtils.java | 48 ++ .../main/java/com/czsj/wechat/utils/Json.java | 20 + .../java/com/czsj/wechat/utils/MD5Util.java | 75 +++ .../java/com/czsj/wechat/utils/MapUtils.java | 20 + .../java/com/czsj/wechat/utils/PageUtils.java | 101 ++++ .../java/com/czsj/wechat/utils/Query.java | 68 +++ .../main/java/com/czsj/wechat/utils/R.java | 61 ++ .../java/com/czsj/wechat/utils/SHA1Util.java | 35 ++ .../java/com/czsj/wechat/xss/HTMLFilter.java | 542 ++++++++++++++++++ .../java/com/czsj/wechat/xss/SQLFilter.java | 41 ++ .../java/com/czsj/wechat/xss/XssFilter.java | 29 + .../xss/XssHttpServletRequestWrapper.java | 139 +++++ .../resources/mapper/wechat/ArticleMapper.xml | 10 + .../mapper/wechat/CzsjWxAccountMapper.xml | 103 ++++ .../mapper/wechat/CzsjWxMessageMapper.xml | 98 ++++ .../mapper/wechat/CzsjWxQrCodeMapper.xml | 103 ++++ .../mapper/wechat/CzsjWxReplyRuleMapper.xml | 113 ++++ .../mapper/wechat/CzsjWxTemplateLogMapper.xml | 108 ++++ .../mapper/wechat/CzsjWxTemplateMapper.xml | 108 ++++ .../mapper/wechat/MsgReplyRuleMapper.xml | 6 + .../mapper/wechat/MsgTemplateMapper.xml | 5 + .../mapper/wechat/TemplateMsgLogMapper.xml | 6 + .../mapper/wechat/WxAccountMapper.xml | 8 + .../resources/mapper/wechat/WxMsgMapper.xml | 6 + .../mapper/wechat/WxQrCodeMapper.xml | 7 + .../resources/mapper/wechat/WxUserMapper.xml | 9 + 140 files changed, 9203 insertions(+) create mode 100644 czsj-admin/src/main/java/com/czsj/web/controller/wechat/ArticleController.java create mode 100644 czsj-admin/src/main/java/com/czsj/web/controller/wechat/CzsjWxAccountController.java create mode 100644 czsj-admin/src/main/java/com/czsj/web/controller/wechat/CzsjWxMessageController.java create mode 100644 czsj-admin/src/main/java/com/czsj/web/controller/wechat/CzsjWxQrCodeController.java create mode 100644 czsj-admin/src/main/java/com/czsj/web/controller/wechat/CzsjWxReplyRuleController.java create mode 100644 czsj-admin/src/main/java/com/czsj/web/controller/wechat/CzsjWxTemplateController.java create mode 100644 czsj-admin/src/main/java/com/czsj/web/controller/wechat/CzsjWxTemplateLogController.java create mode 100644 czsj-admin/src/main/java/com/czsj/web/controller/wechat/WxAuthController.java create mode 100644 czsj-admin/src/main/java/com/czsj/web/controller/wechat/WxMpPortalController.java create mode 100644 czsj-admin/src/main/java/com/czsj/web/controller/wechat/WxUserController.java create mode 100644 czsj-admin/src/main/java/com/czsj/web/controller/wechat/WxUserTagsController.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/config/EventMessageListenerContainerConfig.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/config/TaskExcutor.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/config/WxMpMessageRouterConfiguration.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/config/WxMpServiceConfiguration.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/domain/CzsjWxAccount.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/domain/CzsjWxMessage.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/domain/CzsjWxQrCode.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/domain/CzsjWxReplyRule.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/domain/CzsjWxTemplate.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/domain/CzsjWxTemplateLog.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/dto/PageSizeConstant.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/dto/RegexConstant.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/entity/Article.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/entity/MsgReplyRule.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/entity/MsgTemplate.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/entity/TemplateMsgLog.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/entity/WxAccount.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/entity/WxMsg.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/entity/WxQrCode.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/entity/WxUser.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/enums/ArticleTypeEnum.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/exception/RRException.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/exception/RRExceptionHandler.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/form/AccountBindForm.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/form/MaterialFileDeleteForm.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/form/TemplateMsgBatchForm.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/form/TemplateMsgForm.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/form/WxH5OuthrizeForm.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/form/WxMsgReplyForm.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/form/WxQrCodeForm.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/form/WxUserBatchTaggingForm.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/form/WxUserTagForm.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/form/WxUserTaggingForm.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/handler/AbstractHandler.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/handler/KfSessionHandler.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/handler/LocationHandler.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/handler/LogHandler.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/handler/MenuHandler.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/handler/MsgHandler.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/handler/NullHandler.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/handler/ScanHandler.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/handler/StoreCheckNotifyHandler.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/handler/SubscribeHandler.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/handler/UnsubscribeHandler.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/listener/WxAccountChangedMessageListener.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/mapper/ArticleMapper.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/mapper/CzsjWxAccountMapper.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/mapper/CzsjWxMessageMapper.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/mapper/CzsjWxQrCodeMapper.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/mapper/CzsjWxReplyRuleMapper.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/mapper/CzsjWxTemplateLogMapper.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/mapper/CzsjWxTemplateMapper.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/mapper/MsgReplyRuleMapper.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/mapper/MsgTemplateMapper.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/mapper/TemplateMsgLogMapper.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/mapper/WxAccountMapper.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/mapper/WxMsgMapper.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/mapper/WxQrCodeMapper.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/mapper/WxUserMapper.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/service/ArticleService.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/service/ICzsjWxAccountService.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/service/ICzsjWxMessageService.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/service/ICzsjWxQrCodeService.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/service/ICzsjWxReplyRuleService.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/service/ICzsjWxTemplateLogService.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/service/ICzsjWxTemplateService.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/service/MsgReplyRuleService.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/service/MsgReplyService.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/service/MsgTemplateService.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/service/TemplateMsgLogService.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/service/TemplateMsgService.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/service/WxAccountService.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/service/WxAssetsService.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/service/WxMsgService.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/service/WxQrCodeService.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/service/WxUserService.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/service/WxUserTagsService.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/service/impl/ArticleServiceImpl.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/service/impl/CzsjWxAccountServiceImpl.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/service/impl/CzsjWxMessageServiceImpl.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/service/impl/CzsjWxQrCodeServiceImpl.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/service/impl/CzsjWxReplyRuleServiceImpl.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/service/impl/CzsjWxTemplateLogServiceImpl.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/service/impl/CzsjWxTemplateServiceImpl.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/service/impl/MsgReplyRuleServiceImpl.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/service/impl/MsgReplyServiceImpl.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/service/impl/MsgTemplateServiceImpl.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/service/impl/TemplateMsgLogServiceImpl.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/service/impl/TemplateMsgServiceImpl.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/service/impl/WxAccountServiceImpl.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/service/impl/WxAssetsServiceImpl.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/service/impl/WxMsgServiceImpl.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/service/impl/WxQrCodeServiceImpl.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/service/impl/WxUserServiceImpl.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/service/impl/WxUserTagsServiceImpl.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/utils/ConfigConstant.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/utils/Constant.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/utils/CookieUtil.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/utils/DateUtils.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/utils/IPUtils.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/utils/Json.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/utils/MD5Util.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/utils/MapUtils.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/utils/PageUtils.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/utils/Query.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/utils/R.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/utils/SHA1Util.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/xss/HTMLFilter.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/xss/SQLFilter.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/xss/XssFilter.java create mode 100644 czsj-system/src/main/java/com/czsj/wechat/xss/XssHttpServletRequestWrapper.java create mode 100644 czsj-system/src/main/resources/mapper/wechat/ArticleMapper.xml create mode 100644 czsj-system/src/main/resources/mapper/wechat/CzsjWxAccountMapper.xml create mode 100644 czsj-system/src/main/resources/mapper/wechat/CzsjWxMessageMapper.xml create mode 100644 czsj-system/src/main/resources/mapper/wechat/CzsjWxQrCodeMapper.xml create mode 100644 czsj-system/src/main/resources/mapper/wechat/CzsjWxReplyRuleMapper.xml create mode 100644 czsj-system/src/main/resources/mapper/wechat/CzsjWxTemplateLogMapper.xml create mode 100644 czsj-system/src/main/resources/mapper/wechat/CzsjWxTemplateMapper.xml create mode 100644 czsj-system/src/main/resources/mapper/wechat/MsgReplyRuleMapper.xml create mode 100644 czsj-system/src/main/resources/mapper/wechat/MsgTemplateMapper.xml create mode 100644 czsj-system/src/main/resources/mapper/wechat/TemplateMsgLogMapper.xml create mode 100644 czsj-system/src/main/resources/mapper/wechat/WxAccountMapper.xml create mode 100644 czsj-system/src/main/resources/mapper/wechat/WxMsgMapper.xml create mode 100644 czsj-system/src/main/resources/mapper/wechat/WxQrCodeMapper.xml create mode 100644 czsj-system/src/main/resources/mapper/wechat/WxUserMapper.xml diff --git a/czsj-admin/src/main/java/com/czsj/web/controller/wechat/ArticleController.java b/czsj-admin/src/main/java/com/czsj/web/controller/wechat/ArticleController.java new file mode 100644 index 0000000..9e0b664 --- /dev/null +++ b/czsj-admin/src/main/java/com/czsj/web/controller/wechat/ArticleController.java @@ -0,0 +1,82 @@ +package com.czsj.web.controller.wechat; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import com.czsj.wechat.entity.Article; +import com.czsj.wechat.enums.ArticleTypeEnum; +import com.czsj.wechat.service.ArticleService; +import com.czsj.wechat.utils.R; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * cms文章 + */ +@RestController +@RequestMapping("/article") +@Api(tags = {"CMS文章"}) +public class ArticleController { + @Autowired + ArticleService articleService; + + /** + * 查看文章详情 + * + * @param articleId + * @return + */ + @GetMapping("/detail") + @ApiOperation(value = "文章详情",notes = "") + public R getArticle(int articleId) { + Article article = articleService.findById(articleId); + return R.ok().put(article); + } + + /** + * 查看目录 + * + * @param category + * @return + */ + @GetMapping("/category") + @ApiOperation(value = "目录信息",notes = "") + public R getQuestions(String type, String category) { + ArticleTypeEnum articleType = ArticleTypeEnum.of(type); + if (articleType == null) { + return R.error("文章类型有误"); + } + List
articles = articleService.selectCategory(articleType, category); + return R.ok().put(articles); + } + + /** + * 文章搜索 + * + * @param category + * @param keywords + * @return + */ + @GetMapping("/search") + @ApiOperation(value = "文章搜索",notes = "") + public R getQuestions(String type, + @RequestParam(required = false) String category, + @RequestParam(required = false) String keywords) { + ArticleTypeEnum articleType = ArticleTypeEnum.of(type); + if (articleType == null) { + return R.error("文章类型有误"); + } + if (!StringUtils.hasText(keywords)) { + return R.error("关键词不得为空"); + } + List
articles = articleService.search(articleType, category, keywords); + return R.ok().put(articles); + } + + +} diff --git a/czsj-admin/src/main/java/com/czsj/web/controller/wechat/CzsjWxAccountController.java b/czsj-admin/src/main/java/com/czsj/web/controller/wechat/CzsjWxAccountController.java new file mode 100644 index 0000000..7c4c06f --- /dev/null +++ b/czsj-admin/src/main/java/com/czsj/web/controller/wechat/CzsjWxAccountController.java @@ -0,0 +1,104 @@ +package com.czsj.web.controller.wechat; + +import java.util.List; +import javax.servlet.http.HttpServletResponse; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.czsj.common.annotation.Log; +import com.czsj.common.core.controller.BaseController; +import com.czsj.common.core.domain.AjaxResult; +import com.czsj.common.enums.BusinessType; +import com.czsj.wechat.domain.CzsjWxAccount; +import com.czsj.wechat.service.ICzsjWxAccountService; +import com.czsj.common.utils.poi.ExcelUtil; +import com.czsj.common.core.page.TableDataInfo; + +/** + * 微信公众号Controller + * + * @author czsj + * @date 2024-12-07 + */ +@RestController +@RequestMapping("/wechat/account") +public class CzsjWxAccountController extends BaseController +{ + @Autowired + private ICzsjWxAccountService czsjWxAccountService; + + /** + * 查询微信公众号列表 + */ + @PreAuthorize("@ss.hasPermi('wechat:account:list')") + @GetMapping("/list") + public TableDataInfo list(CzsjWxAccount czsjWxAccount) + { + startPage(); + List list = czsjWxAccountService.selectCzsjWxAccountList(czsjWxAccount); + return getDataTable(list); + } + + /** + * 导出微信公众号列表 + */ + @PreAuthorize("@ss.hasPermi('wechat:account:export')") + @Log(title = "微信公众号", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, CzsjWxAccount czsjWxAccount) + { + List list = czsjWxAccountService.selectCzsjWxAccountList(czsjWxAccount); + ExcelUtil util = new ExcelUtil(CzsjWxAccount.class); + util.exportExcel(response, list, "微信公众号数据"); + } + + /** + * 获取微信公众号详细信息 + */ + @PreAuthorize("@ss.hasPermi('wechat:account:query')") + @GetMapping(value = "/{uid}") + public AjaxResult getInfo(@PathVariable("uid") Long uid) + { + return success(czsjWxAccountService.selectCzsjWxAccountByUid(uid)); + } + + /** + * 新增微信公众号 + */ + @PreAuthorize("@ss.hasPermi('wechat:account:add')") + @Log(title = "微信公众号", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody CzsjWxAccount czsjWxAccount) + { + return toAjax(czsjWxAccountService.insertCzsjWxAccount(czsjWxAccount)); + } + + /** + * 修改微信公众号 + */ + @PreAuthorize("@ss.hasPermi('wechat:account:edit')") + @Log(title = "微信公众号", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody CzsjWxAccount czsjWxAccount) + { + return toAjax(czsjWxAccountService.updateCzsjWxAccount(czsjWxAccount)); + } + + /** + * 删除微信公众号 + */ + @PreAuthorize("@ss.hasPermi('wechat:account:remove')") + @Log(title = "微信公众号", businessType = BusinessType.DELETE) + @DeleteMapping("/{uids}") + public AjaxResult remove(@PathVariable Long[] uids) + { + return toAjax(czsjWxAccountService.deleteCzsjWxAccountByUids(uids)); + } +} diff --git a/czsj-admin/src/main/java/com/czsj/web/controller/wechat/CzsjWxMessageController.java b/czsj-admin/src/main/java/com/czsj/web/controller/wechat/CzsjWxMessageController.java new file mode 100644 index 0000000..ef7a777 --- /dev/null +++ b/czsj-admin/src/main/java/com/czsj/web/controller/wechat/CzsjWxMessageController.java @@ -0,0 +1,104 @@ +package com.czsj.web.controller.wechat; + +import java.util.List; +import javax.servlet.http.HttpServletResponse; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.czsj.common.annotation.Log; +import com.czsj.common.core.controller.BaseController; +import com.czsj.common.core.domain.AjaxResult; +import com.czsj.common.enums.BusinessType; +import com.czsj.wechat.domain.CzsjWxMessage; +import com.czsj.wechat.service.ICzsjWxMessageService; +import com.czsj.common.utils.poi.ExcelUtil; +import com.czsj.common.core.page.TableDataInfo; + +/** + * 微信消息Controller + * + * @author czsj + * @date 2024-12-07 + */ +@RestController +@RequestMapping("/wechat/message") +public class CzsjWxMessageController extends BaseController +{ + @Autowired + private ICzsjWxMessageService czsjWxMessageService; + + /** + * 查询微信消息列表 + */ + @PreAuthorize("@ss.hasPermi('wechat:message:list')") + @GetMapping("/list") + public TableDataInfo list(CzsjWxMessage czsjWxMessage) + { + startPage(); + List list = czsjWxMessageService.selectCzsjWxMessageList(czsjWxMessage); + return getDataTable(list); + } + + /** + * 导出微信消息列表 + */ + @PreAuthorize("@ss.hasPermi('wechat:message:export')") + @Log(title = "微信消息", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, CzsjWxMessage czsjWxMessage) + { + List list = czsjWxMessageService.selectCzsjWxMessageList(czsjWxMessage); + ExcelUtil util = new ExcelUtil(CzsjWxMessage.class); + util.exportExcel(response, list, "微信消息数据"); + } + + /** + * 获取微信消息详细信息 + */ + @PreAuthorize("@ss.hasPermi('wechat:message:query')") + @GetMapping(value = "/{uid}") + public AjaxResult getInfo(@PathVariable("uid") Long uid) + { + return success(czsjWxMessageService.selectCzsjWxMessageByUid(uid)); + } + + /** + * 新增微信消息 + */ + @PreAuthorize("@ss.hasPermi('wechat:message:add')") + @Log(title = "微信消息", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody CzsjWxMessage czsjWxMessage) + { + return toAjax(czsjWxMessageService.insertCzsjWxMessage(czsjWxMessage)); + } + + /** + * 修改微信消息 + */ + @PreAuthorize("@ss.hasPermi('wechat:message:edit')") + @Log(title = "微信消息", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody CzsjWxMessage czsjWxMessage) + { + return toAjax(czsjWxMessageService.updateCzsjWxMessage(czsjWxMessage)); + } + + /** + * 删除微信消息 + */ + @PreAuthorize("@ss.hasPermi('wechat:message:remove')") + @Log(title = "微信消息", businessType = BusinessType.DELETE) + @DeleteMapping("/{uids}") + public AjaxResult remove(@PathVariable Long[] uids) + { + return toAjax(czsjWxMessageService.deleteCzsjWxMessageByUids(uids)); + } +} diff --git a/czsj-admin/src/main/java/com/czsj/web/controller/wechat/CzsjWxQrCodeController.java b/czsj-admin/src/main/java/com/czsj/web/controller/wechat/CzsjWxQrCodeController.java new file mode 100644 index 0000000..5bb1e8e --- /dev/null +++ b/czsj-admin/src/main/java/com/czsj/web/controller/wechat/CzsjWxQrCodeController.java @@ -0,0 +1,104 @@ +package com.czsj.web.controller.wechat; + +import java.util.List; +import javax.servlet.http.HttpServletResponse; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.czsj.common.annotation.Log; +import com.czsj.common.core.controller.BaseController; +import com.czsj.common.core.domain.AjaxResult; +import com.czsj.common.enums.BusinessType; +import com.czsj.wechat.domain.CzsjWxQrCode; +import com.czsj.wechat.service.ICzsjWxQrCodeService; +import com.czsj.common.utils.poi.ExcelUtil; +import com.czsj.common.core.page.TableDataInfo; + +/** + * 公众号二维码Controller + * + * @author czsj + * @date 2024-12-07 + */ +@RestController +@RequestMapping("/wechat/code") +public class CzsjWxQrCodeController extends BaseController +{ + @Autowired + private ICzsjWxQrCodeService czsjWxQrCodeService; + + /** + * 查询公众号二维码列表 + */ + @PreAuthorize("@ss.hasPermi('wechat:code:list')") + @GetMapping("/list") + public TableDataInfo list(CzsjWxQrCode czsjWxQrCode) + { + startPage(); + List list = czsjWxQrCodeService.selectCzsjWxQrCodeList(czsjWxQrCode); + return getDataTable(list); + } + + /** + * 导出公众号二维码列表 + */ + @PreAuthorize("@ss.hasPermi('wechat:code:export')") + @Log(title = "公众号二维码", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, CzsjWxQrCode czsjWxQrCode) + { + List list = czsjWxQrCodeService.selectCzsjWxQrCodeList(czsjWxQrCode); + ExcelUtil util = new ExcelUtil(CzsjWxQrCode.class); + util.exportExcel(response, list, "公众号二维码数据"); + } + + /** + * 获取公众号二维码详细信息 + */ + @PreAuthorize("@ss.hasPermi('wechat:code:query')") + @GetMapping(value = "/{uid}") + public AjaxResult getInfo(@PathVariable("uid") Long uid) + { + return success(czsjWxQrCodeService.selectCzsjWxQrCodeByUid(uid)); + } + + /** + * 新增公众号二维码 + */ + @PreAuthorize("@ss.hasPermi('wechat:code:add')") + @Log(title = "公众号二维码", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody CzsjWxQrCode czsjWxQrCode) + { + return toAjax(czsjWxQrCodeService.insertCzsjWxQrCode(czsjWxQrCode)); + } + + /** + * 修改公众号二维码 + */ + @PreAuthorize("@ss.hasPermi('wechat:code:edit')") + @Log(title = "公众号二维码", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody CzsjWxQrCode czsjWxQrCode) + { + return toAjax(czsjWxQrCodeService.updateCzsjWxQrCode(czsjWxQrCode)); + } + + /** + * 删除公众号二维码 + */ + @PreAuthorize("@ss.hasPermi('wechat:code:remove')") + @Log(title = "公众号二维码", businessType = BusinessType.DELETE) + @DeleteMapping("/{uids}") + public AjaxResult remove(@PathVariable Long[] uids) + { + return toAjax(czsjWxQrCodeService.deleteCzsjWxQrCodeByUids(uids)); + } +} diff --git a/czsj-admin/src/main/java/com/czsj/web/controller/wechat/CzsjWxReplyRuleController.java b/czsj-admin/src/main/java/com/czsj/web/controller/wechat/CzsjWxReplyRuleController.java new file mode 100644 index 0000000..9705783 --- /dev/null +++ b/czsj-admin/src/main/java/com/czsj/web/controller/wechat/CzsjWxReplyRuleController.java @@ -0,0 +1,104 @@ +package com.czsj.web.controller.wechat; + +import java.util.List; +import javax.servlet.http.HttpServletResponse; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.czsj.common.annotation.Log; +import com.czsj.common.core.controller.BaseController; +import com.czsj.common.core.domain.AjaxResult; +import com.czsj.common.enums.BusinessType; +import com.czsj.wechat.domain.CzsjWxReplyRule; +import com.czsj.wechat.service.ICzsjWxReplyRuleService; +import com.czsj.common.utils.poi.ExcelUtil; +import com.czsj.common.core.page.TableDataInfo; + +/** + * 微信消息回复规则Controller + * + * @author czsj + * @date 2024-12-07 + */ +@RestController +@RequestMapping("/wechat/rule") +public class CzsjWxReplyRuleController extends BaseController +{ + @Autowired + private ICzsjWxReplyRuleService czsjWxReplyRuleService; + + /** + * 查询微信消息回复规则列表 + */ + @PreAuthorize("@ss.hasPermi('wechat:rule:list')") + @GetMapping("/list") + public TableDataInfo list(CzsjWxReplyRule czsjWxReplyRule) + { + startPage(); + List list = czsjWxReplyRuleService.selectCzsjWxReplyRuleList(czsjWxReplyRule); + return getDataTable(list); + } + + /** + * 导出微信消息回复规则列表 + */ + @PreAuthorize("@ss.hasPermi('wechat:rule:export')") + @Log(title = "微信消息回复规则", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, CzsjWxReplyRule czsjWxReplyRule) + { + List list = czsjWxReplyRuleService.selectCzsjWxReplyRuleList(czsjWxReplyRule); + ExcelUtil util = new ExcelUtil(CzsjWxReplyRule.class); + util.exportExcel(response, list, "微信消息回复规则数据"); + } + + /** + * 获取微信消息回复规则详细信息 + */ + @PreAuthorize("@ss.hasPermi('wechat:rule:query')") + @GetMapping(value = "/{uid}") + public AjaxResult getInfo(@PathVariable("uid") Long uid) + { + return success(czsjWxReplyRuleService.selectCzsjWxReplyRuleByUid(uid)); + } + + /** + * 新增微信消息回复规则 + */ + @PreAuthorize("@ss.hasPermi('wechat:rule:add')") + @Log(title = "微信消息回复规则", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody CzsjWxReplyRule czsjWxReplyRule) + { + return toAjax(czsjWxReplyRuleService.insertCzsjWxReplyRule(czsjWxReplyRule)); + } + + /** + * 修改微信消息回复规则 + */ + @PreAuthorize("@ss.hasPermi('wechat:rule:edit')") + @Log(title = "微信消息回复规则", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody CzsjWxReplyRule czsjWxReplyRule) + { + return toAjax(czsjWxReplyRuleService.updateCzsjWxReplyRule(czsjWxReplyRule)); + } + + /** + * 删除微信消息回复规则 + */ + @PreAuthorize("@ss.hasPermi('wechat:rule:remove')") + @Log(title = "微信消息回复规则", businessType = BusinessType.DELETE) + @DeleteMapping("/{uids}") + public AjaxResult remove(@PathVariable Long[] uids) + { + return toAjax(czsjWxReplyRuleService.deleteCzsjWxReplyRuleByUids(uids)); + } +} diff --git a/czsj-admin/src/main/java/com/czsj/web/controller/wechat/CzsjWxTemplateController.java b/czsj-admin/src/main/java/com/czsj/web/controller/wechat/CzsjWxTemplateController.java new file mode 100644 index 0000000..5038287 --- /dev/null +++ b/czsj-admin/src/main/java/com/czsj/web/controller/wechat/CzsjWxTemplateController.java @@ -0,0 +1,104 @@ +package com.czsj.web.controller.wechat; + +import java.util.List; +import javax.servlet.http.HttpServletResponse; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.czsj.common.annotation.Log; +import com.czsj.common.core.controller.BaseController; +import com.czsj.common.core.domain.AjaxResult; +import com.czsj.common.enums.BusinessType; +import com.czsj.wechat.domain.CzsjWxTemplate; +import com.czsj.wechat.service.ICzsjWxTemplateService; +import com.czsj.common.utils.poi.ExcelUtil; +import com.czsj.common.core.page.TableDataInfo; + +/** + * 微信消息模板Controller + * + * @author czsj + * @date 2024-12-07 + */ +@RestController +@RequestMapping("/wechat/template") +public class CzsjWxTemplateController extends BaseController +{ + @Autowired + private ICzsjWxTemplateService czsjWxTemplateService; + + /** + * 查询微信消息模板列表 + */ + @PreAuthorize("@ss.hasPermi('wechat:template:list')") + @GetMapping("/list") + public TableDataInfo list(CzsjWxTemplate czsjWxTemplate) + { + startPage(); + List list = czsjWxTemplateService.selectCzsjWxTemplateList(czsjWxTemplate); + return getDataTable(list); + } + + /** + * 导出微信消息模板列表 + */ + @PreAuthorize("@ss.hasPermi('wechat:template:export')") + @Log(title = "微信消息模板", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, CzsjWxTemplate czsjWxTemplate) + { + List list = czsjWxTemplateService.selectCzsjWxTemplateList(czsjWxTemplate); + ExcelUtil util = new ExcelUtil(CzsjWxTemplate.class); + util.exportExcel(response, list, "微信消息模板数据"); + } + + /** + * 获取微信消息模板详细信息 + */ + @PreAuthorize("@ss.hasPermi('wechat:template:query')") + @GetMapping(value = "/{uid}") + public AjaxResult getInfo(@PathVariable("uid") Long uid) + { + return success(czsjWxTemplateService.selectCzsjWxTemplateByUid(uid)); + } + + /** + * 新增微信消息模板 + */ + @PreAuthorize("@ss.hasPermi('wechat:template:add')") + @Log(title = "微信消息模板", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody CzsjWxTemplate czsjWxTemplate) + { + return toAjax(czsjWxTemplateService.insertCzsjWxTemplate(czsjWxTemplate)); + } + + /** + * 修改微信消息模板 + */ + @PreAuthorize("@ss.hasPermi('wechat:template:edit')") + @Log(title = "微信消息模板", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody CzsjWxTemplate czsjWxTemplate) + { + return toAjax(czsjWxTemplateService.updateCzsjWxTemplate(czsjWxTemplate)); + } + + /** + * 删除微信消息模板 + */ + @PreAuthorize("@ss.hasPermi('wechat:template:remove')") + @Log(title = "微信消息模板", businessType = BusinessType.DELETE) + @DeleteMapping("/{uids}") + public AjaxResult remove(@PathVariable Long[] uids) + { + return toAjax(czsjWxTemplateService.deleteCzsjWxTemplateByUids(uids)); + } +} diff --git a/czsj-admin/src/main/java/com/czsj/web/controller/wechat/CzsjWxTemplateLogController.java b/czsj-admin/src/main/java/com/czsj/web/controller/wechat/CzsjWxTemplateLogController.java new file mode 100644 index 0000000..2716845 --- /dev/null +++ b/czsj-admin/src/main/java/com/czsj/web/controller/wechat/CzsjWxTemplateLogController.java @@ -0,0 +1,104 @@ +package com.czsj.web.controller.wechat; + +import java.util.List; +import javax.servlet.http.HttpServletResponse; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.czsj.common.annotation.Log; +import com.czsj.common.core.controller.BaseController; +import com.czsj.common.core.domain.AjaxResult; +import com.czsj.common.enums.BusinessType; +import com.czsj.wechat.domain.CzsjWxTemplateLog; +import com.czsj.wechat.service.ICzsjWxTemplateLogService; +import com.czsj.common.utils.poi.ExcelUtil; +import com.czsj.common.core.page.TableDataInfo; + +/** + * 微信消息模板日志Controller + * + * @author czsj + * @date 2024-12-07 + */ +@RestController +@RequestMapping("/wechat/log") +public class CzsjWxTemplateLogController extends BaseController +{ + @Autowired + private ICzsjWxTemplateLogService czsjWxTemplateLogService; + + /** + * 查询微信消息模板日志列表 + */ + @PreAuthorize("@ss.hasPermi('wechat:log:list')") + @GetMapping("/list") + public TableDataInfo list(CzsjWxTemplateLog czsjWxTemplateLog) + { + startPage(); + List list = czsjWxTemplateLogService.selectCzsjWxTemplateLogList(czsjWxTemplateLog); + return getDataTable(list); + } + + /** + * 导出微信消息模板日志列表 + */ + @PreAuthorize("@ss.hasPermi('wechat:log:export')") + @Log(title = "微信消息模板日志", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, CzsjWxTemplateLog czsjWxTemplateLog) + { + List list = czsjWxTemplateLogService.selectCzsjWxTemplateLogList(czsjWxTemplateLog); + ExcelUtil util = new ExcelUtil(CzsjWxTemplateLog.class); + util.exportExcel(response, list, "微信消息模板日志数据"); + } + + /** + * 获取微信消息模板日志详细信息 + */ + @PreAuthorize("@ss.hasPermi('wechat:log:query')") + @GetMapping(value = "/{uid}") + public AjaxResult getInfo(@PathVariable("uid") Long uid) + { + return success(czsjWxTemplateLogService.selectCzsjWxTemplateLogByUid(uid)); + } + + /** + * 新增微信消息模板日志 + */ + @PreAuthorize("@ss.hasPermi('wechat:log:add')") + @Log(title = "微信消息模板日志", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody CzsjWxTemplateLog czsjWxTemplateLog) + { + return toAjax(czsjWxTemplateLogService.insertCzsjWxTemplateLog(czsjWxTemplateLog)); + } + + /** + * 修改微信消息模板日志 + */ + @PreAuthorize("@ss.hasPermi('wechat:log:edit')") + @Log(title = "微信消息模板日志", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody CzsjWxTemplateLog czsjWxTemplateLog) + { + return toAjax(czsjWxTemplateLogService.updateCzsjWxTemplateLog(czsjWxTemplateLog)); + } + + /** + * 删除微信消息模板日志 + */ + @PreAuthorize("@ss.hasPermi('wechat:log:remove')") + @Log(title = "微信消息模板日志", businessType = BusinessType.DELETE) + @DeleteMapping("/{uids}") + public AjaxResult remove(@PathVariable Long[] uids) + { + return toAjax(czsjWxTemplateLogService.deleteCzsjWxTemplateLogByUids(uids)); + } +} diff --git a/czsj-admin/src/main/java/com/czsj/web/controller/wechat/WxAuthController.java b/czsj-admin/src/main/java/com/czsj/web/controller/wechat/WxAuthController.java new file mode 100644 index 0000000..4547815 --- /dev/null +++ b/czsj-admin/src/main/java/com/czsj/web/controller/wechat/WxAuthController.java @@ -0,0 +1,130 @@ +package com.czsj.web.controller.wechat; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import me.chanjar.weixin.common.bean.WxOAuth2UserInfo; +import me.chanjar.weixin.common.bean.oauth2.WxOAuth2AccessToken; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.api.WxMpService; +import com.czsj.wechat.entity.WxUser; +import com.czsj.wechat.form.WxH5OuthrizeForm; +import com.czsj.wechat.utils.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.Map; +import java.util.TreeMap; +import java.util.UUID; + +/** + * 微信网页授权相关 + */ +@RestController +@RequestMapping("/wxAuth") +@Api(tags = {"微信网页授权"}) +@RequiredArgsConstructor +public class WxAuthController { + Logger logger = LoggerFactory.getLogger(this.getClass()); + + private final WxMpService wxMpService; + + /** + * 使用微信授权code换取openid + * + * @param request + * @param response + * @param form + * @return + */ + @PostMapping("/codeToOpenid") + @CrossOrigin + @ApiOperation(value = "网页登录-code换取openid",notes = "scope为snsapi_base") + public R codeToOpenid(HttpServletRequest request, HttpServletResponse response, + @CookieValue String appid, @RequestBody WxH5OuthrizeForm form) { + try { + this.wxMpService.switchoverTo(appid); + WxOAuth2AccessToken token = wxMpService.getOAuth2Service().getAccessToken(form.getCode()); + String openid = token.getOpenId(); + CookieUtil.setCookie(response, "openid", openid, 365 * 24 * 60 * 60); + String openidToken = MD5Util.getMd5AndSalt(openid); + CookieUtil.setCookie(response, "openidToken", openidToken, 365 * 24 * 60 * 60); + return R.ok().put(openid); + } catch (WxErrorException e) { + logger.error("code换取openid失败", e); + return R.error(e.getError().getErrorMsg()); + } + } + + /** + * 使用微信授权code换取用户信息(需scope为 snsapi_userinfo) + * + * @param request + * @param response + * @param form + * @return + */ + @PostMapping("/codeToUserInfo") + @CrossOrigin + @ApiOperation(value = "网页登录-code换取用户信息",notes = "需scope为 snsapi_userinfo") + public R codeToUserInfo(HttpServletRequest request, HttpServletResponse response, + @CookieValue String appid, @RequestBody WxH5OuthrizeForm form) { + try { + this.wxMpService.switchoverTo(appid); + WxOAuth2AccessToken token = wxMpService.getOAuth2Service().getAccessToken(form.getCode()); + WxOAuth2UserInfo userInfo = wxMpService.getOAuth2Service().getUserInfo(token,"zh_CN"); + String openid = userInfo.getOpenid(); + CookieUtil.setCookie(response, "openid", openid, 365 * 24 * 60 * 60); + String openidToken = MD5Util.getMd5AndSalt(openid); + CookieUtil.setCookie(response, "openidToken", openidToken, 365 * 24 * 60 * 60); + return R.ok().put(new WxUser(userInfo,appid)); + } catch (WxErrorException e) { + logger.error("code换取用户信息失败", e); + return R.error(e.getError().getErrorMsg()); + } + } + + /** + * 获取微信分享的签名配置 + * 允许跨域(只有微信公众号添加了js安全域名的网站才能加载微信分享,故这里不对域名进行校验) + * + * @param request + * @param response + * @return + */ + @GetMapping("/getShareSignature") + @ApiOperation(value = "获取微信分享的签名配置",notes = "微信公众号添加了js安全域名的网站才能加载微信分享") + public R getShareSignature(HttpServletRequest request, HttpServletResponse response,@CookieValue String appid) throws WxErrorException { + this.wxMpService.switchoverTo(appid); + // 1.拼接url(当前网页的URL,不包含#及其后面部分) + String wxShareUrl = request.getHeader(Constant.WX_CLIENT_HREF_HEADER); + if (!StringUtils.hasText(wxShareUrl)) { + return R.error("header中缺少"+Constant.WX_CLIENT_HREF_HEADER+"参数,微信分享加载失败"); + } + wxShareUrl = wxShareUrl.split("#")[0]; + Map wxMap = new TreeMap<>(); + String wxNoncestr = UUID.randomUUID().toString(); + String wxTimestamp = (System.currentTimeMillis() / 1000) + ""; + wxMap.put("noncestr", wxNoncestr); + wxMap.put("timestamp", wxTimestamp); + wxMap.put("jsapi_ticket", wxMpService.getJsapiTicket()); + wxMap.put("url", wxShareUrl); + + // 加密获取signature + StringBuilder wxBaseString = new StringBuilder(); + wxMap.forEach((key, value) -> wxBaseString.append(key).append("=").append(value).append("&")); + String wxSignString = wxBaseString.substring(0, wxBaseString.length() - 1); + // signature + String wxSignature = SHA1Util.sha1(wxSignString); + Map resMap = new TreeMap<>(); + resMap.put("appId", appid); + resMap.put("wxTimestamp", wxTimestamp); + resMap.put("wxNoncestr", wxNoncestr); + resMap.put("wxSignature", wxSignature); + return R.ok().put(resMap); + } +} diff --git a/czsj-admin/src/main/java/com/czsj/web/controller/wechat/WxMpPortalController.java b/czsj-admin/src/main/java/com/czsj/web/controller/wechat/WxMpPortalController.java new file mode 100644 index 0000000..f3512f4 --- /dev/null +++ b/czsj-admin/src/main/java/com/czsj/web/controller/wechat/WxMpPortalController.java @@ -0,0 +1,106 @@ +package com.czsj.web.controller.wechat; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import me.chanjar.weixin.mp.api.WxMpMessageRouter; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.bind.annotation.*; + +/** + * 微信消息 + * @author Binary Wang + */ +@RequiredArgsConstructor +@RestController +@RequestMapping("/wx/msg/{appid}") +@Api(tags = {"微信消息 - 腾讯会调用"}) +public class WxMpPortalController { + private final WxMpService wxService; + private final WxMpMessageRouter messageRouter; + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @GetMapping(produces = "text/plain;charset=utf-8") + @ApiOperation(value = "微信服务器的认证消息",notes = "公众号接入开发模式时腾讯调用此接口") + public String authGet(@PathVariable String appid, + @RequestParam(name = "signature", required = false) String signature, + @RequestParam(name = "timestamp", required = false) String timestamp, + @RequestParam(name = "nonce", required = false) String nonce, + @RequestParam(name = "echostr", required = false) String echostr) { + + logger.info("\n接收到来自微信服务器的认证消息:[{}, {}, {}, {}]", signature, + timestamp, nonce, echostr); + if (StringUtils.isAnyBlank(signature, timestamp, nonce, echostr)) { + throw new IllegalArgumentException("请求参数非法,请核实!"); + } + this.wxService.switchoverTo(appid); + + if (wxService.checkSignature(timestamp, nonce, signature)) { + return echostr; + } + + return "非法请求"; + } + + @PostMapping(produces = "application/xml; charset=UTF-8") + @ApiOperation(value = "微信各类消息",notes = "公众号接入开发模式后才有效") + public String post(@PathVariable String appid, + @RequestBody String requestBody, + @RequestParam("signature") String signature, + @RequestParam("timestamp") String timestamp, + @RequestParam("nonce") String nonce, + @RequestParam("openid") String openid, + @RequestParam(name = "encrypt_type", required = false) String encType, + @RequestParam(name = "msg_signature", required = false) String msgSignature) { +// logger.debug("\n接收微信请求:[openid=[{}], [signature=[{}], encType=[{}], msgSignature=[{}]," +// + " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ", +// openid, signature, encType, msgSignature, timestamp, nonce, requestBody); + this.wxService.switchoverTo(appid); + if (!wxService.checkSignature(timestamp, nonce, signature)) { + throw new IllegalArgumentException("非法请求,可能属于伪造的请求!"); + } + + String out = null; + if (encType == null) { + // 明文传输的消息 + WxMpXmlMessage inMessage = WxMpXmlMessage.fromXml(requestBody); + WxMpXmlOutMessage outMessage = this.route(appid,inMessage); + if (outMessage == null) { + return ""; + } + + out = outMessage.toXml(); + } else if ("aes".equalsIgnoreCase(encType)) { + // aes加密的消息 + WxMpXmlMessage inMessage = WxMpXmlMessage.fromEncryptedXml(requestBody, wxService.getWxMpConfigStorage(), + timestamp, nonce, msgSignature); + logger.debug("\n消息解密后内容为:\n{} ", inMessage.toString()); + WxMpXmlOutMessage outMessage = this.route(appid,inMessage); + if (outMessage == null) { + return ""; + } + + out = outMessage.toEncryptedXml(wxService.getWxMpConfigStorage()); + } + + logger.debug("\n组装回复信息:{}", out); + return out; + } + + private WxMpXmlOutMessage route(String appid,WxMpXmlMessage message) { + try { + return this.messageRouter.route(appid,message); + } catch (Exception e) { + logger.error("路由消息时出现异常!", e); + } + + return null; + } + +} diff --git a/czsj-admin/src/main/java/com/czsj/web/controller/wechat/WxUserController.java b/czsj-admin/src/main/java/com/czsj/web/controller/wechat/WxUserController.java new file mode 100644 index 0000000..4f4c3d4 --- /dev/null +++ b/czsj-admin/src/main/java/com/czsj/web/controller/wechat/WxUserController.java @@ -0,0 +1,38 @@ +package com.czsj.web.controller.wechat; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import me.chanjar.weixin.mp.api.WxMpService; +import com.czsj.wechat.entity.WxUser; +import com.czsj.wechat.service.WxUserService; +import com.czsj.wechat.utils.R; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.CookieValue; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * 微信用户(粉丝) + */ +@RestController +@RequestMapping("/wxUser") +@RequiredArgsConstructor +@Api(tags = {"微信粉丝"}) +public class WxUserController { + Logger logger = LoggerFactory.getLogger(this.getClass()); + @Autowired + WxUserService wxUserService; + private final WxMpService wxMpService; + + @GetMapping("/getUserInfo") + @ApiOperation(value = "获取粉丝信息") + public R getUserInfo(@CookieValue String appid,@CookieValue String openid){ + this.wxMpService.switchoverTo(appid); + WxUser wxUser = wxUserService.getById(openid); + return R.ok().put(wxUser); + } +} diff --git a/czsj-admin/src/main/java/com/czsj/web/controller/wechat/WxUserTagsController.java b/czsj-admin/src/main/java/com/czsj/web/controller/wechat/WxUserTagsController.java new file mode 100644 index 0000000..511ca7b --- /dev/null +++ b/czsj-admin/src/main/java/com/czsj/web/controller/wechat/WxUserTagsController.java @@ -0,0 +1,72 @@ +package com.czsj.web.controller.wechat; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import me.chanjar.weixin.common.error.WxError; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.api.WxMpService; +import com.czsj.wechat.entity.WxUser; +import com.czsj.wechat.form.WxUserTaggingForm; +import com.czsj.wechat.service.WxUserService; +import com.czsj.wechat.service.WxUserTagsService; +import com.czsj.wechat.utils.R; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +/** + * 粉丝标签 + */ +@RestController +@RequestMapping("/wxUserTags") +@RequiredArgsConstructor +@Api(tags = {"粉丝标签"}) +public class WxUserTagsController { + @Autowired + WxUserTagsService wxUserTagsService; + @Autowired + WxUserService wxUserService; + private final WxMpService wxMpService; + + @GetMapping("/userTags") + @ApiOperation(value = "当前用户的标签") + public R userTags(@CookieValue String appid,@CookieValue String openid){ + if(openid==null){ + return R.error("none_openid"); + } + this.wxMpService.switchoverTo(appid); + WxUser wxUser = wxUserService.getById(openid); + if(wxUser==null){ + wxUser=wxUserService.refreshUserInfo(openid,appid); + if(wxUser==null) { + return R.error("not_subscribed"); + } + } + return R.ok().put(wxUser.getTagidList()); + } + + @PostMapping("/tagging") + @ApiOperation(value = "给用户绑定标签") + public R tagging(@CookieValue String appid,@CookieValue String openid , @RequestBody WxUserTaggingForm form) { + this.wxMpService.switchoverTo(appid); + try { + wxUserTagsService.tagging(form.getTagid(),openid); + }catch (WxErrorException e){ + WxError error = e.getError(); + if(50005==error.getErrorCode()){//未关注公众号 + return R.error("not_subscribed"); + }else { + return R.error(error.getErrorMsg()); + } + } + return R.ok(); + } + + @PostMapping("/untagging") + @ApiOperation(value = "解绑标签") + public R untagging(@CookieValue String appid,@CookieValue String openid , @RequestBody WxUserTaggingForm form) throws WxErrorException { + this.wxMpService.switchoverTo(appid); + wxUserTagsService.untagging(form.getTagid(),openid); + return R.ok(); + } +} diff --git a/czsj-common/pom.xml b/czsj-common/pom.xml index e366902..85cf95d 100644 --- a/czsj-common/pom.xml +++ b/czsj-common/pom.xml @@ -124,6 +124,18 @@ javax.servlet-api + + org.projectlombok + lombok + compile + + + + com.alibaba + fastjson + 1.2.83 + + \ No newline at end of file diff --git a/czsj-system/pom.xml b/czsj-system/pom.xml index 881fe3a..1936f02 100644 --- a/czsj-system/pom.xml +++ b/czsj-system/pom.xml @@ -23,6 +23,31 @@ czsj-common + + + com.baomidou + mybatis-plus-boot-starter + 3.5.3.2 + + + + com.github.binarywang + weixin-java-mp + 4.6.0 + + + + + io.springfox + springfox-swagger2 + 2.9.2 + + + + io.springfox + springfox-swagger-ui + 2.9.2 + \ No newline at end of file diff --git a/czsj-system/src/main/java/com/czsj/account/service/ICzsjMemberWxFansService.java b/czsj-system/src/main/java/com/czsj/account/service/ICzsjMemberWxFansService.java index 0ae32f6..6264344 100644 --- a/czsj-system/src/main/java/com/czsj/account/service/ICzsjMemberWxFansService.java +++ b/czsj-system/src/main/java/com/czsj/account/service/ICzsjMemberWxFansService.java @@ -2,6 +2,7 @@ package com.czsj.account.service; import java.util.List; import com.czsj.account.domain.CzsjMemberWxFans; +import com.czsj.wechat.entity.WxUser; /** * 会员微信粉丝Service接口 @@ -11,6 +12,21 @@ import com.czsj.account.domain.CzsjMemberWxFans; */ public interface ICzsjMemberWxFansService { + + /** + * 取消关注,更新关注状态 + * + * @param openid + */ + void unsubscribe(String openid); + /** + * 根据openid更新会员微信粉丝 + * + * @param openid + * @return + */ + void refreshUserInfo(String openid, String appid); + /** * 查询会员微信粉丝 * diff --git a/czsj-system/src/main/java/com/czsj/account/service/impl/CzsjMemberWxFansServiceImpl.java b/czsj-system/src/main/java/com/czsj/account/service/impl/CzsjMemberWxFansServiceImpl.java index a272a2f..4dff013 100644 --- a/czsj-system/src/main/java/com/czsj/account/service/impl/CzsjMemberWxFansServiceImpl.java +++ b/czsj-system/src/main/java/com/czsj/account/service/impl/CzsjMemberWxFansServiceImpl.java @@ -1,7 +1,16 @@ package com.czsj.account.service.impl; +import java.util.Date; import java.util.List; + +import com.czsj.common.core.domain.entity.SysUser; +import com.czsj.common.core.domain.model.LoginUser; import com.czsj.common.utils.DateUtils; +import com.czsj.common.utils.SecurityUtils; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.result.WxMpUser; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.czsj.account.mapper.CzsjMemberWxFansMapper; @@ -17,8 +26,56 @@ import com.czsj.account.service.ICzsjMemberWxFansService; @Service public class CzsjMemberWxFansServiceImpl implements ICzsjMemberWxFansService { + Logger logger = LoggerFactory.getLogger(this.getClass()); + @Autowired private CzsjMemberWxFansMapper czsjMemberWxFansMapper; + @Autowired + private WxMpService wxMpService; + + @Override + public void unsubscribe(String openid) { + CzsjMemberWxFans fans = new CzsjMemberWxFans(); + fans.setOpenId(openid); + fans.setSubscribeStatus(1); + fans.setUnsubscribeTime(new Date()); + czsjMemberWxFansMapper.updateCzsjMemberWxFans(fans); + } + + @Override + public void refreshUserInfo(String openid, String appid) { + try { + LoginUser loginUser = SecurityUtils.getLoginUser(); + SysUser currentUser = loginUser.getUser(); + // 获取微信用户基本信息 + logger.info("更新用户信息,openid={}",openid); + wxMpService.switchover(appid); + WxMpUser userWxInfo = wxMpService.getUserService().userInfo(openid, null); + if (userWxInfo == null) { + logger.error("获取不到用户信息,无法更新,openid:{}",openid); + return ; + } + CzsjMemberWxFans fans = new CzsjMemberWxFans(); + fans.setOpenId(openid); + List czsjMemberWxFans = czsjMemberWxFansMapper.selectCzsjMemberWxFansList(fans); + fans.setAppId(appid); + fans.setCreateUserId(currentUser.getUserId()); + fans.setUpdateUserId(currentUser.getUserId()); + fans.setUpdateTime(new Date()); + fans.setName(userWxInfo.getNickname()); + fans.setImageUrl(userWxInfo.getHeadImgUrl()); + fans.setSubscribeStatus(0); + fans.setRemark(userWxInfo.getRemark()); + if (!czsjMemberWxFans.isEmpty()){ + czsjMemberWxFansMapper.updateCzsjMemberWxFans(fans); + }else { + fans.setCreateTime(new Date()); + czsjMemberWxFansMapper.insertCzsjMemberWxFans(fans); + } + } catch (Exception e) { + logger.error("更新用户信息失败,openid:{}",openid); + } + } /** * 查询会员微信粉丝 diff --git a/czsj-system/src/main/java/com/czsj/wechat/config/EventMessageListenerContainerConfig.java b/czsj-system/src/main/java/com/czsj/wechat/config/EventMessageListenerContainerConfig.java new file mode 100644 index 0000000..83767fd --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/config/EventMessageListenerContainerConfig.java @@ -0,0 +1,52 @@ +package com.czsj.wechat.config; + +import com.czsj.wechat.listener.WxAccountChangedMessageListener; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.task.TaskExecutor; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.listener.ChannelTopic; +import org.springframework.data.redis.listener.RedisMessageListenerContainer; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +import java.util.concurrent.ThreadPoolExecutor; + +/** + * @Auther: cheng.tang + * @Date: 2023/11/11 + * @Description: wx-api + */ +@Configuration +public class EventMessageListenerContainerConfig { + + public static final String WX_ACCOUNT_UPDATE = "event_wx_accounts_changed"; + + @Autowired + private WxAccountChangedMessageListener wxAccountChangedMessageListener; + + @Bean + public TaskExecutor taskExecutor() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setCorePoolSize(2); + executor.setMaxPoolSize(50); + executor.setQueueCapacity(100); + executor.setKeepAliveSeconds(600); + executor.setThreadNamePrefix("rEvent-"); + executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); + return executor; + } + + @Bean + public RedisMessageListenerContainer redisMessageListenerContainer(RedisConnectionFactory redisConnectionFactory, + @Qualifier("taskExecutor")ThreadPoolTaskExecutor threadPoolTaskExecutor) { + RedisMessageListenerContainer container = new RedisMessageListenerContainer(); + container.setConnectionFactory(redisConnectionFactory); + container.setTaskExecutor(threadPoolTaskExecutor); + container.addMessageListener(wxAccountChangedMessageListener, new ChannelTopic(WX_ACCOUNT_UPDATE)); + return container; + } + + +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/config/TaskExcutor.java b/czsj-system/src/main/java/com/czsj/wechat/config/TaskExcutor.java new file mode 100644 index 0000000..420c96c --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/config/TaskExcutor.java @@ -0,0 +1,60 @@ +package com.czsj.wechat.config; + +import java.util.concurrent.*; + +/** + * 系统线程池,系统各种任务使用同一个线程池,以防止创建过多线程池 + */ +public class TaskExcutor { + private TaskExcutor(){} + + /** + * 使用静态内部类实现单例懒加载 + */ + private static class ExcutorHolder{ + /** + * 线程池 + * corePoolSize=5 核心线程数 + * maximumPoolSize=30 最大线程数 + * keepAliveTime=10,unit=TimeUnit.SECOND 线程最大空闲时间为10秒 + * workQueue=new SynchronousQueue() 链表队列 + * handler=new ThreadPoolExecutor.CallerRunsPolicy() + */ + private static final ExecutorService EXCUTOR = new ThreadPoolExecutor( + 5,30,60L, TimeUnit.SECONDS, + new SynchronousQueue(), + new ThreadPoolExecutor.CallerRunsPolicy()); + } + /** + * 使用静态内部类实现单例懒加载 + */ + private static class SchedulerHolder{ + private static final ScheduledExecutorService SCHEDULER = + Executors.newScheduledThreadPool(5); + } + + /** + * 将任务提交到系统线程池中执行 + * 1.如果线程数未达核心线程,创建核心线程 + * 2.已达核心线程数,添加到任务队列 + * 3.核心线程已满、队列已满,创建新空闲线程 + * 4.核心线程已满、队列已满、无法创建新空闲线程,执行拒绝策略 + * 本工具类拒绝策略使用内置ThreadPoolExecutor.CallerRunsPolicy,即让添加任务的主线程来执行任务,这样主线程被占用无法继续添加任务,相当于线程池全满后添加任务的线程会被阻塞 + * @param task + * @return + */ + public static Future submit(Runnable task){ + return ExcutorHolder.EXCUTOR.submit(task); + } + + /** + * 将定时任务添加到系统线程池 + * @param task + * @param delay + * @param unit + * @return + */ + public static ScheduledFuture schedule(Runnable task,long delay, TimeUnit unit){ + return SchedulerHolder.SCHEDULER.schedule(task,delay,unit); + } +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/config/WxMpMessageRouterConfiguration.java b/czsj-system/src/main/java/com/czsj/wechat/config/WxMpMessageRouterConfiguration.java new file mode 100644 index 0000000..1fc8b67 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/config/WxMpMessageRouterConfiguration.java @@ -0,0 +1,52 @@ +package com.czsj.wechat.config; + +import com.czsj.wechat.handler.*; +import lombok.RequiredArgsConstructor; +import me.chanjar.weixin.mp.api.WxMpMessageRouter; +import me.chanjar.weixin.mp.api.WxMpService; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import static me.chanjar.weixin.common.api.WxConsts.EventType; +import static me.chanjar.weixin.common.api.WxConsts.EventType.*; +import static me.chanjar.weixin.common.api.WxConsts.XmlMsgType.EVENT; +import static me.chanjar.weixin.mp.constant.WxMpEventConstants.CustomerService.KF_CREATE_SESSION; + +@RequiredArgsConstructor +@Configuration +public class WxMpMessageRouterConfiguration { + private final LogHandler logHandler; + private final NullHandler nullHandler; + private final KfSessionHandler kfSessionHandler; + private final MenuHandler menuHandler; + private final MsgHandler msgHandler; + private final ScanHandler scanHandler; + private final UnsubscribeHandler unsubscribeHandler; + private final SubscribeHandler subscribeHandler; + + @Bean + public WxMpMessageRouter messageRouter(WxMpService wxMpService) { + final WxMpMessageRouter newRouter = new WxMpMessageRouter(wxMpService); + + // 记录所有事件的日志 + newRouter.rule().async(false).handler(this.logHandler).next(); + + // 接收客服会话管理事件 + newRouter.rule().async(false).msgType(EVENT).event(KF_CREATE_SESSION).handler(this.kfSessionHandler).end(); + // 自定义菜单事件 + newRouter.rule().async(false).msgType(EVENT).event(EventType.CLICK).handler(this.menuHandler).end(); + // 关注事件 + newRouter.rule().async(false).msgType(EVENT).event(SUBSCRIBE).handler(this.subscribeHandler).end(); + // 取消关注事件 + newRouter.rule().async(false).msgType(EVENT).event(UNSUBSCRIBE).handler(this.unsubscribeHandler).end(); + //扫描带参二维码事件 + newRouter.rule().async(false).msgType(EVENT).event(SCAN).handler(this.scanHandler).end(); + //其他事件 + newRouter.rule().async(false).msgType(EVENT).handler(this.nullHandler).end(); + + // 默认 + newRouter.rule().async(false).handler(this.msgHandler).end(); + + return newRouter; + } +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/config/WxMpServiceConfiguration.java b/czsj-system/src/main/java/com/czsj/wechat/config/WxMpServiceConfiguration.java new file mode 100644 index 0000000..592651e --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/config/WxMpServiceConfiguration.java @@ -0,0 +1,29 @@ +package com.czsj.wechat.config; + +import lombok.RequiredArgsConstructor; +import me.chanjar.weixin.common.redis.RedisTemplateWxRedisOps; +import me.chanjar.weixin.common.redis.WxRedisOps; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.core.StringRedisTemplate; + +@RequiredArgsConstructor +@Configuration +public class WxMpServiceConfiguration { + + @Bean + public WxMpService wxMpService() { + WxMpService wxMpService = new WxMpServiceImpl(); + wxMpService.setMaxRetryTimes(3); + return wxMpService; + } + + @Bean + public WxRedisOps wxRedisOps(StringRedisTemplate stringRedisTemplate) { + return new RedisTemplateWxRedisOps(stringRedisTemplate); + } + + +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/domain/CzsjWxAccount.java b/czsj-system/src/main/java/com/czsj/wechat/domain/CzsjWxAccount.java new file mode 100644 index 0000000..1939808 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/domain/CzsjWxAccount.java @@ -0,0 +1,164 @@ +package com.czsj.wechat.domain; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import com.czsj.common.annotation.Excel; +import com.czsj.common.core.domain.BaseEntity; + +/** + * 微信公众号对象 czsj_wx_account + * + * @author czsj + * @date 2024-12-07 + */ +public class CzsjWxAccount extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 微信公众号ID */ + private Long uid; + + /** 公众号appID */ + @Excel(name = "公众号appID") + private String appId; + + /** 公众号名称 */ + @Excel(name = "公众号名称") + private String name; + + /** 认证状态 */ + @Excel(name = "认证状态") + private Integer verified; + + /** 公众号secret */ + @Excel(name = "公众号secret") + private String secret; + + /** 公众号aesKey */ + @Excel(name = "公众号aesKey") + private String aesKey; + + /** 公众号token */ + @Excel(name = "公众号token") + private String token; + + /** 有效标识,0有效,1无效 */ + private Integer delFlag; + + /** 创建人ID */ + @Excel(name = "创建人ID") + private Long createUserId; + + /** 修改人ID */ + @Excel(name = "修改人ID") + private Long updateUserId; + + public void setUid(Long uid) + { + this.uid = uid; + } + + public Long getUid() + { + return uid; + } + public void setAppId(String appId) + { + this.appId = appId; + } + + public String getAppId() + { + return appId; + } + public void setName(String name) + { + this.name = name; + } + + public String getName() + { + return name; + } + public void setVerified(Integer verified) + { + this.verified = verified; + } + + public Integer getVerified() + { + return verified; + } + public void setSecret(String secret) + { + this.secret = secret; + } + + public String getSecret() + { + return secret; + } + public void setAesKey(String aesKey) + { + this.aesKey = aesKey; + } + + public String getAesKey() + { + return aesKey; + } + public void setToken(String token) + { + this.token = token; + } + + public String getToken() + { + return token; + } + public void setDelFlag(Integer delFlag) + { + this.delFlag = delFlag; + } + + public Integer getDelFlag() + { + return delFlag; + } + public void setCreateUserId(Long createUserId) + { + this.createUserId = createUserId; + } + + public Long getCreateUserId() + { + return createUserId; + } + public void setUpdateUserId(Long updateUserId) + { + this.updateUserId = updateUserId; + } + + public Long getUpdateUserId() + { + return updateUserId; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("uid", getUid()) + .append("appId", getAppId()) + .append("name", getName()) + .append("verified", getVerified()) + .append("secret", getSecret()) + .append("aesKey", getAesKey()) + .append("token", getToken()) + .append("createTime", getCreateTime()) + .append("updateTime", getUpdateTime()) + .append("delFlag", getDelFlag()) + .append("createUserId", getCreateUserId()) + .append("updateUserId", getUpdateUserId()) + .toString(); + } +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/domain/CzsjWxMessage.java b/czsj-system/src/main/java/com/czsj/wechat/domain/CzsjWxMessage.java new file mode 100644 index 0000000..3081d81 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/domain/CzsjWxMessage.java @@ -0,0 +1,150 @@ +package com.czsj.wechat.domain; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import com.czsj.common.annotation.Excel; +import com.czsj.common.core.domain.BaseEntity; + +/** + * 微信消息对象 czsj_wx_message + * + * @author czsj + * @date 2024-12-07 + */ +public class CzsjWxMessage extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 微信消息ID */ + private Long uid; + + /** 公众号appID */ + @Excel(name = "公众号appID") + private String appId; + + /** 微信openID */ + @Excel(name = "微信openID") + private String openId; + + /** 消息方向 */ + @Excel(name = "消息方向") + private Long inOut; + + /** 消息类型 */ + @Excel(name = "消息类型") + private String msgType; + + /** 消息详情 */ + @Excel(name = "消息详情") + private String detail; + + /** 有效标识,0有效,1无效 */ + private Integer delFlag; + + /** 创建人ID */ + @Excel(name = "创建人ID") + private Long createUserId; + + /** 修改人ID */ + @Excel(name = "修改人ID") + private Long updateUserId; + + public void setUid(Long uid) + { + this.uid = uid; + } + + public Long getUid() + { + return uid; + } + public void setAppId(String appId) + { + this.appId = appId; + } + + public String getAppId() + { + return appId; + } + public void setOpenId(String openId) + { + this.openId = openId; + } + + public String getOpenId() + { + return openId; + } + public void setInOut(Long inOut) + { + this.inOut = inOut; + } + + public Long getInOut() + { + return inOut; + } + public void setMsgType(String msgType) + { + this.msgType = msgType; + } + + public String getMsgType() + { + return msgType; + } + public void setDetail(String detail) + { + this.detail = detail; + } + + public String getDetail() + { + return detail; + } + public void setDelFlag(Integer delFlag) + { + this.delFlag = delFlag; + } + + public Integer getDelFlag() + { + return delFlag; + } + public void setCreateUserId(Long createUserId) + { + this.createUserId = createUserId; + } + + public Long getCreateUserId() + { + return createUserId; + } + public void setUpdateUserId(Long updateUserId) + { + this.updateUserId = updateUserId; + } + + public Long getUpdateUserId() + { + return updateUserId; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("uid", getUid()) + .append("appId", getAppId()) + .append("openId", getOpenId()) + .append("inOut", getInOut()) + .append("msgType", getMsgType()) + .append("detail", getDetail()) + .append("createTime", getCreateTime()) + .append("updateTime", getUpdateTime()) + .append("delFlag", getDelFlag()) + .append("createUserId", getCreateUserId()) + .append("updateUserId", getUpdateUserId()) + .toString(); + } +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/domain/CzsjWxQrCode.java b/czsj-system/src/main/java/com/czsj/wechat/domain/CzsjWxQrCode.java new file mode 100644 index 0000000..6bb85ef --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/domain/CzsjWxQrCode.java @@ -0,0 +1,167 @@ +package com.czsj.wechat.domain; + +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import com.czsj.common.annotation.Excel; +import com.czsj.common.core.domain.BaseEntity; + +/** + * 公众号二维码对象 czsj_wx_qr_code + * + * @author czsj + * @date 2024-12-07 + */ +public class CzsjWxQrCode extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 公众号二维码ID */ + private Long uid; + + /** 公众号appID */ + @Excel(name = "公众号appID") + private String appId; + + /** 二维码类型 */ + @Excel(name = "二维码类型") + private Integer isTemp; + + /** 场景值ID */ + @Excel(name = "场景值ID") + private String sceneStr; + + /** 二维码ticket */ + @Excel(name = "二维码ticket") + private String ticket; + + /** 二维码图片解析地址 */ + @Excel(name = "二维码图片解析地址") + private String imageUrl; + + /** 该二维码失效时间 */ + @JsonFormat(pattern = "yyyy-MM-dd") + @Excel(name = "该二维码失效时间", width = 30, dateFormat = "yyyy-MM-dd") + private Date expireTime; + + /** 有效标识,0有效,1无效 */ + private Integer delFlag; + + /** 创建人ID */ + @Excel(name = "创建人ID") + private Long createUserId; + + /** 修改人ID */ + @Excel(name = "修改人ID") + private Long updateUserId; + + public void setUid(Long uid) + { + this.uid = uid; + } + + public Long getUid() + { + return uid; + } + public void setAppId(String appId) + { + this.appId = appId; + } + + public String getAppId() + { + return appId; + } + public void setIsTemp(Integer isTemp) + { + this.isTemp = isTemp; + } + + public Integer getIsTemp() + { + return isTemp; + } + public void setSceneStr(String sceneStr) + { + this.sceneStr = sceneStr; + } + + public String getSceneStr() + { + return sceneStr; + } + public void setTicket(String ticket) + { + this.ticket = ticket; + } + + public String getTicket() + { + return ticket; + } + public void setImageUrl(String imageUrl) + { + this.imageUrl = imageUrl; + } + + public String getImageUrl() + { + return imageUrl; + } + public void setExpireTime(Date expireTime) + { + this.expireTime = expireTime; + } + + public Date getExpireTime() + { + return expireTime; + } + public void setDelFlag(Integer delFlag) + { + this.delFlag = delFlag; + } + + public Integer getDelFlag() + { + return delFlag; + } + public void setCreateUserId(Long createUserId) + { + this.createUserId = createUserId; + } + + public Long getCreateUserId() + { + return createUserId; + } + public void setUpdateUserId(Long updateUserId) + { + this.updateUserId = updateUserId; + } + + public Long getUpdateUserId() + { + return updateUserId; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("uid", getUid()) + .append("appId", getAppId()) + .append("isTemp", getIsTemp()) + .append("sceneStr", getSceneStr()) + .append("ticket", getTicket()) + .append("imageUrl", getImageUrl()) + .append("expireTime", getExpireTime()) + .append("createTime", getCreateTime()) + .append("updateTime", getUpdateTime()) + .append("delFlag", getDelFlag()) + .append("createUserId", getCreateUserId()) + .append("updateUserId", getUpdateUserId()) + .toString(); + } +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/domain/CzsjWxReplyRule.java b/czsj-system/src/main/java/com/czsj/wechat/domain/CzsjWxReplyRule.java new file mode 100644 index 0000000..b8bf353 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/domain/CzsjWxReplyRule.java @@ -0,0 +1,196 @@ +package com.czsj.wechat.domain; + +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import com.czsj.common.annotation.Excel; +import com.czsj.common.core.domain.BaseEntity; + +/** + * 微信消息回复规则对象 czsj_wx_reply_rule + * + * @author czsj + * @date 2024-12-07 + */ +public class CzsjWxReplyRule extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 回复规则ID */ + private Long uid; + + /** 公众号appID */ + @Excel(name = "公众号appID") + private String appId; + + /** 规则名称 */ + @Excel(name = "规则名称") + private String ruleName; + + /** 匹配关键词 */ + @Excel(name = "匹配关键词") + private String matchValue; + + /** 是否精确匹配 */ + @Excel(name = "是否精确匹配") + private Integer exactMatch; + + /** 回复类型 */ + @Excel(name = "回复类型") + private String replyType; + + /** 回复内容 */ + @Excel(name = "回复内容") + private String replyContent; + + /** 开始时间 */ + @JsonFormat(pattern = "yyyy-MM-dd") + @Excel(name = "开始时间", width = 30, dateFormat = "yyyy-MM-dd") + private Date startTime; + + /** 结束时间 */ + @JsonFormat(pattern = "yyyy-MM-dd") + @Excel(name = "结束时间", width = 30, dateFormat = "yyyy-MM-dd") + private Date endTime; + + /** 有效标识,0有效,1无效 */ + private Integer delFlag; + + /** 创建人ID */ + @Excel(name = "创建人ID") + private Long createUserId; + + /** 修改人ID */ + @Excel(name = "修改人ID") + private Long updateUserId; + + public void setUid(Long uid) + { + this.uid = uid; + } + + public Long getUid() + { + return uid; + } + public void setAppId(String appId) + { + this.appId = appId; + } + + public String getAppId() + { + return appId; + } + public void setRuleName(String ruleName) + { + this.ruleName = ruleName; + } + + public String getRuleName() + { + return ruleName; + } + public void setMatchValue(String matchValue) + { + this.matchValue = matchValue; + } + + public String getMatchValue() + { + return matchValue; + } + public void setExactMatch(Integer exactMatch) + { + this.exactMatch = exactMatch; + } + + public Integer getExactMatch() + { + return exactMatch; + } + public void setReplyType(String replyType) + { + this.replyType = replyType; + } + + public String getReplyType() + { + return replyType; + } + public void setReplyContent(String replyContent) + { + this.replyContent = replyContent; + } + + public String getReplyContent() + { + return replyContent; + } + public void setStartTime(Date startTime) + { + this.startTime = startTime; + } + + public Date getStartTime() + { + return startTime; + } + public void setEndTime(Date endTime) + { + this.endTime = endTime; + } + + public Date getEndTime() + { + return endTime; + } + public void setDelFlag(Integer delFlag) + { + this.delFlag = delFlag; + } + + public Integer getDelFlag() + { + return delFlag; + } + public void setCreateUserId(Long createUserId) + { + this.createUserId = createUserId; + } + + public Long getCreateUserId() + { + return createUserId; + } + public void setUpdateUserId(Long updateUserId) + { + this.updateUserId = updateUserId; + } + + public Long getUpdateUserId() + { + return updateUserId; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("uid", getUid()) + .append("appId", getAppId()) + .append("ruleName", getRuleName()) + .append("matchValue", getMatchValue()) + .append("exactMatch", getExactMatch()) + .append("replyType", getReplyType()) + .append("replyContent", getReplyContent()) + .append("startTime", getStartTime()) + .append("endTime", getEndTime()) + .append("createTime", getCreateTime()) + .append("updateTime", getUpdateTime()) + .append("delFlag", getDelFlag()) + .append("createUserId", getCreateUserId()) + .append("updateUserId", getUpdateUserId()) + .toString(); + } +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/domain/CzsjWxTemplate.java b/czsj-system/src/main/java/com/czsj/wechat/domain/CzsjWxTemplate.java new file mode 100644 index 0000000..ecac046 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/domain/CzsjWxTemplate.java @@ -0,0 +1,178 @@ +package com.czsj.wechat.domain; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import com.czsj.common.annotation.Excel; +import com.czsj.common.core.domain.BaseEntity; + +/** + * 微信消息模板对象 czsj_wx_template + * + * @author czsj + * @date 2024-12-07 + */ +public class CzsjWxTemplate extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 消息模板ID */ + private Long uid; + + /** 公众号ID */ + @Excel(name = "公众号ID") + private String appId; + + /** 模板ID */ + @Excel(name = "模板ID") + private String templateId; + + /** 模板标题 */ + @Excel(name = "模板标题") + private String title; + + /** 主行业分类 */ + @Excel(name = "主行业分类") + private String primaryIndustry; + + /** 副行业分类 */ + @Excel(name = "副行业分类") + private String deputyIndustry; + + /** 内容 */ + @Excel(name = "内容") + private String content; + + /** 示例 */ + @Excel(name = "示例") + private String example; + + /** 有效标识,0有效,1无效 */ + private Integer delFlag; + + /** 创建人ID */ + @Excel(name = "创建人ID") + private Long createUserId; + + /** 修改人ID */ + @Excel(name = "修改人ID") + private Long updateUserId; + + public void setUid(Long uid) + { + this.uid = uid; + } + + public Long getUid() + { + return uid; + } + public void setAppId(String appId) + { + this.appId = appId; + } + + public String getAppId() + { + return appId; + } + public void setTemplateId(String templateId) + { + this.templateId = templateId; + } + + public String getTemplateId() + { + return templateId; + } + public void setTitle(String title) + { + this.title = title; + } + + public String getTitle() + { + return title; + } + public void setPrimaryIndustry(String primaryIndustry) + { + this.primaryIndustry = primaryIndustry; + } + + public String getPrimaryIndustry() + { + return primaryIndustry; + } + public void setDeputyIndustry(String deputyIndustry) + { + this.deputyIndustry = deputyIndustry; + } + + public String getDeputyIndustry() + { + return deputyIndustry; + } + public void setContent(String content) + { + this.content = content; + } + + public String getContent() + { + return content; + } + public void setExample(String example) + { + this.example = example; + } + + public String getExample() + { + return example; + } + public void setDelFlag(Integer delFlag) + { + this.delFlag = delFlag; + } + + public Integer getDelFlag() + { + return delFlag; + } + public void setCreateUserId(Long createUserId) + { + this.createUserId = createUserId; + } + + public Long getCreateUserId() + { + return createUserId; + } + public void setUpdateUserId(Long updateUserId) + { + this.updateUserId = updateUserId; + } + + public Long getUpdateUserId() + { + return updateUserId; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("uid", getUid()) + .append("appId", getAppId()) + .append("templateId", getTemplateId()) + .append("title", getTitle()) + .append("primaryIndustry", getPrimaryIndustry()) + .append("deputyIndustry", getDeputyIndustry()) + .append("content", getContent()) + .append("example", getExample()) + .append("createTime", getCreateTime()) + .append("updateTime", getUpdateTime()) + .append("delFlag", getDelFlag()) + .append("createUserId", getCreateUserId()) + .append("updateUserId", getUpdateUserId()) + .toString(); + } +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/domain/CzsjWxTemplateLog.java b/czsj-system/src/main/java/com/czsj/wechat/domain/CzsjWxTemplateLog.java new file mode 100644 index 0000000..2cc171b --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/domain/CzsjWxTemplateLog.java @@ -0,0 +1,178 @@ +package com.czsj.wechat.domain; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import com.czsj.common.annotation.Excel; +import com.czsj.common.core.domain.BaseEntity; + +/** + * 微信消息模板日志对象 czsj_wx_template_log + * + * @author czsj + * @date 2024-12-07 + */ +public class CzsjWxTemplateLog extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 消息模板日志ID */ + private Long uid; + + /** 公众号ID */ + @Excel(name = "公众号ID") + private String appId; + + /** 接收者OpenID */ + @Excel(name = "接收者OpenID") + private String toUser; + + /** 模板ID */ + @Excel(name = "模板ID") + private Long templateUid; + + /** 消息体 */ + @Excel(name = "消息体") + private String data; + + /** URL链接 */ + @Excel(name = "URL链接") + private String url; + + /** 跳转的小程序 */ + @Excel(name = "跳转的小程序") + private String miniProgram; + + /** 发送结果 */ + @Excel(name = "发送结果") + private String sendResult; + + /** 有效标识,0有效,1无效 */ + private Integer delFlag; + + /** 创建人ID */ + @Excel(name = "创建人ID") + private Long createUserId; + + /** 修改人ID */ + @Excel(name = "修改人ID") + private Long updateUserId; + + public void setUid(Long uid) + { + this.uid = uid; + } + + public Long getUid() + { + return uid; + } + public void setAppId(String appId) + { + this.appId = appId; + } + + public String getAppId() + { + return appId; + } + public void setToUser(String toUser) + { + this.toUser = toUser; + } + + public String getToUser() + { + return toUser; + } + public void setTemplateUid(Long templateUid) + { + this.templateUid = templateUid; + } + + public Long getTemplateUid() + { + return templateUid; + } + public void setData(String data) + { + this.data = data; + } + + public String getData() + { + return data; + } + public void setUrl(String url) + { + this.url = url; + } + + public String getUrl() + { + return url; + } + public void setMiniProgram(String miniProgram) + { + this.miniProgram = miniProgram; + } + + public String getMiniProgram() + { + return miniProgram; + } + public void setSendResult(String sendResult) + { + this.sendResult = sendResult; + } + + public String getSendResult() + { + return sendResult; + } + public void setDelFlag(Integer delFlag) + { + this.delFlag = delFlag; + } + + public Integer getDelFlag() + { + return delFlag; + } + public void setCreateUserId(Long createUserId) + { + this.createUserId = createUserId; + } + + public Long getCreateUserId() + { + return createUserId; + } + public void setUpdateUserId(Long updateUserId) + { + this.updateUserId = updateUserId; + } + + public Long getUpdateUserId() + { + return updateUserId; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("uid", getUid()) + .append("appId", getAppId()) + .append("toUser", getToUser()) + .append("templateUid", getTemplateUid()) + .append("data", getData()) + .append("url", getUrl()) + .append("miniProgram", getMiniProgram()) + .append("sendResult", getSendResult()) + .append("createTime", getCreateTime()) + .append("updateTime", getUpdateTime()) + .append("delFlag", getDelFlag()) + .append("createUserId", getCreateUserId()) + .append("updateUserId", getUpdateUserId()) + .toString(); + } +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/dto/PageSizeConstant.java b/czsj-system/src/main/java/com/czsj/wechat/dto/PageSizeConstant.java new file mode 100644 index 0000000..a983ae4 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/dto/PageSizeConstant.java @@ -0,0 +1,9 @@ +package com.czsj.wechat.dto; + +public class PageSizeConstant { + /** + * 默认分页大小 + */ + public static final int PAGE_SIZE_SMALL = 20; + public static final int PAGE_SIZE_MEDIUM = 50; +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/dto/RegexConstant.java b/czsj-system/src/main/java/com/czsj/wechat/dto/RegexConstant.java new file mode 100644 index 0000000..fed6e4b --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/dto/RegexConstant.java @@ -0,0 +1,44 @@ +package com.czsj.wechat.dto; + +/** + * 常用正则表达式 + */ +public class RegexConstant { + /** + * 手机号码 + */ + public static final String PHONE_NUM = "1\\d{10}"; + /** + * 六位数字 + */ + public static final String SIX_NUMBER = "\\d{6}"; + /** + * 六位字符 + */ + public static final String SIX_CHAR = ".{6}"; + /** + * 图片文件名 + */ + public static final String IMAGE_FILE_NAME = ".*\\.(jpg|JPG|jpeg|JPEG|gif|GIF|png|PNG)$"; + /** + * SQL注入常用字符 + */ + public static final String SQL_INJECTION_WORDS = ".*([';]+|(--)+).*"; + /** + * 逗号分割的数字列表 + */ + public static final String NUMBER_ARRAY = "^\\d+(,\\d+)*$"; + /** + * 时间戳,毫秒标识的时间格式 + */ + public static final String TIME_MILLIS = "^[0-9]{10,}$"; + /** + * 日期字符串格式,如 2018-01-01 + */ + public static final String DATE_STRING = "^\\d{2}-\\d{2}-\\d{2}$"; + /** + * 时间字符串格式,如 12:00:00 + */ + public static final String TIME_STRING = "^\\d{2}:\\d{2}:\\d{2}$"; + +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/entity/Article.java b/czsj-system/src/main/java/com/czsj/wechat/entity/Article.java new file mode 100644 index 0000000..caa0dc3 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/entity/Article.java @@ -0,0 +1,39 @@ +package com.czsj.wechat.entity; + +import com.baomidou.mybatisplus.annotation.*; +import com.czsj.wechat.utils.Json; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import java.io.Serializable; +import java.util.Date; + +/** + * cms文章 + */ +@Data +@TableName("cms_article") +public class Article implements Serializable { + private static final long serialVersionUID = 1L; + @TableId(type = IdType.AUTO) + private Long id; + private int type; + @TableField(insertStrategy = FieldStrategy.IGNORED)//title重复则不插入 + @NotEmpty(message = "标题不得为空") + private String title; + private String tags; + private String summary; + private String content; + private String category; + private String subCategory; + private Date createTime; + private Date updateTime; + private int openCount; + private String targetLink; + private String image; + + @Override + public String toString() { + return Json.toJsonString(this); + } +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/entity/MsgReplyRule.java b/czsj-system/src/main/java/com/czsj/wechat/entity/MsgReplyRule.java new file mode 100644 index 0000000..52e5a6c --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/entity/MsgReplyRule.java @@ -0,0 +1,48 @@ +package com.czsj.wechat.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.czsj.wechat.utils.Json; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import java.io.Serializable; +import java.sql.Time; +import java.util.Date; + +/** + * 自动回复规则 + * @author Nifury + * @date 2017-11-1 + */ +@Data +@TableName("wx_msg_reply_rule") +public class MsgReplyRule implements Serializable { + private static final long serialVersionUID = 1L; + @TableId(type = IdType.AUTO) + private Long ruleId; + private String appid; + @NotEmpty(message = "规则名称不得为空") + private String ruleName; + @NotEmpty(message = "匹配关键词不得为空") + private String matchValue; + private boolean exactMatch; + private String replyType; + @NotEmpty(message = "回复内容不得为空") + private String replyContent; + @TableField(value = "`status`") + private boolean status; + @TableField(value = "`desc`") + private String desc; + private Time effectTimeStart; + private Time effectTimeEnd; + private int priority; + private Date updateTime; + + @Override + public String toString() { + return Json.toJsonString(this); + } +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/entity/MsgTemplate.java b/czsj-system/src/main/java/com/czsj/wechat/entity/MsgTemplate.java new file mode 100644 index 0000000..80fcb56 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/entity/MsgTemplate.java @@ -0,0 +1,56 @@ +package com.czsj.wechat.entity; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.czsj.wechat.utils.Json; +import lombok.Data; +import me.chanjar.weixin.mp.bean.template.WxMpTemplate; + +import java.io.Serializable; +import java.util.Date; + +/** + * 模板消息模板 + * @author Nifury + * @date 2017-9-27 + */ +@Data +@TableName("wx_msg_template") +public class MsgTemplate implements Serializable { + private static final long serialVersionUID = 1L; + @TableId(type = IdType.AUTO) + private Long id; + private String appid; + private String templateId; + @TableField(value = "`name`") + private String name; + private String title; + private String content; + private JSONArray data; + private String url; + private JSONObject miniprogram; + @TableField(value = "`status`") + private boolean status; + private Date updateTime; + public MsgTemplate() { + + } + public MsgTemplate(WxMpTemplate mpTemplate,String appid) { + this.appid = appid; + this.templateId=mpTemplate.getTemplateId(); + this.title=mpTemplate.getTitle(); + this.name=mpTemplate.getTemplateId(); + this.content = mpTemplate.getContent(); + this.status=true; + } + + @Override + public String toString() { + return Json.toJsonString(this); + } + +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/entity/TemplateMsgLog.java b/czsj-system/src/main/java/com/czsj/wechat/entity/TemplateMsgLog.java new file mode 100644 index 0000000..53e26b4 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/entity/TemplateMsgLog.java @@ -0,0 +1,56 @@ +package com.czsj.wechat.entity; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.czsj.wechat.utils.Json; +import lombok.Data; +import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage; + +import java.io.Serializable; +import java.util.Date; + +/** + * 模板消息日志 + * @author Nifury + * @date 2017-9-27 + */ +@Data +@TableName("wx_template_msg_log") +public class TemplateMsgLog implements Serializable { + + private static final long serialVersionUID = 1L; + @TableId(type = IdType.AUTO) + private Long logId; + private String appid; + private String touser; + private String templateId; + private JSONArray data; + private String url; + private JSONObject miniprogram; + private Date sendTime; + private String sendResult; + + public TemplateMsgLog() { + } + + public TemplateMsgLog(WxMpTemplateMessage msg,String appid, String sendResult) { + this.appid = appid; + this.touser = msg.getToUser(); + this.templateId = msg.getTemplateId(); + this.url = msg.getUrl(); + this.miniprogram = JSONObject.parseObject(JSON.toJSONString(msg.getMiniProgram())); + this.data = JSONArray.parseArray(JSON.toJSONString(msg.getData())); + this.sendTime = new Date(); + this.sendResult = sendResult; + } + + @Override + public String toString() { + return Json.toJsonString(this); + } + +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/entity/WxAccount.java b/czsj-system/src/main/java/com/czsj/wechat/entity/WxAccount.java new file mode 100644 index 0000000..3146e3f --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/entity/WxAccount.java @@ -0,0 +1,65 @@ +package com.czsj.wechat.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl; + +import javax.validation.constraints.NotEmpty; +import java.io.Serializable; + +/** + * 公众号账号 + * + * @author niefy + * @date 2020-06-17 13:56:51 + */ +@Data +@TableName("wx_account") +public class WxAccount implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * id + */ + @TableId(type = IdType.INPUT) + @NotEmpty(message = "appid不得为空") + private String appid; + /** + * 公众号名称 + */ + @NotEmpty(message = "名称不得为空") + private String name; + /** + * 账号类型 + */ + private int type; + /** + * 认证状态 + */ + private boolean verified; + /** + * appsecret + */ + @NotEmpty(message = "appSecret不得为空") + private String secret; + /** + * token + */ + private String token; + /** + * aesKey + */ + private String aesKey; + + public WxMpDefaultConfigImpl toWxMpConfigStorage(){ + WxMpDefaultConfigImpl configStorage = new WxMpDefaultConfigImpl(); + configStorage.setAppId(appid); + configStorage.setSecret(secret); + configStorage.setToken(token); + configStorage.setAesKey(aesKey); + return configStorage; + } + +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/entity/WxMsg.java b/czsj-system/src/main/java/com/czsj/wechat/entity/WxMsg.java new file mode 100644 index 0000000..0a1ceef --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/entity/WxMsg.java @@ -0,0 +1,103 @@ +package com.czsj.wechat.entity; + +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.util.WxMpConfigStorageHolder; + +import java.io.Serializable; +import java.util.Date; + +/** + * 微信消息 + * + * @author niefy + * @date 2020-05-14 17:28:34 + */ +@Data +@TableName("wx_msg") +public class WxMsg implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId + private Long id; + private String appid; + /** + * 微信用户ID + */ + private String openid; + /** + * 消息方向 + */ + private byte inOut; + /** + * 消息类型 + */ + private String msgType; + /** + * 消息详情 + */ + private JSONObject detail; + /** + * 创建时间 + */ + private Date createTime; + + public static class WxMsgInOut{ + static final byte IN=0; + static final byte OUT=1; + } + + public WxMsg() { + } + public WxMsg(WxMpXmlMessage wxMessage) { + this.openid=wxMessage.getFromUser(); + this.appid= WxMpConfigStorageHolder.get(); + this.inOut = WxMsgInOut.IN; + this.msgType = wxMessage.getMsgType(); + this.detail = new JSONObject(); + Long createTime = wxMessage.getCreateTime(); + this.createTime = createTime==null?new Date():new Date(createTime*1000); + if(WxConsts.XmlMsgType.TEXT.equals(this.msgType)){ + this.detail.put("content",wxMessage.getContent()); + }else if(WxConsts.XmlMsgType.IMAGE.equals(this.msgType)){ + this.detail.put("picUrl",wxMessage.getPicUrl()); + this.detail.put("mediaId",wxMessage.getMediaId()); + }else if(WxConsts.XmlMsgType.VOICE.equals(this.msgType)){ + this.detail.put("format",wxMessage.getFormat()); + this.detail.put("mediaId",wxMessage.getMediaId()); + }else if(WxConsts.XmlMsgType.VIDEO.equals(this.msgType) || + WxConsts.XmlMsgType.SHORTVIDEO.equals(this.msgType)){ + this.detail.put("thumbMediaId",wxMessage.getThumbMediaId()); + this.detail.put("mediaId",wxMessage.getMediaId()); + }else if(WxConsts.XmlMsgType.LOCATION.equals(this.msgType)){ + this.detail.put("locationX",wxMessage.getLocationX()); + this.detail.put("locationY",wxMessage.getLocationY()); + this.detail.put("scale",wxMessage.getScale()); + this.detail.put("label",wxMessage.getLabel()); + }else if(WxConsts.XmlMsgType.LINK.equals(this.msgType)){ + this.detail.put("title",wxMessage.getTitle()); + this.detail.put("description",wxMessage.getDescription()); + this.detail.put("url",wxMessage.getUrl()); + }else if(WxConsts.XmlMsgType.EVENT.equals(this.msgType)){ + this.detail.put("event",wxMessage.getEvent()); + this.detail.put("eventKey",wxMessage.getEventKey()); + } + } + public static WxMsg buildOutMsg(String msgType,String openid,JSONObject detail){ + WxMsg wxMsg = new WxMsg(); + wxMsg.appid= WxMpConfigStorageHolder.get(); + wxMsg.msgType = msgType; + wxMsg.openid = openid; + wxMsg.detail = detail; + wxMsg.createTime=new Date(); + wxMsg.inOut = WxMsgInOut.OUT; + return wxMsg; + } +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/entity/WxQrCode.java b/czsj-system/src/main/java/com/czsj/wechat/entity/WxQrCode.java new file mode 100644 index 0000000..5366577 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/entity/WxQrCode.java @@ -0,0 +1,63 @@ +package com.czsj.wechat.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.czsj.wechat.form.WxQrCodeForm; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +/** + * 公众号带参二维码 + * + * @author niefy + * @email niefy@qq.com + * @date 2020-01-02 11:11:55 + */ +@Data +@TableName("wx_qr_code") +public class WxQrCode implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * ID + */ + @TableId + private Long id; + private String appid; + /** + * 二维码类型 + */ + private Boolean isTemp; + /** + * 场景值ID + */ + private String sceneStr; + /** + * 二维码ticket + */ + private String ticket; + /** + * 二维码图片解析后的地址 + */ + private String url; + /** + * 该二维码失效时间 + */ + private Date expireTime; + /** + * 该二维码创建时间 + */ + private Date createTime; + + public WxQrCode() { + } + + public WxQrCode(WxQrCodeForm form,String appid) { + this.appid = appid; + this.isTemp = form.getIsTemp(); + this.sceneStr = form.getSceneStr(); + this.createTime = new Date(); + } +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/entity/WxUser.java b/czsj-system/src/main/java/com/czsj/wechat/entity/WxUser.java new file mode 100644 index 0000000..aa448b2 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/entity/WxUser.java @@ -0,0 +1,85 @@ +package com.czsj.wechat.entity; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.annotation.JSONField; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.czsj.wechat.utils.Json; +import lombok.Data; +import me.chanjar.weixin.common.bean.WxOAuth2UserInfo; +import me.chanjar.weixin.mp.bean.result.WxMpUser; +import org.springframework.util.StringUtils; + +import java.io.Serializable; +import java.util.Date; + +/** + * 微信粉丝 + * @author Nifury + * @date 2017-9-27 + */ +@Data +@TableName("wx_user") +public class WxUser implements Serializable { + + private static final long serialVersionUID = 1L; + @TableId(type = IdType.INPUT) + private String openid; + private String appid; + private String phone; + private String nickname; + private int sex; + private String city; + private String province; + private String headimgurl; + @JSONField(name = "subscribe_time") + private Date subscribeTime; + private boolean subscribe; + private String unionid; + private String remark; + private JSONArray tagidList; + private String subscribeScene; + private String qrSceneStr; + + public WxUser() { + } + + public WxUser(String openid) { + this.openid = openid; + } + + public WxUser(WxMpUser wxMpUser,String appid) { + this.openid = wxMpUser.getOpenId(); + this.appid = appid; + this.subscribe=wxMpUser.getSubscribe(); + if(wxMpUser.getSubscribe()){ + this.nickname = wxMpUser.getNickname(); + this.headimgurl = wxMpUser.getHeadImgUrl(); + this.subscribeTime = new Date(wxMpUser.getSubscribeTime()*1000); + this.unionid=wxMpUser.getUnionId(); + this.remark=wxMpUser.getRemark(); + this.tagidList=JSONArray.parseArray(JSONObject.toJSONString(wxMpUser.getTagIds())); + this.subscribeScene=wxMpUser.getSubscribeScene(); + String qrScene = wxMpUser.getQrScene(); + this.qrSceneStr= !StringUtils.hasText(qrScene) ? wxMpUser.getQrSceneStr() : qrScene; + } + } + + public WxUser(WxOAuth2UserInfo wxMpUser, String appid) { + this.openid = wxMpUser.getOpenid(); + this.appid = appid; + this.subscribe=wxMpUser.getNickname()!=null; + if(this.subscribe){ + this.nickname = wxMpUser.getNickname(); + this.headimgurl = wxMpUser.getHeadImgUrl(); + this.unionid=wxMpUser.getUnionId(); + } + } + + @Override + public String toString() { + return Json.toJsonString(this); + } +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/enums/ArticleTypeEnum.java b/czsj-system/src/main/java/com/czsj/wechat/enums/ArticleTypeEnum.java new file mode 100644 index 0000000..eec6ea9 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/enums/ArticleTypeEnum.java @@ -0,0 +1,35 @@ +package com.czsj.wechat.enums; + +/** + * 定义文章类型 + */ +public enum ArticleTypeEnum { + /** + * 普通文章 + */ + COMMON(1), + /** + * 帮助中心文章 + */ + QUESTION(5); + /** + * 数据库属性值 + */ + private int value; + + ArticleTypeEnum(int type) { + this.value = type; + } + + public int getValue() { + return this.value; + } + + public static ArticleTypeEnum of(String name) { + try { + return ArticleTypeEnum.valueOf(name); + } catch (Exception e) { + return null; + } + } +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/exception/RRException.java b/czsj-system/src/main/java/com/czsj/wechat/exception/RRException.java new file mode 100644 index 0000000..a9edd70 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/exception/RRException.java @@ -0,0 +1,52 @@ +package com.czsj.wechat.exception; + +/** + * 自定义异常 + * @author Mark sunlightcs@gmail.com + */ +public class RRException extends RuntimeException { + private static final long serialVersionUID = 1L; + + private String msg; + private int code = 500; + + public RRException(String msg) { + super(msg); + this.msg = msg; + } + + public RRException(String msg, Throwable e) { + super(msg, e); + this.msg = msg; + } + + public RRException(String msg, int code) { + super(msg); + this.msg = msg; + this.code = code; + } + + public RRException(String msg, int code, Throwable e) { + super(msg, e); + this.msg = msg; + this.code = code; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/exception/RRExceptionHandler.java b/czsj-system/src/main/java/com/czsj/wechat/exception/RRExceptionHandler.java new file mode 100644 index 0000000..d5edff2 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/exception/RRExceptionHandler.java @@ -0,0 +1,67 @@ +package com.czsj.wechat.exception; + +import me.chanjar.weixin.common.error.WxErrorException; +import com.czsj.wechat.utils.R; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.dao.DuplicateKeyException; +import org.springframework.web.bind.MissingRequestCookieException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +/** + * 异常处理器 + * @author Mark sunlightcs@gmail.com + */ +@RestControllerAdvice +public class RRExceptionHandler { + private Logger logger = LoggerFactory.getLogger(getClass()); + + /** + * 处理自定义异常 + */ + @ExceptionHandler(RRException.class) + public R handleRrException(RRException e) { + R r = new R(); + r.put("code", e.getCode()); + r.put("msg", e.getMessage()); + + return r; + } + +// @ExceptionHandler(NoHandlerFoundException.class) +// public R handlerNoFoundException(Exception e) { +// logger.error(e.getMessage(), e); +// return R.error(404, "路径不存在,请检查路径是否正确"); +// } + + @ExceptionHandler(DuplicateKeyException.class) + public R handleDuplicateKeyException(DuplicateKeyException e) { + logger.error(e.getMessage(), e); + return R.error("数据库中已存在该记录"); + } + +// @ExceptionHandler(AuthorizationException.class) +// public R handleAuthorizationException(AuthorizationException e) { +// logger.error(e.getMessage(), e); +// return R.error("没有权限,请联系管理员授权"); +// } + + @ExceptionHandler(MissingRequestCookieException.class) + public R handleMissingRequestCookieException(MissingRequestCookieException e) { + logger.error(e.getMessage(), e); + return R.error("请先添加公众号"); + } + + @ExceptionHandler({WxErrorException.class}) + public R handleWxErrorException(WxErrorException e) { + logger.error(e.getMessage(), e); + return R.error("微信公众平台接口错误:" + e.getError().getErrorMsg()); + } + + @ExceptionHandler(Exception.class) + public R handleException(Exception e) { + logger.error(e.getMessage(), e); + return R.error(); + } +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/form/AccountBindForm.java b/czsj-system/src/main/java/com/czsj/wechat/form/AccountBindForm.java new file mode 100644 index 0000000..9daab6a --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/form/AccountBindForm.java @@ -0,0 +1,15 @@ +package com.czsj.wechat.form; + +import com.czsj.wechat.utils.Json; +import lombok.Data; + +@Data +public class AccountBindForm { + String phoneNum; + String idCodeSuffix; + + @Override + public String toString() { + return Json.toJsonString(this); + } +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/form/MaterialFileDeleteForm.java b/czsj-system/src/main/java/com/czsj/wechat/form/MaterialFileDeleteForm.java new file mode 100644 index 0000000..9a9508b --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/form/MaterialFileDeleteForm.java @@ -0,0 +1,14 @@ +package com.czsj.wechat.form; + +import com.czsj.wechat.utils.Json; +import lombok.Data; + +@Data +public class MaterialFileDeleteForm { + String mediaId; + + @Override + public String toString() { + return Json.toJsonString(this); + } +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/form/TemplateMsgBatchForm.java b/czsj-system/src/main/java/com/czsj/wechat/form/TemplateMsgBatchForm.java new file mode 100644 index 0000000..7260264 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/form/TemplateMsgBatchForm.java @@ -0,0 +1,33 @@ +package com.czsj.wechat.form; + +import com.czsj.wechat.utils.Json; +import lombok.Data; +import me.chanjar.weixin.mp.bean.template.WxMpTemplateData; +import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.List; +import java.util.Map; + +/** + * 批量发送模板消息表单 + * 通过用户筛选条件(一般使用标签筛选),将消息发送给数据库中所有符合筛选条件的用户 + * 若所有筛选条件都为空,则表示发送给所有用户 + * + */ +@Data +public class TemplateMsgBatchForm { + @NotNull(message = "需用户筛选条件参数") + Map wxUserFilterParams; + @NotEmpty(message = "模板ID不得为空") + private String templateId; + private String url; + private WxMpTemplateMessage.MiniProgram miniprogram; + @NotEmpty(message = "消息模板数据不得为空") + private List data; + @Override + public String toString() { + return Json.toJsonString(this); + } +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/form/TemplateMsgForm.java b/czsj-system/src/main/java/com/czsj/wechat/form/TemplateMsgForm.java new file mode 100644 index 0000000..cfc621a --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/form/TemplateMsgForm.java @@ -0,0 +1,24 @@ +package com.czsj.wechat.form; + +import com.czsj.wechat.exception.RRException; +import com.czsj.wechat.utils.Json; +import lombok.Data; + +@Data +public class TemplateMsgForm { + private String openid; + private String msg; + private String template; + + @Override + public String toString() { + return Json.toJsonString(this); + } + + public boolean isValid() { + if (openid == null || openid.isEmpty() || msg == null || msg.isEmpty() || template == null || template.isEmpty()) { + throw new RRException("缺少必要参数"); + } + return true; + } +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/form/WxH5OuthrizeForm.java b/czsj-system/src/main/java/com/czsj/wechat/form/WxH5OuthrizeForm.java new file mode 100644 index 0000000..641420a --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/form/WxH5OuthrizeForm.java @@ -0,0 +1,16 @@ +package com.czsj.wechat.form; + +import com.czsj.wechat.utils.Json; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +@Data +public class WxH5OuthrizeForm { + @NotEmpty(message = "code不得为空") + private String code; + + @Override + public String toString() { + return Json.toJsonString(this); + } +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/form/WxMsgReplyForm.java b/czsj-system/src/main/java/com/czsj/wechat/form/WxMsgReplyForm.java new file mode 100644 index 0000000..8f91936 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/form/WxMsgReplyForm.java @@ -0,0 +1,15 @@ +package com.czsj.wechat.form; + +import lombok.Data; + +import javax.validation.constraints.NotEmpty; + +@Data +public class WxMsgReplyForm { + @NotEmpty(message = "用户信息不得为空") + private String openid; + @NotEmpty(message = "回复类型不得为空") + private String replyType; + @NotEmpty(message = "回复内容不得为空") + private String replyContent; +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/form/WxQrCodeForm.java b/czsj-system/src/main/java/com/czsj/wechat/form/WxQrCodeForm.java new file mode 100644 index 0000000..5c7338b --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/form/WxQrCodeForm.java @@ -0,0 +1,17 @@ +package com.czsj.wechat.form; + +import lombok.Data; + +import javax.validation.constraints.Max; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.Size; + +@Data +public class WxQrCodeForm { + @NotEmpty(message = "场景值ID不得为空") + @Size(min = 1, max = 64, message = "场景值长度限制为1到64") + private String sceneStr; + @Max(value = 2592000, message = "过期时间不得超过30天") + private Integer expireSeconds; + private Boolean isTemp = true; +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/form/WxUserBatchTaggingForm.java b/czsj-system/src/main/java/com/czsj/wechat/form/WxUserBatchTaggingForm.java new file mode 100644 index 0000000..88e8e1d --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/form/WxUserBatchTaggingForm.java @@ -0,0 +1,14 @@ +package com.czsj.wechat.form; + +import lombok.Data; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.NotNull; +@Data +public class WxUserBatchTaggingForm { + @NotNull(message = "标签ID不得为空") + private Long tagid; + @NotNull(message = "openid列表不得为空") + @Length(min = 1,max = 50,message = "每次处理数量1-50个") + private String[] openidList; +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/form/WxUserTagForm.java b/czsj-system/src/main/java/com/czsj/wechat/form/WxUserTagForm.java new file mode 100644 index 0000000..12ae339 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/form/WxUserTagForm.java @@ -0,0 +1,14 @@ +package com.czsj.wechat.form; + +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.Size; + +@Data +public class WxUserTagForm { + private Long id; + @NotEmpty(message = "标签名称不得为空") + @Size(min = 1,max = 30,message = "标签名称长度必须为1-30字符") + private String name; +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/form/WxUserTaggingForm.java b/czsj-system/src/main/java/com/czsj/wechat/form/WxUserTaggingForm.java new file mode 100644 index 0000000..ea8afbf --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/form/WxUserTaggingForm.java @@ -0,0 +1,11 @@ +package com.czsj.wechat.form; + +import lombok.Data; + +import javax.validation.constraints.NotNull; + +@Data +public class WxUserTaggingForm { + @NotNull(message = "标签ID不得为空") + private Long tagid; +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/handler/AbstractHandler.java b/czsj-system/src/main/java/com/czsj/wechat/handler/AbstractHandler.java new file mode 100644 index 0000000..da5b266 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/handler/AbstractHandler.java @@ -0,0 +1,14 @@ +package com.czsj.wechat.handler; + +import me.chanjar.weixin.mp.api.WxMpMessageHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author Binary Wang + */ +public abstract class AbstractHandler implements WxMpMessageHandler { + + protected Logger logger = LoggerFactory.getLogger(getClass()); + +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/handler/KfSessionHandler.java b/czsj-system/src/main/java/com/czsj/wechat/handler/KfSessionHandler.java new file mode 100644 index 0000000..7cc6e77 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/handler/KfSessionHandler.java @@ -0,0 +1,25 @@ +package com.czsj.wechat.handler; + +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; +import org.springframework.stereotype.Component; + +import java.util.Map; + +/** + * @author Binary Wang + */ +@Component +public class KfSessionHandler extends AbstractHandler { + + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, + Map context, WxMpService wxMpService, + WxSessionManager sessionManager) { + + return null; + } + +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/handler/LocationHandler.java b/czsj-system/src/main/java/com/czsj/wechat/handler/LocationHandler.java new file mode 100644 index 0000000..a7a5670 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/handler/LocationHandler.java @@ -0,0 +1,40 @@ +package com.czsj.wechat.handler; + + +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; +import org.springframework.stereotype.Component; + +import java.util.Map; + +import static me.chanjar.weixin.common.api.WxConsts.XmlMsgType; + +/** + * @author Binary Wang + */ +@Component +public class LocationHandler extends AbstractHandler { + + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, + Map context, WxMpService wxMpService, + WxSessionManager sessionManager) { + if (wxMessage.getMsgType().equals(XmlMsgType.LOCATION)) { + //TODO 接收处理用户发送的地理位置消息 + + } + + //上报地理位置事件 + this.logger.info("\n上报地理位置 。。。 "); + this.logger.info("\n纬度 : " + wxMessage.getLatitude()); + this.logger.info("\n经度 : " + wxMessage.getLongitude()); + this.logger.info("\n精度 : " + wxMessage.getPrecision()); + + //TODO 可以将用户地理位置信息保存到本地数据库,以便以后使用 + + return null; + } + +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/handler/LogHandler.java b/czsj-system/src/main/java/com/czsj/wechat/handler/LogHandler.java new file mode 100644 index 0000000..89826d1 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/handler/LogHandler.java @@ -0,0 +1,37 @@ +package com.czsj.wechat.handler; + +import com.czsj.wechat.utils.Json; +import com.czsj.wechat.entity.WxMsg; +import com.czsj.wechat.service.WxMsgService; +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Map; + +/** + * @author Binary Wang + */ +@Component +public class LogHandler extends AbstractHandler { + @Autowired + WxMsgService wxMsgService; + + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, + Map context, WxMpService wxMpService, + WxSessionManager sessionManager) { + try { + this.logger.debug("\n接收到请求消息,内容:{}", Json.toJsonString(wxMessage)); + wxMsgService.addWxMsg(new WxMsg(wxMessage)); + } catch (Exception e) { + this.logger.error("记录消息异常",e); + } + + return null; + } + +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/handler/MenuHandler.java b/czsj-system/src/main/java/com/czsj/wechat/handler/MenuHandler.java new file mode 100644 index 0000000..b8c6a3c --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/handler/MenuHandler.java @@ -0,0 +1,37 @@ +package com.czsj.wechat.handler; + +import com.czsj.wechat.service.MsgReplyService; +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; +import me.chanjar.weixin.mp.util.WxMpConfigStorageHolder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Map; + +/** + * @author Binary Wang + */ +@Component +public class MenuHandler extends AbstractHandler { + @Autowired + MsgReplyService msgReplyService; + + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, + Map context, WxMpService weixinService, + WxSessionManager sessionManager) { + if (WxConsts.EventType.VIEW.equals(wxMessage.getEvent())) { + return null; + } + String appid = WxMpConfigStorageHolder.get(); + logger.info("菜单事件:" + wxMessage.getEventKey()); + msgReplyService.tryAutoReply(appid, true, wxMessage.getFromUser(), wxMessage.getEventKey()); + return null; + } + + +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/handler/MsgHandler.java b/czsj-system/src/main/java/com/czsj/wechat/handler/MsgHandler.java new file mode 100644 index 0000000..7ace736 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/handler/MsgHandler.java @@ -0,0 +1,52 @@ +package com.czsj.wechat.handler; + + +import com.czsj.wechat.entity.WxMsg; +import com.czsj.wechat.service.MsgReplyService; +import com.czsj.wechat.service.WxMsgService; +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; +import me.chanjar.weixin.mp.util.WxMpConfigStorageHolder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Map; + +/** + * @author Binary Wang + */ +@Component +public class MsgHandler extends AbstractHandler { + Logger logger = LoggerFactory.getLogger(this.getClass()); + @Autowired + MsgReplyService msgReplyService; + @Autowired + WxMsgService wxMsgService; + private static final String TRANSFER_CUSTOMER_SERVICE_KEY = "人工"; + + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, + Map context, WxMpService wxMpService, + WxSessionManager sessionManager) { + + String textContent = wxMessage.getContent(); + String fromUser = wxMessage.getFromUser(); + String appid = WxMpConfigStorageHolder.get(); + boolean autoReplyed = msgReplyService.tryAutoReply(appid,false, fromUser, textContent); + //当用户输入关键词如“你好”,“客服”等,并且有客服在线时,把消息转发给在线客服 + if (TRANSFER_CUSTOMER_SERVICE_KEY.equals(textContent) || !autoReplyed) { + wxMsgService.addWxMsg(WxMsg.buildOutMsg(WxConsts.KefuMsgType.TRANSFER_CUSTOMER_SERVICE,fromUser,null)); + return WxMpXmlOutMessage + .TRANSFER_CUSTOMER_SERVICE().fromUser(wxMessage.getToUser()) + .toUser(fromUser).build(); + } + return null; + + } + +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/handler/NullHandler.java b/czsj-system/src/main/java/com/czsj/wechat/handler/NullHandler.java new file mode 100644 index 0000000..30aa649 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/handler/NullHandler.java @@ -0,0 +1,24 @@ +package com.czsj.wechat.handler; + +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; +import org.springframework.stereotype.Component; + +import java.util.Map; + +/** + * @author Binary Wang + */ +@Component +public class NullHandler extends AbstractHandler { + + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, + Map context, WxMpService wxMpService, + WxSessionManager sessionManager) { + return null; + } + +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/handler/ScanHandler.java b/czsj-system/src/main/java/com/czsj/wechat/handler/ScanHandler.java new file mode 100644 index 0000000..f9b31f2 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/handler/ScanHandler.java @@ -0,0 +1,32 @@ +package com.czsj.wechat.handler; + +import com.czsj.wechat.service.MsgReplyService; +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; +import me.chanjar.weixin.mp.util.WxMpConfigStorageHolder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Map; + +/** + * @author Binary Wang + */ +@Component +public class ScanHandler extends AbstractHandler { + @Autowired + MsgReplyService msgReplyService; + + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMpXmlMessage, Map map, + WxMpService wxMpService, WxSessionManager wxSessionManager) { + //扫码事件处理 + this.logger.info("用户扫描带参二维码 OPENID: " + wxMpXmlMessage.getFromUser()); + String appid = WxMpConfigStorageHolder.get(); + msgReplyService.tryAutoReply(appid, true, wxMpXmlMessage.getFromUser(), wxMpXmlMessage.getEventKey()); + + return null; + } +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/handler/StoreCheckNotifyHandler.java b/czsj-system/src/main/java/com/czsj/wechat/handler/StoreCheckNotifyHandler.java new file mode 100644 index 0000000..a74b9f7 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/handler/StoreCheckNotifyHandler.java @@ -0,0 +1,27 @@ +package com.czsj.wechat.handler; + +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; +import org.springframework.stereotype.Component; + +import java.util.Map; + +/** + * 门店审核事件处理 + * + * @author 王彬 (Binary Wang) + */ +@Component +public class StoreCheckNotifyHandler extends AbstractHandler { + + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, + Map context, WxMpService wxMpService, + WxSessionManager sessionManager) { + // TODO 处理门店审核事件 + return null; + } + +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/handler/SubscribeHandler.java b/czsj-system/src/main/java/com/czsj/wechat/handler/SubscribeHandler.java new file mode 100644 index 0000000..e817383 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/handler/SubscribeHandler.java @@ -0,0 +1,61 @@ +package com.czsj.wechat.handler; + +import com.czsj.account.service.ICzsjMemberWxFansService; +import com.czsj.wechat.service.MsgReplyService; +import com.czsj.wechat.service.WxUserService; +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; +import me.chanjar.weixin.mp.util.WxMpConfigStorageHolder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +import java.util.Map; + +/** + * @author Binary Wang + */ +@Component +public class SubscribeHandler extends AbstractHandler { + @Autowired + MsgReplyService msgReplyService; + @Autowired + private ICzsjMemberWxFansService iCzsjMemberWxFansService; + @Autowired + WxUserService userService; + + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map context, WxMpService wxMpService, + WxSessionManager sessionManager) { + + this.logger.info("新关注用户 OPENID: " + wxMessage.getFromUser() + ",事件:" + wxMessage.getEventKey()); + String appid = WxMpConfigStorageHolder.get(); + this.logger.info("appid:{}",appid); + iCzsjMemberWxFansService.refreshUserInfo(wxMessage.getFromUser(),appid); + + msgReplyService.tryAutoReply(appid, true, wxMessage.getFromUser(), wxMessage.getEvent()); + + if (StringUtils.hasText(wxMessage.getEventKey())) {// 处理特殊事件,如用户扫描带参二维码关注 + msgReplyService.tryAutoReply(appid, true, wxMessage.getFromUser(), wxMessage.getEventKey()); + } + return null; + } + + /** + * 处理特殊请求,比如如果是扫码进来的,可以做相应处理 + */ + protected WxMpXmlOutMessage handleSpecial(WxMpXmlMessage wxMessage) { + this.logger.info("特殊请求-新关注用户 OPENID: " + wxMessage.getFromUser()); + //对关注事件和扫码事件分别处理 + String appid = WxMpConfigStorageHolder.get(); + userService.refreshUserInfo(wxMessage.getFromUser(),appid); + msgReplyService.tryAutoReply(appid, true, wxMessage.getFromUser(), wxMessage.getEvent()); + if (StringUtils.hasText(wxMessage.getEventKey())) { + msgReplyService.tryAutoReply(appid, true, wxMessage.getFromUser(), wxMessage.getEventKey()); + } + return null; + } + +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/handler/UnsubscribeHandler.java b/czsj-system/src/main/java/com/czsj/wechat/handler/UnsubscribeHandler.java new file mode 100644 index 0000000..fc69524 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/handler/UnsubscribeHandler.java @@ -0,0 +1,34 @@ +package com.czsj.wechat.handler; + +import com.czsj.account.service.ICzsjMemberWxFansService; +import com.czsj.wechat.service.WxUserService; +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Map; + +/** + * @author Binary Wang + */ +@Component +public class UnsubscribeHandler extends AbstractHandler { + @Autowired + WxUserService userService; + @Autowired + ICzsjMemberWxFansService iCzsjMemberWxFansService; + + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, + Map context, WxMpService wxMpService, + WxSessionManager sessionManager) { + String openid = wxMessage.getFromUser(); + this.logger.info("取消关注用户 OPENID: " + openid); + iCzsjMemberWxFansService.unsubscribe(openid); + return null; + } + +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/listener/WxAccountChangedMessageListener.java b/czsj-system/src/main/java/com/czsj/wechat/listener/WxAccountChangedMessageListener.java new file mode 100644 index 0000000..526ccee --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/listener/WxAccountChangedMessageListener.java @@ -0,0 +1,34 @@ +package com.czsj.wechat.listener; + +import com.czsj.wechat.service.WxAccountService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.connection.Message; +import org.springframework.data.redis.connection.MessageListener; +import org.springframework.stereotype.Service; + +/** + * @Auther: cheng.tang + * @Date: 2023/11/11 + * @Description: wx-api + */ +@Service +@Slf4j +public class WxAccountChangedMessageListener implements MessageListener { + + @Autowired + private WxAccountService wxAccountService; + + @Override + public void onMessage(Message message, byte[] pattern) { + log.info("receiving channel {} body {} pattern {} ", new String(message.getChannel()), new String(message.getBody()), new String(pattern)); + try { + wxAccountService.loadWxMpConfigStorages(); + log.info("finish "); + } catch (Exception e) { + log.error("消息处理失败了 {} ", e.getMessage()); + } + } + + +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/mapper/ArticleMapper.java b/czsj-system/src/main/java/com/czsj/wechat/mapper/ArticleMapper.java new file mode 100644 index 0000000..d45abf7 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/mapper/ArticleMapper.java @@ -0,0 +1,14 @@ +package com.czsj.wechat.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.CacheNamespace; +import org.apache.ibatis.annotations.Mapper; +import com.czsj.wechat.entity.Article; +import org.springframework.scheduling.annotation.Async; + +@Mapper +@CacheNamespace(flushInterval = 300000L)//缓存五分钟过期 +public interface ArticleMapper extends BaseMapper
{ + @Async + void addOpenCount(int id); +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/mapper/CzsjWxAccountMapper.java b/czsj-system/src/main/java/com/czsj/wechat/mapper/CzsjWxAccountMapper.java new file mode 100644 index 0000000..780349e --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/mapper/CzsjWxAccountMapper.java @@ -0,0 +1,61 @@ +package com.czsj.wechat.mapper; + +import java.util.List; +import com.czsj.wechat.domain.CzsjWxAccount; + +/** + * 微信公众号Mapper接口 + * + * @author czsj + * @date 2024-12-07 + */ +public interface CzsjWxAccountMapper +{ + /** + * 查询微信公众号 + * + * @param uid 微信公众号主键 + * @return 微信公众号 + */ + public CzsjWxAccount selectCzsjWxAccountByUid(Long uid); + + /** + * 查询微信公众号列表 + * + * @param czsjWxAccount 微信公众号 + * @return 微信公众号集合 + */ + public List selectCzsjWxAccountList(CzsjWxAccount czsjWxAccount); + + /** + * 新增微信公众号 + * + * @param czsjWxAccount 微信公众号 + * @return 结果 + */ + public int insertCzsjWxAccount(CzsjWxAccount czsjWxAccount); + + /** + * 修改微信公众号 + * + * @param czsjWxAccount 微信公众号 + * @return 结果 + */ + public int updateCzsjWxAccount(CzsjWxAccount czsjWxAccount); + + /** + * 删除微信公众号 + * + * @param uid 微信公众号主键 + * @return 结果 + */ + public int deleteCzsjWxAccountByUid(Long uid); + + /** + * 批量删除微信公众号 + * + * @param uids 需要删除的数据主键集合 + * @return 结果 + */ + public int deleteCzsjWxAccountByUids(Long[] uids); +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/mapper/CzsjWxMessageMapper.java b/czsj-system/src/main/java/com/czsj/wechat/mapper/CzsjWxMessageMapper.java new file mode 100644 index 0000000..aeb09c4 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/mapper/CzsjWxMessageMapper.java @@ -0,0 +1,61 @@ +package com.czsj.wechat.mapper; + +import java.util.List; +import com.czsj.wechat.domain.CzsjWxMessage; + +/** + * 微信消息Mapper接口 + * + * @author czsj + * @date 2024-12-07 + */ +public interface CzsjWxMessageMapper +{ + /** + * 查询微信消息 + * + * @param uid 微信消息主键 + * @return 微信消息 + */ + public CzsjWxMessage selectCzsjWxMessageByUid(Long uid); + + /** + * 查询微信消息列表 + * + * @param czsjWxMessage 微信消息 + * @return 微信消息集合 + */ + public List selectCzsjWxMessageList(CzsjWxMessage czsjWxMessage); + + /** + * 新增微信消息 + * + * @param czsjWxMessage 微信消息 + * @return 结果 + */ + public int insertCzsjWxMessage(CzsjWxMessage czsjWxMessage); + + /** + * 修改微信消息 + * + * @param czsjWxMessage 微信消息 + * @return 结果 + */ + public int updateCzsjWxMessage(CzsjWxMessage czsjWxMessage); + + /** + * 删除微信消息 + * + * @param uid 微信消息主键 + * @return 结果 + */ + public int deleteCzsjWxMessageByUid(Long uid); + + /** + * 批量删除微信消息 + * + * @param uids 需要删除的数据主键集合 + * @return 结果 + */ + public int deleteCzsjWxMessageByUids(Long[] uids); +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/mapper/CzsjWxQrCodeMapper.java b/czsj-system/src/main/java/com/czsj/wechat/mapper/CzsjWxQrCodeMapper.java new file mode 100644 index 0000000..64e60a8 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/mapper/CzsjWxQrCodeMapper.java @@ -0,0 +1,61 @@ +package com.czsj.wechat.mapper; + +import java.util.List; +import com.czsj.wechat.domain.CzsjWxQrCode; + +/** + * 公众号二维码Mapper接口 + * + * @author czsj + * @date 2024-12-07 + */ +public interface CzsjWxQrCodeMapper +{ + /** + * 查询公众号二维码 + * + * @param uid 公众号二维码主键 + * @return 公众号二维码 + */ + public CzsjWxQrCode selectCzsjWxQrCodeByUid(Long uid); + + /** + * 查询公众号二维码列表 + * + * @param czsjWxQrCode 公众号二维码 + * @return 公众号二维码集合 + */ + public List selectCzsjWxQrCodeList(CzsjWxQrCode czsjWxQrCode); + + /** + * 新增公众号二维码 + * + * @param czsjWxQrCode 公众号二维码 + * @return 结果 + */ + public int insertCzsjWxQrCode(CzsjWxQrCode czsjWxQrCode); + + /** + * 修改公众号二维码 + * + * @param czsjWxQrCode 公众号二维码 + * @return 结果 + */ + public int updateCzsjWxQrCode(CzsjWxQrCode czsjWxQrCode); + + /** + * 删除公众号二维码 + * + * @param uid 公众号二维码主键 + * @return 结果 + */ + public int deleteCzsjWxQrCodeByUid(Long uid); + + /** + * 批量删除公众号二维码 + * + * @param uids 需要删除的数据主键集合 + * @return 结果 + */ + public int deleteCzsjWxQrCodeByUids(Long[] uids); +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/mapper/CzsjWxReplyRuleMapper.java b/czsj-system/src/main/java/com/czsj/wechat/mapper/CzsjWxReplyRuleMapper.java new file mode 100644 index 0000000..16d9e1f --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/mapper/CzsjWxReplyRuleMapper.java @@ -0,0 +1,61 @@ +package com.czsj.wechat.mapper; + +import java.util.List; +import com.czsj.wechat.domain.CzsjWxReplyRule; + +/** + * 微信消息回复规则Mapper接口 + * + * @author czsj + * @date 2024-12-07 + */ +public interface CzsjWxReplyRuleMapper +{ + /** + * 查询微信消息回复规则 + * + * @param uid 微信消息回复规则主键 + * @return 微信消息回复规则 + */ + public CzsjWxReplyRule selectCzsjWxReplyRuleByUid(Long uid); + + /** + * 查询微信消息回复规则列表 + * + * @param czsjWxReplyRule 微信消息回复规则 + * @return 微信消息回复规则集合 + */ + public List selectCzsjWxReplyRuleList(CzsjWxReplyRule czsjWxReplyRule); + + /** + * 新增微信消息回复规则 + * + * @param czsjWxReplyRule 微信消息回复规则 + * @return 结果 + */ + public int insertCzsjWxReplyRule(CzsjWxReplyRule czsjWxReplyRule); + + /** + * 修改微信消息回复规则 + * + * @param czsjWxReplyRule 微信消息回复规则 + * @return 结果 + */ + public int updateCzsjWxReplyRule(CzsjWxReplyRule czsjWxReplyRule); + + /** + * 删除微信消息回复规则 + * + * @param uid 微信消息回复规则主键 + * @return 结果 + */ + public int deleteCzsjWxReplyRuleByUid(Long uid); + + /** + * 批量删除微信消息回复规则 + * + * @param uids 需要删除的数据主键集合 + * @return 结果 + */ + public int deleteCzsjWxReplyRuleByUids(Long[] uids); +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/mapper/CzsjWxTemplateLogMapper.java b/czsj-system/src/main/java/com/czsj/wechat/mapper/CzsjWxTemplateLogMapper.java new file mode 100644 index 0000000..e574102 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/mapper/CzsjWxTemplateLogMapper.java @@ -0,0 +1,61 @@ +package com.czsj.wechat.mapper; + +import java.util.List; +import com.czsj.wechat.domain.CzsjWxTemplateLog; + +/** + * 微信消息模板日志Mapper接口 + * + * @author czsj + * @date 2024-12-07 + */ +public interface CzsjWxTemplateLogMapper +{ + /** + * 查询微信消息模板日志 + * + * @param uid 微信消息模板日志主键 + * @return 微信消息模板日志 + */ + public CzsjWxTemplateLog selectCzsjWxTemplateLogByUid(Long uid); + + /** + * 查询微信消息模板日志列表 + * + * @param czsjWxTemplateLog 微信消息模板日志 + * @return 微信消息模板日志集合 + */ + public List selectCzsjWxTemplateLogList(CzsjWxTemplateLog czsjWxTemplateLog); + + /** + * 新增微信消息模板日志 + * + * @param czsjWxTemplateLog 微信消息模板日志 + * @return 结果 + */ + public int insertCzsjWxTemplateLog(CzsjWxTemplateLog czsjWxTemplateLog); + + /** + * 修改微信消息模板日志 + * + * @param czsjWxTemplateLog 微信消息模板日志 + * @return 结果 + */ + public int updateCzsjWxTemplateLog(CzsjWxTemplateLog czsjWxTemplateLog); + + /** + * 删除微信消息模板日志 + * + * @param uid 微信消息模板日志主键 + * @return 结果 + */ + public int deleteCzsjWxTemplateLogByUid(Long uid); + + /** + * 批量删除微信消息模板日志 + * + * @param uids 需要删除的数据主键集合 + * @return 结果 + */ + public int deleteCzsjWxTemplateLogByUids(Long[] uids); +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/mapper/CzsjWxTemplateMapper.java b/czsj-system/src/main/java/com/czsj/wechat/mapper/CzsjWxTemplateMapper.java new file mode 100644 index 0000000..13c9a7d --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/mapper/CzsjWxTemplateMapper.java @@ -0,0 +1,61 @@ +package com.czsj.wechat.mapper; + +import java.util.List; +import com.czsj.wechat.domain.CzsjWxTemplate; + +/** + * 微信消息模板Mapper接口 + * + * @author czsj + * @date 2024-12-07 + */ +public interface CzsjWxTemplateMapper +{ + /** + * 查询微信消息模板 + * + * @param uid 微信消息模板主键 + * @return 微信消息模板 + */ + public CzsjWxTemplate selectCzsjWxTemplateByUid(Long uid); + + /** + * 查询微信消息模板列表 + * + * @param czsjWxTemplate 微信消息模板 + * @return 微信消息模板集合 + */ + public List selectCzsjWxTemplateList(CzsjWxTemplate czsjWxTemplate); + + /** + * 新增微信消息模板 + * + * @param czsjWxTemplate 微信消息模板 + * @return 结果 + */ + public int insertCzsjWxTemplate(CzsjWxTemplate czsjWxTemplate); + + /** + * 修改微信消息模板 + * + * @param czsjWxTemplate 微信消息模板 + * @return 结果 + */ + public int updateCzsjWxTemplate(CzsjWxTemplate czsjWxTemplate); + + /** + * 删除微信消息模板 + * + * @param uid 微信消息模板主键 + * @return 结果 + */ + public int deleteCzsjWxTemplateByUid(Long uid); + + /** + * 批量删除微信消息模板 + * + * @param uids 需要删除的数据主键集合 + * @return 结果 + */ + public int deleteCzsjWxTemplateByUids(Long[] uids); +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/mapper/MsgReplyRuleMapper.java b/czsj-system/src/main/java/com/czsj/wechat/mapper/MsgReplyRuleMapper.java new file mode 100644 index 0000000..7cc0fc0 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/mapper/MsgReplyRuleMapper.java @@ -0,0 +1,11 @@ +package com.czsj.wechat.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.CacheNamespace; +import org.apache.ibatis.annotations.Mapper; +import com.czsj.wechat.entity.MsgReplyRule; + +@Mapper +@CacheNamespace(flushInterval = 300000L)//缓存五分钟过期 +public interface MsgReplyRuleMapper extends BaseMapper { +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/mapper/MsgTemplateMapper.java b/czsj-system/src/main/java/com/czsj/wechat/mapper/MsgTemplateMapper.java new file mode 100644 index 0000000..6a147d4 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/mapper/MsgTemplateMapper.java @@ -0,0 +1,11 @@ +package com.czsj.wechat.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.CacheNamespace; +import org.apache.ibatis.annotations.Mapper; +import com.czsj.wechat.entity.MsgTemplate; + +@Mapper +@CacheNamespace(flushInterval = 300000L)//缓存五分钟过期 +public interface MsgTemplateMapper extends BaseMapper { +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/mapper/TemplateMsgLogMapper.java b/czsj-system/src/main/java/com/czsj/wechat/mapper/TemplateMsgLogMapper.java new file mode 100644 index 0000000..ef2bf75 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/mapper/TemplateMsgLogMapper.java @@ -0,0 +1,9 @@ +package com.czsj.wechat.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; +import com.czsj.wechat.entity.TemplateMsgLog; + +@Mapper +public interface TemplateMsgLogMapper extends BaseMapper { +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/mapper/WxAccountMapper.java b/czsj-system/src/main/java/com/czsj/wechat/mapper/WxAccountMapper.java new file mode 100644 index 0000000..c3f08ad --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/mapper/WxAccountMapper.java @@ -0,0 +1,18 @@ +package com.czsj.wechat.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.CacheNamespace; +import org.apache.ibatis.annotations.Mapper; +import com.czsj.wechat.entity.WxAccount; + +/** + * 公众号账号 + * + * @author niefy + * @date 2020-06-17 13:56:51 + */ +@Mapper +@CacheNamespace(flushInterval = 300000L)//缓存五分钟过期 +public interface WxAccountMapper extends BaseMapper { + +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/mapper/WxMsgMapper.java b/czsj-system/src/main/java/com/czsj/wechat/mapper/WxMsgMapper.java new file mode 100644 index 0000000..770be79 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/mapper/WxMsgMapper.java @@ -0,0 +1,18 @@ +package com.czsj.wechat.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.CacheNamespace; +import org.apache.ibatis.annotations.Mapper; +import com.czsj.wechat.entity.WxMsg; + +/** + * 微信消息 + * + * @author niefy + * @date 2020-05-14 17:28:34 + */ +@Mapper +@CacheNamespace(flushInterval = 10*1000L)//缓存过期时间(毫秒) +public interface WxMsgMapper extends BaseMapper { + +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/mapper/WxQrCodeMapper.java b/czsj-system/src/main/java/com/czsj/wechat/mapper/WxQrCodeMapper.java new file mode 100644 index 0000000..6704de1 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/mapper/WxQrCodeMapper.java @@ -0,0 +1,19 @@ +package com.czsj.wechat.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.CacheNamespace; +import org.apache.ibatis.annotations.Mapper; +import com.czsj.wechat.entity.WxQrCode; + +/** + * 公众号带参二维码 + * + * @author niefy + * @email niefy@qq.com + * @date 2020-01-02 11:11:55 + */ +@Mapper +@CacheNamespace(flushInterval = 300000L)//缓存五分钟过期 +public interface WxQrCodeMapper extends BaseMapper { + +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/mapper/WxUserMapper.java b/czsj-system/src/main/java/com/czsj/wechat/mapper/WxUserMapper.java new file mode 100644 index 0000000..e43a76c --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/mapper/WxUserMapper.java @@ -0,0 +1,13 @@ +package com.czsj.wechat.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.CacheNamespace; +import org.apache.ibatis.annotations.Mapper; +import com.czsj.wechat.entity.WxUser; + +@Mapper +@CacheNamespace(flushInterval = 300000L)//缓存五分钟过期 +public interface WxUserMapper extends BaseMapper { + + void unsubscribe(String openid); +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/service/ArticleService.java b/czsj-system/src/main/java/com/czsj/wechat/service/ArticleService.java new file mode 100644 index 0000000..559f9e6 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/service/ArticleService.java @@ -0,0 +1,62 @@ +package com.czsj.wechat.service; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import com.czsj.wechat.utils.PageUtils; +import com.czsj.wechat.entity.Article; +import com.czsj.wechat.enums.ArticleTypeEnum; + +import java.util.List; +import java.util.Map; + +public interface ArticleService extends IService
{ + /** + * 分页查询用户数据 + * @param params 查询参数 + * @return PageUtils 分页结果 + */ + PageUtils queryPage(Map params); + + /** + * 查询文章详情,每次查询后增加点击次数 + * + * @param id + * @return + */ + Article findById(int id); + + /** + * 添加或编辑文章,同名文章不可重复添加 + * + * @param article + */ + boolean saveArticle(Article article); + + /** + * 按条件分页查询 + * + * @param title + * @param page + * @return + */ + IPage
getArticles(String title, int page); + + /** + * 查看目录,不返回文章详情字段 + * + * @param articleType + * @param category + * @return + */ + List
selectCategory(ArticleTypeEnum articleType, String category); + + /** + * 文章查找,不返回文章详情字段 + * + * @param articleType + * @param category + * @param keywords + * @return + */ + List
search(ArticleTypeEnum articleType, String category, String keywords); +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/service/ICzsjWxAccountService.java b/czsj-system/src/main/java/com/czsj/wechat/service/ICzsjWxAccountService.java new file mode 100644 index 0000000..da2a72b --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/service/ICzsjWxAccountService.java @@ -0,0 +1,61 @@ +package com.czsj.wechat.service; + +import java.util.List; +import com.czsj.wechat.domain.CzsjWxAccount; + +/** + * 微信公众号Service接口 + * + * @author czsj + * @date 2024-12-07 + */ +public interface ICzsjWxAccountService +{ + /** + * 查询微信公众号 + * + * @param uid 微信公众号主键 + * @return 微信公众号 + */ + public CzsjWxAccount selectCzsjWxAccountByUid(Long uid); + + /** + * 查询微信公众号列表 + * + * @param czsjWxAccount 微信公众号 + * @return 微信公众号集合 + */ + public List selectCzsjWxAccountList(CzsjWxAccount czsjWxAccount); + + /** + * 新增微信公众号 + * + * @param czsjWxAccount 微信公众号 + * @return 结果 + */ + public int insertCzsjWxAccount(CzsjWxAccount czsjWxAccount); + + /** + * 修改微信公众号 + * + * @param czsjWxAccount 微信公众号 + * @return 结果 + */ + public int updateCzsjWxAccount(CzsjWxAccount czsjWxAccount); + + /** + * 批量删除微信公众号 + * + * @param uids 需要删除的微信公众号主键集合 + * @return 结果 + */ + public int deleteCzsjWxAccountByUids(Long[] uids); + + /** + * 删除微信公众号信息 + * + * @param uid 微信公众号主键 + * @return 结果 + */ + public int deleteCzsjWxAccountByUid(Long uid); +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/service/ICzsjWxMessageService.java b/czsj-system/src/main/java/com/czsj/wechat/service/ICzsjWxMessageService.java new file mode 100644 index 0000000..824bd55 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/service/ICzsjWxMessageService.java @@ -0,0 +1,61 @@ +package com.czsj.wechat.service; + +import java.util.List; +import com.czsj.wechat.domain.CzsjWxMessage; + +/** + * 微信消息Service接口 + * + * @author czsj + * @date 2024-12-07 + */ +public interface ICzsjWxMessageService +{ + /** + * 查询微信消息 + * + * @param uid 微信消息主键 + * @return 微信消息 + */ + public CzsjWxMessage selectCzsjWxMessageByUid(Long uid); + + /** + * 查询微信消息列表 + * + * @param czsjWxMessage 微信消息 + * @return 微信消息集合 + */ + public List selectCzsjWxMessageList(CzsjWxMessage czsjWxMessage); + + /** + * 新增微信消息 + * + * @param czsjWxMessage 微信消息 + * @return 结果 + */ + public int insertCzsjWxMessage(CzsjWxMessage czsjWxMessage); + + /** + * 修改微信消息 + * + * @param czsjWxMessage 微信消息 + * @return 结果 + */ + public int updateCzsjWxMessage(CzsjWxMessage czsjWxMessage); + + /** + * 批量删除微信消息 + * + * @param uids 需要删除的微信消息主键集合 + * @return 结果 + */ + public int deleteCzsjWxMessageByUids(Long[] uids); + + /** + * 删除微信消息信息 + * + * @param uid 微信消息主键 + * @return 结果 + */ + public int deleteCzsjWxMessageByUid(Long uid); +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/service/ICzsjWxQrCodeService.java b/czsj-system/src/main/java/com/czsj/wechat/service/ICzsjWxQrCodeService.java new file mode 100644 index 0000000..fff8d2c --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/service/ICzsjWxQrCodeService.java @@ -0,0 +1,61 @@ +package com.czsj.wechat.service; + +import java.util.List; +import com.czsj.wechat.domain.CzsjWxQrCode; + +/** + * 公众号二维码Service接口 + * + * @author czsj + * @date 2024-12-07 + */ +public interface ICzsjWxQrCodeService +{ + /** + * 查询公众号二维码 + * + * @param uid 公众号二维码主键 + * @return 公众号二维码 + */ + public CzsjWxQrCode selectCzsjWxQrCodeByUid(Long uid); + + /** + * 查询公众号二维码列表 + * + * @param czsjWxQrCode 公众号二维码 + * @return 公众号二维码集合 + */ + public List selectCzsjWxQrCodeList(CzsjWxQrCode czsjWxQrCode); + + /** + * 新增公众号二维码 + * + * @param czsjWxQrCode 公众号二维码 + * @return 结果 + */ + public int insertCzsjWxQrCode(CzsjWxQrCode czsjWxQrCode); + + /** + * 修改公众号二维码 + * + * @param czsjWxQrCode 公众号二维码 + * @return 结果 + */ + public int updateCzsjWxQrCode(CzsjWxQrCode czsjWxQrCode); + + /** + * 批量删除公众号二维码 + * + * @param uids 需要删除的公众号二维码主键集合 + * @return 结果 + */ + public int deleteCzsjWxQrCodeByUids(Long[] uids); + + /** + * 删除公众号二维码信息 + * + * @param uid 公众号二维码主键 + * @return 结果 + */ + public int deleteCzsjWxQrCodeByUid(Long uid); +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/service/ICzsjWxReplyRuleService.java b/czsj-system/src/main/java/com/czsj/wechat/service/ICzsjWxReplyRuleService.java new file mode 100644 index 0000000..d35bafa --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/service/ICzsjWxReplyRuleService.java @@ -0,0 +1,61 @@ +package com.czsj.wechat.service; + +import java.util.List; +import com.czsj.wechat.domain.CzsjWxReplyRule; + +/** + * 微信消息回复规则Service接口 + * + * @author czsj + * @date 2024-12-07 + */ +public interface ICzsjWxReplyRuleService +{ + /** + * 查询微信消息回复规则 + * + * @param uid 微信消息回复规则主键 + * @return 微信消息回复规则 + */ + public CzsjWxReplyRule selectCzsjWxReplyRuleByUid(Long uid); + + /** + * 查询微信消息回复规则列表 + * + * @param czsjWxReplyRule 微信消息回复规则 + * @return 微信消息回复规则集合 + */ + public List selectCzsjWxReplyRuleList(CzsjWxReplyRule czsjWxReplyRule); + + /** + * 新增微信消息回复规则 + * + * @param czsjWxReplyRule 微信消息回复规则 + * @return 结果 + */ + public int insertCzsjWxReplyRule(CzsjWxReplyRule czsjWxReplyRule); + + /** + * 修改微信消息回复规则 + * + * @param czsjWxReplyRule 微信消息回复规则 + * @return 结果 + */ + public int updateCzsjWxReplyRule(CzsjWxReplyRule czsjWxReplyRule); + + /** + * 批量删除微信消息回复规则 + * + * @param uids 需要删除的微信消息回复规则主键集合 + * @return 结果 + */ + public int deleteCzsjWxReplyRuleByUids(Long[] uids); + + /** + * 删除微信消息回复规则信息 + * + * @param uid 微信消息回复规则主键 + * @return 结果 + */ + public int deleteCzsjWxReplyRuleByUid(Long uid); +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/service/ICzsjWxTemplateLogService.java b/czsj-system/src/main/java/com/czsj/wechat/service/ICzsjWxTemplateLogService.java new file mode 100644 index 0000000..05477a4 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/service/ICzsjWxTemplateLogService.java @@ -0,0 +1,61 @@ +package com.czsj.wechat.service; + +import java.util.List; +import com.czsj.wechat.domain.CzsjWxTemplateLog; + +/** + * 微信消息模板日志Service接口 + * + * @author czsj + * @date 2024-12-07 + */ +public interface ICzsjWxTemplateLogService +{ + /** + * 查询微信消息模板日志 + * + * @param uid 微信消息模板日志主键 + * @return 微信消息模板日志 + */ + public CzsjWxTemplateLog selectCzsjWxTemplateLogByUid(Long uid); + + /** + * 查询微信消息模板日志列表 + * + * @param czsjWxTemplateLog 微信消息模板日志 + * @return 微信消息模板日志集合 + */ + public List selectCzsjWxTemplateLogList(CzsjWxTemplateLog czsjWxTemplateLog); + + /** + * 新增微信消息模板日志 + * + * @param czsjWxTemplateLog 微信消息模板日志 + * @return 结果 + */ + public int insertCzsjWxTemplateLog(CzsjWxTemplateLog czsjWxTemplateLog); + + /** + * 修改微信消息模板日志 + * + * @param czsjWxTemplateLog 微信消息模板日志 + * @return 结果 + */ + public int updateCzsjWxTemplateLog(CzsjWxTemplateLog czsjWxTemplateLog); + + /** + * 批量删除微信消息模板日志 + * + * @param uids 需要删除的微信消息模板日志主键集合 + * @return 结果 + */ + public int deleteCzsjWxTemplateLogByUids(Long[] uids); + + /** + * 删除微信消息模板日志信息 + * + * @param uid 微信消息模板日志主键 + * @return 结果 + */ + public int deleteCzsjWxTemplateLogByUid(Long uid); +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/service/ICzsjWxTemplateService.java b/czsj-system/src/main/java/com/czsj/wechat/service/ICzsjWxTemplateService.java new file mode 100644 index 0000000..e5c3451 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/service/ICzsjWxTemplateService.java @@ -0,0 +1,61 @@ +package com.czsj.wechat.service; + +import java.util.List; +import com.czsj.wechat.domain.CzsjWxTemplate; + +/** + * 微信消息模板Service接口 + * + * @author czsj + * @date 2024-12-07 + */ +public interface ICzsjWxTemplateService +{ + /** + * 查询微信消息模板 + * + * @param uid 微信消息模板主键 + * @return 微信消息模板 + */ + public CzsjWxTemplate selectCzsjWxTemplateByUid(Long uid); + + /** + * 查询微信消息模板列表 + * + * @param czsjWxTemplate 微信消息模板 + * @return 微信消息模板集合 + */ + public List selectCzsjWxTemplateList(CzsjWxTemplate czsjWxTemplate); + + /** + * 新增微信消息模板 + * + * @param czsjWxTemplate 微信消息模板 + * @return 结果 + */ + public int insertCzsjWxTemplate(CzsjWxTemplate czsjWxTemplate); + + /** + * 修改微信消息模板 + * + * @param czsjWxTemplate 微信消息模板 + * @return 结果 + */ + public int updateCzsjWxTemplate(CzsjWxTemplate czsjWxTemplate); + + /** + * 批量删除微信消息模板 + * + * @param uids 需要删除的微信消息模板主键集合 + * @return 结果 + */ + public int deleteCzsjWxTemplateByUids(Long[] uids); + + /** + * 删除微信消息模板信息 + * + * @param uid 微信消息模板主键 + * @return 结果 + */ + public int deleteCzsjWxTemplateByUid(Long uid); +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/service/MsgReplyRuleService.java b/czsj-system/src/main/java/com/czsj/wechat/service/MsgReplyRuleService.java new file mode 100644 index 0000000..e70717a --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/service/MsgReplyRuleService.java @@ -0,0 +1,51 @@ +package com.czsj.wechat.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.czsj.wechat.utils.PageUtils; +import com.czsj.wechat.entity.MsgReplyRule; + +import java.util.List; +import java.util.Map; + +public interface MsgReplyRuleService extends IService { + /** + * 分页查询用户数据 + * @param params 查询参数 + * @return PageUtils 分页结果 + */ + PageUtils queryPage(Map params); + + /** + * 保存自动回复规则 + * + * @param msgReplyRule + */ + + @Override + boolean save(MsgReplyRule msgReplyRule); + + /** + * 获取所有的回复规则 + * + * @return + */ + List getRules(); + + /** + * 获取当前时段内所有有效的回复规则 + * + * @return 有效的规则列表 + */ + List getValidRules(); + + /** + * 筛选符合条件的回复规则 + * + * + * @param appid + * @param exactMatch 是否精确匹配 + * @param keywords 关键词 + * @return 规则列表 + */ + List getMatchedRules(String appid, boolean exactMatch, String keywords); +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/service/MsgReplyService.java b/czsj-system/src/main/java/com/czsj/wechat/service/MsgReplyService.java new file mode 100644 index 0000000..a67ea9a --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/service/MsgReplyService.java @@ -0,0 +1,107 @@ +package com.czsj.wechat.service; + +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.common.error.WxErrorException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * 公众号消息处理 + * 官方文档:https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Service_Center_messages.html#7 + * WxJava客服消息文档:https://github.com/Wechat-Group/WxJava/wiki/MP_主动发送消息(客服消息) + */ +public interface MsgReplyService { + Logger logger = LoggerFactory.getLogger(MsgReplyService.class); + + /** + * 根据规则配置通过微信客服消息接口自动回复消息 + * + * + * @param appid + * @param exactMatch 是否精确匹配 + * @param toUser 用户openid + * @param keywords 匹配关键词 + * @return 是否已自动回复,无匹配规则则不自动回复 + */ + boolean tryAutoReply(String appid, boolean exactMatch, String toUser, String keywords); + + default void reply(String toUser,String replyType, String replyContent){ + try { + if (WxConsts.KefuMsgType.TEXT.equals(replyType)) { + this.replyText(toUser, replyContent); + } else if (WxConsts.KefuMsgType.IMAGE.equals(replyType)) { + this.replyImage(toUser, replyContent); + } else if (WxConsts.KefuMsgType.VOICE.equals(replyType)) { + this.replyVoice(toUser, replyContent); + } else if (WxConsts.KefuMsgType.VIDEO.equals(replyType)) { + this.replyVideo(toUser, replyContent); + } else if (WxConsts.KefuMsgType.MUSIC.equals(replyType)) { + this.replyMusic(toUser, replyContent); + } else if (WxConsts.KefuMsgType.NEWS.equals(replyType)) { + this.replyNews(toUser, replyContent); + } else if (WxConsts.KefuMsgType.MPNEWS.equals(replyType)) { + this.replyMpNews(toUser, replyContent); + } else if (WxConsts.KefuMsgType.WXCARD.equals(replyType)) { + this.replyWxCard(toUser, replyContent); + } else if (WxConsts.KefuMsgType.MINIPROGRAMPAGE.equals(replyType)) { + this.replyMiniProgram(toUser, replyContent); + } else if (WxConsts.KefuMsgType.MSGMENU.equals(replyType)) { + this.replyMsgMenu(toUser, replyContent); + } + } catch (Exception e) { + logger.error("自动回复出错:", e); + } + } + + /** + * 回复文字消息 + */ + void replyText(String toUser, String replyContent) throws WxErrorException; + + /** + * 回复图片消息 + */ + void replyImage(String toUser, String mediaId) throws WxErrorException; + + /** + * 回复录音消息 + */ + void replyVoice(String toUser, String mediaId) throws WxErrorException; + + /** + * 回复视频消息 + */ + void replyVideo(String toUser, String mediaId) throws WxErrorException; + + /** + * 回复音乐消息 + */ + void replyMusic(String toUser, String mediaId) throws WxErrorException; + + /** + * 回复图文消息(点击跳转到外链) + * 图文消息条数限制在1条以内 + */ + void replyNews(String toUser, String newsInfoJson) throws WxErrorException; + + /** + * 回复公众号文章消息(点击跳转到图文消息页面) + * 图文消息条数限制在1条以内 + */ + void replyMpNews(String toUser, String mediaId) throws WxErrorException; + + /** + * 回复卡券消息 + */ + void replyWxCard(String toUser, String cardId) throws WxErrorException; + + /** + * 回复小程序消息 + */ + void replyMiniProgram(String toUser, String miniProgramInfoJson) throws WxErrorException; + + /** + * 回复菜单消息 + */ + void replyMsgMenu(String toUser, String msgMenusJson) throws WxErrorException; +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/service/MsgTemplateService.java b/czsj-system/src/main/java/com/czsj/wechat/service/MsgTemplateService.java new file mode 100644 index 0000000..42320ed --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/service/MsgTemplateService.java @@ -0,0 +1,41 @@ +package com.czsj.wechat.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.czsj.wechat.utils.PageUtils; +import com.czsj.wechat.entity.MsgTemplate; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.bean.template.WxMpTemplate; + +import java.util.List; +import java.util.Map; + +/** + * 消息模板 + * + * @author niefy + * @email niefy@qq.com + * @date 2019-11-12 18:30:15 + */ +public interface MsgTemplateService extends IService { + /** + * 分页查询用户数据 + * @param params 查询参数 + * @return PageUtils 分页结果 + */ + PageUtils queryPage(Map params); + + /** + * 通过模板名称查询 + * + * @param name + * @return + */ + MsgTemplate selectByName(String name); + + /** + * 同步公众号已添加的消息模板 + * @throws WxErrorException + */ + void syncWxTemplate(String appid, List allPrivateTemplateList) throws WxErrorException; +} + diff --git a/czsj-system/src/main/java/com/czsj/wechat/service/TemplateMsgLogService.java b/czsj-system/src/main/java/com/czsj/wechat/service/TemplateMsgLogService.java new file mode 100644 index 0000000..06bcdbf --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/service/TemplateMsgLogService.java @@ -0,0 +1,23 @@ +package com.czsj.wechat.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.czsj.wechat.utils.PageUtils; +import com.czsj.wechat.entity.TemplateMsgLog; + +import java.util.Map; + +public interface TemplateMsgLogService extends IService { + /** + * 分页查询用户数据 + * @param params 查询参数 + * @return PageUtils 分页结果 + */ + PageUtils queryPage(Map params); + + /** + * 记录log,异步入库 + * + * @param log + */ + void addLog(TemplateMsgLog log); +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/service/TemplateMsgService.java b/czsj-system/src/main/java/com/czsj/wechat/service/TemplateMsgService.java new file mode 100644 index 0000000..32190bb --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/service/TemplateMsgService.java @@ -0,0 +1,18 @@ +package com.czsj.wechat.service; + +import com.czsj.wechat.form.TemplateMsgBatchForm; +import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage; + +public interface TemplateMsgService { + /** + * 发送微信模版消息 + */ + void sendTemplateMsg(WxMpTemplateMessage msg,String appid); + + /** + * 批量消息发送 + * @param form + * @param appid + */ + void sendMsgBatch(TemplateMsgBatchForm form,String appid); +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/service/WxAccountService.java b/czsj-system/src/main/java/com/czsj/wechat/service/WxAccountService.java new file mode 100644 index 0000000..d9de011 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/service/WxAccountService.java @@ -0,0 +1,31 @@ +package com.czsj.wechat.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.czsj.wechat.utils.PageUtils; +import com.czsj.wechat.entity.WxAccount; + +import java.util.Collection; +import java.util.Map; + +/** + * 公众号账号 + * + * @author niefy + * @date 2020-06-17 13:56:51 + */ +public interface WxAccountService extends IService { + /** + * 分页查询用户数据 + * @param params 查询参数 + * @return PageUtils 分页结果 + */ + PageUtils queryPage(Map params); + + void loadWxMpConfigStorages(); + + boolean saveOrUpdateWxAccount(WxAccount entity); + + @Override + boolean removeByIds(Collection idList); +} + diff --git a/czsj-system/src/main/java/com/czsj/wechat/service/WxAssetsService.java b/czsj-system/src/main/java/com/czsj/wechat/service/WxAssetsService.java new file mode 100644 index 0000000..1f99dc4 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/service/WxAssetsService.java @@ -0,0 +1,89 @@ +package com.czsj.wechat.service; + +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.bean.draft.WxMpDraftArticles; +import me.chanjar.weixin.mp.bean.draft.WxMpUpdateDraft; +import me.chanjar.weixin.mp.bean.material.*; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.util.List; + +public interface WxAssetsService { + /** + * 获取素材总数 + * @return + * @throws WxErrorException + * @param appid + */ + WxMpMaterialCountResult materialCount(String appid) throws WxErrorException; + + /** + * 获取图文素材详情 + * + * @param appid + * @param mediaId + * @return + * @throws WxErrorException + */ + WxMpMaterialNews materialNewsInfo(String appid, String mediaId) throws WxErrorException; + /** + * 根据类别分页获取非图文素材列表 + * + * @param appid + * @param type + * @param page + * @return + * @throws WxErrorException + */ + WxMpMaterialFileBatchGetResult materialFileBatchGet(String appid, String type, int page) throws WxErrorException; + + /** + * 分页获取图文素材列表 + * + * @param appid + * @param page + * @return + * @throws WxErrorException + */ + WxMpMaterialNewsBatchGetResult materialNewsBatchGet(String appid, int page) throws WxErrorException; + + /** + * 添加图文永久素材 + * + * @param appid + * @param articles + * @return + * @throws WxErrorException + */ + WxMpMaterialUploadResult materialNewsUpload(String appid, List articles)throws WxErrorException; + + /** + * 更新图文素材中的某篇文章 + * @param appid + * @param form + */ + void materialArticleUpdate(String appid, WxMpUpdateDraft form) throws WxErrorException; + + /** + * 添加多媒体永久素材 + * + * @param appid + * @param mediaType + * @param fileName + * @param file + * @return + * @throws WxErrorException + */ + WxMpMaterialUploadResult materialFileUpload(String appid, String mediaType, String fileName, MultipartFile file) throws WxErrorException, IOException; + + /** + * 删除素材 + * + * @param appid + * @param mediaId + * @return + * @throws WxErrorException + */ + boolean materialDelete(String appid, String mediaId)throws WxErrorException; +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/service/WxMsgService.java b/czsj-system/src/main/java/com/czsj/wechat/service/WxMsgService.java new file mode 100644 index 0000000..070404e --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/service/WxMsgService.java @@ -0,0 +1,29 @@ +package com.czsj.wechat.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.czsj.wechat.utils.PageUtils; +import com.czsj.wechat.entity.WxMsg; + +import java.util.Map; + +/** + * 微信消息 + * + * @author niefy + * @date 2020-05-14 17:28:34 + */ +public interface WxMsgService extends IService { + /** + * 分页查询用户数据 + * @param params 查询参数 + * @return PageUtils 分页结果 + */ + PageUtils queryPage(Map params); + + /** + * 记录msg,异步入库 + * @param msg + */ + void addWxMsg(WxMsg msg); +} + diff --git a/czsj-system/src/main/java/com/czsj/wechat/service/WxQrCodeService.java b/czsj-system/src/main/java/com/czsj/wechat/service/WxQrCodeService.java new file mode 100644 index 0000000..901cec4 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/service/WxQrCodeService.java @@ -0,0 +1,37 @@ +package com.czsj.wechat.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.czsj.wechat.utils.PageUtils; +import com.czsj.wechat.entity.WxQrCode; +import com.czsj.wechat.form.WxQrCodeForm; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket; + +import java.util.Map; + +/** + * 公众号带参二维码 + * + * @author niefy + * @email niefy@qq.com + * @date 2020-01-02 11:11:55 + */ +public interface WxQrCodeService extends IService { + /** + * 分页查询用户数据 + * @param params 查询参数 + * @return PageUtils 分页结果 + */ + PageUtils queryPage(Map params); + + /** + * 创建公众号带参二维码 + * + * + * @param appid + * @param form + * @return + */ + WxMpQrCodeTicket createQrCode(String appid, WxQrCodeForm form) throws WxErrorException; +} + diff --git a/czsj-system/src/main/java/com/czsj/wechat/service/WxUserService.java b/czsj-system/src/main/java/com/czsj/wechat/service/WxUserService.java new file mode 100644 index 0000000..4cd4d79 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/service/WxUserService.java @@ -0,0 +1,56 @@ +package com.czsj.wechat.service; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import com.czsj.wechat.entity.WxUser; + +import java.util.List; +import java.util.Map; + +public interface WxUserService extends IService { + /** + * 分页查询用户数据 + * @param params 查询参数 + * @return PageUtils 分页结果 + */ + IPage queryPage(Map params); + + /** + * 根据openid更新用户信息 + * + * @param openid + * @return + */ + WxUser refreshUserInfo(String openid,String appid); + + /** + * 异步批量更新用户信息 + * @param openidList + */ + void refreshUserInfoAsync(String[] openidList,String appid); + + /** + * 数据存在时更新,否则新增 + * + * @param user + */ + void updateOrInsert(WxUser user); + + /** + * 取消关注,更新关注状态 + * + * @param openid + */ + void unsubscribe(String openid); + /** + * 同步用户列表 + */ + void syncWxUsers(String appid); + + /** + * 通过传入的openid列表,同步用户列表 + * @param openids + */ + void syncWxUsers(List openids,String appid); + +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/service/WxUserTagsService.java b/czsj-system/src/main/java/com/czsj/wechat/service/WxUserTagsService.java new file mode 100644 index 0000000..7a72e13 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/service/WxUserTagsService.java @@ -0,0 +1,79 @@ +package com.czsj.wechat.service; + +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.bean.tag.WxUserTag; + +import java.util.List; + +public interface WxUserTagsService { + /** + * 获取公众号用户标签 + * @return + * @throws WxErrorException + * @param appid + */ + List getWxTags(String appid) throws WxErrorException; + + /** + * 创建标签 + * @param appid + * @param name 标签名称 + */ + void creatTag(String appid, String name) throws WxErrorException; + + /** + * 修改标签 + * @param appid + * @param tagid 标签ID + * @param name 标签名称 + */ + void updateTag(String appid, Long tagid, String name) throws WxErrorException; + + /** + * 删除标签 + * + * @param appid + * @param tagid 标签ID + * @throws WxErrorException + */ + void deleteTag(String appid, Long tagid) throws WxErrorException; + + /** + * 批量给用户打标签 + * + * @param appid + * @param tagid 标签ID + * @param openidList 用户openid列表 + * @throws WxErrorException + */ + void batchTagging(String appid, Long tagid, String[] openidList) throws WxErrorException; + + /** + * 批量取消用户标签 + * + * @param appid + * @param tagid 标签ID + * @param openidList 用户openid列表 + * @throws WxErrorException + */ + void batchUnTagging(String appid, Long tagid, String[] openidList) throws WxErrorException; + + /** + * 为用户绑定标签 + * @param tagid + * @param openid + * @throws WxErrorException + */ + void tagging(Long tagid, String openid) throws WxErrorException; + + /** + * 取消用户所绑定的某一个标签 + * @param tagid + * @param openid + * @throws WxErrorException + */ + void untagging(Long tagid, String openid) throws WxErrorException; + + + +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/service/impl/ArticleServiceImpl.java b/czsj-system/src/main/java/com/czsj/wechat/service/impl/ArticleServiceImpl.java new file mode 100644 index 0000000..bc44306 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/service/impl/ArticleServiceImpl.java @@ -0,0 +1,153 @@ +package com.czsj.wechat.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.czsj.wechat.exception.RRException; +import com.czsj.wechat.utils.PageUtils; +import com.czsj.wechat.utils.Query; +import com.czsj.wechat.mapper.ArticleMapper; +import com.czsj.wechat.dto.PageSizeConstant; +import com.czsj.wechat.entity.Article; +import com.czsj.wechat.enums.ArticleTypeEnum; +import com.czsj.wechat.service.ArticleService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; + +import java.util.Date; +import java.util.List; +import java.util.Map; + +/** + * @author Nifury + * @date 2017-10-27 + */ +@Service +public class ArticleServiceImpl extends ServiceImpl implements ArticleService { + private static final String ID_PLACEHOLDER = "${articleId}"; + /** + * 查询文章列表时返回的字段(过滤掉详情字段以加快速度) + */ + private static final String LIST_FILEDS = "id,summary,image,sub_category,update_time,title,type,tags,create_time,target_link,open_count,category"; + @Autowired + ArticleMapper articleMapper; + + @Override + public PageUtils queryPage(Map params) { + String title = (String) params.get("title"); + String type = (String) params.get("type"); + String category = (String) params.get("category"); + String subCategory = (String) params.get("subCategory"); + IPage
page = this.page( + new Query
().getPage(params), + new QueryWrapper
() + .select(LIST_FILEDS) + .eq(StringUtils.hasText(type), "type", type) + .like(StringUtils.hasText(category), "category", category) + .like(StringUtils.hasText(subCategory), "sub_category", subCategory) + .like(StringUtils.hasText(title), "title", title) + ); + + return new PageUtils(page); + } + + /** + * 查询文章详情,每次查询后增加点击次数 + * + * @param id + * @return + */ + @Override + public Article findById(int id) { + if (id <= 0) { + return null; + } + Article article = articleMapper.selectById(id); + if (article != null) { + articleMapper.addOpenCount(id); + } + return article; + } + + + /** + * 添加或编辑文章,同名文章不可重复添加 + * + * @param article + */ + + @Override + public boolean saveArticle(Article article) { + article.setUpdateTime(new Date()); + if (null != article.getId() && article.getId() > 0) { + articleMapper.updateById(article); + } else { + String title = article.getTitle(); + long count = articleMapper.selectCount( + new QueryWrapper
().eq("title", title) + .eq("category", article.getCategory()) + .eq("sub_category", article.getSubCategory()) + ); + if (count > 0) { + throw new RRException("同目录下文章[" + title + "]已存在,不可重复添加"); + } + article.setCreateTime(new Date()); + articleMapper.insert(article); + } + String targetLink = article.getTargetLink(); + if (targetLink.indexOf(ID_PLACEHOLDER) > -1) { + article.setTargetLink(targetLink.replace(ID_PLACEHOLDER, article.getId() + "")); + articleMapper.updateById(article); + } + return true; + } + + /** + * 按条件分页查询 + * + * @param title + * @param page + * @return + */ + @Override + public IPage
getArticles(String title, int page) { + return this.page(new Page
(page, PageSizeConstant.PAGE_SIZE_SMALL), + new QueryWrapper
().like(StringUtils.hasText("title"), "title", title) + .select(LIST_FILEDS) + .orderBy(true, false, "update_time")); + } + + /** + * 查看目录,不返回文章详情字段 + * + * @param articleType + * @param category + * @return + */ + @Override + public List
selectCategory(ArticleTypeEnum articleType, String category) { + return this.list(new QueryWrapper
() + .select(LIST_FILEDS) + .eq("type", articleType.getValue()) + .eq("category", category)); + } + + /** + * 文章查找,不返回文章详情字段 + * + * @param articleType + * @param category + * @param keywords + * @return + */ + @Override + public List
search(ArticleTypeEnum articleType, String category, String keywords) { + return this.list(new QueryWrapper
() + .select(LIST_FILEDS) + .eq("type", articleType.getValue()) + .eq(StringUtils.hasText(category), "category", category) + .and(i -> i.like("summary", keywords).or().like("title", keywords))); + } +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/service/impl/CzsjWxAccountServiceImpl.java b/czsj-system/src/main/java/com/czsj/wechat/service/impl/CzsjWxAccountServiceImpl.java new file mode 100644 index 0000000..8e2c5c6 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/service/impl/CzsjWxAccountServiceImpl.java @@ -0,0 +1,96 @@ +package com.czsj.wechat.service.impl; + +import java.util.List; +import com.czsj.common.utils.DateUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.czsj.wechat.mapper.CzsjWxAccountMapper; +import com.czsj.wechat.domain.CzsjWxAccount; +import com.czsj.wechat.service.ICzsjWxAccountService; + +/** + * 微信公众号Service业务层处理 + * + * @author czsj + * @date 2024-12-07 + */ +@Service +public class CzsjWxAccountServiceImpl implements ICzsjWxAccountService +{ + @Autowired + private CzsjWxAccountMapper czsjWxAccountMapper; + + /** + * 查询微信公众号 + * + * @param uid 微信公众号主键 + * @return 微信公众号 + */ + @Override + public CzsjWxAccount selectCzsjWxAccountByUid(Long uid) + { + return czsjWxAccountMapper.selectCzsjWxAccountByUid(uid); + } + + /** + * 查询微信公众号列表 + * + * @param czsjWxAccount 微信公众号 + * @return 微信公众号 + */ + @Override + public List selectCzsjWxAccountList(CzsjWxAccount czsjWxAccount) + { + return czsjWxAccountMapper.selectCzsjWxAccountList(czsjWxAccount); + } + + /** + * 新增微信公众号 + * + * @param czsjWxAccount 微信公众号 + * @return 结果 + */ + @Override + public int insertCzsjWxAccount(CzsjWxAccount czsjWxAccount) + { + czsjWxAccount.setCreateTime(DateUtils.getNowDate()); + return czsjWxAccountMapper.insertCzsjWxAccount(czsjWxAccount); + } + + /** + * 修改微信公众号 + * + * @param czsjWxAccount 微信公众号 + * @return 结果 + */ + @Override + public int updateCzsjWxAccount(CzsjWxAccount czsjWxAccount) + { + czsjWxAccount.setUpdateTime(DateUtils.getNowDate()); + return czsjWxAccountMapper.updateCzsjWxAccount(czsjWxAccount); + } + + /** + * 批量删除微信公众号 + * + * @param uids 需要删除的微信公众号主键 + * @return 结果 + */ + @Override + public int deleteCzsjWxAccountByUids(Long[] uids) + { + return czsjWxAccountMapper.deleteCzsjWxAccountByUids(uids); + } + + /** + * 删除微信公众号信息 + * + * @param uid 微信公众号主键 + * @return 结果 + */ + @Override + public int deleteCzsjWxAccountByUid(Long uid) + { + return czsjWxAccountMapper.deleteCzsjWxAccountByUid(uid); + } +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/service/impl/CzsjWxMessageServiceImpl.java b/czsj-system/src/main/java/com/czsj/wechat/service/impl/CzsjWxMessageServiceImpl.java new file mode 100644 index 0000000..2d1f72c --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/service/impl/CzsjWxMessageServiceImpl.java @@ -0,0 +1,96 @@ +package com.czsj.wechat.service.impl; + +import java.util.List; +import com.czsj.common.utils.DateUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.czsj.wechat.mapper.CzsjWxMessageMapper; +import com.czsj.wechat.domain.CzsjWxMessage; +import com.czsj.wechat.service.ICzsjWxMessageService; + +/** + * 微信消息Service业务层处理 + * + * @author czsj + * @date 2024-12-07 + */ +@Service +public class CzsjWxMessageServiceImpl implements ICzsjWxMessageService +{ + @Autowired + private CzsjWxMessageMapper czsjWxMessageMapper; + + /** + * 查询微信消息 + * + * @param uid 微信消息主键 + * @return 微信消息 + */ + @Override + public CzsjWxMessage selectCzsjWxMessageByUid(Long uid) + { + return czsjWxMessageMapper.selectCzsjWxMessageByUid(uid); + } + + /** + * 查询微信消息列表 + * + * @param czsjWxMessage 微信消息 + * @return 微信消息 + */ + @Override + public List selectCzsjWxMessageList(CzsjWxMessage czsjWxMessage) + { + return czsjWxMessageMapper.selectCzsjWxMessageList(czsjWxMessage); + } + + /** + * 新增微信消息 + * + * @param czsjWxMessage 微信消息 + * @return 结果 + */ + @Override + public int insertCzsjWxMessage(CzsjWxMessage czsjWxMessage) + { + czsjWxMessage.setCreateTime(DateUtils.getNowDate()); + return czsjWxMessageMapper.insertCzsjWxMessage(czsjWxMessage); + } + + /** + * 修改微信消息 + * + * @param czsjWxMessage 微信消息 + * @return 结果 + */ + @Override + public int updateCzsjWxMessage(CzsjWxMessage czsjWxMessage) + { + czsjWxMessage.setUpdateTime(DateUtils.getNowDate()); + return czsjWxMessageMapper.updateCzsjWxMessage(czsjWxMessage); + } + + /** + * 批量删除微信消息 + * + * @param uids 需要删除的微信消息主键 + * @return 结果 + */ + @Override + public int deleteCzsjWxMessageByUids(Long[] uids) + { + return czsjWxMessageMapper.deleteCzsjWxMessageByUids(uids); + } + + /** + * 删除微信消息信息 + * + * @param uid 微信消息主键 + * @return 结果 + */ + @Override + public int deleteCzsjWxMessageByUid(Long uid) + { + return czsjWxMessageMapper.deleteCzsjWxMessageByUid(uid); + } +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/service/impl/CzsjWxQrCodeServiceImpl.java b/czsj-system/src/main/java/com/czsj/wechat/service/impl/CzsjWxQrCodeServiceImpl.java new file mode 100644 index 0000000..ff9968c --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/service/impl/CzsjWxQrCodeServiceImpl.java @@ -0,0 +1,96 @@ +package com.czsj.wechat.service.impl; + +import java.util.List; +import com.czsj.common.utils.DateUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.czsj.wechat.mapper.CzsjWxQrCodeMapper; +import com.czsj.wechat.domain.CzsjWxQrCode; +import com.czsj.wechat.service.ICzsjWxQrCodeService; + +/** + * 公众号二维码Service业务层处理 + * + * @author czsj + * @date 2024-12-07 + */ +@Service +public class CzsjWxQrCodeServiceImpl implements ICzsjWxQrCodeService +{ + @Autowired + private CzsjWxQrCodeMapper czsjWxQrCodeMapper; + + /** + * 查询公众号二维码 + * + * @param uid 公众号二维码主键 + * @return 公众号二维码 + */ + @Override + public CzsjWxQrCode selectCzsjWxQrCodeByUid(Long uid) + { + return czsjWxQrCodeMapper.selectCzsjWxQrCodeByUid(uid); + } + + /** + * 查询公众号二维码列表 + * + * @param czsjWxQrCode 公众号二维码 + * @return 公众号二维码 + */ + @Override + public List selectCzsjWxQrCodeList(CzsjWxQrCode czsjWxQrCode) + { + return czsjWxQrCodeMapper.selectCzsjWxQrCodeList(czsjWxQrCode); + } + + /** + * 新增公众号二维码 + * + * @param czsjWxQrCode 公众号二维码 + * @return 结果 + */ + @Override + public int insertCzsjWxQrCode(CzsjWxQrCode czsjWxQrCode) + { + czsjWxQrCode.setCreateTime(DateUtils.getNowDate()); + return czsjWxQrCodeMapper.insertCzsjWxQrCode(czsjWxQrCode); + } + + /** + * 修改公众号二维码 + * + * @param czsjWxQrCode 公众号二维码 + * @return 结果 + */ + @Override + public int updateCzsjWxQrCode(CzsjWxQrCode czsjWxQrCode) + { + czsjWxQrCode.setUpdateTime(DateUtils.getNowDate()); + return czsjWxQrCodeMapper.updateCzsjWxQrCode(czsjWxQrCode); + } + + /** + * 批量删除公众号二维码 + * + * @param uids 需要删除的公众号二维码主键 + * @return 结果 + */ + @Override + public int deleteCzsjWxQrCodeByUids(Long[] uids) + { + return czsjWxQrCodeMapper.deleteCzsjWxQrCodeByUids(uids); + } + + /** + * 删除公众号二维码信息 + * + * @param uid 公众号二维码主键 + * @return 结果 + */ + @Override + public int deleteCzsjWxQrCodeByUid(Long uid) + { + return czsjWxQrCodeMapper.deleteCzsjWxQrCodeByUid(uid); + } +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/service/impl/CzsjWxReplyRuleServiceImpl.java b/czsj-system/src/main/java/com/czsj/wechat/service/impl/CzsjWxReplyRuleServiceImpl.java new file mode 100644 index 0000000..9ec7545 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/service/impl/CzsjWxReplyRuleServiceImpl.java @@ -0,0 +1,96 @@ +package com.czsj.wechat.service.impl; + +import java.util.List; +import com.czsj.common.utils.DateUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.czsj.wechat.mapper.CzsjWxReplyRuleMapper; +import com.czsj.wechat.domain.CzsjWxReplyRule; +import com.czsj.wechat.service.ICzsjWxReplyRuleService; + +/** + * 微信消息回复规则Service业务层处理 + * + * @author czsj + * @date 2024-12-07 + */ +@Service +public class CzsjWxReplyRuleServiceImpl implements ICzsjWxReplyRuleService +{ + @Autowired + private CzsjWxReplyRuleMapper czsjWxReplyRuleMapper; + + /** + * 查询微信消息回复规则 + * + * @param uid 微信消息回复规则主键 + * @return 微信消息回复规则 + */ + @Override + public CzsjWxReplyRule selectCzsjWxReplyRuleByUid(Long uid) + { + return czsjWxReplyRuleMapper.selectCzsjWxReplyRuleByUid(uid); + } + + /** + * 查询微信消息回复规则列表 + * + * @param czsjWxReplyRule 微信消息回复规则 + * @return 微信消息回复规则 + */ + @Override + public List selectCzsjWxReplyRuleList(CzsjWxReplyRule czsjWxReplyRule) + { + return czsjWxReplyRuleMapper.selectCzsjWxReplyRuleList(czsjWxReplyRule); + } + + /** + * 新增微信消息回复规则 + * + * @param czsjWxReplyRule 微信消息回复规则 + * @return 结果 + */ + @Override + public int insertCzsjWxReplyRule(CzsjWxReplyRule czsjWxReplyRule) + { + czsjWxReplyRule.setCreateTime(DateUtils.getNowDate()); + return czsjWxReplyRuleMapper.insertCzsjWxReplyRule(czsjWxReplyRule); + } + + /** + * 修改微信消息回复规则 + * + * @param czsjWxReplyRule 微信消息回复规则 + * @return 结果 + */ + @Override + public int updateCzsjWxReplyRule(CzsjWxReplyRule czsjWxReplyRule) + { + czsjWxReplyRule.setUpdateTime(DateUtils.getNowDate()); + return czsjWxReplyRuleMapper.updateCzsjWxReplyRule(czsjWxReplyRule); + } + + /** + * 批量删除微信消息回复规则 + * + * @param uids 需要删除的微信消息回复规则主键 + * @return 结果 + */ + @Override + public int deleteCzsjWxReplyRuleByUids(Long[] uids) + { + return czsjWxReplyRuleMapper.deleteCzsjWxReplyRuleByUids(uids); + } + + /** + * 删除微信消息回复规则信息 + * + * @param uid 微信消息回复规则主键 + * @return 结果 + */ + @Override + public int deleteCzsjWxReplyRuleByUid(Long uid) + { + return czsjWxReplyRuleMapper.deleteCzsjWxReplyRuleByUid(uid); + } +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/service/impl/CzsjWxTemplateLogServiceImpl.java b/czsj-system/src/main/java/com/czsj/wechat/service/impl/CzsjWxTemplateLogServiceImpl.java new file mode 100644 index 0000000..ca26e5b --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/service/impl/CzsjWxTemplateLogServiceImpl.java @@ -0,0 +1,96 @@ +package com.czsj.wechat.service.impl; + +import java.util.List; +import com.czsj.common.utils.DateUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.czsj.wechat.mapper.CzsjWxTemplateLogMapper; +import com.czsj.wechat.domain.CzsjWxTemplateLog; +import com.czsj.wechat.service.ICzsjWxTemplateLogService; + +/** + * 微信消息模板日志Service业务层处理 + * + * @author czsj + * @date 2024-12-07 + */ +@Service +public class CzsjWxTemplateLogServiceImpl implements ICzsjWxTemplateLogService +{ + @Autowired + private CzsjWxTemplateLogMapper czsjWxTemplateLogMapper; + + /** + * 查询微信消息模板日志 + * + * @param uid 微信消息模板日志主键 + * @return 微信消息模板日志 + */ + @Override + public CzsjWxTemplateLog selectCzsjWxTemplateLogByUid(Long uid) + { + return czsjWxTemplateLogMapper.selectCzsjWxTemplateLogByUid(uid); + } + + /** + * 查询微信消息模板日志列表 + * + * @param czsjWxTemplateLog 微信消息模板日志 + * @return 微信消息模板日志 + */ + @Override + public List selectCzsjWxTemplateLogList(CzsjWxTemplateLog czsjWxTemplateLog) + { + return czsjWxTemplateLogMapper.selectCzsjWxTemplateLogList(czsjWxTemplateLog); + } + + /** + * 新增微信消息模板日志 + * + * @param czsjWxTemplateLog 微信消息模板日志 + * @return 结果 + */ + @Override + public int insertCzsjWxTemplateLog(CzsjWxTemplateLog czsjWxTemplateLog) + { + czsjWxTemplateLog.setCreateTime(DateUtils.getNowDate()); + return czsjWxTemplateLogMapper.insertCzsjWxTemplateLog(czsjWxTemplateLog); + } + + /** + * 修改微信消息模板日志 + * + * @param czsjWxTemplateLog 微信消息模板日志 + * @return 结果 + */ + @Override + public int updateCzsjWxTemplateLog(CzsjWxTemplateLog czsjWxTemplateLog) + { + czsjWxTemplateLog.setUpdateTime(DateUtils.getNowDate()); + return czsjWxTemplateLogMapper.updateCzsjWxTemplateLog(czsjWxTemplateLog); + } + + /** + * 批量删除微信消息模板日志 + * + * @param uids 需要删除的微信消息模板日志主键 + * @return 结果 + */ + @Override + public int deleteCzsjWxTemplateLogByUids(Long[] uids) + { + return czsjWxTemplateLogMapper.deleteCzsjWxTemplateLogByUids(uids); + } + + /** + * 删除微信消息模板日志信息 + * + * @param uid 微信消息模板日志主键 + * @return 结果 + */ + @Override + public int deleteCzsjWxTemplateLogByUid(Long uid) + { + return czsjWxTemplateLogMapper.deleteCzsjWxTemplateLogByUid(uid); + } +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/service/impl/CzsjWxTemplateServiceImpl.java b/czsj-system/src/main/java/com/czsj/wechat/service/impl/CzsjWxTemplateServiceImpl.java new file mode 100644 index 0000000..5df4389 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/service/impl/CzsjWxTemplateServiceImpl.java @@ -0,0 +1,96 @@ +package com.czsj.wechat.service.impl; + +import java.util.List; +import com.czsj.common.utils.DateUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.czsj.wechat.mapper.CzsjWxTemplateMapper; +import com.czsj.wechat.domain.CzsjWxTemplate; +import com.czsj.wechat.service.ICzsjWxTemplateService; + +/** + * 微信消息模板Service业务层处理 + * + * @author czsj + * @date 2024-12-07 + */ +@Service +public class CzsjWxTemplateServiceImpl implements ICzsjWxTemplateService +{ + @Autowired + private CzsjWxTemplateMapper czsjWxTemplateMapper; + + /** + * 查询微信消息模板 + * + * @param uid 微信消息模板主键 + * @return 微信消息模板 + */ + @Override + public CzsjWxTemplate selectCzsjWxTemplateByUid(Long uid) + { + return czsjWxTemplateMapper.selectCzsjWxTemplateByUid(uid); + } + + /** + * 查询微信消息模板列表 + * + * @param czsjWxTemplate 微信消息模板 + * @return 微信消息模板 + */ + @Override + public List selectCzsjWxTemplateList(CzsjWxTemplate czsjWxTemplate) + { + return czsjWxTemplateMapper.selectCzsjWxTemplateList(czsjWxTemplate); + } + + /** + * 新增微信消息模板 + * + * @param czsjWxTemplate 微信消息模板 + * @return 结果 + */ + @Override + public int insertCzsjWxTemplate(CzsjWxTemplate czsjWxTemplate) + { + czsjWxTemplate.setCreateTime(DateUtils.getNowDate()); + return czsjWxTemplateMapper.insertCzsjWxTemplate(czsjWxTemplate); + } + + /** + * 修改微信消息模板 + * + * @param czsjWxTemplate 微信消息模板 + * @return 结果 + */ + @Override + public int updateCzsjWxTemplate(CzsjWxTemplate czsjWxTemplate) + { + czsjWxTemplate.setUpdateTime(DateUtils.getNowDate()); + return czsjWxTemplateMapper.updateCzsjWxTemplate(czsjWxTemplate); + } + + /** + * 批量删除微信消息模板 + * + * @param uids 需要删除的微信消息模板主键 + * @return 结果 + */ + @Override + public int deleteCzsjWxTemplateByUids(Long[] uids) + { + return czsjWxTemplateMapper.deleteCzsjWxTemplateByUids(uids); + } + + /** + * 删除微信消息模板信息 + * + * @param uid 微信消息模板主键 + * @return 结果 + */ + @Override + public int deleteCzsjWxTemplateByUid(Long uid) + { + return czsjWxTemplateMapper.deleteCzsjWxTemplateByUid(uid); + } +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/service/impl/MsgReplyRuleServiceImpl.java b/czsj-system/src/main/java/com/czsj/wechat/service/impl/MsgReplyRuleServiceImpl.java new file mode 100644 index 0000000..702e0bd --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/service/impl/MsgReplyRuleServiceImpl.java @@ -0,0 +1,127 @@ +package com.czsj.wechat.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.czsj.wechat.utils.PageUtils; +import com.czsj.wechat.utils.Query; +import com.czsj.wechat.mapper.MsgReplyRuleMapper; +import com.czsj.wechat.entity.MsgReplyRule; +import com.czsj.wechat.service.MsgReplyRuleService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; + +import java.time.LocalTime; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Service +public class MsgReplyRuleServiceImpl extends ServiceImpl implements MsgReplyRuleService { + @Autowired + MsgReplyRuleMapper msgReplyRuleMapper; + + @Override + public PageUtils queryPage(Map params) { + String matchValue = (String) params.get("matchValue"); + String appid = (String) params.get("appid"); + IPage page = this.page( + new Query().getPage(params), + new QueryWrapper() + .eq(StringUtils.hasText(appid), "appid", appid) + .or() + .apply("appid is null or appid = ''") + .like(StringUtils.hasText(matchValue), "match_value", matchValue) + .orderByDesc("update_time") + ); + + return new PageUtils(page); + } + + /** + * 保存自动回复规则 + * + * @param msgReplyRule + */ + + @Override + public boolean save(MsgReplyRule msgReplyRule) { + if (msgReplyRule.getRuleId() > 0) { + msgReplyRuleMapper.updateById(msgReplyRule); + } else { + msgReplyRuleMapper.insert(msgReplyRule); + } + return false; + } + + /** + * 获取所有的回复规则 + * + * @return + */ + @Override + public List getRules() { + return msgReplyRuleMapper.selectList(new QueryWrapper().orderByDesc("rule_id")); + } + + /** + * 获取当前时段内所有有效的回复规则 + * + * @return + */ + @Override + public List getValidRules() { + return msgReplyRuleMapper.selectList( + new QueryWrapper() + .eq("status", 1) + .isNotNull("match_value") + .ne("match_value", "") + .orderByDesc("priority")); + } + + /** + * 筛选符合条件的回复规则 + * + * + * @param appid 公众号appid + * @param exactMatch 是否精确匹配 + * @param keywords 关键词 + * @return 规则列表 + */ + @Override + public List getMatchedRules(String appid, boolean exactMatch, String keywords) { + LocalTime now = LocalTime.now(); + return this.getValidRules().stream() + .filter(rule->!StringUtils.hasText(rule.getAppid()) || appid.equals(rule.getAppid())) // 检测是否是对应公众号的规则,如果appid为空则为通用规则 + .filter(rule->null == rule.getEffectTimeStart() || rule.getEffectTimeStart().toLocalTime().isBefore(now))// 检测是否在有效时段,effectTimeStart为null则一直有效 + .filter(rule->null == rule.getEffectTimeEnd() || rule.getEffectTimeEnd().toLocalTime().isAfter(now)) // 检测是否在有效时段,effectTimeEnd为null则一直有效 + .filter(rule->isMatch(exactMatch || rule.isExactMatch(),rule.getMatchValue().split(","),keywords)) //检测是否符合匹配规则 + .collect(Collectors.toList()); + } + + /** + * 检测文字是否匹配规则 + * 精确匹配时,需关键词与规则词语一致 + * 非精确匹配时,检测文字需包含任意一个规则词语 + * + * @param exactMatch 是否精确匹配 + * @param ruleWords 规则列表 + * @param checkWords 需检测的文字 + * @return + */ + public static boolean isMatch(boolean exactMatch, String[] ruleWords, String checkWords) { + if (!StringUtils.hasText(checkWords)) { + return false; + } + for (String words : ruleWords) { + if (exactMatch && words.equals(checkWords)) { + return true;//精确匹配,需关键词与规则词语一致 + } + if (!exactMatch && checkWords.contains(words)) { + return true;//模糊匹配 + } + } + return false; + } +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/service/impl/MsgReplyServiceImpl.java b/czsj-system/src/main/java/com/czsj/wechat/service/impl/MsgReplyServiceImpl.java new file mode 100644 index 0000000..ba538da --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/service/impl/MsgReplyServiceImpl.java @@ -0,0 +1,189 @@ +package com.czsj.wechat.service.impl; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.czsj.wechat.config.TaskExcutor; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.kefu.WxMpKefuMessage; + +import com.czsj.wechat.entity.MsgReplyRule; +import com.czsj.wechat.entity.WxMsg; +import com.czsj.wechat.service.MsgReplyRuleService; +import com.czsj.wechat.service.MsgReplyService; +import com.czsj.wechat.service.WxMsgService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +/** + * 微信公众号消息处理 + * 官方文档:https://developers.weixin.qq.com/doc/offiaccount/Message_Ma nagement/Service_Center_messages.html#7 + * 参考WxJava客服消息文档:https://github.com/Wechat-Group/WxJava/wiki/MP_主动发送消息(客服消息) + */ +@Service +@RequiredArgsConstructor +@Slf4j +public class MsgReplyServiceImpl implements MsgReplyService { + @Autowired + MsgReplyRuleService msgReplyRuleService; + @Autowired + WxMpService wxMpService; + @Value("${wx.mp.autoReplyInterval:1000}") + Long autoReplyInterval; + @Autowired + WxMsgService wxMsgService; + + /** + * 根据规则配置通过微信客服消息接口自动回复消息 + * + * + * @param appid 公众号appid + * @param exactMatch 是否精确匹配 + * @param toUser 用户openid + * @param keywords 匹配关键词 + * @return 是否已自动回复,无匹配规则则不自动回复 + */ + @Override + public boolean tryAutoReply(String appid, boolean exactMatch, String toUser, String keywords) { + try { + List rules = msgReplyRuleService.getMatchedRules(appid,exactMatch, keywords); + if (rules.isEmpty()) { + return false; + } + long delay = 0; + for (MsgReplyRule rule : rules) { + TaskExcutor.schedule(() -> { + wxMpService.switchover(appid); + this.reply(toUser,rule.getReplyType(),rule.getReplyContent()); + }, delay, TimeUnit.MILLISECONDS); + delay += autoReplyInterval; + } + return true; + } catch (Exception e) { + log.error("自动回复出错:", e); + } + return false; + } + + @Override + public void replyText(String toUser, String content) throws WxErrorException { + wxMpService.getKefuService().sendKefuMessage(WxMpKefuMessage.TEXT().toUser(toUser).content(content).build()); + + JSONObject json = new JSONObject().fluentPut("content",content); + wxMsgService.addWxMsg(WxMsg.buildOutMsg(WxConsts.KefuMsgType.TEXT,toUser,json)); + } + + @Override + public void replyImage(String toUser, String mediaId) throws WxErrorException { + wxMpService.getKefuService().sendKefuMessage(WxMpKefuMessage.IMAGE().toUser(toUser).mediaId(mediaId).build()); + + JSONObject json = new JSONObject().fluentPut("mediaId",mediaId); + wxMsgService.addWxMsg(WxMsg.buildOutMsg(WxConsts.KefuMsgType.IMAGE,toUser,json)); + } + + @Override + public void replyVoice(String toUser, String mediaId) throws WxErrorException { + wxMpService.getKefuService().sendKefuMessage(WxMpKefuMessage.VOICE().toUser(toUser).mediaId(mediaId).build()); + + JSONObject json = new JSONObject().fluentPut("mediaId",mediaId); + wxMsgService.addWxMsg(WxMsg.buildOutMsg(WxConsts.KefuMsgType.VOICE,toUser,json)); + } + + @Override + public void replyVideo(String toUser, String mediaId) throws WxErrorException { + wxMpService.getKefuService().sendKefuMessage(WxMpKefuMessage.VIDEO().toUser(toUser).mediaId(mediaId).build()); + + JSONObject json = new JSONObject().fluentPut("mediaId",mediaId); + wxMsgService.addWxMsg(WxMsg.buildOutMsg(WxConsts.KefuMsgType.VIDEO,toUser,json)); + } + + @Override + public void replyMusic(String toUser, String musicInfoJson) throws WxErrorException { + JSONObject json = JSON.parseObject(musicInfoJson); + wxMpService.getKefuService().sendKefuMessage( + WxMpKefuMessage.MUSIC().toUser(toUser) + .musicUrl(json.getString("musicurl")) + .hqMusicUrl(json.getString("hqmusicurl")) + .title(json.getString("title")) + .description(json.getString("description")) + .thumbMediaId(json.getString("thumb_media_id")) + .build()); + + wxMsgService.addWxMsg(WxMsg.buildOutMsg(WxConsts.KefuMsgType.IMAGE,toUser,json)); + } + + /** + * 发送图文消息(点击跳转到外链) 图文消息条数限制在1条以内 + * @param toUser + * @param newsInfoJson + * @throws WxErrorException + */ + @Override + public void replyNews(String toUser, String newsInfoJson) throws WxErrorException { + WxMpKefuMessage.WxArticle wxArticle = JSON.parseObject(newsInfoJson, WxMpKefuMessage.WxArticle.class); + List newsList = new ArrayList(){{add(wxArticle);}}; + wxMpService.getKefuService().sendKefuMessage(WxMpKefuMessage.NEWS().toUser(toUser).articles(newsList).build()); + + wxMsgService.addWxMsg(WxMsg.buildOutMsg(WxConsts.KefuMsgType.NEWS,toUser,JSON.parseObject(newsInfoJson))); + } + + /** + * 发送图文消息(点击跳转到图文消息页面) 图文消息条数限制在1条以内 + * @param toUser + * @param mediaId + * @throws WxErrorException + */ + @Override + public void replyMpNews(String toUser, String mediaId) throws WxErrorException { + wxMpService.getKefuService().sendKefuMessage(WxMpKefuMessage.MPNEWS().toUser(toUser).mediaId(mediaId).build()); + + JSONObject json = new JSONObject().fluentPut("mediaId",mediaId); + wxMsgService.addWxMsg(WxMsg.buildOutMsg(WxConsts.KefuMsgType.MPNEWS,toUser,json)); + } + + @Override + public void replyWxCard(String toUser, String cardId) throws WxErrorException { + wxMpService.getKefuService().sendKefuMessage(WxMpKefuMessage.WXCARD().toUser(toUser).cardId(cardId).build()); + + JSONObject json = new JSONObject().fluentPut("cardId",cardId); + wxMsgService.addWxMsg(WxMsg.buildOutMsg(WxConsts.KefuMsgType.WXCARD,toUser,json)); + } + + @Override + public void replyMiniProgram(String toUser, String miniProgramInfoJson) throws WxErrorException { + JSONObject json = JSON.parseObject(miniProgramInfoJson); + wxMpService.getKefuService().sendKefuMessage( + WxMpKefuMessage.MINIPROGRAMPAGE() + .toUser(toUser) + .title(json.getString("title")) + .appId(json.getString("appid")) + .pagePath(json.getString("pagepath")) + .thumbMediaId(json.getString("thumb_media_id")) + .build()); + + wxMsgService.addWxMsg(WxMsg.buildOutMsg(WxConsts.KefuMsgType.IMAGE,toUser,json)); + } + + @Override + public void replyMsgMenu(String toUser, String msgMenusJson) throws WxErrorException { + JSONObject json = JSON.parseObject(msgMenusJson); + List msgMenus = JSON.parseArray(json.getString("list"),WxMpKefuMessage.MsgMenu.class); + wxMpService.getKefuService().sendKefuMessage( + WxMpKefuMessage.MSGMENU() + .toUser(toUser) + .headContent(json.getString("head_content")) + .tailContent(json.getString("tail_content")) + .msgMenus(msgMenus).build()); + + wxMsgService.addWxMsg(WxMsg.buildOutMsg(WxConsts.KefuMsgType.IMAGE,toUser,json)); + } + +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/service/impl/MsgTemplateServiceImpl.java b/czsj-system/src/main/java/com/czsj/wechat/service/impl/MsgTemplateServiceImpl.java new file mode 100644 index 0000000..9e031ed --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/service/impl/MsgTemplateServiceImpl.java @@ -0,0 +1,71 @@ +package com.czsj.wechat.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.czsj.wechat.utils.PageUtils; +import com.czsj.wechat.utils.Query; +import com.czsj.wechat.mapper.MsgTemplateMapper; +import com.czsj.wechat.entity.MsgTemplate; +import com.czsj.wechat.service.MsgTemplateService; +import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.bean.template.WxMpTemplate; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + + +@Service("msgTemplateService") +@Slf4j +public class MsgTemplateServiceImpl extends ServiceImpl implements MsgTemplateService { + + @Override + public PageUtils queryPage(Map params) { + String title = (String) params.get("title"); + String name = (String) params.get("name"); + String appid = (String) params.get("appid"); + IPage page = this.page( + new Query().getPage(params), + new QueryWrapper() + .eq(StringUtils.hasText(appid), "appid", appid) + .like(StringUtils.hasText(title), "title", title) + .like(StringUtils.hasText(name), "name", name) + ); + + return new PageUtils(page); + } + + @Override + public MsgTemplate selectByName(String name) { + Assert.hasText(name, "模板名称不得为空"); + return this.getOne(new QueryWrapper() + .eq("name", name) + .eq("status", 1) + .last("LIMIT 1")); + } + + @Transactional(rollbackFor = Exception.class) + @Override + public void syncWxTemplate(String appid, List allPrivateTemplateList) throws WxErrorException { + List templates = allPrivateTemplateList.stream().map(item -> new MsgTemplate(item, appid)).collect(Collectors.toList()); + List templateIds = templates.stream().map(MsgTemplate::getTemplateId).collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(templateIds)) { + LambdaQueryWrapper qryRoomUser = Wrappers.lambdaQuery(); + qryRoomUser.in(MsgTemplate::getTemplateId, templateIds); + this.remove(qryRoomUser); + this.saveBatch(templates); + return; + } + log.info("没有模板 appid {} ", appid); + } + +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/service/impl/TemplateMsgLogServiceImpl.java b/czsj-system/src/main/java/com/czsj/wechat/service/impl/TemplateMsgLogServiceImpl.java new file mode 100644 index 0000000..45aa06b --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/service/impl/TemplateMsgLogServiceImpl.java @@ -0,0 +1,42 @@ +package com.czsj.wechat.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.czsj.wechat.utils.PageUtils; +import com.czsj.wechat.utils.Query; +import com.czsj.wechat.mapper.TemplateMsgLogMapper; +import com.czsj.wechat.entity.TemplateMsgLog; +import com.czsj.wechat.service.TemplateMsgLogService; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; + +import java.util.Map; + +@Service +public class TemplateMsgLogServiceImpl extends ServiceImpl implements TemplateMsgLogService { + + @Override + public PageUtils queryPage(Map params) { + String appid = (String) params.get("appid"); + IPage page = this.page( + new Query().getPage(params), + new QueryWrapper() + .eq(StringUtils.hasText(appid), "appid", appid) + ); + + return new PageUtils(page); + } + + /** + * 记录log,异步入库 + * + * @param log + */ + @Override + @Async + public void addLog(TemplateMsgLog log) { + this.baseMapper.insert(log); + } +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/service/impl/TemplateMsgServiceImpl.java b/czsj-system/src/main/java/com/czsj/wechat/service/impl/TemplateMsgServiceImpl.java new file mode 100644 index 0000000..2ee9f3e --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/service/impl/TemplateMsgServiceImpl.java @@ -0,0 +1,91 @@ +package com.czsj.wechat.service.impl; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.czsj.wechat.entity.TemplateMsgLog; +import com.czsj.wechat.entity.WxUser; +import com.czsj.wechat.form.TemplateMsgBatchForm; +import com.czsj.wechat.service.MsgTemplateService; +import com.czsj.wechat.service.TemplateMsgLogService; +import com.czsj.wechat.service.TemplateMsgService; +import com.czsj.wechat.service.WxUserService; +import lombok.RequiredArgsConstructor; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author Nifury + * @date 2017-9-27 + */ +@Service +@RequiredArgsConstructor +public class TemplateMsgServiceImpl implements TemplateMsgService { + Logger logger = LoggerFactory.getLogger(this.getClass()); + @Autowired + private TemplateMsgLogService templateMsgLogService; + private final WxMpService wxService; + @Autowired + MsgTemplateService msgTemplateService; + @Autowired + WxUserService wxUserService; + + /** + * 发送微信模版消息,使用固定线程的线程池 + */ + @Override + @Async + public void sendTemplateMsg(WxMpTemplateMessage msg,String appid) { + String result; + try { + wxService.switchover(appid); + result = wxService.getTemplateMsgService().sendTemplateMsg(msg); + } catch (WxErrorException e) { + result = e.getMessage(); + } + + //保存发送日志 + TemplateMsgLog log = new TemplateMsgLog(msg,appid, result); + templateMsgLogService.addLog(log); + } + + @Override + @Async + public void sendMsgBatch(TemplateMsgBatchForm form, String appid) { + logger.info("批量发送模板消息任务开始,参数:{}",form.toString()); + wxService.switchover(appid); + WxMpTemplateMessage.WxMpTemplateMessageBuilder builder = WxMpTemplateMessage.builder() + .templateId(form.getTemplateId()) + .url(form.getUrl()) + .miniProgram(form.getMiniprogram()) + .data(form.getData()); + Map filterParams = form.getWxUserFilterParams(); + if(filterParams==null) { + filterParams=new HashMap<>(8); + } + long currentPage=1L,totalPages=Long.MAX_VALUE; + filterParams.put("appid",appid); + filterParams.put("limit","500"); + while (currentPage<=totalPages){ + filterParams.put("page",String.valueOf(currentPage)); + //按条件查询用户 + IPage wxUsers = wxUserService.queryPage(filterParams); + logger.info("批量发送模板消息任务,使用查询条件,处理第{}页,总用户数:{}",currentPage,wxUsers.getTotal()); + wxUsers.getRecords().forEach(user->{ + WxMpTemplateMessage msg = builder.toUser(user.getOpenid()).build(); + this.sendTemplateMsg(msg,appid); + }); + currentPage=wxUsers.getCurrent()+1L; + totalPages=wxUsers.getPages(); + } + logger.info("批量发送模板消息任务结束"); + } + +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/service/impl/WxAccountServiceImpl.java b/czsj-system/src/main/java/com/czsj/wechat/service/impl/WxAccountServiceImpl.java new file mode 100644 index 0000000..871346d --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/service/impl/WxAccountServiceImpl.java @@ -0,0 +1,113 @@ +package com.czsj.wechat.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.baomidou.mybatisplus.extension.toolkit.SqlHelper; +import com.czsj.wechat.utils.PageUtils; +import com.czsj.wechat.utils.Query; +import com.czsj.wechat.mapper.WxAccountMapper; +import com.czsj.wechat.entity.WxAccount; +import com.czsj.wechat.service.WxAccountService; +import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.common.redis.WxRedisOps; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl; +import me.chanjar.weixin.mp.config.impl.WxMpRedisConfigImpl; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; + +import javax.annotation.PostConstruct; +import java.util.Collection; +import java.util.List; +import java.util.Map; + + +@Service("wxAccountService") +@Slf4j +public class WxAccountServiceImpl extends ServiceImpl implements WxAccountService { + + @Autowired + private WxMpService wxMpService; + + @Autowired + private WxRedisOps wxRedisOps; + + @Override + public PageUtils queryPage(Map params) { + String name = (String) params.get("name"); + IPage page = this.page( + new Query().getPage(params), + new QueryWrapper() + .like(StringUtils.hasText(name), "name", name) + ); + + return new PageUtils(page); + } + + @PostConstruct + public void loadWxMpConfigStorages(){ + log.info("加载公众号配置..."); +// List accountList = this.list(); +// if (accountList == null || accountList.isEmpty()) { +// log.info("未读取到公众号配置,请在管理后台添加"); +// return; +// } +// log.info("加载到{}条公众号配置",accountList.size()); +// accountList.forEach(this::addAccountToRuntime); + log.info("公众号配置加载完成"); + } + + @Override + public boolean saveOrUpdateWxAccount(WxAccount entity) { + Assert.notNull(entity, "WxAccount不得为空"); + boolean saveOrUpdate = saveOrUpdate(entity); + log.info(" saveOrUpdate {} appid: {} ", saveOrUpdate, entity.getAppid()); + this.addAccountToRuntime(entity); + return saveOrUpdate; + } + + @Override + public boolean removeByIds(Collection idList) { + Assert.notEmpty(idList,"WxAccount不得为空"); + // 更新wxMpService配置 + log.info("同步移除公众号配置"); + idList.forEach(id-> wxMpService.removeConfigStorage((String) id)); + return SqlHelper.retBool(this.baseMapper.deleteBatchIds(idList)); + } + + /** + * 判断当前账号是存在 + * @param appid + * @return + */ + private boolean isAccountInRuntime(String appid){ + try { + return wxMpService.switchover(appid); + }catch (NullPointerException e){// sdk bug,未添加任何账号时configStorageMap为null会出错 + return false; + } + } + /** + * 添加账号到当前程序,如首次添加需初始化configStorageMap + * @param entity + */ + private synchronized void addAccountToRuntime(WxAccount entity) { + String appid = entity.getAppid(); + WxMpDefaultConfigImpl config = buildWxMpConfigImpl(entity); + wxMpService.addConfigStorage(appid, config); + } + + private WxMpDefaultConfigImpl buildWxMpConfigImpl(WxAccount entity) { + WxMpRedisConfigImpl configStorage = new WxMpRedisConfigImpl(wxRedisOps, "v1:@ss.hasPermi(mp"); + configStorage.setAppId(entity.getAppid()); + configStorage.setSecret(entity.getSecret()); + configStorage.setToken(entity.getToken()); + configStorage.setAesKey(entity.getAesKey()); + return configStorage; + } + + +} \ No newline at end of file diff --git a/czsj-system/src/main/java/com/czsj/wechat/service/impl/WxAssetsServiceImpl.java b/czsj-system/src/main/java/com/czsj/wechat/service/impl/WxAssetsServiceImpl.java new file mode 100644 index 0000000..f9a5989 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/service/impl/WxAssetsServiceImpl.java @@ -0,0 +1,122 @@ +package com.czsj.wechat.service.impl; + +import com.czsj.wechat.dto.PageSizeConstant; +import com.czsj.wechat.service.WxAssetsService; +import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.draft.WxMpAddDraft; +import me.chanjar.weixin.mp.bean.draft.WxMpDraftArticles; +import me.chanjar.weixin.mp.bean.draft.WxMpUpdateDraft; +import me.chanjar.weixin.mp.bean.material.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; +import org.springframework.util.Assert; +import org.springframework.web.multipart.MultipartFile; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.Objects; + +@Service +@CacheConfig(cacheNames = {"wxAssetsServiceCache"}) +@Slf4j +public class WxAssetsServiceImpl implements WxAssetsService { + @Autowired + WxMpService wxMpService; + + @Override + @Cacheable(key="methodName+ #appid") + public WxMpMaterialCountResult materialCount(String appid) throws WxErrorException { + log.info("从API获取素材总量"); + wxMpService.switchoverTo(appid); + return wxMpService.getMaterialService().materialCount(); + } + + @Override + @Cacheable(key="methodName + #appid + #mediaId") + public WxMpMaterialNews materialNewsInfo(String appid, String mediaId) throws WxErrorException { + log.info("从API获取图文素材详情,mediaId={}",mediaId); + wxMpService.switchoverTo(appid); + return wxMpService.getMaterialService().materialNewsInfo(mediaId); + } + + @Override + @Cacheable(key="methodName + #appid + #type + #page") + public WxMpMaterialFileBatchGetResult materialFileBatchGet(String appid, String type, int page) throws WxErrorException { + log.info("从API获取媒体素材列表,type={},page={}",type,page); + wxMpService.switchoverTo(appid); + final int pageSize = PageSizeConstant.PAGE_SIZE_SMALL; + int offset=(page-1)* pageSize; + return wxMpService.getMaterialService().materialFileBatchGet(type,offset, pageSize); + } + + @Cacheable(key="methodName + #appid + #page") + @Override + public WxMpMaterialNewsBatchGetResult materialNewsBatchGet(String appid, int page) throws WxErrorException { + log.info("从API获取媒体素材列表,page={}",page); + wxMpService.switchoverTo(appid); + final int pageSize = PageSizeConstant.PAGE_SIZE_SMALL; + int offset=(page-1)*pageSize; + return wxMpService.getMaterialService().materialNewsBatchGet(offset, pageSize); + } + + @Override + @CacheEvict(allEntries = true) + public WxMpMaterialUploadResult materialNewsUpload(String appid, List articles) throws WxErrorException { + Assert.notEmpty(articles,"图文列表不得为空"); + log.info("上传图文素材..."); + wxMpService.switchoverTo(appid); + WxMpAddDraft news = new WxMpAddDraft(); + news.setArticles(articles); + String draftMediaId = wxMpService.getDraftService().addDraft(news); + WxMpMaterialUploadResult result = new WxMpMaterialUploadResult(); + result.setMediaId(draftMediaId); + result.setErrCode(0); + return result; + } + + /** + * 更新图文素材中的某篇文章 + * @param appid + * @param form + */ + @Override + @CacheEvict(allEntries = true) + public void materialArticleUpdate(String appid, WxMpUpdateDraft form) throws WxErrorException{ + log.info("更新图文素材..."); + wxMpService.switchoverTo(appid); + wxMpService.getDraftService().updateDraft(form); + } + @Override + @CacheEvict(allEntries = true) + public WxMpMaterialUploadResult materialFileUpload(String appid, String mediaType, String fileName, MultipartFile file) throws WxErrorException, IOException { + log.info("上传媒体素材:{}",fileName); + wxMpService.switchoverTo(appid); + String originalFilename=file.getOriginalFilename(); + File tempFile = File.createTempFile(fileName+"--", Objects.requireNonNull(originalFilename).substring(originalFilename.lastIndexOf("."))); + file.transferTo(tempFile); + WxMpMaterial wxMaterial = new WxMpMaterial(); + wxMaterial.setFile(tempFile); + wxMaterial.setName(fileName); + if(WxConsts.MediaFileType.VIDEO.equals(mediaType)){ + wxMaterial.setVideoTitle(fileName); + } + WxMpMaterialUploadResult res = wxMpService.getMaterialService().materialFileUpload(mediaType,wxMaterial); + tempFile.deleteOnExit(); + return res; + } + + @Override + @CacheEvict(allEntries = true) + public boolean materialDelete(String appid, String mediaId) throws WxErrorException { + log.info("删除素材,mediaId={}",mediaId); + wxMpService.switchoverTo(appid); + return wxMpService.getMaterialService().materialDelete(mediaId); + } +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/service/impl/WxMsgServiceImpl.java b/czsj-system/src/main/java/com/czsj/wechat/service/impl/WxMsgServiceImpl.java new file mode 100644 index 0000000..86cc9fd --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/service/impl/WxMsgServiceImpl.java @@ -0,0 +1,50 @@ +package com.czsj.wechat.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.czsj.wechat.utils.PageUtils; +import com.czsj.wechat.utils.Query; +import com.czsj.wechat.mapper.WxMsgMapper; +import com.czsj.wechat.entity.WxMsg; +import com.czsj.wechat.service.WxMsgService; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; + +import java.util.Arrays; +import java.util.Map; + + +@Service("wxMsgService") +public class WxMsgServiceImpl extends ServiceImpl implements WxMsgService { + + @Override + public PageUtils queryPage(Map params) { + String msgTypes = (String)params.get("msgTypes"); + String startTime = (String)params.get("startTime"); + String openid = (String)params.get("openid"); + String appid = (String) params.get("appid"); + IPage page = this.page( + new Query().getPage(params), + new QueryWrapper() + .eq(StringUtils.hasText(appid), "appid", appid) + .in(StringUtils.hasText(msgTypes),"msg_type", Arrays.asList(msgTypes.split(","))) + .eq(StringUtils.hasText(openid),"openid",openid) + .ge(StringUtils.hasText(startTime),"create_time",startTime) + ); + + return new PageUtils(page); + } + + /** + * 记录msg,异步入库 + * @param msg + */ + @Override + @Async + public void addWxMsg(WxMsg msg) { + this.baseMapper.insert(msg); + } + +} \ No newline at end of file diff --git a/czsj-system/src/main/java/com/czsj/wechat/service/impl/WxQrCodeServiceImpl.java b/czsj-system/src/main/java/com/czsj/wechat/service/impl/WxQrCodeServiceImpl.java new file mode 100644 index 0000000..74f0ea9 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/service/impl/WxQrCodeServiceImpl.java @@ -0,0 +1,68 @@ +package com.czsj.wechat.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.czsj.wechat.utils.PageUtils; +import com.czsj.wechat.utils.Query; +import com.czsj.wechat.mapper.WxQrCodeMapper; +import com.czsj.wechat.entity.WxQrCode; +import com.czsj.wechat.form.WxQrCodeForm; +import com.czsj.wechat.service.WxQrCodeService; +import lombok.RequiredArgsConstructor; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; + +import java.util.Date; +import java.util.Map; + + +@Service("wxQrCodeService") +@RequiredArgsConstructor +public class WxQrCodeServiceImpl extends ServiceImpl implements WxQrCodeService { + private final WxMpService wxService; + + @Override + public PageUtils queryPage(Map params) { + String sceneStr = (String) params.get("sceneStr"); + String appid = (String) params.get("appid"); + IPage page = this.page( + new Query().getPage(params), + new QueryWrapper() + .eq(StringUtils.hasText(appid), "appid", appid) + .like(StringUtils.hasText(sceneStr), "scene_str", sceneStr) + ); + + return new PageUtils(page); + } + + /** + * 创建公众号带参二维码 + * + * + * @param appid + * @param form + * @return + */ + @Override + public WxMpQrCodeTicket createQrCode(String appid, WxQrCodeForm form) throws WxErrorException { + WxMpQrCodeTicket ticket; + if (form.getIsTemp()) {//创建临时二维码 + ticket = wxService.getQrcodeService().qrCodeCreateTmpTicket(form.getSceneStr(), form.getExpireSeconds()); + } else {//创建永久二维码 + ticket = wxService.getQrcodeService().qrCodeCreateLastTicket(form.getSceneStr()); + } + WxQrCode wxQrCode = new WxQrCode(form,appid); + wxQrCode.setTicket(ticket.getTicket()); + wxQrCode.setUrl(ticket.getUrl()); + if (form.getIsTemp()) { + wxQrCode.setExpireTime(new Date(System.currentTimeMillis() + ticket.getExpireSeconds() * 1000L)); + } + this.save(wxQrCode); + return ticket; + } + +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/service/impl/WxUserServiceImpl.java b/czsj-system/src/main/java/com/czsj/wechat/service/impl/WxUserServiceImpl.java new file mode 100644 index 0000000..c15d194 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/service/impl/WxUserServiceImpl.java @@ -0,0 +1,190 @@ +package com.czsj.wechat.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.czsj.wechat.config.TaskExcutor; +import com.czsj.wechat.utils.Query; +import com.czsj.wechat.mapper.WxUserMapper; +import com.czsj.wechat.entity.WxUser; +import com.czsj.wechat.service.WxUserService; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.api.WxMpUserService; +import me.chanjar.weixin.mp.bean.result.WxMpUser; +import me.chanjar.weixin.mp.bean.result.WxMpUserList; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.task.TaskExecutor; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * @author Nifury + * @date 2017-9-27 + */ +@Service +public class WxUserServiceImpl extends ServiceImpl implements WxUserService { + Logger logger = LoggerFactory.getLogger(this.getClass()); + @Autowired + private WxUserMapper userMapper; + @Autowired + private WxMpService wxMpService; + private volatile static boolean syncWxUserTaskRunning=false; + + @Override + public IPage queryPage(Map params) { + String openid = (String) params.get("openid"); + String nickname = (String) params.get("nickname"); + String appid = (String) params.get("appid"); + String city = (String) params.get("city"); + String tagId = (String) params.get("tagid"); + String qrSceneStr = (String) params.get("qrSceneStr"); + return this.page( + new Query().getPage(params), + new QueryWrapper() + .eq(StringUtils.hasText(appid), "appid", appid) + .eq(StringUtils.hasText(openid), "openid", openid) + .like(StringUtils.hasText(nickname), "nickname", nickname) + .eq(StringUtils.hasText(city), "city", city) + .eq(StringUtils.hasText(qrSceneStr), "qrSceneStr", qrSceneStr) + .apply(StringUtils.hasText(tagId),"JSON_CONTAINS(tagid_list,{0})",tagId) + ); + } + + /** + * 根据openid更新用户信息 + * + * @param openid + * @return + */ + @Override + public WxUser refreshUserInfo(String openid,String appid) { + try { + // 获取微信用户基本信息 + logger.info("更新用户信息,openid={}",openid); + wxMpService.switchover(appid); + WxMpUser userWxInfo = wxMpService.getUserService().userInfo(openid, null); + if (userWxInfo == null) { + logger.error("获取不到用户信息,无法更新,openid:{}",openid); + return null; + } + WxUser user = new WxUser(userWxInfo,appid); + this.saveOrUpdate(user); + return user; + } catch (Exception e) { + logger.error("更新用户信息失败,openid:{}",openid); + } + return null; + } + + /** + * 异步批量同步用户信息 + * @param openidList + */ + @Override + @Async + public void refreshUserInfoAsync(String[] openidList,String appid) { + logger.info("批量更新用户信息:任务开始"); + for(String openid:openidList){ + wxMpService.switchover(appid); + TaskExcutor.submit(()->this.refreshUserInfo(openid,appid)); + } + logger.info("批量更新用户信息:任务全部添加到线程池"); + } + + /** + * 数据存在时更新,否则新增 + * + * @param user + */ + @Override + public void updateOrInsert(WxUser user) { + int updateCount = userMapper.updateById(user); + if (updateCount < 1) { + userMapper.insert(user); + } + } + + @Override + public void unsubscribe(String openid) { + userMapper.unsubscribe(openid); + } + + /** + * 同步用户列表,公众号一次拉取调用最多拉取10000个关注者的OpenID,可以通过传入nextOpenid参数多次拉取 + */ + @Override + @Async + public void syncWxUsers(String appid) { + //同步较慢,防止个多线程重复执行同步任务 + Assert.isTrue(!syncWxUserTaskRunning,"后台有同步任务正在进行中,请稍后重试"); + wxMpService.switchoverTo(appid); + syncWxUserTaskRunning=true; + logger.info("同步公众号粉丝列表:任务开始"); + wxMpService.switchover(appid); + boolean hasMore=true; + String nextOpenid=null; + WxMpUserService wxMpUserService = wxMpService.getUserService(); + try { + int page=1; + while (hasMore){ + WxMpUserList wxMpUserList = wxMpUserService.userList(nextOpenid);//拉取openid列表,每次最多1万个 + logger.info("拉取openid列表:第{}页,数量:{}",page++,wxMpUserList.getCount()); + List openids = wxMpUserList.getOpenids(); + this.syncWxUsers(openids,appid); + nextOpenid=wxMpUserList.getNextOpenid(); + hasMore=StringUtils.hasText(nextOpenid) && wxMpUserList.getCount()>=10000; + } + } catch (WxErrorException e) { + logger.error("同步公众号粉丝出错:",e); + }finally { + syncWxUserTaskRunning=false; + } + logger.info("同步公众号粉丝列表:完成"); + } + + /** + * 通过传入的openid列表,同步用户列表 + * @param openids + */ + @Override + public void syncWxUsers(List openids,String appid) { + if(openids.size()<1) { + return; + } + final String batch=openids.get(0).substring(20);//截取首个openid的一部分做批次号(打印日志时使用,无实际意义) + WxMpUserService wxMpUserService = wxMpService.getUserService(); + int start=0,batchSize=openids.size(),end=Math.min(100,batchSize); + logger.info("开始处理批次:{},批次数量:{}",batch,batchSize); + while (start subOpenids=openids.subList(finalStart,finalEnd); + TaskExcutor.submit(()->{//使用线程池同步数据,否则大量粉丝数据需同步时会很慢 + logger.info("同步批次:【{}--{}-{}】,数量:{}",batch, finalStart, finalEnd,subOpenids.size()); + wxMpService.switchover(appid); + List wxMpUsers = null;//批量获取用户信息,每次最多100个 + try { + wxMpUsers = wxMpUserService.userInfoList(subOpenids); + } catch (WxErrorException e) { + logger.error("同步出错,批次:【{}--{}-{}】,错误信息:{}",batch, finalStart, finalEnd,e); + } + if(wxMpUsers!=null && !wxMpUsers.isEmpty()){ + List wxUsers=wxMpUsers.parallelStream().map(item->new WxUser(item,appid)).collect(Collectors.toList()); + this.saveOrUpdateBatch(wxUsers); + } + }); + start=end; + end=Math.min(end+100,openids.size()); + } + logger.info("批次:{}处理完成",batch); + } + +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/service/impl/WxUserTagsServiceImpl.java b/czsj-system/src/main/java/com/czsj/wechat/service/impl/WxUserTagsServiceImpl.java new file mode 100644 index 0000000..8dcf0e7 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/service/impl/WxUserTagsServiceImpl.java @@ -0,0 +1,88 @@ +package com.czsj.wechat.service.impl; + + +import com.czsj.wechat.service.WxUserService; +import com.czsj.wechat.service.WxUserTagsService; +import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.tag.WxUserTag; +import me.chanjar.weixin.mp.util.WxMpConfigStorageHolder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@CacheConfig(cacheNames = {"wxUserTagsServiceCache"}) +@Slf4j +public class WxUserTagsServiceImpl implements WxUserTagsService { + @Autowired + private WxMpService wxMpService; + @Autowired + private WxUserService wxUserService; + public static final String CACHE_KEY="'WX_USER_TAGS'"; + + @Override + @Cacheable(key = CACHE_KEY+"+ #appid") + public List getWxTags(String appid) throws WxErrorException { + log.info("拉取公众号用户标签"); + wxMpService.switchoverTo(appid); + return wxMpService.getUserTagService().tagGet(); + } + + @Override + @CacheEvict(key = CACHE_KEY+"+ #appid") + public void creatTag(String appid, String name) throws WxErrorException { + wxMpService.switchoverTo(appid); + wxMpService.getUserTagService().tagCreate(name); + } + + @Override + @CacheEvict(key = CACHE_KEY+"+ #appid") + public void updateTag(String appid, Long tagid, String name) throws WxErrorException { + wxMpService.switchoverTo(appid); + wxMpService.getUserTagService().tagUpdate(tagid,name); + } + + @Override + @CacheEvict(key = CACHE_KEY+"+ #appid") + public void deleteTag(String appid, Long tagid) throws WxErrorException { + wxMpService.switchoverTo(appid); + wxMpService.getUserTagService().tagDelete(tagid); + } + + @Override + public void batchTagging(String appid, Long tagid, String[] openidList) throws WxErrorException { + wxMpService.switchoverTo(appid); + wxMpService.getUserTagService().batchTagging(tagid,openidList); + wxUserService.refreshUserInfoAsync(openidList,appid);//标签更新后更新对应用户信息 + } + + @Override + public void batchUnTagging(String appid, Long tagid, String[] openidList) throws WxErrorException { + wxMpService.switchoverTo(appid); + wxMpService.getUserTagService().batchUntagging(tagid,openidList); + wxUserService.refreshUserInfoAsync(openidList,appid);//标签更新后更新对应用户信息 + } + + @Override + public void tagging(Long tagid, String openid) throws WxErrorException { + wxMpService.getUserTagService().batchTagging(tagid,new String[]{openid}); + String appid = WxMpConfigStorageHolder.get(); + wxUserService.refreshUserInfo(openid,appid); + } + + @Override + public void untagging(Long tagid, String openid) throws WxErrorException { + wxMpService.getUserTagService().batchUntagging(tagid,new String[]{openid}); + String appid = WxMpConfigStorageHolder.get(); + wxUserService.refreshUserInfo(openid,appid); + } + + + +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/utils/ConfigConstant.java b/czsj-system/src/main/java/com/czsj/wechat/utils/ConfigConstant.java new file mode 100644 index 0000000..6f767c2 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/utils/ConfigConstant.java @@ -0,0 +1,12 @@ +package com.czsj.wechat.utils; + +/** + * 系统参数相关Key + * @author Mark sunlightcs@gmail.com + */ +public class ConfigConstant { + /** + * 云存储配置KEY + */ + public final static String CLOUD_STORAGE_CONFIG_KEY = "CLOUD_STORAGE_CONFIG_KEY"; +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/utils/Constant.java b/czsj-system/src/main/java/com/czsj/wechat/utils/Constant.java new file mode 100644 index 0000000..8ead7ed --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/utils/Constant.java @@ -0,0 +1,122 @@ +package com.czsj.wechat.utils; + +/** + * 常量 + * @author Mark sunlightcs@gmail.com + */ +public class Constant { + /** 超级管理员ID */ + public static final int SUPER_ADMIN = 1; + /** + * 当前页码 + */ + public static final String PAGE = "page"; + /** + * 每页显示记录数 + */ + public static final String LIMIT = "limit"; + /** + * 排序字段 + */ + public static final String ORDER_FIELD = "sidx"; + /** + * 排序方式 + */ + public static final String ORDER = "order"; + /** + * 升序 + */ + public static final String ASC = "asc"; + + /** + * 请求header中的微信用户端源链接参数 + */ + public static final String WX_CLIENT_HREF_HEADER = "wx-client-href"; + + /** + * 菜单类型 + * @author chenshun + * @email sunlightcs@gmail.com + * @date 2016年11月15日 下午1:24:29 + */ + public enum MenuType { + /** + * 目录 + */ + CATALOG(0), + /** + * 菜单 + */ + MENU(1), + /** + * 按钮 + */ + BUTTON(2); + + private int value; + + MenuType(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + } + + /** + * 定时任务状态 + * @author chenshun + * @email sunlightcs@gmail.com + * @date 2016年12月3日 上午12:07:22 + */ + public enum ScheduleStatus { + /** + * 正常 + */ + NORMAL(0), + /** + * 暂停 + */ + PAUSE(1); + + private int value; + + ScheduleStatus(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + } + + /** + * 云服务商 + */ + public enum CloudService { + /** + * 七牛云 + */ + QINIU(1), + /** + * 阿里云 + */ + ALIYUN(2), + /** + * 腾讯云 + */ + QCLOUD(3); + + private int value; + + CloudService(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + } + +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/utils/CookieUtil.java b/czsj-system/src/main/java/com/czsj/wechat/utils/CookieUtil.java new file mode 100644 index 0000000..fd2ee64 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/utils/CookieUtil.java @@ -0,0 +1,64 @@ +package com.czsj.wechat.utils; + +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * Cookie工具类 + */ +public class CookieUtil { + + /** + * 设置cookie + * + * @param maxAge 秒 + */ + public static void setCookie(HttpServletResponse response, String cookieName, String cookieValue, + int maxAge) { + Cookie cookie = new Cookie(cookieName, cookieValue); + maxAge = Math.max(maxAge, 0); + cookie.setMaxAge(maxAge); + cookie.setPath("/"); + response.addCookie(cookie); + } + + public static void clearCookie(HttpServletResponse response, String cookieName, String domain) { + Cookie cookie = new Cookie(cookieName, ""); + cookie.setMaxAge(0); + cookie.setDomain(domain); + cookie.setPath("/"); + response.addCookie(cookie); + } + + public static void refreshCookie(HttpServletRequest request, HttpServletResponse response, String cookieName, + String domain, int maxAge) { + Cookie cookie = getCookie(request, cookieName); + if (cookie != null) { + cookie.setMaxAge(maxAge); + cookie.setDomain(domain); + cookie.setPath("/"); + response.addCookie(cookie); + } + } + + public static String getCookieValue(HttpServletRequest request, String cookieName) { + Cookie cookie = getCookie(request, cookieName); + if (cookie != null) { + return cookie.getValue(); + } + return null; + } + + private static Cookie getCookie(HttpServletRequest request, String cookieName) { + Cookie[] cookies = request.getCookies(); + if (cookies != null) { + for (int i = 0; i < cookies.length; i++) { + if (cookieName.equals(cookies[i].getName())) { + return cookies[i]; + } + } + } + return null; + } +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/utils/DateUtils.java b/czsj-system/src/main/java/com/czsj/wechat/utils/DateUtils.java new file mode 100644 index 0000000..2d46449 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/utils/DateUtils.java @@ -0,0 +1,88 @@ +package com.czsj.wechat.utils; + +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * 日期处理 + * @author Mark sunlightcs@gmail.com + */ +public class DateUtils { + /** 时间格式(yyyy-MM-dd) */ + public final static String DATE_PATTERN = "yyyy-MM-dd"; + /** 时间格式(yyyy-MM-dd HH:mm:ss) */ + public final static String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss"; + + /** + * 日期格式化 日期格式为:yyyy-MM-dd + * @param date 日期 + * @return 返回yyyy-MM-dd格式日期 + */ + public static String format(Date date) { + return format(date, DATE_PATTERN); + } + + /** + * 日期格式化 日期格式为:yyyy-MM-dd + * @param date 日期 + * @param pattern 格式,如:DateUtils.DATE_TIME_PATTERN + * @return 返回yyyy-MM-dd格式日期 + */ + public static String format(Date date, String pattern) { + if (date != null) { + SimpleDateFormat df = new SimpleDateFormat(pattern); + return df.format(date); + } + return null; + } + + /** + * 对日期的【秒】进行加/减 + * @param date 日期 + * @param seconds 秒数,负数为减 + * @return 加/减几秒后的日期 + */ + public static Date addDateSeconds(Date date, int seconds) { + return new Date(date.getTime()+seconds*1000); + } + + /** + * 对日期的【分钟】进行加/减 + * @param date 日期 + * @param minutes 分钟数,负数为减 + * @return 加/减几分钟后的日期 + */ + public static Date addDateMinutes(Date date, int minutes) { + return new Date(date.getTime()+minutes*60*1000); + } + + /** + * 对日期的【小时】进行加/减 + * @param date 日期 + * @param hours 小时数,负数为减 + * @return 加/减几小时后的日期 + */ + public static Date addDateHours(Date date, int hours) { + return new Date(date.getTime()+hours*60*60*1000); + } + + /** + * 对日期的【天】进行加/减 + * @param date 日期 + * @param days 天数,负数为减 + * @return 加/减几天后的日期 + */ + public static Date addDateDays(Date date, int days) { + return new Date(date.getTime()+days*24*60*60*1000); + } + + /** + * 对日期的【周】进行加/减 + * @param date 日期 + * @param weeks 周数,负数为减 + * @return 加/减几周后的日期 + */ + public static Date addDateWeeks(Date date, int weeks) { + return new Date(date.getTime()+weeks*7*24*60*60*1000); + } +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/utils/IPUtils.java b/czsj-system/src/main/java/com/czsj/wechat/utils/IPUtils.java new file mode 100644 index 0000000..3d867c0 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/utils/IPUtils.java @@ -0,0 +1,48 @@ +package com.czsj.wechat.utils; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.StringUtils; + +import javax.servlet.http.HttpServletRequest; + +/** + * IP地址 + * @author Mark sunlightcs@gmail.com + */ +public class IPUtils { + private static Logger logger = LoggerFactory.getLogger(IPUtils.class); + private static final String UNKNOWN = "unknown"; + + /** + * 获取IP地址 + * 使用Nginx等反向代理软件, 则不能通过request.getRemoteAddr()获取IP地址 + * 如果使用了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP地址,X-Forwarded-For中第一个非unknown的有效IP字符串,则为真实IP地址 + */ + public static String getIpAddr(HttpServletRequest request) { + String ip = null; + try { + ip = request.getHeader("x-forwarded-for"); + if (!StringUtils.hasText(ip) || UNKNOWN.equalsIgnoreCase(ip)) { + ip = request.getHeader("Proxy-Client-IP"); + } + if (!StringUtils.hasText(ip) || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) { + ip = request.getHeader("WL-Proxy-Client-IP"); + } + if (!StringUtils.hasText(ip) || UNKNOWN.equalsIgnoreCase(ip)) { + ip = request.getHeader("HTTP_CLIENT_IP"); + } + if (!StringUtils.hasText(ip) || UNKNOWN.equalsIgnoreCase(ip)) { + ip = request.getHeader("HTTP_X_FORWARDED_FOR"); + } + if (!StringUtils.hasText(ip) || UNKNOWN.equalsIgnoreCase(ip)) { + ip = request.getRemoteAddr(); + } + } catch (Exception e) { + logger.error("IPUtils ERROR ", e); + } + + return ip; + } + +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/utils/Json.java b/czsj-system/src/main/java/com/czsj/wechat/utils/Json.java new file mode 100644 index 0000000..d5bee4f --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/utils/Json.java @@ -0,0 +1,20 @@ +package com.czsj.wechat.utils; + +import com.alibaba.fastjson.JSON; + +public class Json { + + /** + * 对象序列化为JSON字符串 + * + * @param object + * @return + */ + public static String toJsonString(Object object) { + return JSON.toJSONString(object); + } + + public static T fromJson(String jsonStr, Class clazz) { + return JSON.parseObject(jsonStr, clazz); + } +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/utils/MD5Util.java b/czsj-system/src/main/java/com/czsj/wechat/utils/MD5Util.java new file mode 100644 index 0000000..efecafe --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/utils/MD5Util.java @@ -0,0 +1,75 @@ +package com.czsj.wechat.utils; + +import java.security.MessageDigest; +import java.util.Objects; + +/** + * MD5加密工具类 + */ +public class MD5Util { + private static final String DEFAULT_MD_5_SALT = "fjdsl321312kf349832&*^*903294[JNLIUIK]%fsdjfkl";//加盐md5盐值 + + /** + * 获得字符串的md5值 + * + * @return md5加密后的字符串 + */ + public static String getMd5(String s) { + char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + try { + byte[] btInput = s.getBytes(); + // 获得MD5摘要算法的 MessageDigest 对象 + MessageDigest mdInst = MessageDigest.getInstance("MD5"); + // 使用指定的字节更新摘要 + mdInst.update(btInput); + // 获得密文 + byte[] md = mdInst.digest(); + // 把密文转换成十六进制的字符串形式 + int j = md.length; + char[] str = new char[j * 2]; + int k = 0; + for (int i = 0; i < j; i++) { + byte byte0 = md[i]; + str[k++] = hexDigits[byte0 >>> 4 & 0xf]; + str[k++] = hexDigits[byte0 & 0xf]; + } + return new String(str); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + /** + * 校验字符串的md5值 + * + * @param str 目标字符串 + * @param md5 基准md5 + * @return 校验结果 + */ + public static boolean checkMd5(String str, String md5) { + return Objects.requireNonNull(getMd5(str)).equalsIgnoreCase(md5); + } + + /** + * 获得加盐md5,算法过程是原字符串md5后连接加盐字符串后再进行md5 + * + * @param str 待加密的字符串 + * @param salt 盐 + * @return 加盐md5 + */ + public static String getMd5AndSalt(String str, String salt) { + return getMd5(Objects.requireNonNull(getMd5(str)).concat(salt)); + } + + /** + * 获得加盐md5,算法过程是原字符串md5后连接加盐字符串后再进行md5 + * 使用默认盐值 + * + * @param str 待加密的字符串 + * @return 加盐md5 + */ + public static String getMd5AndSalt(String str) { + return getMd5(Objects.requireNonNull(getMd5(str)).concat(DEFAULT_MD_5_SALT)); + } +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/utils/MapUtils.java b/czsj-system/src/main/java/com/czsj/wechat/utils/MapUtils.java new file mode 100644 index 0000000..4f7b3dd --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/utils/MapUtils.java @@ -0,0 +1,20 @@ +package com.czsj.wechat.utils; + +import java.util.HashMap; + + +/** + * Map工具类 + * @author Mark sunlightcs@gmail.com + */ +public class MapUtils extends HashMap { + + + private static final long serialVersionUID = 1L; + + @Override + public MapUtils put(String key, Object value) { + super.put(key, value); + return this; + } +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/utils/PageUtils.java b/czsj-system/src/main/java/com/czsj/wechat/utils/PageUtils.java new file mode 100644 index 0000000..02c1949 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/utils/PageUtils.java @@ -0,0 +1,101 @@ +package com.czsj.wechat.utils; + +import com.baomidou.mybatisplus.core.metadata.IPage; + +import java.io.Serializable; +import java.util.List; + +/** + * 分页工具类 + * @author Mark sunlightcs@gmail.com + */ +public class PageUtils implements Serializable { + private static final long serialVersionUID = 1L; + /** + * 总记录数 + */ + private int totalCount; + /** + * 每页记录数 + */ + private int pageSize; + /** + * 总页数 + */ + private int totalPage; + /** + * 当前页数 + */ + private int currPage; + /** + * 列表数据 + */ + private List list; + + /** + * 分页 + * @param list 列表数据 + * @param totalCount 总记录数 + * @param pageSize 每页记录数 + * @param currPage 当前页数 + */ + public PageUtils(List list, int totalCount, int pageSize, int currPage) { + this.list = list; + this.totalCount = totalCount; + this.pageSize = pageSize; + this.currPage = currPage; + this.totalPage = (int) Math.ceil((double) totalCount / pageSize); + } + + /** + * 分页 + */ + public PageUtils(IPage page) { + this.list = page.getRecords(); + this.totalCount = (int) page.getTotal(); + this.pageSize = (int) page.getSize(); + this.currPage = (int) page.getCurrent(); + this.totalPage = (int) page.getPages(); + } + + public int getTotalCount() { + return totalCount; + } + + public void setTotalCount(int totalCount) { + this.totalCount = totalCount; + } + + public int getPageSize() { + return pageSize; + } + + public void setPageSize(int pageSize) { + this.pageSize = pageSize; + } + + public int getTotalPage() { + return totalPage; + } + + public void setTotalPage(int totalPage) { + this.totalPage = totalPage; + } + + public int getCurrPage() { + return currPage; + } + + public void setCurrPage(int currPage) { + this.currPage = currPage; + } + + public List getList() { + return list; + } + + public void setList(List list) { + this.list = list; + } + +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/utils/Query.java b/czsj-system/src/main/java/com/czsj/wechat/utils/Query.java new file mode 100644 index 0000000..3f9b658 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/utils/Query.java @@ -0,0 +1,68 @@ +package com.czsj.wechat.utils; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.metadata.OrderItem; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.czsj.wechat.xss.SQLFilter; +import org.apache.commons.lang3.StringUtils; + +import java.util.Map; + +/** + * 查询参数 + * @author Mark sunlightcs@gmail.com + */ +public class Query { + + public IPage getPage(Map params) { + return this.getPage(params, null, false); + } + + public IPage getPage(Map params, String defaultOrderField, boolean isAsc) { + //分页参数 + long curPage = 1; + long limit = 10; + + if (params.get(Constant.PAGE) != null) { + curPage = Long.parseLong((String) params.get(Constant.PAGE)); + } + if (params.get(Constant.LIMIT) != null) { + limit = Long.parseLong((String) params.get(Constant.LIMIT)); + } + + //分页对象 + Page page = new Page<>(curPage, limit); + + //分页参数 + params.put(Constant.PAGE, page); + + //排序字段 + //防止SQL注入(因为sidx、order是通过拼接SQL实现排序的,会有SQL注入风险) + String orderField = SQLFilter.sqlInject((String) params.get(Constant.ORDER_FIELD)); + String order = (String) params.get(Constant.ORDER); + + + //前端字段排序 + if (StringUtils.isNotEmpty(orderField) && StringUtils.isNotEmpty(order)) { + if (Constant.ASC.equalsIgnoreCase(order)) { + return page.addOrder(OrderItem.asc(orderField)); + } else { + return page.addOrder(OrderItem.desc(orderField)); + } + } + + //没有排序字段,则不排序 + if (StringUtils.isBlank(defaultOrderField)) { + return page; + } + + //默认排序 + if (isAsc) { + page.addOrder(OrderItem.asc(defaultOrderField)); + } else { + page.addOrder(OrderItem.desc(defaultOrderField)); + } + + return page; + } +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/utils/R.java b/czsj-system/src/main/java/com/czsj/wechat/utils/R.java new file mode 100644 index 0000000..5365259 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/utils/R.java @@ -0,0 +1,61 @@ +package com.czsj.wechat.utils; + +import org.apache.http.HttpStatus; + +import java.util.HashMap; +import java.util.Map; + +/** + * 返回数据 + * @author Mark sunlightcs@gmail.com + */ +public class R extends HashMap { + private static final long serialVersionUID = 1L; + + public R() { + put("code", 200); + put("msg", "success"); + } + + public static R error() { + return error(HttpStatus.SC_INTERNAL_SERVER_ERROR, "未知异常,请联系管理员"); + } + + public static R error(String msg) { + return error(HttpStatus.SC_INTERNAL_SERVER_ERROR, msg); + } + + public static R error(int code, String msg) { + R r = new R(); + r.put("code", code); + r.put("msg", msg); + return r; + } + + public static R ok(String msg) { + R r = new R(); + r.put("msg", msg); + return r; + } + + public static R ok(Map map) { + R r = new R(); + r.putAll(map); + return r; + } + + public static R ok() { + return new R(); + } + + @Override + public R put(String key, Object value) { + super.put(key, value); + return this; + } + + public R put(Object value) { + super.put("data", value); + return this; + } +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/utils/SHA1Util.java b/czsj-system/src/main/java/com/czsj/wechat/utils/SHA1Util.java new file mode 100644 index 0000000..14dc317 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/utils/SHA1Util.java @@ -0,0 +1,35 @@ +package com.czsj.wechat.utils; + +import java.security.MessageDigest; + +/** + * SHA1加密工具类 + */ +public class SHA1Util { + + public static String sha1(String s) { + char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + try { + byte[] btInput = s.getBytes(); + // 获得SHA1摘要算法的 MessageDigest 对象 + MessageDigest mdInst = MessageDigest.getInstance("sha-1"); + // 使用指定的字节更新摘要 + mdInst.update(btInput); + // 获得密文 + byte[] md = mdInst.digest(); + // 把密文转换成十六进制的字符串形式 + int j = md.length; + char[] str = new char[j * 2]; + int k = 0; + for (int i = 0; i < j; i++) { + byte byte0 = md[i]; + str[k++] = hexDigits[byte0 >>> 4 & 0xf]; + str[k++] = hexDigits[byte0 & 0xf]; + } + return new String(str); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/xss/HTMLFilter.java b/czsj-system/src/main/java/com/czsj/wechat/xss/HTMLFilter.java new file mode 100644 index 0000000..be12528 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/xss/HTMLFilter.java @@ -0,0 +1,542 @@ +package com.czsj.wechat.xss; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * HTML filtering utility for protecting against XSS (Cross Site Scripting). + * This code is licensed LGPLv3 + * This code is a Java port of the original work in PHP by Cal Hendersen. + * http://code.iamcal.com/php/lib_filter/ + * The trickiest part of the translation was handling the differences in regex handling + * between PHP and Java. These resources were helpful in the process: + * http://java.sun.com/j2se/1.4.2/docs/api/java/util/regex/Pattern.html + * http://us2.php.net/manual/en/reference.pcre.pattern.modifiers.php + * http://www.regular-expressions.info/modifiers.html + * A note on naming conventions: instance variables are prefixed with a "v"; global + * constants are in all caps. + * Sample use: + * String input = ... + * String clean = new HTMLFilter().filter( input ); + * The class is not thread safe. Create a new instance if in doubt. + * If you find bugs or have suggestions on improvement (especially regarding + * performance), please contact us. The latest version of this + * source, and our contact details, can be found at http://xss-html-filter.sf.net + * + * @author Joseph O'Connell + * @author Cal Hendersen + * @author Michael Semb Wever + */ +public final class HTMLFilter { + + /** + * regex flag union representing /si modifiers in php + **/ + private static final int REGEX_FLAGS_SI = Pattern.CASE_INSENSITIVE | Pattern.DOTALL; + private static final Pattern P_COMMENTS = Pattern.compile("", Pattern.DOTALL); + private static final Pattern P_COMMENT = Pattern.compile("^!--(.*)--$", REGEX_FLAGS_SI); + private static final Pattern P_TAGS = Pattern.compile("<(.*?)>", Pattern.DOTALL); + private static final Pattern P_END_TAG = Pattern.compile("^/([a-z0-9]+)", REGEX_FLAGS_SI); + private static final Pattern P_START_TAG = Pattern.compile("^([a-z0-9]+)(.*?)(/?)$", REGEX_FLAGS_SI); + private static final Pattern P_QUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)=([\"'])(.*?)\\2", REGEX_FLAGS_SI); + private static final Pattern P_UNQUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)(=)([^\"\\s']+)", REGEX_FLAGS_SI); + private static final Pattern P_PROTOCOL = Pattern.compile("^([^:]+):", REGEX_FLAGS_SI); + private static final Pattern P_ENTITY = Pattern.compile("&#(\\d+);?"); + private static final Pattern P_ENTITY_UNICODE = Pattern.compile("&#x([0-9a-f]+);?"); + private static final Pattern P_ENCODE = Pattern.compile("%([0-9a-f]{2});?"); + private static final Pattern P_VALID_ENTITIES = Pattern.compile("&([^&;]*)(?=(;|&|$))"); + private static final Pattern P_VALID_QUOTES = Pattern.compile("(>|^)([^<]+?)(<|$)", Pattern.DOTALL); + private static final Pattern P_END_ARROW = Pattern.compile("^>"); + private static final Pattern P_BODY_TO_END = Pattern.compile("<([^>]*?)(?=<|$)"); + private static final Pattern P_XML_CONTENT = Pattern.compile("(^|>)([^<]*?)(?=>)"); + private static final Pattern P_STRAY_LEFT_ARROW = Pattern.compile("<([^>]*?)(?=<|$)"); + private static final Pattern P_STRAY_RIGHT_ARROW = Pattern.compile("(^|>)([^<]*?)(?=>)"); + private static final Pattern P_AMP = Pattern.compile("&"); + private static final Pattern P_QUOTE = Pattern.compile("<"); + private static final Pattern P_LEFT_ARROW = Pattern.compile("<"); + private static final Pattern P_RIGHT_ARROW = Pattern.compile(">"); + private static final Pattern P_BOTH_ARROWS = Pattern.compile("<>"); + + // @xxx could grow large... maybe use sesat's ReferenceMap + private static final ConcurrentMap P_REMOVE_PAIR_BLANKS = new ConcurrentHashMap<>(); + private static final ConcurrentMap P_REMOVE_SELF_BLANKS = new ConcurrentHashMap<>(); + + /** + * set of allowed html elements, along with allowed attributes for each element + **/ + private final Map> vAllowed; + /** + * counts of open tags for each (allowable) html element + **/ + private final Map vTagCounts = new HashMap<>(); + + /** + * html elements which must always be self-closing (e.g. "") + **/ + private final String[] vSelfClosingTags; + /** + * html elements which must always have separate opening and closing tags (e.g. "") + **/ + private final String[] vNeedClosingTags; + /** + * set of disallowed html elements + **/ + private final String[] vDisallowed; + /** + * attributes which should be checked for valid protocols + **/ + private final String[] vProtocolAtts; + /** + * allowed protocols + **/ + private final String[] vAllowedProtocols; + /** + * tags which should be removed if they contain no content (e.g. "" or "") + **/ + private final String[] vRemoveBlanks; + /** + * entities allowed within html markup + **/ + private final String[] vAllowedEntities; + /** + * flag determining whether comments are allowed in input String. + */ + private final boolean stripComment; + private final boolean encodeQuotes; + private boolean vDebug = false; + /** + * flag determining whether to try to make tags when presented with "unbalanced" + * angle brackets (e.g. "" becomes " text "). If set to false, + * unbalanced angle brackets will be html escaped. + */ + private final boolean alwaysMakeTags; + + /** + * Default constructor. + */ + public HTMLFilter() { + vAllowed = new HashMap<>(); + + final ArrayList aAtts = new ArrayList<>(); + aAtts.add("href"); + aAtts.add("target"); + vAllowed.put("a", aAtts); + + final ArrayList imgAtts = new ArrayList<>(); + imgAtts.add("src"); + imgAtts.add("width"); + imgAtts.add("height"); + imgAtts.add("alt"); + vAllowed.put("img", imgAtts); + + final ArrayList noAtts = new ArrayList<>(); + vAllowed.put("b", noAtts); + vAllowed.put("strong", noAtts); + vAllowed.put("i", noAtts); + vAllowed.put("em", noAtts); + + vSelfClosingTags = new String[]{"img"}; + vNeedClosingTags = new String[]{"a", "b", "strong", "i", "em"}; + vDisallowed = new String[]{}; + vAllowedProtocols = new String[]{"http", "mailto", "https"}; // no ftp. + vProtocolAtts = new String[]{"src", "href"}; + vRemoveBlanks = new String[]{"a", "b", "strong", "i", "em"}; + vAllowedEntities = new String[]{"amp", "gt", "lt", "quot"}; + stripComment = true; + encodeQuotes = true; + alwaysMakeTags = true; + } + + /** + * Set debug flag to true. Otherwise use default settings. See the default constructor. + * + * @param debug turn debug on with a true argument + */ + public HTMLFilter(final boolean debug) { + this(); + vDebug = debug; + + } + + /** + * Map-parameter configurable constructor. + * + * @param conf map containing configuration. keys match field names. + */ + public HTMLFilter(final Map conf) { + + assert conf.containsKey("vAllowed") : "configuration requires vAllowed"; + assert conf.containsKey("vSelfClosingTags") : "configuration requires vSelfClosingTags"; + assert conf.containsKey("vNeedClosingTags") : "configuration requires vNeedClosingTags"; + assert conf.containsKey("vDisallowed") : "configuration requires vDisallowed"; + assert conf.containsKey("vAllowedProtocols") : "configuration requires vAllowedProtocols"; + assert conf.containsKey("vProtocolAtts") : "configuration requires vProtocolAtts"; + assert conf.containsKey("vRemoveBlanks") : "configuration requires vRemoveBlanks"; + assert conf.containsKey("vAllowedEntities") : "configuration requires vAllowedEntities"; + + vAllowed = Collections.unmodifiableMap((HashMap>) conf.get("vAllowed")); + vSelfClosingTags = (String[]) conf.get("vSelfClosingTags"); + vNeedClosingTags = (String[]) conf.get("vNeedClosingTags"); + vDisallowed = (String[]) conf.get("vDisallowed"); + vAllowedProtocols = (String[]) conf.get("vAllowedProtocols"); + vProtocolAtts = (String[]) conf.get("vProtocolAtts"); + vRemoveBlanks = (String[]) conf.get("vRemoveBlanks"); + vAllowedEntities = (String[]) conf.get("vAllowedEntities"); + stripComment = conf.containsKey("stripComment") ? (Boolean) conf.get("stripComment") : true; + encodeQuotes = conf.containsKey("encodeQuotes") ? (Boolean) conf.get("encodeQuotes") : true; + alwaysMakeTags = conf.containsKey("alwaysMakeTags") ? (Boolean) conf.get("alwaysMakeTags") : true; + } + + private void reset() { + vTagCounts.clear(); + } + + private void debug(final String msg) { + if (vDebug) { + Logger.getAnonymousLogger().info(msg); + } + } + + //--------------------------------------------------------------- + // my versions of some PHP library functions + public static String chr(final int decimal) { + return String.valueOf((char) decimal); + } + + public static String htmlSpecialChars(final String s) { + String result = s; + result = regexReplace(P_AMP, "&", result); + result = regexReplace(P_QUOTE, """, result); + result = regexReplace(P_LEFT_ARROW, "<", result); + result = regexReplace(P_RIGHT_ARROW, ">", result); + return result; + } + + //--------------------------------------------------------------- + + /** + * given a user submitted input String, filter out any invalid or restricted + * html. + * + * @param input text (i.e. submitted by a user) than may contain html + * @return "clean" version of input, with only valid, whitelisted html elements allowed + */ + public String filter(final String input) { + reset(); + String s = input; + + debug("************************************************"); + debug(" INPUT: " + input); + + s = escapeComments(s); + debug(" escapeComments: " + s); + + s = balanceHtml(s); + debug(" balanceHTML: " + s); + + s = checkTags(s); + debug(" checkTags: " + s); + + s = processRemoveBlanks(s); + debug("processRemoveBlanks: " + s); + + s = validateEntities(s); + debug(" validateEntites: " + s); + + debug("************************************************\n\n"); + return s; + } + + public boolean isAlwaysMakeTags() { + return alwaysMakeTags; + } + + public boolean isStripComments() { + return stripComment; + } + + private String escapeComments(final String s) { + final Matcher m = P_COMMENTS.matcher(s); + final StringBuffer buf = new StringBuffer(); + if (m.find()) { + final String match = m.group(1); //(.*?) + m.appendReplacement(buf, Matcher.quoteReplacement("")); + } + m.appendTail(buf); + + return buf.toString(); + } + + private String balanceHtml(String s) { + if (alwaysMakeTags) { + // + // try and form html + // + s = regexReplace(P_END_ARROW, "", s); + s = regexReplace(P_BODY_TO_END, "<$1>", s); + s = regexReplace(P_XML_CONTENT, "$1<$2", s); + + } else { + // + // escape stray brackets + // + s = regexReplace(P_STRAY_LEFT_ARROW, "<$1", s); + s = regexReplace(P_STRAY_RIGHT_ARROW, "$1$2><", s); + + // + // the last regexp causes '<>' entities to appear + // (we need to do a lookahead assertion so that the last bracket can + // be used in the next pass of the regexp) + // + s = regexReplace(P_BOTH_ARROWS, "", s); + } + + return s; + } + + private String checkTags(String s) { + Matcher m = P_TAGS.matcher(s); + + final StringBuffer buf = new StringBuffer(); + while (m.find()) { + String replaceStr = m.group(1); + replaceStr = processTag(replaceStr); + m.appendReplacement(buf, Matcher.quoteReplacement(replaceStr)); + } + m.appendTail(buf); + + s = buf.toString(); + + // these get tallied in processTag + // (remember to reset before subsequent calls to filter method) + for (String key : vTagCounts.keySet()) { + for (int ii = 0; ii < vTagCounts.get(key); ii++) { + s += ""; + } + } + + return s; + } + + private String processRemoveBlanks(final String s) { + String result = s; + for (String tag : vRemoveBlanks) { + if (!P_REMOVE_PAIR_BLANKS.containsKey(tag)) { + P_REMOVE_PAIR_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?>")); + } + result = regexReplace(P_REMOVE_PAIR_BLANKS.get(tag), "", result); + if (!P_REMOVE_SELF_BLANKS.containsKey(tag)) { + P_REMOVE_SELF_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?/>")); + } + result = regexReplace(P_REMOVE_SELF_BLANKS.get(tag), "", result); + } + + return result; + } + + private static String regexReplace(final Pattern regexPattern, final String replacement, final String s) { + Matcher m = regexPattern.matcher(s); + return m.replaceAll(replacement); + } + + private String processTag(final String s) { + // ending tags + Matcher m = P_END_TAG.matcher(s); + if (m.find()) { + final String name = m.group(1).toLowerCase(); + if (allowed(name)) { + if (!inArray(name, vSelfClosingTags)) { + if (vTagCounts.containsKey(name)) { + vTagCounts.put(name, vTagCounts.get(name) - 1); + return ""; + } + } + } + } + + // starting tags + m = P_START_TAG.matcher(s); + if (m.find()) { + final String name = m.group(1).toLowerCase(); + final String body = m.group(2); + String ending = m.group(3); + + //debug( "in a starting tag, name='" + name + "'; body='" + body + "'; ending='" + ending + "'" ); + if (allowed(name)) { + String params = ""; + + final Matcher m2 = P_QUOTED_ATTRIBUTES.matcher(body); + final Matcher m3 = P_UNQUOTED_ATTRIBUTES.matcher(body); + final List paramNames = new ArrayList(); + final List paramValues = new ArrayList(); + while (m2.find()) { + paramNames.add(m2.group(1)); //([a-z0-9]+) + paramValues.add(m2.group(3)); //(.*?) + } + while (m3.find()) { + paramNames.add(m3.group(1)); //([a-z0-9]+) + paramValues.add(m3.group(3)); //([^\"\\s']+) + } + + String paramName, paramValue; + for (int ii = 0; ii < paramNames.size(); ii++) { + paramName = paramNames.get(ii).toLowerCase(); + paramValue = paramValues.get(ii); + + if (allowedAttribute(name, paramName)) { + if (inArray(paramName, vProtocolAtts)) { + paramValue = processParamProtocol(paramValue); + } + params += " " + paramName + "=\"" + paramValue + "\""; + } + } + + if (inArray(name, vSelfClosingTags)) { + ending = " /"; + } + + if (inArray(name, vNeedClosingTags)) { + ending = ""; + } + + if (ending == null || ending.length() < 1) { + if (vTagCounts.containsKey(name)) { + vTagCounts.put(name, vTagCounts.get(name) + 1); + } else { + vTagCounts.put(name, 1); + } + } else { + ending = " /"; + } + return "<" + name + params + ending + ">"; + } else { + return ""; + } + } + + // comments + m = P_COMMENT.matcher(s); + if (!stripComment && m.find()) { + return "<" + m.group() + ">"; + } + + return ""; + } + + private String processParamProtocol(String s) { + s = decodeEntities(s); + final Matcher m = P_PROTOCOL.matcher(s); + if (m.find()) { + final String protocol = m.group(1); + if (!inArray(protocol, vAllowedProtocols)) { + // bad protocol, turn into local anchor link instead + s = "#" + s.substring(protocol.length() + 1); + if (s.startsWith("#//")) { + s = "#" + s.substring(3); + } + } + } + + return s; + } + + private String decodeEntities(String s) { + StringBuffer buf = new StringBuffer(); + + Matcher m = P_ENTITY.matcher(s); + while (m.find()) { + final String match = m.group(1); + final int decimal = Integer.decode(match); + m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal))); + } + m.appendTail(buf); + s = buf.toString(); + + buf = new StringBuffer(); + m = P_ENTITY_UNICODE.matcher(s); + while (m.find()) { + final String match = m.group(1); + final int decimal = Integer.valueOf(match, 16); + m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal))); + } + m.appendTail(buf); + s = buf.toString(); + + buf = new StringBuffer(); + m = P_ENCODE.matcher(s); + while (m.find()) { + final String match = m.group(1); + final int decimal = Integer.valueOf(match, 16); + m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal))); + } + m.appendTail(buf); + s = buf.toString(); + + s = validateEntities(s); + return s; + } + + private String validateEntities(final String s) { + StringBuffer buf = new StringBuffer(); + + // validate entities throughout the string + Matcher m = P_VALID_ENTITIES.matcher(s); + while (m.find()) { + final String one = m.group(1); //([^&;]*) + final String two = m.group(2); //(?=(;|&|$)) + m.appendReplacement(buf, Matcher.quoteReplacement(checkEntity(one, two))); + } + m.appendTail(buf); + + return encodeQuotes(buf.toString()); + } + + private String encodeQuotes(final String s) { + if (encodeQuotes) { + StringBuffer buf = new StringBuffer(); + Matcher m = P_VALID_QUOTES.matcher(s); + while (m.find()) { + final String one = m.group(1); //(>|^) + final String two = m.group(2); //([^<]+?) + final String three = m.group(3); //(<|$) + m.appendReplacement(buf, Matcher.quoteReplacement(one + regexReplace(P_QUOTE, """, two) + three)); + } + m.appendTail(buf); + return buf.toString(); + } else { + return s; + } + } + + private String checkEntity(final String preamble, final String term) { + + return ";".equals(term) && isValidEntity(preamble) + ? '&' + preamble + : "&" + preamble; + } + + private boolean isValidEntity(final String entity) { + return inArray(entity, vAllowedEntities); + } + + private static boolean inArray(final String s, final String[] array) { + for (String item : array) { + if (item != null && item.equals(s)) { + return true; + } + } + return false; + } + + private boolean allowed(final String name) { + return (vAllowed.isEmpty() || vAllowed.containsKey(name)) && !inArray(name, vDisallowed); + } + + private boolean allowedAttribute(final String name, final String paramName) { + return allowed(name) && (vAllowed.isEmpty() || vAllowed.get(name).contains(paramName)); + } +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/xss/SQLFilter.java b/czsj-system/src/main/java/com/czsj/wechat/xss/SQLFilter.java new file mode 100644 index 0000000..585e162 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/xss/SQLFilter.java @@ -0,0 +1,41 @@ +package com.czsj.wechat.xss; + +import com.czsj.wechat.exception.RRException; +import org.apache.commons.lang3.StringUtils; + +/** + * SQL过滤 + * @author Mark sunlightcs@gmail.com + */ +public class SQLFilter { + + /** + * SQL注入过滤 + * @param str 待验证的字符串 + */ + public static String sqlInject(String str) { + if (StringUtils.isBlank(str)) { + return null; + } + //去掉'|"|;|\字符 + str = StringUtils.replace(str, "'", ""); + str = StringUtils.replace(str, "\"", ""); + str = StringUtils.replace(str, ";", ""); + str = StringUtils.replace(str, "\\", ""); + + //转换成小写 + str = str.toLowerCase(); + + //非法字符 + String[] keywords = {"master", "truncate", "insert", "select", "delete", "update", "declare", "alter", "drop"}; + + //判断是否包含非法字符 + for (String keyword : keywords) { + if (str.indexOf(keyword) != -1) { + throw new RRException("包含非法字符"); + } + } + + return str; + } +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/xss/XssFilter.java b/czsj-system/src/main/java/com/czsj/wechat/xss/XssFilter.java new file mode 100644 index 0000000..5cae2cb --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/xss/XssFilter.java @@ -0,0 +1,29 @@ +package com.czsj.wechat.xss; + +import javax.servlet.*; +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; + +/** + * XSS过滤 + * @author Mark sunlightcs@gmail.com + */ +public class XssFilter implements Filter { + + @Override + public void init(FilterConfig config) { + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper( + (HttpServletRequest) request); + chain.doFilter(xssRequest, response); + } + + @Override + public void destroy() { + } + +} diff --git a/czsj-system/src/main/java/com/czsj/wechat/xss/XssHttpServletRequestWrapper.java b/czsj-system/src/main/java/com/czsj/wechat/xss/XssHttpServletRequestWrapper.java new file mode 100644 index 0000000..26f8827 --- /dev/null +++ b/czsj-system/src/main/java/com/czsj/wechat/xss/XssHttpServletRequestWrapper.java @@ -0,0 +1,139 @@ +package com.czsj.wechat.xss; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; + +import javax.servlet.ReadListener; +import javax.servlet.ServletInputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * XSS过滤处理 + * @author Mark sunlightcs@gmail.com + */ +public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper { + //没被包装过的HttpServletRequest(特殊场景,需要自己过滤) + HttpServletRequest orgRequest; + //html过滤 + private final static HTMLFilter HTML_FILTER = new HTMLFilter(); + + public XssHttpServletRequestWrapper(HttpServletRequest request) { + super(request); + orgRequest = request; + } + + @Override + public ServletInputStream getInputStream() throws IOException { + //非json类型,直接返回 + if (!MediaType.APPLICATION_JSON_VALUE.equalsIgnoreCase(super.getHeader(HttpHeaders.CONTENT_TYPE))) { + return super.getInputStream(); + } + + //为空,直接返回 + String json = IOUtils.toString(super.getInputStream(), StandardCharsets.UTF_8); + if (StringUtils.isBlank(json)) { + return super.getInputStream(); + } + + //xss过滤 + json = xssEncode(json); + final ByteArrayInputStream bis = new ByteArrayInputStream(json.getBytes(StandardCharsets.UTF_8)); + return new ServletInputStream() { + @Override + public boolean isFinished() { + return true; + } + + @Override + public boolean isReady() { + return true; + } + + @Override + public void setReadListener(ReadListener readListener) { + + } + + @Override + public int read() { + return bis.read(); + } + }; + } + + @Override + public String getParameter(String name) { + String value = super.getParameter(xssEncode(name)); + if (StringUtils.isNotBlank(value)) { + value = xssEncode(value); + } + return value; + } + + @Override + public String[] getParameterValues(String name) { + String[] parameters = super.getParameterValues(name); + if (parameters == null || parameters.length == 0) { + return null; + } + + for (int i = 0; i < parameters.length; i++) { + parameters[i] = xssEncode(parameters[i]); + } + return parameters; + } + + @Override + public Map getParameterMap() { + Map map = new LinkedHashMap<>(); + Map parameters = super.getParameterMap(); + for (String key : parameters.keySet()) { + String[] values = parameters.get(key); + for (int i = 0; i < values.length; i++) { + values[i] = xssEncode(values[i]); + } + map.put(key, values); + } + return map; + } + + @Override + public String getHeader(String name) { + String value = super.getHeader(xssEncode(name)); + if (StringUtils.isNotBlank(value)) { + value = xssEncode(value); + } + return value; + } + + private String xssEncode(String input) { + return HTML_FILTER.filter(input); + } + + /** + * 获取最原始的request + */ + public HttpServletRequest getOrgRequest() { + return orgRequest; + } + + /** + * 获取最原始的request + */ + public static HttpServletRequest getOrgRequest(HttpServletRequest request) { + if (request instanceof XssHttpServletRequestWrapper) { + return ((XssHttpServletRequestWrapper) request).getOrgRequest(); + } + + return request; + } + +} diff --git a/czsj-system/src/main/resources/mapper/wechat/ArticleMapper.xml b/czsj-system/src/main/resources/mapper/wechat/ArticleMapper.xml new file mode 100644 index 0000000..a9b88e0 --- /dev/null +++ b/czsj-system/src/main/resources/mapper/wechat/ArticleMapper.xml @@ -0,0 +1,10 @@ + + + + + + + + UPDATE cms_article SET open_count=open_count+1 WHERE id=#{id} + + \ No newline at end of file diff --git a/czsj-system/src/main/resources/mapper/wechat/CzsjWxAccountMapper.xml b/czsj-system/src/main/resources/mapper/wechat/CzsjWxAccountMapper.xml new file mode 100644 index 0000000..442d3f2 --- /dev/null +++ b/czsj-system/src/main/resources/mapper/wechat/CzsjWxAccountMapper.xml @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + select uid, app_id, name, verified, secret, aesKey, token, create_time, update_time, del_flag, create_user_id, update_user_id from czsj_wx_account + + + + + + + + insert into czsj_wx_account + + app_id, + name, + verified, + secret, + aesKey, + token, + create_time, + update_time, + del_flag, + create_user_id, + update_user_id, + + + #{appId}, + #{name}, + #{verified}, + #{secret}, + #{aesKey}, + #{token}, + #{createTime}, + #{updateTime}, + #{delFlag}, + #{createUserId}, + #{updateUserId}, + + + + + update czsj_wx_account + + app_id = #{appId}, + name = #{name}, + verified = #{verified}, + secret = #{secret}, + aesKey = #{aesKey}, + token = #{token}, + create_time = #{createTime}, + update_time = #{updateTime}, + del_flag = #{delFlag}, + create_user_id = #{createUserId}, + update_user_id = #{updateUserId}, + + where uid = #{uid} + + + + delete from czsj_wx_account where uid = #{uid} + + + + delete from czsj_wx_account where uid in + + #{uid} + + + \ No newline at end of file diff --git a/czsj-system/src/main/resources/mapper/wechat/CzsjWxMessageMapper.xml b/czsj-system/src/main/resources/mapper/wechat/CzsjWxMessageMapper.xml new file mode 100644 index 0000000..2ac1360 --- /dev/null +++ b/czsj-system/src/main/resources/mapper/wechat/CzsjWxMessageMapper.xml @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + select uid, app_id, open_id, in_out, msg_type, detail, create_time, update_time, del_flag, create_user_id, update_user_id from czsj_wx_message + + + + + + + + insert into czsj_wx_message + + app_id, + open_id, + in_out, + msg_type, + detail, + create_time, + update_time, + del_flag, + create_user_id, + update_user_id, + + + #{appId}, + #{openId}, + #{inOut}, + #{msgType}, + #{detail}, + #{createTime}, + #{updateTime}, + #{delFlag}, + #{createUserId}, + #{updateUserId}, + + + + + update czsj_wx_message + + app_id = #{appId}, + open_id = #{openId}, + in_out = #{inOut}, + msg_type = #{msgType}, + detail = #{detail}, + create_time = #{createTime}, + update_time = #{updateTime}, + del_flag = #{delFlag}, + create_user_id = #{createUserId}, + update_user_id = #{updateUserId}, + + where uid = #{uid} + + + + delete from czsj_wx_message where uid = #{uid} + + + + delete from czsj_wx_message where uid in + + #{uid} + + + \ No newline at end of file diff --git a/czsj-system/src/main/resources/mapper/wechat/CzsjWxQrCodeMapper.xml b/czsj-system/src/main/resources/mapper/wechat/CzsjWxQrCodeMapper.xml new file mode 100644 index 0000000..67620cc --- /dev/null +++ b/czsj-system/src/main/resources/mapper/wechat/CzsjWxQrCodeMapper.xml @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + select uid, app_id, is_temp, scene_str, ticket, image_url, expire_time, create_time, update_time, del_flag, create_user_id, update_user_id from czsj_wx_qr_code + + + + + + + + insert into czsj_wx_qr_code + + app_id, + is_temp, + scene_str, + ticket, + image_url, + expire_time, + create_time, + update_time, + del_flag, + create_user_id, + update_user_id, + + + #{appId}, + #{isTemp}, + #{sceneStr}, + #{ticket}, + #{imageUrl}, + #{expireTime}, + #{createTime}, + #{updateTime}, + #{delFlag}, + #{createUserId}, + #{updateUserId}, + + + + + update czsj_wx_qr_code + + app_id = #{appId}, + is_temp = #{isTemp}, + scene_str = #{sceneStr}, + ticket = #{ticket}, + image_url = #{imageUrl}, + expire_time = #{expireTime}, + create_time = #{createTime}, + update_time = #{updateTime}, + del_flag = #{delFlag}, + create_user_id = #{createUserId}, + update_user_id = #{updateUserId}, + + where uid = #{uid} + + + + delete from czsj_wx_qr_code where uid = #{uid} + + + + delete from czsj_wx_qr_code where uid in + + #{uid} + + + \ No newline at end of file diff --git a/czsj-system/src/main/resources/mapper/wechat/CzsjWxReplyRuleMapper.xml b/czsj-system/src/main/resources/mapper/wechat/CzsjWxReplyRuleMapper.xml new file mode 100644 index 0000000..2fe13ac --- /dev/null +++ b/czsj-system/src/main/resources/mapper/wechat/CzsjWxReplyRuleMapper.xml @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + + + + + + + + + select uid, app_id, rule_name, match_value, exact_match, reply_type, reply_content, start_time, end_time, create_time, update_time, del_flag, create_user_id, update_user_id from czsj_wx_reply_rule + + + + + + + + insert into czsj_wx_reply_rule + + app_id, + rule_name, + match_value, + exact_match, + reply_type, + reply_content, + start_time, + end_time, + create_time, + update_time, + del_flag, + create_user_id, + update_user_id, + + + #{appId}, + #{ruleName}, + #{matchValue}, + #{exactMatch}, + #{replyType}, + #{replyContent}, + #{startTime}, + #{endTime}, + #{createTime}, + #{updateTime}, + #{delFlag}, + #{createUserId}, + #{updateUserId}, + + + + + update czsj_wx_reply_rule + + app_id = #{appId}, + rule_name = #{ruleName}, + match_value = #{matchValue}, + exact_match = #{exactMatch}, + reply_type = #{replyType}, + reply_content = #{replyContent}, + start_time = #{startTime}, + end_time = #{endTime}, + create_time = #{createTime}, + update_time = #{updateTime}, + del_flag = #{delFlag}, + create_user_id = #{createUserId}, + update_user_id = #{updateUserId}, + + where uid = #{uid} + + + + delete from czsj_wx_reply_rule where uid = #{uid} + + + + delete from czsj_wx_reply_rule where uid in + + #{uid} + + + \ No newline at end of file diff --git a/czsj-system/src/main/resources/mapper/wechat/CzsjWxTemplateLogMapper.xml b/czsj-system/src/main/resources/mapper/wechat/CzsjWxTemplateLogMapper.xml new file mode 100644 index 0000000..100e9f4 --- /dev/null +++ b/czsj-system/src/main/resources/mapper/wechat/CzsjWxTemplateLogMapper.xml @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + select uid, app_id, to_user, template_uid, data, url, mini_program, send_result, create_time, update_time, del_flag, create_user_id, update_user_id from czsj_wx_template_log + + + + + + + + insert into czsj_wx_template_log + + app_id, + to_user, + template_uid, + data, + url, + mini_program, + send_result, + create_time, + update_time, + del_flag, + create_user_id, + update_user_id, + + + #{appId}, + #{toUser}, + #{templateUid}, + #{data}, + #{url}, + #{miniProgram}, + #{sendResult}, + #{createTime}, + #{updateTime}, + #{delFlag}, + #{createUserId}, + #{updateUserId}, + + + + + update czsj_wx_template_log + + app_id = #{appId}, + to_user = #{toUser}, + template_uid = #{templateUid}, + data = #{data}, + url = #{url}, + mini_program = #{miniProgram}, + send_result = #{sendResult}, + create_time = #{createTime}, + update_time = #{updateTime}, + del_flag = #{delFlag}, + create_user_id = #{createUserId}, + update_user_id = #{updateUserId}, + + where uid = #{uid} + + + + delete from czsj_wx_template_log where uid = #{uid} + + + + delete from czsj_wx_template_log where uid in + + #{uid} + + + \ No newline at end of file diff --git a/czsj-system/src/main/resources/mapper/wechat/CzsjWxTemplateMapper.xml b/czsj-system/src/main/resources/mapper/wechat/CzsjWxTemplateMapper.xml new file mode 100644 index 0000000..adf0ee3 --- /dev/null +++ b/czsj-system/src/main/resources/mapper/wechat/CzsjWxTemplateMapper.xml @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + select uid, app_id, template_id, title, primary_industry, deputy_industry, content, example, create_time, update_time, del_flag, create_user_id, update_user_id from czsj_wx_template + + + + + + + + insert into czsj_wx_template + + app_id, + template_id, + title, + primary_industry, + deputy_industry, + content, + example, + create_time, + update_time, + del_flag, + create_user_id, + update_user_id, + + + #{appId}, + #{templateId}, + #{title}, + #{primaryIndustry}, + #{deputyIndustry}, + #{content}, + #{example}, + #{createTime}, + #{updateTime}, + #{delFlag}, + #{createUserId}, + #{updateUserId}, + + + + + update czsj_wx_template + + app_id = #{appId}, + template_id = #{templateId}, + title = #{title}, + primary_industry = #{primaryIndustry}, + deputy_industry = #{deputyIndustry}, + content = #{content}, + example = #{example}, + create_time = #{createTime}, + update_time = #{updateTime}, + del_flag = #{delFlag}, + create_user_id = #{createUserId}, + update_user_id = #{updateUserId}, + + where uid = #{uid} + + + + delete from czsj_wx_template where uid = #{uid} + + + + delete from czsj_wx_template where uid in + + #{uid} + + + \ No newline at end of file diff --git a/czsj-system/src/main/resources/mapper/wechat/MsgReplyRuleMapper.xml b/czsj-system/src/main/resources/mapper/wechat/MsgReplyRuleMapper.xml new file mode 100644 index 0000000..cab11c5 --- /dev/null +++ b/czsj-system/src/main/resources/mapper/wechat/MsgReplyRuleMapper.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/czsj-system/src/main/resources/mapper/wechat/MsgTemplateMapper.xml b/czsj-system/src/main/resources/mapper/wechat/MsgTemplateMapper.xml new file mode 100644 index 0000000..4176203 --- /dev/null +++ b/czsj-system/src/main/resources/mapper/wechat/MsgTemplateMapper.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/czsj-system/src/main/resources/mapper/wechat/TemplateMsgLogMapper.xml b/czsj-system/src/main/resources/mapper/wechat/TemplateMsgLogMapper.xml new file mode 100644 index 0000000..522dce1 --- /dev/null +++ b/czsj-system/src/main/resources/mapper/wechat/TemplateMsgLogMapper.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/czsj-system/src/main/resources/mapper/wechat/WxAccountMapper.xml b/czsj-system/src/main/resources/mapper/wechat/WxAccountMapper.xml new file mode 100644 index 0000000..dc3b8a2 --- /dev/null +++ b/czsj-system/src/main/resources/mapper/wechat/WxAccountMapper.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/czsj-system/src/main/resources/mapper/wechat/WxMsgMapper.xml b/czsj-system/src/main/resources/mapper/wechat/WxMsgMapper.xml new file mode 100644 index 0000000..f53b240 --- /dev/null +++ b/czsj-system/src/main/resources/mapper/wechat/WxMsgMapper.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/czsj-system/src/main/resources/mapper/wechat/WxQrCodeMapper.xml b/czsj-system/src/main/resources/mapper/wechat/WxQrCodeMapper.xml new file mode 100644 index 0000000..9ba41a8 --- /dev/null +++ b/czsj-system/src/main/resources/mapper/wechat/WxQrCodeMapper.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/czsj-system/src/main/resources/mapper/wechat/WxUserMapper.xml b/czsj-system/src/main/resources/mapper/wechat/WxUserMapper.xml new file mode 100644 index 0000000..bc8a723 --- /dev/null +++ b/czsj-system/src/main/resources/mapper/wechat/WxUserMapper.xml @@ -0,0 +1,9 @@ + + + + + + + UPDATE wx_user SET subscribe=0 WHERE openid=#{openid} + +