diff --git a/db/5pigxx_job.sql b/db/5pigxx_job.sql index 1b19b9956..05c2855ef 100644 --- a/db/5pigxx_job.sql +++ b/db/5pigxx_job.sql @@ -21,8 +21,8 @@ SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for `job_execution_log` -- ---------------------------- -DROP TABLE IF EXISTS `job_execution_log`; -CREATE TABLE `job_execution_log` ( +DROP TABLE IF EXISTS `JOB_EXECUTION_LOG`; +CREATE TABLE `JOB_EXECUTION_LOG` ( `id` varchar(40) NOT NULL, `job_name` varchar(100) NOT NULL, `task_id` varchar(255) NOT NULL, @@ -40,8 +40,8 @@ CREATE TABLE `job_execution_log` ( -- ---------------------------- -- Table structure for `job_status_trace_log` -- ---------------------------- -DROP TABLE IF EXISTS `job_status_trace_log`; -CREATE TABLE `job_status_trace_log` ( +DROP TABLE IF EXISTS `JOB_STATUS_TRACE_LOG`; +CREATE TABLE `JOB_STATUS_TRACE_LOG` ( `id` varchar(40) NOT NULL, `job_name` varchar(100) NOT NULL, `original_task_id` varchar(255) NOT NULL, @@ -60,8 +60,8 @@ CREATE TABLE `job_status_trace_log` ( -- ---------------------------- -- Table structure for `qrtz_blob_triggers` -- ---------------------------- -DROP TABLE IF EXISTS `qrtz_blob_triggers`; -CREATE TABLE `qrtz_blob_triggers` ( +DROP TABLE IF EXISTS `QRTZ_BLOB_TRIGGERS`; +CREATE TABLE `QRTZ_BLOB_TRIGGERS` ( `sched_name` varchar(120) NOT NULL, `trigger_name` varchar(200) NOT NULL, `trigger_group` varchar(200) NOT NULL, @@ -73,8 +73,8 @@ CREATE TABLE `qrtz_blob_triggers` ( -- ---------------------------- -- Table structure for `qrtz_calendars` -- ---------------------------- -DROP TABLE IF EXISTS `qrtz_calendars`; -CREATE TABLE `qrtz_calendars` ( +DROP TABLE IF EXISTS `QRTZ_CALENDARS`; +CREATE TABLE `QRTZ_CALENDARS` ( `sched_name` varchar(120) NOT NULL, `calendar_name` varchar(200) NOT NULL, `calendar` blob NOT NULL, @@ -84,8 +84,8 @@ CREATE TABLE `qrtz_calendars` ( -- ---------------------------- -- Table structure for `qrtz_cron_triggers` -- ---------------------------- -DROP TABLE IF EXISTS `qrtz_cron_triggers`; -CREATE TABLE `qrtz_cron_triggers` ( +DROP TABLE IF EXISTS `QRTZ_CRON_TRIGGERS`; +CREATE TABLE `QRTZ_CRON_TRIGGERS` ( `sched_name` varchar(120) NOT NULL, `trigger_name` varchar(200) NOT NULL, `trigger_group` varchar(200) NOT NULL, @@ -99,14 +99,14 @@ CREATE TABLE `qrtz_cron_triggers` ( -- Records of `qrtz_cron_triggers` -- ---------------------------- BEGIN; -INSERT INTO `qrtz_cron_triggers` VALUES ('clusteredScheduler', '测试任务', 'demo', '0 * * * * ? *', 'Asia/Shanghai'); +INSERT INTO `QRTZ_CRON_TRIGGERS` VALUES ('clusteredScheduler', '测试任务', 'demo', '0 * * * * ? *', 'Asia/Shanghai'); COMMIT; -- ---------------------------- -- Table structure for `qrtz_fired_triggers` -- ---------------------------- -DROP TABLE IF EXISTS `qrtz_fired_triggers`; -CREATE TABLE `qrtz_fired_triggers` ( +DROP TABLE IF EXISTS `QRTZ_FIRED_TRIGGERS`; +CREATE TABLE `QRTZ_FIRED_TRIGGERS` ( `sched_name` varchar(120) NOT NULL, `entry_id` varchar(95) NOT NULL, `trigger_name` varchar(200) NOT NULL, @@ -126,8 +126,8 @@ CREATE TABLE `qrtz_fired_triggers` ( -- ---------------------------- -- Table structure for `qrtz_job_details` -- ---------------------------- -DROP TABLE IF EXISTS `qrtz_job_details`; -CREATE TABLE `qrtz_job_details` ( +DROP TABLE IF EXISTS `QRTZ_JOB_DETAILS`; +CREATE TABLE `QRTZ_JOB_DETAILS` ( `sched_name` varchar(120) NOT NULL, `job_name` varchar(200) NOT NULL, `job_group` varchar(200) NOT NULL, @@ -145,14 +145,14 @@ CREATE TABLE `qrtz_job_details` ( -- Records of `qrtz_job_details` -- ---------------------------- BEGIN; -INSERT INTO `qrtz_job_details` VALUES ('clusteredScheduler', '测试任务', 'demo', null, 'com.pig4cloud.pigx.daemon.quartz.config.PigxQuartzFactory', '0', '1', '0', '0', 0xaced0005737200156f72672e71756172747a2e4a6f62446174614d61709fb083e8bfa9b0cb020000787200266f72672e71756172747a2e7574696c732e537472696e674b65794469727479466c61674d61708208e8c3fbc55d280200015a0013616c6c6f77735472616e7369656e74446174617872001d6f72672e71756172747a2e7574696c732e4469727479466c61674d617013e62ead28760ace0200025a000564697274794c00036d617074000f4c6a6176612f7574696c2f4d61703b787001737200116a6176612e7574696c2e486173684d61700507dac1c31660d103000246000a6c6f6164466163746f724900097468726573686f6c6478703f4000000000000c7708000000100000000174000b7363686564756c654a6f627372002e636f6d2e70696734636c6f75642e706967782e6461656d6f6e2e71756172747a2e656e746974792e5379734a6f6200000000000000010200174c0009636c6173734e616d657400124c6a6176612f6c616e672f537472696e673b4c0008637265617465427971007e00094c000a63726561746554696d657400194c6a6176612f74696d652f4c6f63616c4461746554696d653b4c000e63726f6e45787072657373696f6e71007e00094c000b657865637574655061746871007e00094c00106a6f624578656375746553746174757371007e00094c00086a6f6247726f757071007e00094c00056a6f6249647400134c6a6176612f6c616e672f496e74656765723b4c00076a6f624e616d6571007e00094c00086a6f624f7264657271007e00094c00096a6f6253746174757371007e00094c000d6a6f6254656e616e745479706571007e00094c00076a6f625479706571007e00094c000a6d6574686f644e616d6571007e00094c00116d6574686f64506172616d7356616c756571007e00094c000d6d697366697265506f6c69637971007e00094c00086e65787454696d6571007e000a4c000c70726576696f757354696d6571007e000a4c000672656d61726b71007e00094c0009737461727454696d6571007e000a4c000874656e616e74496471007e000b4c0008757064617465427971007e00094c000a75706461746554696d6571007e000a78720035636f6d2e62616f6d69646f752e6d796261746973706c75732e657874656e73696f6e2e6163746976657265636f72642e4d6f64656c0000000000000001020000787074000464656d6f74000561646d696e7372000d6a6176612e74696d652e536572955d84ba1b2248b20c00007870770a05000007e303190e00f17874000d30202a202a202a202a203f202a7400007400013074000464656d6f737200116a6176612e6c616e672e496e746567657212e2a0a4f781873802000149000576616c7565787200106a6176612e6c616e672e4e756d62657286ac951d0b94e08b02000078700000000174000ce6b58be8af95e4bbbbe58aa17400013574000133740001317400013274000a64656d6f4d6574686f6474000970696734636c6f7564740001337371007e0010770905000007e3031916e2787371007e0010770a05000007e30319161ccd78740020e6bc94e7a4ba537072696e67204265616ee79a84e5ae9ae697b6e4bbbbe58aa17371007e0010770a05000007e303191600de7871007e001874000561646d696e7371007e0010770a05000007e303190e00f1787800); +INSERT INTO `QRTZ_JOB_DETAILS` VALUES ('clusteredScheduler', '测试任务', 'demo', null, 'com.pig4cloud.pigx.daemon.quartz.config.PigxQuartzFactory', '0', '1', '0', '0', 0xaced0005737200156f72672e71756172747a2e4a6f62446174614d61709fb083e8bfa9b0cb020000787200266f72672e71756172747a2e7574696c732e537472696e674b65794469727479466c61674d61708208e8c3fbc55d280200015a0013616c6c6f77735472616e7369656e74446174617872001d6f72672e71756172747a2e7574696c732e4469727479466c61674d617013e62ead28760ace0200025a000564697274794c00036d617074000f4c6a6176612f7574696c2f4d61703b787001737200116a6176612e7574696c2e486173684d61700507dac1c31660d103000246000a6c6f6164466163746f724900097468726573686f6c6478703f4000000000000c7708000000100000000174000b7363686564756c654a6f627372002e636f6d2e70696734636c6f75642e706967782e6461656d6f6e2e71756172747a2e656e746974792e5379734a6f6200000000000000010200174c0009636c6173734e616d657400124c6a6176612f6c616e672f537472696e673b4c0008637265617465427971007e00094c000a63726561746554696d657400194c6a6176612f74696d652f4c6f63616c4461746554696d653b4c000e63726f6e45787072657373696f6e71007e00094c000b657865637574655061746871007e00094c00106a6f624578656375746553746174757371007e00094c00086a6f6247726f757071007e00094c00056a6f6249647400134c6a6176612f6c616e672f496e74656765723b4c00076a6f624e616d6571007e00094c00086a6f624f7264657271007e00094c00096a6f6253746174757371007e00094c000d6a6f6254656e616e745479706571007e00094c00076a6f625479706571007e00094c000a6d6574686f644e616d6571007e00094c00116d6574686f64506172616d7356616c756571007e00094c000d6d697366697265506f6c69637971007e00094c00086e65787454696d6571007e000a4c000c70726576696f757354696d6571007e000a4c000672656d61726b71007e00094c0009737461727454696d6571007e000a4c000874656e616e74496471007e000b4c0008757064617465427971007e00094c000a75706461746554696d6571007e000a78720035636f6d2e62616f6d69646f752e6d796261746973706c75732e657874656e73696f6e2e6163746976657265636f72642e4d6f64656c0000000000000001020000787074000464656d6f74000561646d696e7372000d6a6176612e74696d652e536572955d84ba1b2248b20c00007870770a05000007e303190e00f17874000d30202a202a202a202a203f202a7400007400013074000464656d6f737200116a6176612e6c616e672e496e746567657212e2a0a4f781873802000149000576616c7565787200106a6176612e6c616e672e4e756d62657286ac951d0b94e08b02000078700000000174000ce6b58be8af95e4bbbbe58aa17400013574000133740001317400013274000a64656d6f4d6574686f6474000970696734636c6f7564740001337371007e0010770905000007e3031916e2787371007e0010770a05000007e30319161ccd78740020e6bc94e7a4ba537072696e67204265616ee79a84e5ae9ae697b6e4bbbbe58aa17371007e0010770a05000007e303191600de7871007e001874000561646d696e7371007e0010770a05000007e303190e00f1787800); COMMIT; -- ---------------------------- -- Table structure for `qrtz_locks` -- ---------------------------- -DROP TABLE IF EXISTS `qrtz_locks`; -CREATE TABLE `qrtz_locks` ( +DROP TABLE IF EXISTS `QRTZ_LOCKS`; +CREATE TABLE `QRTZ_LOCKS` ( `sched_name` varchar(120) NOT NULL, `lock_name` varchar(40) NOT NULL, PRIMARY KEY (`sched_name`,`lock_name`) USING BTREE @@ -162,14 +162,14 @@ CREATE TABLE `qrtz_locks` ( -- Records of `qrtz_locks` -- ---------------------------- BEGIN; -INSERT INTO `qrtz_locks` VALUES ('clusteredScheduler', 'STATE_ACCESS'), ('clusteredScheduler', 'TRIGGER_ACCESS'); +INSERT INTO `QRTZ_LOCKS` VALUES ('clusteredScheduler', 'STATE_ACCESS'), ('clusteredScheduler', 'TRIGGER_ACCESS'); COMMIT; -- ---------------------------- -- Table structure for `qrtz_paused_trigger_grps` -- ---------------------------- -DROP TABLE IF EXISTS `qrtz_paused_trigger_grps`; -CREATE TABLE `qrtz_paused_trigger_grps` ( +DROP TABLE IF EXISTS `QRTZ_PAUSED_TRIGGER_GRPS`; +CREATE TABLE `QRTZ_PAUSED_TRIGGER_GRPS` ( `sched_name` varchar(120) NOT NULL, `trigger_group` varchar(200) NOT NULL, PRIMARY KEY (`sched_name`,`trigger_group`) USING BTREE @@ -178,8 +178,8 @@ CREATE TABLE `qrtz_paused_trigger_grps` ( -- ---------------------------- -- Table structure for `qrtz_scheduler_state` -- ---------------------------- -DROP TABLE IF EXISTS `qrtz_scheduler_state`; -CREATE TABLE `qrtz_scheduler_state` ( +DROP TABLE IF EXISTS `QRTZ_SCHEDULER_STATE`; +CREATE TABLE `QRTZ_SCHEDULER_STATE` ( `sched_name` varchar(120) NOT NULL, `instance_name` varchar(200) NOT NULL, `last_checkin_time` bigint(13) NOT NULL, @@ -191,7 +191,7 @@ CREATE TABLE `qrtz_scheduler_state` ( -- Records of `qrtz_scheduler_state` -- ---------------------------- BEGIN; -INSERT INTO `qrtz_scheduler_state` VALUES ('clusteredScheduler', 'lengleng1553564320591', '1553568907589', '10000'); +INSERT INTO `QRTZ_SCHEDULER_STATE` VALUES ('clusteredScheduler', 'lengleng1553564320591', '1553568907589', '10000'); COMMIT; -- ---------------------------- @@ -206,14 +206,14 @@ CREATE TABLE `qrtz_simple_triggers` ( `repeat_interval` bigint(12) NOT NULL, `times_triggered` bigint(10) NOT NULL, PRIMARY KEY (`sched_name`,`trigger_name`,`trigger_group`) USING BTREE, - CONSTRAINT `qrtz_simple_triggers_ibfk_1` FOREIGN KEY (`sched_name`, `trigger_name`, `trigger_group`) REFERENCES `qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`) + CONSTRAINT `QRTZ_SIMPLE_TRIGGERS_IBFK_1` FOREIGN KEY (`sched_name`, `trigger_name`, `trigger_group`) REFERENCES `qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC; -- ---------------------------- -- Table structure for `qrtz_simprop_triggers` -- ---------------------------- -DROP TABLE IF EXISTS `qrtz_simprop_triggers`; -CREATE TABLE `qrtz_simprop_triggers` ( +DROP TABLE IF EXISTS `QRTZ_SIMPROP_TRIGGERS`; +CREATE TABLE `QRTZ_SIMPROP_TRIGGERS` ( `sched_name` varchar(120) NOT NULL, `trigger_name` varchar(200) NOT NULL, `trigger_group` varchar(200) NOT NULL, @@ -229,14 +229,14 @@ CREATE TABLE `qrtz_simprop_triggers` ( `bool_prop_1` varchar(1) DEFAULT NULL, `bool_prop_2` varchar(1) DEFAULT NULL, PRIMARY KEY (`sched_name`,`trigger_name`,`trigger_group`) USING BTREE, - CONSTRAINT `qrtz_simprop_triggers_ibfk_1` FOREIGN KEY (`sched_name`, `trigger_name`, `trigger_group`) REFERENCES `qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`) + CONSTRAINT `QRTZ_SIMPROP_TRIGGERS_IBFK_1` FOREIGN KEY (`sched_name`, `trigger_name`, `trigger_group`) REFERENCES `qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC; -- ---------------------------- -- Table structure for `qrtz_triggers` -- ---------------------------- -DROP TABLE IF EXISTS `qrtz_triggers`; -CREATE TABLE `qrtz_triggers` ( +DROP TABLE IF EXISTS `QRTZ_TRIGGERS`; +CREATE TABLE `QRTZ_TRIGGERS` ( `sched_name` varchar(120) NOT NULL, `trigger_name` varchar(200) NOT NULL, `trigger_group` varchar(200) NOT NULL, @@ -262,7 +262,7 @@ CREATE TABLE `qrtz_triggers` ( -- Records of `qrtz_triggers` -- ---------------------------- BEGIN; -INSERT INTO `qrtz_triggers` VALUES ('clusteredScheduler', '测试任务', 'demo', '测试任务', 'demo', null, '1553568960000', '1553568900000', '5', 'WAITING', 'CRON', '1553564598000', '0', null, '2', ''); +INSERT INTO `QRTZ_TRIGGERS` VALUES ('clusteredScheduler', '测试任务', 'demo', '测试任务', 'demo', null, '1553568960000', '1553568900000', '5', 'WAITING', 'CRON', '1553564598000', '0', null, '2', ''); COMMIT; -- ---------------------------- diff --git a/docker-compose.yml b/docker-compose.yml index 30ce43425..4eaafb588 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,4 +1,4 @@ -# 使用说明 V2.7.0 +# 使用说明 V2.8.0 # 1. 使用docker-compose 宿主机不需要配置host来发现 # 2. 无需修改源码,根目录 docker-compose up 即可 # 3. 静静等待服务启动 diff --git a/pigx-auth/pom.xml b/pigx-auth/pom.xml index 9ca4c3f2e..0138ddba4 100644 --- a/pigx-auth/pom.xml +++ b/pigx-auth/pom.xml @@ -24,7 +24,7 @@ com.pig4cloud pigx - 2.7.0 + 2.8.0 pigx-auth diff --git a/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/endpoint/PigxTokenEndpoint.java b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/endpoint/PigxTokenEndpoint.java index fb897a81c..53738f210 100644 --- a/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/endpoint/PigxTokenEndpoint.java +++ b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/endpoint/PigxTokenEndpoint.java @@ -111,6 +111,9 @@ public class PigxTokenEndpoint { @Inner @DeleteMapping("/{token}") public R delToken(@PathVariable("token") String token) { + if (token != null) { + throw new RuntimeException("lalalala"); + } OAuth2AccessToken oAuth2AccessToken = tokenStore.readAccessToken(token); tokenStore.removeAccessToken(oAuth2AccessToken); return new R<>(); diff --git a/pigx-common/pigx-common-bom/pom.xml b/pigx-common/pigx-common-bom/pom.xml index 8c50b0471..76a64821e 100644 --- a/pigx-common/pigx-common-bom/pom.xml +++ b/pigx-common/pigx-common-bom/pom.xml @@ -16,10 +16,11 @@ pigx 公共版本控制 - 2.7.0 + 2.8.0 3.1.0 - 8.0.13 + 8.0.15 1.5.22 + 3.3.0 @@ -104,6 +105,17 @@ swagger-annotations ${swagger.core.version} + + + com.github.binarywang + weixin-java-mp + ${mp.weixin.version} + + + com.github.binarywang + weixin-java-common + ${mp.weixin.version} + diff --git a/pigx-common/pigx-common-core/pom.xml b/pigx-common/pigx-common-core/pom.xml index f2f46e6eb..6b4aa513c 100644 --- a/pigx-common/pigx-common-core/pom.xml +++ b/pigx-common/pigx-common-core/pom.xml @@ -24,7 +24,7 @@ com.pig4cloud pigx-common - 2.7.0 + 2.8.0 pigx-common-core diff --git a/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/constant/SecurityConstants.java b/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/constant/SecurityConstants.java index 75a18f63c..5225be97f 100644 --- a/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/constant/SecurityConstants.java +++ b/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/constant/SecurityConstants.java @@ -155,4 +155,8 @@ public interface SecurityConstants { */ String DETAILS_LICENSE = "license"; + /** + * AES 加密 + */ + String AES = "aes"; } diff --git a/pigx-common/pigx-common-data/pom.xml b/pigx-common/pigx-common-data/pom.xml index a51afb387..5b69ce245 100644 --- a/pigx-common/pigx-common-data/pom.xml +++ b/pigx-common/pigx-common-data/pom.xml @@ -24,7 +24,7 @@ com.pig4cloud pigx-common - 2.7.0 + 2.8.0 pigx-common-data diff --git a/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/tenant/PigxTenantHandler.java b/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/tenant/PigxTenantHandler.java index 64eaf0dae..af49345f5 100644 --- a/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/tenant/PigxTenantHandler.java +++ b/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/tenant/PigxTenantHandler.java @@ -21,6 +21,7 @@ import com.baomidou.mybatisplus.extension.plugins.tenant.TenantHandler; import lombok.extern.slf4j.Slf4j; import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.LongValue; +import net.sf.jsqlparser.expression.NullValue; import org.springframework.beans.factory.annotation.Autowired; /** @@ -43,6 +44,10 @@ public class PigxTenantHandler implements TenantHandler { public Expression getTenantId() { Integer tenantId = TenantContextHolder.getTenantId(); log.debug("当前租户为 >> {}", tenantId); + + if (tenantId == null) { + return new NullValue(); + } return new LongValue(tenantId); } @@ -64,6 +69,12 @@ public class PigxTenantHandler implements TenantHandler { */ @Override public boolean doTableFilter(String tableName) { + Integer tenantId = TenantContextHolder.getTenantId(); + // 租户中ID 为空,查询全部,不进行过滤 + if (tenantId == null) { + return Boolean.TRUE; + } + return !properties.getTables().contains(tableName); } } diff --git a/pigx-common/pigx-common-gateway/pom.xml b/pigx-common/pigx-common-gateway/pom.xml index 346f29141..7854a5bce 100644 --- a/pigx-common/pigx-common-gateway/pom.xml +++ b/pigx-common/pigx-common-gateway/pom.xml @@ -24,7 +24,7 @@ com.pig4cloud pigx-common - 2.7.0 + 2.8.0 pigx-common-gateway diff --git a/pigx-common/pigx-common-job/pom.xml b/pigx-common/pigx-common-job/pom.xml index 550338fab..f016255db 100644 --- a/pigx-common/pigx-common-job/pom.xml +++ b/pigx-common/pigx-common-job/pom.xml @@ -24,7 +24,7 @@ com.pig4cloud pigx-common - 2.7.0 + 2.8.0 pigx-common-job diff --git a/pigx-common/pigx-common-log/pom.xml b/pigx-common/pigx-common-log/pom.xml index 4ec70cafb..afc2b8813 100644 --- a/pigx-common/pigx-common-log/pom.xml +++ b/pigx-common/pigx-common-log/pom.xml @@ -24,7 +24,7 @@ com.pig4cloud pigx-common - 2.7.0 + 2.8.0 pigx-common-log diff --git a/pigx-common/pigx-common-minio/pom.xml b/pigx-common/pigx-common-minio/pom.xml index aa859eba8..d86c37e9d 100755 --- a/pigx-common/pigx-common-minio/pom.xml +++ b/pigx-common/pigx-common-minio/pom.xml @@ -6,7 +6,7 @@ com.pig4cloud pigx-common - 2.7.0 + 2.8.0 pigx-common-minio diff --git a/pigx-common/pigx-common-security/pom.xml b/pigx-common/pigx-common-security/pom.xml index 1f244e842..54fd01845 100644 --- a/pigx-common/pigx-common-security/pom.xml +++ b/pigx-common/pigx-common-security/pom.xml @@ -23,7 +23,7 @@ com.pig4cloud pigx-common - 2.7.0 + 2.8.0 pigx-common-security diff --git a/pigx-common/pigx-common-security/src/main/java/org/springframework/cloud/openfeign/PigxFeignFallback.java b/pigx-common/pigx-common-security/src/main/java/org/springframework/cloud/openfeign/PigxFeignFallback.java index fb849f19e..21d7c9ff1 100644 --- a/pigx-common/pigx-common-security/src/main/java/org/springframework/cloud/openfeign/PigxFeignFallback.java +++ b/pigx-common/pigx-common-security/src/main/java/org/springframework/cloud/openfeign/PigxFeignFallback.java @@ -18,7 +18,7 @@ package org.springframework.cloud.openfeign; import cn.hutool.core.util.StrUtil; -import com.pig4cloud.pigx.common.core.constant.CommonConstants; +import cn.hutool.json.JSONUtil; import com.pig4cloud.pigx.common.core.util.R; import feign.FeignException; import lombok.AllArgsConstructor; @@ -57,8 +57,7 @@ public class PigxFeignFallback implements MethodInterceptor { String str = StrUtil.str(content, StandardCharsets.UTF_8); log.error("PigxFeignFallback:[{}.{}] serviceId:[{}] message:[{}]", targetType.getName(), method.getName(), targetName, str); - return R.builder().code(CommonConstants.FAIL) - .msg(str).build(); + return JSONUtil.toBean(str, R.class); } @Override diff --git a/pigx-common/pigx-common-swagger/pom.xml b/pigx-common/pigx-common-swagger/pom.xml index de0de37df..6bc15b33d 100644 --- a/pigx-common/pigx-common-swagger/pom.xml +++ b/pigx-common/pigx-common-swagger/pom.xml @@ -24,7 +24,7 @@ com.pig4cloud pigx-common - 2.7.0 + 2.8.0 pigx-common-swagger diff --git a/pigx-common/pigx-common-transaction/pom.xml b/pigx-common/pigx-common-transaction/pom.xml index 7a4a68163..e32c6d6a7 100644 --- a/pigx-common/pigx-common-transaction/pom.xml +++ b/pigx-common/pigx-common-transaction/pom.xml @@ -5,7 +5,7 @@ com.pig4cloud pigx-common - 2.7.0 + 2.8.0 pigx-common-transaction diff --git a/pigx-common/pom.xml b/pigx-common/pom.xml index d4cc03e9d..5d238a181 100644 --- a/pigx-common/pom.xml +++ b/pigx-common/pom.xml @@ -24,7 +24,7 @@ com.pig4cloud pigx - 2.7.0 + 2.8.0 pigx-common diff --git a/pigx-config/pom.xml b/pigx-config/pom.xml index 13c3036be..d7481420d 100644 --- a/pigx-config/pom.xml +++ b/pigx-config/pom.xml @@ -24,7 +24,7 @@ com.pig4cloud pigx - 2.7.0 + 2.8.0 pigx-config diff --git a/pigx-config/src/main/resources/config/pigx-codegen-dev.yml b/pigx-config/src/main/resources/config/pigx-codegen-dev.yml index 47d1fcfce..d8800e42a 100644 --- a/pigx-config/src/main/resources/config/pigx-codegen-dev.yml +++ b/pigx-config/src/main/resources/config/pigx-codegen-dev.yml @@ -12,6 +12,12 @@ spring: driver-class-name: com.mysql.cj.jdbc.Driver username: root password: root - url: jdbc:mysql://pigx-mysql:3306/pigxx?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8 + url: jdbc:mysql://pigx-mysql:3306/coffeewx?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8 resources: static-locations: classpath:/static/,classpath:/views/ + +pigx: + tenant: + column: tenant_id + tables: + - sys_datasource_conf \ No newline at end of file diff --git a/pigx-config/src/main/resources/config/pigx-mp-manager-dev.yml b/pigx-config/src/main/resources/config/pigx-mp-manager-dev.yml new file mode 100644 index 000000000..49280daac --- /dev/null +++ b/pigx-config/src/main/resources/config/pigx-mp-manager-dev.yml @@ -0,0 +1,33 @@ +## spring security 配置 +security: + oauth2: + client: + client-id: ENC(gPFcUOmJm8WqM3k3eSqS0Q==) + client-secret: ENC(gPFcUOmJm8WqM3k3eSqS0Q==) + scope: server + ignore-urls: + - /actuator/** + - /v2/api-docs + - /*/portal + +# 数据源配置 +spring: + datasource: + type: com.zaxxer.hikari.HikariDataSource + driver-class-name: com.mysql.cj.jdbc.Driver + username: root + password: root + url: jdbc:mysql://pigx-mysql:3306/coffeewx?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8 + hikari: + connection-init-sql: SET NAMES utf8mb4 + resources: + static-locations: classpath:/static/,classpath:/views/ + + +# 租户表维护 +pigx: + tenant: + column: tenant_id + tables: + - t_wx_account + - t_wx_account_fans \ No newline at end of file diff --git a/pigx-eureka/pom.xml b/pigx-eureka/pom.xml index 48b061c65..205b64354 100644 --- a/pigx-eureka/pom.xml +++ b/pigx-eureka/pom.xml @@ -24,7 +24,7 @@ com.pig4cloud pigx - 2.7.0 + 2.8.0 pigx-eureka diff --git a/pigx-gateway/pom.xml b/pigx-gateway/pom.xml index cf82cd02e..75e7d739e 100644 --- a/pigx-gateway/pom.xml +++ b/pigx-gateway/pom.xml @@ -24,7 +24,7 @@ com.pig4cloud pigx - 2.7.0 + 2.8.0 pigx-gateway diff --git a/pigx-upms/pigx-upms-api/pom.xml b/pigx-upms/pigx-upms-api/pom.xml index 164585399..cf377bc86 100644 --- a/pigx-upms/pigx-upms-api/pom.xml +++ b/pigx-upms/pigx-upms-api/pom.xml @@ -24,7 +24,7 @@ com.pig4cloud pigx-upms - 2.7.0 + 2.8.0 pigx-upms-api diff --git a/pigx-upms/pigx-upms-biz/pom.xml b/pigx-upms/pigx-upms-biz/pom.xml index e24090894..82ba9cc74 100644 --- a/pigx-upms/pigx-upms-biz/pom.xml +++ b/pigx-upms/pigx-upms-biz/pom.xml @@ -24,7 +24,7 @@ com.pig4cloud pigx-upms - 2.7.0 + 2.8.0 pigx-upms-biz diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/DeptController.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/DeptController.java index 28d952fc5..9570d3562 100644 --- a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/DeptController.java +++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/controller/DeptController.java @@ -68,16 +68,6 @@ public class DeptController { return new R<>(sysDeptService.selectTree()); } - /** - * 返回当前用户树形菜单集合 - * - * @return 树形菜单 - */ - @GetMapping(value = "/user-tree") - public R getUserTree() { - return new R<>(sysDeptService.getUserTree()); - } - /** * 添加 * diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/mapper/SysDeptMapper.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/mapper/SysDeptMapper.java index 6df92577f..aeb1e4ae5 100644 --- a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/mapper/SysDeptMapper.java +++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/mapper/SysDeptMapper.java @@ -22,8 +22,6 @@ package com.pig4cloud.pigx.admin.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.pig4cloud.pigx.admin.api.entity.SysDept; -import java.util.List; - /** *

* 部门管理 Mapper 接口 @@ -34,10 +32,4 @@ import java.util.List; */ public interface SysDeptMapper extends BaseMapper { - /** - * 关联dept——relation - * - * @return 数据列表 - */ - List listDepts(); } diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/SysDeptService.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/SysDeptService.java index d7cffea73..54417a797 100644 --- a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/SysDeptService.java +++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/SysDeptService.java @@ -42,13 +42,6 @@ public interface SysDeptService extends IService { */ List selectTree(); - /** - * 查询用户部门树 - * - * @return - */ - List getUserTree(); - /** * 添加信息部门 * diff --git a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysDeptServiceImpl.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysDeptServiceImpl.java index db853a5fc..82bc07eab 100644 --- a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysDeptServiceImpl.java +++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysDeptServiceImpl.java @@ -29,7 +29,6 @@ import com.pig4cloud.pigx.admin.api.vo.TreeUtil; import com.pig4cloud.pigx.admin.mapper.SysDeptMapper; import com.pig4cloud.pigx.admin.service.SysDeptRelationService; import com.pig4cloud.pigx.admin.service.SysDeptService; -import com.pig4cloud.pigx.common.security.util.SecurityUtils; import lombok.AllArgsConstructor; import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Service; @@ -79,11 +78,11 @@ public class SysDeptServiceImpl extends ServiceImpl impl public Boolean removeDeptById(Integer id) { //级联删除部门 List idList = sysDeptRelationService - .list(Wrappers.query().lambda() - .eq(SysDeptRelation::getAncestor, id)) - .stream() - .map(SysDeptRelation::getDescendant) - .collect(Collectors.toList()); + .list(Wrappers.query().lambda() + .eq(SysDeptRelation::getAncestor, id)) + .stream() + .map(SysDeptRelation::getDescendant) + .collect(Collectors.toList()); if (CollUtil.isNotEmpty(idList)) { this.removeByIds(idList); @@ -123,23 +122,6 @@ public class SysDeptServiceImpl extends ServiceImpl impl return getDeptTree(this.list(Wrappers.emptyWrapper())); } - /** - * 查询用户部门树 - * - * @return - */ - @Override - public List getUserTree() { - Integer deptId = SecurityUtils.getUser().getDeptId(); - List descendantIdList = sysDeptRelationService - .list(Wrappers.query().lambda() - .eq(SysDeptRelation::getAncestor, deptId)) - .stream().map(SysDeptRelation::getDescendant) - .collect(Collectors.toList()); - - List deptList = baseMapper.selectBatchIds(descendantIdList); - return getDeptTree(deptList); - } /** * 构建部门树 @@ -149,14 +131,14 @@ public class SysDeptServiceImpl extends ServiceImpl impl */ private List getDeptTree(List depts) { List treeList = depts.stream() - .filter(dept -> !dept.getDeptId().equals(dept.getParentId())) - .map(dept -> { - DeptTree node = new DeptTree(); - node.setId(dept.getDeptId()); - node.setParentId(dept.getParentId()); - node.setName(dept.getName()); - return node; - }).collect(Collectors.toList()); + .filter(dept -> !dept.getDeptId().equals(dept.getParentId())) + .map(dept -> { + DeptTree node = new DeptTree(); + node.setId(dept.getDeptId()); + node.setParentId(dept.getParentId()); + node.setName(dept.getName()); + return node; + }).collect(Collectors.toList()); return TreeUtil.build(treeList, 0); } } diff --git a/pigx-upms/pigx-upms-biz/src/main/resources/mapper/SysDeptMapper.xml b/pigx-upms/pigx-upms-biz/src/main/resources/mapper/SysDeptMapper.xml index 667c55728..7f0befa96 100644 --- a/pigx-upms/pigx-upms-biz/src/main/resources/mapper/SysDeptMapper.xml +++ b/pigx-upms/pigx-upms-biz/src/main/resources/mapper/SysDeptMapper.xml @@ -21,28 +21,4 @@ - - - - - - - - - - - - - dept_id AS deptId, parent_id AS parentId, name, sort, create_time AS createTime, update_time AS updateTime, del_flag AS delFlag - - - - diff --git a/pigx-upms/pigx-upms-biz/src/main/resources/mapper/SysUserMapper.xml b/pigx-upms/pigx-upms-biz/src/main/resources/mapper/SysUserMapper.xml index ac2822964..4a265e6f6 100644 --- a/pigx-upms/pigx-upms-biz/src/main/resources/mapper/SysUserMapper.xml +++ b/pigx-upms/pigx-upms-biz/src/main/resources/mapper/SysUserMapper.xml @@ -149,7 +149,7 @@ `user`.avatar, `user`.wx_openid, `user`.qq_openid, - `user`.dept_id, + `user`.dept_id AS deptId, `user`.create_time AS ucreate_time, `user`.update_time AS uupdate_time, `user`.del_flag AS udel_flag, diff --git a/pigx-upms/pigx-upms-biz/src/test/java/com/pig4cloud/pigx/admin/BitMapTest.java b/pigx-upms/pigx-upms-biz/src/test/java/com/pig4cloud/pigx/admin/BitMapTest.java new file mode 100644 index 000000000..f9344df9e --- /dev/null +++ b/pigx-upms/pigx-upms-biz/src/test/java/com/pig4cloud/pigx/admin/BitMapTest.java @@ -0,0 +1,86 @@ +package com.pig4cloud.pigx.admin; + +import java.util.BitSet; + +/** + * @author lengleng + * @date 2019-03-26 + */ +public class BitMapTest { + private int[] bigArray; + + public BitMapTest(long size) { + bigArray = new int[(int) (size / 32 + 1)]; + } + + public void set1(int num) { + //确定数组 index + int arrayIndex = num >> 5; + //确定bit index + int bitIndex = num & 31; + //设置0 + bigArray[arrayIndex] |= 1 << bitIndex; + + System.out.println(bigArray[arrayIndex]); + } + + public void set0(int num) { + //确定数组 index + int arrayIndex = num >> 5; + //确定bit index + int bitIndex = num & 31; + //设置0 + bigArray[arrayIndex] &= ~(1 << bitIndex); + System.out.println(get32BitBinString(bigArray[arrayIndex])); + } + + public boolean isExist(int num) { + //确定数组 index + int arrayIndex = num >> 5; + //确定bit index + int bitIndex = num & 31; + + //判断是否存在 + return (bigArray[arrayIndex] & ((1 << bitIndex))) != 0; + } + + /** + * 将整型数字转换为二进制字符串,一共32位,不舍弃前面的0 + * + * @param number 整型数字 + * @return 二进制字符串 + */ + private static String get32BitBinString(int number) { + StringBuilder sBuilder = new StringBuilder(); + for (int i = 0; i < 32; i++) { + sBuilder.append(number & 1); + number = number >>> 1; + } + return sBuilder.reverse().toString(); + } + + public static void main(String[] args) { + + int[] array = new int[]{1, 2, 3, 22, 0, 3, 63}; + BitSet bitSet = new BitSet(1); + System.out.println(bitSet.size()); //64 + bitSet = new BitSet(65); + System.out.println(bitSet.size()); //128 + bitSet = new BitSet(23); + System.out.println(bitSet.size()); //64 + + //将数组内容组bitmap + for (int i = 0; i < array.length; i++) { + bitSet.set(array[i], true); + } + + System.out.println(bitSet.get(22)); + System.out.println(bitSet.get(60)); + + System.out.println("下面开始遍历BitSet:"); + for (int i = 0; i < bitSet.size(); i++) { + System.out.println(bitSet.get(i)); + } + } + +} diff --git a/pigx-upms/pom.xml b/pigx-upms/pom.xml index ab20d7607..27545bc74 100644 --- a/pigx-upms/pom.xml +++ b/pigx-upms/pom.xml @@ -24,7 +24,7 @@ com.pig4cloud pigx - 2.7.0 + 2.8.0 pigx-upms diff --git a/pigx-visual/pigx-activiti/pom.xml b/pigx-visual/pigx-activiti/pom.xml index 45542b234..235acb84f 100644 --- a/pigx-visual/pigx-activiti/pom.xml +++ b/pigx-visual/pigx-activiti/pom.xml @@ -23,7 +23,7 @@ com.pig4cloud pigx-visual - 2.7.0 + 2.8.0 pigx-activiti diff --git a/pigx-visual/pigx-codegen/pom.xml b/pigx-visual/pigx-codegen/pom.xml index af9750be0..1805d57a7 100755 --- a/pigx-visual/pigx-codegen/pom.xml +++ b/pigx-visual/pigx-codegen/pom.xml @@ -6,7 +6,7 @@ com.pig4cloud pigx-visual - 2.7.0 + 2.8.0 pigx-codegen @@ -49,6 +49,10 @@ com.pig4cloud pigx-common-security + + com.pig4cloud + pigx-common-log + velocity diff --git a/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/PigxCodeGenApplication.java b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/PigxCodeGenApplication.java index 1939b0796..25a8ae599 100755 --- a/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/PigxCodeGenApplication.java +++ b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/PigxCodeGenApplication.java @@ -17,8 +17,8 @@ package com.pig4cloud.pigx.codegen; -import com.pig4cloud.pigx.common.security.annotation.EnablePigxResourceServer; import com.pig4cloud.pigx.common.security.annotation.EnablePigxFeignClients; +import com.pig4cloud.pigx.common.security.annotation.EnablePigxResourceServer; import com.pig4cloud.pigx.common.swagger.annotation.EnablePigxSwagger2; import org.springframework.boot.SpringApplication; import org.springframework.cloud.client.SpringCloudApplication; diff --git a/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/config/DynamicDataSource.java b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/config/DynamicDataSource.java new file mode 100644 index 000000000..252b8d87f --- /dev/null +++ b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/config/DynamicDataSource.java @@ -0,0 +1,25 @@ +package com.pig4cloud.pigx.codegen.config; + +import com.pig4cloud.pigx.codegen.util.DynamicDataSourceContextHolder; +import lombok.extern.slf4j.Slf4j; +import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; + +/** + * @author lengleng + * @date 2019-03-31 + *

+ * 动态数据源类 + */ +@Slf4j +public class DynamicDataSource extends AbstractRoutingDataSource { + + /** + * 指定路由Key + * + * @return + */ + @Override + protected Object determineCurrentLookupKey() { + return DynamicDataSourceContextHolder.getDataSourceType(); + } +} \ No newline at end of file diff --git a/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/config/DynamicDataSourceConfig.java b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/config/DynamicDataSourceConfig.java new file mode 100644 index 000000000..41f175e25 --- /dev/null +++ b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/config/DynamicDataSourceConfig.java @@ -0,0 +1,102 @@ +package com.pig4cloud.pigx.codegen.config; + +import com.mysql.cj.jdbc.Driver; +import com.pig4cloud.pigx.codegen.util.DataSourceConstant; +import com.zaxxer.hikari.HikariDataSource; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.jasypt.encryption.StringEncryptor; +import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.datasource.DataSourceTransactionManager; +import org.springframework.jdbc.datasource.DriverManagerDataSource; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.annotation.TransactionManagementConfigurer; + +import javax.annotation.PostConstruct; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +/** + * @author lengleng + * @date 2019-03-31 + *

+ * 动态数据源切换配置 + */ +@Slf4j +@Configuration +@AllArgsConstructor +public class DynamicDataSourceConfig implements TransactionManagementConfigurer { + private final Map dataSourceMap = new HashMap<>(8); + private final DataSourceProperties dataSourceProperties; + private final StringEncryptor stringEncryptor; + + @Bean("dynamicDataSource") + public DynamicDataSource dataSource() { + DynamicDataSource ds = new DynamicDataSource(); + HikariDataSource cads = new HikariDataSource(); + cads.setJdbcUrl(dataSourceProperties.getUrl()); + cads.setDriverClassName(dataSourceProperties.getDriverClassName()); + cads.setUsername(dataSourceProperties.getUsername()); + cads.setPassword(dataSourceProperties.getPassword()); + ds.setDefaultTargetDataSource(cads); + dataSourceMap.put(0, cads); + ds.setTargetDataSources(dataSourceMap); + return ds; + } + + /** + * 组装默认配置的数据源,查询数据库配置 + */ + @PostConstruct + public void init() { + DriverManagerDataSource dds = new DriverManagerDataSource(); + dds.setUrl(dataSourceProperties.getUrl()); + dds.setDriverClassName(dataSourceProperties.getDriverClassName()); + dds.setUsername(dataSourceProperties.getUsername()); + dds.setPassword(dataSourceProperties.getPassword()); + + List> dbList = new JdbcTemplate(dds).queryForList(DataSourceConstant.QUERY_DS_SQL); + log.info("开始 -> 初始化动态数据源"); + Optional.of(dbList).ifPresent(list -> list.forEach(db -> { + log.info("数据源:{}", db.get(DataSourceConstant.DS_NAME)); + HikariDataSource ds = new HikariDataSource(); + ds.setJdbcUrl(String.valueOf(db.get(DataSourceConstant.DS_JDBC_URL))); + ds.setDriverClassName(Driver.class.getName()); + ds.setUsername((String) db.get(DataSourceConstant.DS_NAME)); + + String decPwd = stringEncryptor.decrypt((String) db.get(DataSourceConstant.DS_USER_PWD)); + ds.setPassword(decPwd); + dataSourceMap.put(db.get(DataSourceConstant.DS_ROUTE_KEY), ds); + })); + + log.info("完毕 -> 初始化动态数据源,共计 {} 条", dataSourceMap.size()); + } + + /** + * 重新加载数据源配置 + */ + public Boolean reload() { + init(); + DynamicDataSource dataSource = dataSource(); + dataSource.setTargetDataSources(dataSourceMap); + dataSource.afterPropertiesSet(); + return Boolean.FALSE; + } + + + @Bean + public PlatformTransactionManager txManager() { + return new DataSourceTransactionManager(dataSource()); + } + + @Override + public PlatformTransactionManager annotationDrivenTransactionManager() { + return txManager(); + } + +} \ No newline at end of file diff --git a/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/controller/SysDsConfController.java b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/controller/SysDsConfController.java new file mode 100755 index 000000000..57cbafe66 --- /dev/null +++ b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/controller/SysDsConfController.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2018-2025, lengleng All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the pig4cloud.com developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: lengleng (wangiegie@gmail.com) + */ +package com.pig4cloud.pigx.codegen.controller; + +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.pig4cloud.pigx.codegen.entity.SysDatasourceConf; +import com.pig4cloud.pigx.codegen.service.SysDatasourceConfService; +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.common.log.annotation.SysLog; +import lombok.AllArgsConstructor; +import org.springframework.web.bind.annotation.*; + + +/** + * 数据源管理 + * + * @author pigx code generator + * @date 2019-03-31 16:00:20 + */ +@RestController +@AllArgsConstructor +@RequestMapping("/dsconf") +public class SysDsConfController { + private final SysDatasourceConfService sysDatasourceConfService; + + /** + * 分页查询 + * + * @param page 分页对象 + * @param sysDatasourceConf 数据源表 + * @return + */ + @GetMapping("/page") + public R getSysDatasourceConfPage(Page page, SysDatasourceConf sysDatasourceConf) { + return new R<>(sysDatasourceConfService.page(page, Wrappers.query(sysDatasourceConf))); + } + + /** + * 查询全部数据源 + * + * @return + */ + @GetMapping("/list") + public R list() { + return new R<>(sysDatasourceConfService.list()); + } + + + /** + * 通过id查询数据源表 + * + * @param id id + * @return R + */ + @GetMapping("/{id}") + public R getById(@PathVariable("id") Integer id) { + return new R<>(sysDatasourceConfService.getById(id)); + } + + /** + * 新增数据源表 + * + * @param sysDatasourceConf 数据源表 + * @return R + */ + @SysLog("新增数据源表") + @PostMapping + public R save(@RequestBody SysDatasourceConf sysDatasourceConf) { + return new R<>(sysDatasourceConfService.saveDsByEnc(sysDatasourceConf)); + } + + /** + * 修改数据源表 + * + * @param sysDatasourceConf 数据源表 + * @return R + */ + @SysLog("修改数据源表") + @PutMapping + public R updateById(@RequestBody SysDatasourceConf sysDatasourceConf) { + return new R<>(sysDatasourceConfService.updateDsByEnc(sysDatasourceConf)); + } + + /** + * 通过id删除数据源表 + * + * @param id id + * @return R + */ + @SysLog("删除数据源表") + @DeleteMapping("/{id}") + public R removeById(@PathVariable Integer id) { + return new R<>(sysDatasourceConfService.removeById(id)); + } + +} diff --git a/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/controller/SysGeneratorController.java b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/controller/SysGeneratorController.java index 33ce4aa7a..42eb67911 100755 --- a/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/controller/SysGeneratorController.java +++ b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/controller/SysGeneratorController.java @@ -28,7 +28,6 @@ import org.springframework.http.HttpHeaders; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletResponse; -import java.io.IOException; /** * 代码生成器 @@ -46,11 +45,12 @@ public class SysGeneratorController { * 列表 * * @param tableName 参数集 + * @param id 数据源编号 * @return 数据库表 */ @GetMapping("/page") - public R getPage(Page page, String tableName) { - return new R<>(sysGeneratorService.getPage(page, tableName)); + public R getPage(Page page, String tableName, Integer id) { + return new R<>(sysGeneratorService.getPage(page, tableName, id)); } /** @@ -60,7 +60,6 @@ public class SysGeneratorController { @PostMapping("/code") public void generatorCode(@RequestBody GenConfig genConfig, HttpServletResponse response) { byte[] data = sysGeneratorService.generatorCode(genConfig); - response.reset(); response.setHeader(HttpHeaders.CONTENT_DISPOSITION, String.format("attachment; filename=%s.zip", genConfig.getTableName())); response.addHeader(HttpHeaders.CONTENT_LENGTH, String.valueOf(data.length)); diff --git a/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/entity/GenConfig.java b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/entity/GenConfig.java index 5ad6dd6e6..cb270c897 100644 --- a/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/entity/GenConfig.java +++ b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/entity/GenConfig.java @@ -26,6 +26,10 @@ import lombok.Data; */ @Data public class GenConfig { + /** + * 数据源ID + */ + private Integer id; /** * 包名 */ diff --git a/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/entity/SysDatasourceConf.java b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/entity/SysDatasourceConf.java new file mode 100755 index 000000000..218d8c969 --- /dev/null +++ b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/entity/SysDatasourceConf.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2018-2025, lengleng All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the pig4cloud.com developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: lengleng (wangiegie@gmail.com) + */ +package com.pig4cloud.pigx.codegen.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.time.LocalDateTime; + +/** + * 数据源表 + * + * @author pigx code generator + * @date 2019-03-31 16:00:20 + */ +@Data +@TableName("sys_datasource_conf") +@EqualsAndHashCode(callSuper = true) +public class SysDatasourceConf extends Model { + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId + private Integer id; + /** + * 名称 + */ + private String name; + /** + * jdbcurl + */ + private String url; + /** + * 用户名 + */ + private String username; + /** + * 密码 + */ + private String password; + /** + * 创建时间 + */ + private LocalDateTime createDate; + /** + * 更新 + */ + private LocalDateTime updateDate; + /** + * 删除标记 + */ + @TableLogic + private String delFlag; + /** + * 租户ID + */ + private Integer tenantId; + +} diff --git a/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/mapper/SysDatasourceConfMapper.java b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/mapper/SysDatasourceConfMapper.java new file mode 100755 index 000000000..c44231e48 --- /dev/null +++ b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/mapper/SysDatasourceConfMapper.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2018-2025, lengleng All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the pig4cloud.com developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: lengleng (wangiegie@gmail.com) + */ +package com.pig4cloud.pigx.codegen.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.pig4cloud.pigx.codegen.entity.SysDatasourceConf; + +/** + * 数据源表 + * + * @author pigx code generator + * @date 2019-03-31 16:00:20 + */ +public interface SysDatasourceConfMapper extends BaseMapper { + +} diff --git a/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/service/SysDatasourceConfService.java b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/service/SysDatasourceConfService.java new file mode 100755 index 000000000..8a2100605 --- /dev/null +++ b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/service/SysDatasourceConfService.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2018-2025, lengleng All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the pig4cloud.com developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: lengleng (wangiegie@gmail.com) + */ +package com.pig4cloud.pigx.codegen.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.pig4cloud.pigx.codegen.entity.SysDatasourceConf; + +/** + * 数据源表 + * + * @author pigx code generator + * @date 2019-03-31 16:00:20 + */ +public interface SysDatasourceConfService extends IService { + /** + * 保存数据源并且加密 + * + * @param sysDatasourceConf + * @return + */ + Boolean saveDsByEnc(SysDatasourceConf sysDatasourceConf); + + /** + * 更新数据源 + * + * @param sysDatasourceConf + * @return + */ + Boolean updateDsByEnc(SysDatasourceConf sysDatasourceConf); +} diff --git a/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/service/SysGeneratorService.java b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/service/SysGeneratorService.java index 08b943e28..4e5644235 100644 --- a/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/service/SysGeneratorService.java +++ b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/service/SysGeneratorService.java @@ -39,8 +39,10 @@ public interface SysGeneratorService { /** * 分页查询表 + * * @param tableName 表名 + * @param id 数据源ID * @return */ - IPage>> getPage(Page page, String tableName); + IPage>> getPage(Page page, String tableName, Integer id); } diff --git a/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/service/impl/SysDatasourceConfServiceImpl.java b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/service/impl/SysDatasourceConfServiceImpl.java new file mode 100755 index 000000000..74e923eb3 --- /dev/null +++ b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/service/impl/SysDatasourceConfServiceImpl.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2018-2025, lengleng All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the pig4cloud.com developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: lengleng (wangiegie@gmail.com) + */ +package com.pig4cloud.pigx.codegen.service.impl; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.pig4cloud.pigx.codegen.config.DynamicDataSourceConfig; +import com.pig4cloud.pigx.codegen.entity.SysDatasourceConf; +import com.pig4cloud.pigx.codegen.mapper.SysDatasourceConfMapper; +import com.pig4cloud.pigx.codegen.service.SysDatasourceConfService; +import lombok.AllArgsConstructor; +import org.jasypt.encryption.StringEncryptor; +import org.springframework.stereotype.Service; + +/** + * 数据源表 + * + * @author pigx code generator + * @date 2019-03-31 16:00:20 + */ +@Service +@AllArgsConstructor +public class SysDatasourceConfServiceImpl extends ServiceImpl implements SysDatasourceConfService { + private final DynamicDataSourceConfig dynamicDataSourceConfig; + private final StringEncryptor stringEncryptor; + + /** + * 保存数据源并且加密 + * + * @param sysDatasourceConf + * @return + */ + @Override + public Boolean saveDsByEnc(SysDatasourceConf sysDatasourceConf) { + sysDatasourceConf.setPassword(stringEncryptor.encrypt(sysDatasourceConf.getPassword())); + this.baseMapper.insert(sysDatasourceConf); + return dynamicDataSourceConfig.reload(); + } + + /** + * 更新数据源 + * + * @param sysDatasourceConf + * @return + */ + @Override + public Boolean updateDsByEnc(SysDatasourceConf sysDatasourceConf) { + if (StrUtil.isNotBlank(sysDatasourceConf.getPassword())) { + sysDatasourceConf.setPassword(stringEncryptor.encrypt(sysDatasourceConf.getPassword())); + } + this.baseMapper.updateById(sysDatasourceConf); + return dynamicDataSourceConfig.reload(); + } +} diff --git a/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/service/impl/SysGeneratorServiceImpl.java b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/service/impl/SysGeneratorServiceImpl.java index 339485532..16a688e45 100755 --- a/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/service/impl/SysGeneratorServiceImpl.java +++ b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/service/impl/SysGeneratorServiceImpl.java @@ -21,8 +21,10 @@ import cn.hutool.core.io.IoUtil; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.pig4cloud.pigx.codegen.entity.GenConfig; +import com.pig4cloud.pigx.codegen.mapper.SysDatasourceConfMapper; import com.pig4cloud.pigx.codegen.mapper.SysGeneratorMapper; import com.pig4cloud.pigx.codegen.service.SysGeneratorService; +import com.pig4cloud.pigx.codegen.util.DynamicDataSourceContextHolder; import com.pig4cloud.pigx.codegen.util.GenUtils; import lombok.AllArgsConstructor; import org.springframework.stereotype.Service; @@ -41,18 +43,20 @@ import java.util.zip.ZipOutputStream; @Service @AllArgsConstructor public class SysGeneratorServiceImpl implements SysGeneratorService { + private final SysDatasourceConfMapper sysDatasourceConfMapper; private final SysGeneratorMapper sysGeneratorMapper; - /** * 分页查询表 * * @param tableName 查询条件 + * @param id * @return */ @Override - public IPage>> getPage(Page page, String tableName) { - return sysGeneratorMapper.queryList(page,tableName); + public IPage>> getPage(Page page, String tableName, Integer id) { + DynamicDataSourceContextHolder.setDataSourceType(id); + return sysGeneratorMapper.queryList(page, tableName); } /** @@ -63,6 +67,7 @@ public class SysGeneratorServiceImpl implements SysGeneratorService { */ @Override public byte[] generatorCode(GenConfig genConfig) { + DynamicDataSourceContextHolder.setDataSourceType(genConfig.getId()); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); ZipOutputStream zip = new ZipOutputStream(outputStream); diff --git a/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/util/DataSourceConstant.java b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/util/DataSourceConstant.java new file mode 100644 index 000000000..d69d719b3 --- /dev/null +++ b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/util/DataSourceConstant.java @@ -0,0 +1,40 @@ +package com.pig4cloud.pigx.codegen.util; + +/** + * @author lengleng + * @date 2019-04-01 + *

+ * 数据源相关常量 + */ +public interface DataSourceConstant { + /** + * 查询数据源的SQL + */ + String QUERY_DS_SQL = "select * from sys_datasource_conf where del_flag = 0"; + + /** + * 动态路由KEY + */ + String DS_ROUTE_KEY = "id"; + + /** + * 数据源名称 + */ + String DS_NAME = "name"; + + /** + * jdbcurl + */ + String DS_JDBC_URL = "url"; + + /** + * 用户名 + */ + String DS_USER_NAME = "username"; + + /** + * 密码 + */ + String DS_USER_PWD = "password"; + +} diff --git a/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/util/DynamicDataSourceContextHolder.java b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/util/DynamicDataSourceContextHolder.java new file mode 100644 index 000000000..4e0c2d546 --- /dev/null +++ b/pigx-visual/pigx-codegen/src/main/java/com/pig4cloud/pigx/codegen/util/DynamicDataSourceContextHolder.java @@ -0,0 +1,26 @@ +package com.pig4cloud.pigx.codegen.util; + +import lombok.experimental.UtilityClass; + +/** + * @author lengleng + * @date 2019-03-31 + *

+ * 保存上线文中数据库路由 + */ +@UtilityClass +public class DynamicDataSourceContextHolder { + private final ThreadLocal CONTEXT_HOLDER = new ThreadLocal<>(); + + public void setDataSourceType(Integer dataSourceType) { + CONTEXT_HOLDER.set(dataSourceType); + } + + public Integer getDataSourceType() { + return CONTEXT_HOLDER.get(); + } + + public void clearDataSourceType() { + CONTEXT_HOLDER.remove(); + } +} \ No newline at end of file diff --git a/pigx-visual/pigx-codegen/src/main/resources/template/index.vue.vm b/pigx-visual/pigx-codegen/src/main/resources/template/index.vue.vm index 6fd88767a..c27431e56 100755 --- a/pigx-visual/pigx-codegen/src/main/resources/template/index.vue.vm +++ b/pigx-visual/pigx-codegen/src/main/resources/template/index.vue.vm @@ -62,10 +62,6 @@ tableOption: tableOption } }, - created() { - }, - mounted: function () { - }, computed: { ...mapGetters(['permissions']), permissionList() { @@ -98,11 +94,7 @@ return delObj(row.$pk.lowerAttrName) }).then(data => { _this.tableData.splice(index, 1) - _this.$message({ - showClose: true, - message: '删除成功', - type: 'success' - }) + _this.$message.success('删除成功') this.getList(this.page) }).catch(function (err) { }) @@ -117,11 +109,7 @@ handleUpdate: function (row, index, done) { putObj(row).then(data => { this.tableData.splice(index, 1, Object.assign({}, row)) - this.$message({ - showClose: true, - message: '修改成功', - type: 'success' - }) + _this.$message.success('修改成功') done() this.getList(this.page) }) @@ -135,11 +123,7 @@ handleSave: function (row, done) { addObj(row).then(data => { this.tableData.push(Object.assign({}, row)) - this.$message({ - showClose: true, - message: '添加成功', - type: 'success' - }) + _this.$message.success('添加成功') done() this.getList(this.page) }) diff --git a/pigx-visual/pigx-daemon-elastic-job/pom.xml b/pigx-visual/pigx-daemon-elastic-job/pom.xml index d1111705c..47a291a04 100644 --- a/pigx-visual/pigx-daemon-elastic-job/pom.xml +++ b/pigx-visual/pigx-daemon-elastic-job/pom.xml @@ -23,7 +23,7 @@ com.pig4cloud pigx-visual - 2.7.0 + 2.8.0 pigx-daemon-elastic-job diff --git a/pigx-visual/pigx-daemon-elastic-job/src/main/java/com/pig4cloud/pigx/daemon/elastic/entity/ExecutionLog.java b/pigx-visual/pigx-daemon-elastic-job/src/main/java/com/pig4cloud/pigx/daemon/elastic/entity/ExecutionLog.java index df7f52671..e1bc379af 100644 --- a/pigx-visual/pigx-daemon-elastic-job/src/main/java/com/pig4cloud/pigx/daemon/elastic/entity/ExecutionLog.java +++ b/pigx-visual/pigx-daemon-elastic-job/src/main/java/com/pig4cloud/pigx/daemon/elastic/entity/ExecutionLog.java @@ -17,7 +17,7 @@ import java.time.LocalDateTime; */ @Data @EqualsAndHashCode(callSuper = true) -@TableName("job_execution_log") +@TableName("JOB_EXECUTION_LOG") public class ExecutionLog extends Model { private static final long serialVersionUID = 1L; diff --git a/pigx-visual/pigx-daemon-elastic-job/src/main/java/com/pig4cloud/pigx/daemon/elastic/entity/StatusTraceLog.java b/pigx-visual/pigx-daemon-elastic-job/src/main/java/com/pig4cloud/pigx/daemon/elastic/entity/StatusTraceLog.java index dcf1acc38..2e071cea3 100644 --- a/pigx-visual/pigx-daemon-elastic-job/src/main/java/com/pig4cloud/pigx/daemon/elastic/entity/StatusTraceLog.java +++ b/pigx-visual/pigx-daemon-elastic-job/src/main/java/com/pig4cloud/pigx/daemon/elastic/entity/StatusTraceLog.java @@ -16,7 +16,7 @@ import java.time.LocalDateTime; */ @Data @EqualsAndHashCode(callSuper = true) -@TableName("job_status_trace_log") +@TableName("JOB_STATUS_TRACE_LOG") public class StatusTraceLog extends Model { private static final long serialVersionUID = 1L; diff --git a/pigx-visual/pigx-daemon-quartz/pom.xml b/pigx-visual/pigx-daemon-quartz/pom.xml index 36fcd37f5..0f6b1860f 100644 --- a/pigx-visual/pigx-daemon-quartz/pom.xml +++ b/pigx-visual/pigx-daemon-quartz/pom.xml @@ -5,7 +5,7 @@ com.pig4cloud pigx-visual - 2.7.0 + 2.8.0 4.0.0 diff --git a/pigx-visual/pigx-monitor/pom.xml b/pigx-visual/pigx-monitor/pom.xml index dd41f551d..bf2432ce0 100644 --- a/pigx-visual/pigx-monitor/pom.xml +++ b/pigx-visual/pigx-monitor/pom.xml @@ -24,7 +24,7 @@ com.pig4cloud pigx-visual - 2.7.0 + 2.8.0 pigx-monitor @@ -36,7 +36,7 @@ com.pig4cloud pigx-common-core - 2.7.0 + 2.8.0 org.springframework.boot diff --git a/pigx-visual/pigx-mp-manager/Dockerfile b/pigx-visual/pigx-mp-manager/Dockerfile new file mode 100644 index 000000000..702a7171c --- /dev/null +++ b/pigx-visual/pigx-mp-manager/Dockerfile @@ -0,0 +1,15 @@ +FROM anapsix/alpine-java:8_server-jre_unlimited + +MAINTAINER wangiegie@gmail.com + +RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime + +RUN mkdir -p /pigx-mp-manager + +WORKDIR /pigx-mp-manager + +EXPOSE 5003 + +ADD ./pigx-visual/pigx-mp-manager/target/pigx-mp-manager.jar ./ + +CMD java -Djava.security.egd=file:/dev/./urandom -jar pigx-mp-manager.jar diff --git a/pigx-visual/pigx-mp-manager/pom.xml b/pigx-visual/pigx-mp-manager/pom.xml new file mode 100755 index 000000000..60be05627 --- /dev/null +++ b/pigx-visual/pigx-mp-manager/pom.xml @@ -0,0 +1,85 @@ + + + 4.0.0 + + + com.pig4cloud + pigx-visual + 2.8.0 + + + pigx-mp-manager + jar + + 微信公众号管理模块 + + + + + org.springframework.cloud + spring-cloud-starter-config + + + + com.pig4cloud + pigx-common-data + + + + com.baomidou + mybatis-plus-boot-starter + + + mysql + mysql-connector-java + + + + com.pig4cloud + pigx-common-core + + + + com.pig4cloud + pigx-common-swagger + + + + com.pig4cloud + pigx-common-security + + + com.pig4cloud + pigx-common-log + + + + com.github.binarywang + weixin-java-mp + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-undertow + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + com.spotify + docker-maven-plugin + + + + diff --git a/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/PigxMpManagerApplication.java b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/PigxMpManagerApplication.java new file mode 100755 index 000000000..ee64a45b6 --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/PigxMpManagerApplication.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2018-2025, lengleng All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the pig4cloud.com developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: lengleng (wangiegie@gmail.com) + */ + +package com.pig4cloud.pigx.mp; + +import com.pig4cloud.pigx.common.security.annotation.EnablePigxFeignClients; +import com.pig4cloud.pigx.common.security.annotation.EnablePigxResourceServer; +import com.pig4cloud.pigx.common.swagger.annotation.EnablePigxSwagger2; +import org.springframework.boot.SpringApplication; +import org.springframework.cloud.client.SpringCloudApplication; + +/** + * @author lengleng + * @date 2019/03/25 + * 代码生成模块 + */ +@EnablePigxSwagger2 +@SpringCloudApplication +@EnablePigxFeignClients +@EnablePigxResourceServer +public class PigxMpManagerApplication { + + public static void main(String[] args) { + SpringApplication.run(PigxMpManagerApplication.class, args); + } +} diff --git a/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/builder/AbstractBuilder.java b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/builder/AbstractBuilder.java new file mode 100755 index 000000000..7a94beb73 --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/builder/AbstractBuilder.java @@ -0,0 +1,21 @@ +package com.pig4cloud.pigx.mp.builder; + +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; + +/** + * @author Binary Wang(https://github.com/binarywang) + */ +public abstract class AbstractBuilder { + /** + * 构建返回微信消息报文 + * + * @param content + * @param wxMessage + * @param service + * @return + */ + public abstract WxMpXmlOutMessage build(String content, + WxMpXmlMessage wxMessage, WxMpService service); +} diff --git a/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/builder/ImageBuilder.java b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/builder/ImageBuilder.java new file mode 100755 index 000000000..07d8686f6 --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/builder/ImageBuilder.java @@ -0,0 +1,24 @@ +package com.pig4cloud.pigx.mp.builder; + +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutImageMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; + +/** + * @author Binary Wang(https://github.com/binarywang) + */ +public class ImageBuilder extends AbstractBuilder { + + @Override + public WxMpXmlOutMessage build(String content, WxMpXmlMessage wxMessage, + WxMpService service) { + + WxMpXmlOutImageMessage m = WxMpXmlOutMessage.IMAGE().mediaId(content) + .fromUser(wxMessage.getToUser()).toUser(wxMessage.getFromUser()) + .build(); + + return m; + } + +} diff --git a/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/builder/TextBuilder.java b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/builder/TextBuilder.java new file mode 100755 index 000000000..a212ddc27 --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/builder/TextBuilder.java @@ -0,0 +1,22 @@ +package com.pig4cloud.pigx.mp.builder; + +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.bean.message.WxMpXmlOutTextMessage; + +/** + * @author Binary Wang(https://github.com/binarywang) + */ +public class TextBuilder extends AbstractBuilder { + + @Override + public WxMpXmlOutMessage build(String content, WxMpXmlMessage wxMessage, + WxMpService service) { + WxMpXmlOutTextMessage m = WxMpXmlOutMessage.TEXT().content(content) + .fromUser(wxMessage.getToUser()).toUser(wxMessage.getFromUser()) + .build(); + return m; + } + +} diff --git a/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/config/WxMpConfiguration.java b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/config/WxMpConfiguration.java new file mode 100755 index 000000000..6211b502a --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/config/WxMpConfiguration.java @@ -0,0 +1,149 @@ +package com.pig4cloud.pigx.mp.config; + +import com.google.common.collect.Maps; +import com.pig4cloud.pigx.mp.handler.*; +import com.pig4cloud.pigx.mp.service.WxAccountService; +import me.chanjar.weixin.mp.api.WxMpMessageRouter; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl; +import me.chanjar.weixin.mp.constant.WxMpEventConstants; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.core.RedisTemplate; + +import javax.annotation.PostConstruct; +import java.util.Map; +import java.util.stream.Collectors; + +import static me.chanjar.weixin.common.api.WxConsts.*; + +/** + * @author Binary Wang + * @author lengleng + *

+ * 微信公众号基础配置,初始化配置 + */ +@Configuration +public class WxMpConfiguration { + public static Map getRouters() { + return routers; + } + + public static Map getMpServices() { + return mpServices; + } + + private WxAccountService accountService; + private LogHandler logHandler; + private NullHandler nullHandler; + private KfSessionHandler kfSessionHandler; + private StoreCheckNotifyHandler storeCheckNotifyHandler; + private LocationHandler locationHandler; + private MenuHandler menuHandler; + private MsgHandler msgHandler; + private UnsubscribeHandler unsubscribeHandler; + private SubscribeHandler subscribeHandler; + private ScanHandler scanHandler; + private RedisTemplate redisTemplate; + + private static Map routers = Maps.newHashMap(); + private static Map mpServices = Maps.newHashMap(); + + @Autowired + public WxMpConfiguration(WxAccountService accountService, LogHandler logHandler, NullHandler nullHandler + , KfSessionHandler kfSessionHandler, StoreCheckNotifyHandler storeCheckNotifyHandler + , LocationHandler locationHandler, MenuHandler menuHandler + , MsgHandler msgHandler, UnsubscribeHandler unsubscribeHandler + , SubscribeHandler subscribeHandler, ScanHandler scanHandler + , RedisTemplate pigxRedisTemplate) { + this.accountService = accountService; + this.logHandler = logHandler; + this.nullHandler = nullHandler; + this.kfSessionHandler = kfSessionHandler; + this.storeCheckNotifyHandler = storeCheckNotifyHandler; + this.locationHandler = locationHandler; + this.menuHandler = menuHandler; + this.msgHandler = msgHandler; + this.unsubscribeHandler = unsubscribeHandler; + this.subscribeHandler = subscribeHandler; + this.scanHandler = scanHandler; + this.redisTemplate = pigxRedisTemplate; + } + + @PostConstruct + public void initServices() { + mpServices = accountService.list().stream().map(a -> { + WxMpInRedisConfigStorage configStorage = new WxMpInRedisConfigStorage(redisTemplate); + configStorage.setAppId(a.getAppid()); + configStorage.setSecret(a.getAppsecret()); + configStorage.setToken(a.getToken()); + configStorage.setAesKey(a.getAeskey()); + + WxMpService service = new WxMpServiceImpl(); + service.setWxMpConfigStorage(configStorage); + routers.put(a.getAppid(), this.newRouter(service)); + return service; + }).collect(Collectors.toMap(s -> s.getWxMpConfigStorage().getAppId(), a -> a)); + } + + private WxMpMessageRouter newRouter(WxMpService wxMpService) { + final WxMpMessageRouter newRouter = new WxMpMessageRouter(wxMpService); + + // 记录所有事件的日志 (异步执行) + newRouter.rule().handler(this.logHandler).next(); + + // 接收客服会话管理事件 + newRouter.rule().async(false).msgType(XmlMsgType.EVENT) + .event(WxMpEventConstants.CustomerService.KF_CREATE_SESSION) + .handler(this.kfSessionHandler).end(); + newRouter.rule().async(false).msgType(XmlMsgType.EVENT) + .event(WxMpEventConstants.CustomerService.KF_CLOSE_SESSION) + .handler(this.kfSessionHandler) + .end(); + newRouter.rule().async(false).msgType(XmlMsgType.EVENT) + .event(WxMpEventConstants.CustomerService.KF_SWITCH_SESSION) + .handler(this.kfSessionHandler).end(); + + // 门店审核事件 + newRouter.rule().async(false).msgType(XmlMsgType.EVENT) + .event(WxMpEventConstants.POI_CHECK_NOTIFY) + .handler(this.storeCheckNotifyHandler).end(); + + // 自定义菜单事件 + newRouter.rule().async(false).msgType(XmlMsgType.EVENT) + .event(MenuButtonType.CLICK).handler(this.menuHandler).end(); + + // 点击菜单连接事件 + newRouter.rule().async(false).msgType(XmlMsgType.EVENT) + .event(MenuButtonType.VIEW).handler(this.nullHandler).end(); + + // 关注事件 + newRouter.rule().async(false).msgType(XmlMsgType.EVENT) + .event(EventType.SUBSCRIBE).handler(this.subscribeHandler) + .end(); + + // 取消关注事件 + newRouter.rule().async(false).msgType(XmlMsgType.EVENT) + .event(EventType.UNSUBSCRIBE) + .handler(this.unsubscribeHandler).end(); + + // 上报地理位置事件 + newRouter.rule().async(false).msgType(XmlMsgType.EVENT) + .event(EventType.LOCATION).handler(this.locationHandler) + .end(); + + // 接收地理位置消息 + newRouter.rule().async(false).msgType(XmlMsgType.LOCATION) + .handler(this.locationHandler).end(); + + // 扫码事件 + newRouter.rule().async(false).msgType(XmlMsgType.EVENT) + .event(EventType.SCAN).handler(this.scanHandler).end(); + + // 默认 + newRouter.rule().async(false).handler(this.msgHandler).end(); + + return newRouter; + } + +} diff --git a/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/config/WxMpContextHolder.java b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/config/WxMpContextHolder.java new file mode 100644 index 000000000..9f73e4a01 --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/config/WxMpContextHolder.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2018-2025, lengleng All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the pig4cloud.com developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: lengleng (wangiegie@gmail.com) + */ + +package com.pig4cloud.pigx.mp.config; + +import com.alibaba.ttl.TransmittableThreadLocal; +import lombok.experimental.UtilityClass; + +/** + * @author lengleng + * @date 2019/03/27 + * 微信上下文工具类 + */ +@UtilityClass +public class WxMpContextHolder { + + private final ThreadLocal THREAD_LOCAL_APPID = new TransmittableThreadLocal<>(); + + + /** + * TTL 设置appId + * + * @param appId + */ + public void setAppId(String appId) { + THREAD_LOCAL_APPID.set(appId); + } + + /** + * 获取TTL中的appId + * + * @return + */ + public String getAppId() { + return THREAD_LOCAL_APPID.get(); + } + + public void clear() { + THREAD_LOCAL_APPID.remove(); + } +} diff --git a/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/config/WxMpInRedisConfigStorage.java b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/config/WxMpInRedisConfigStorage.java new file mode 100644 index 000000000..a045b6ca5 --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/config/WxMpInRedisConfigStorage.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2018-2025, 云集汇通 All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the yunjihuitong.com developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + */ + +package com.pig4cloud.pigx.mp.config; + +import me.chanjar.weixin.mp.api.WxMpInMemoryConfigStorage; +import me.chanjar.weixin.mp.enums.TicketType; +import org.springframework.data.redis.core.RedisTemplate; + +import java.util.concurrent.TimeUnit; + +/** + * @author lengleng + * @date 2019/03/26 + *

+ * 微信SDK redis扩展 + */ +public class WxMpInRedisConfigStorage extends WxMpInMemoryConfigStorage { + + private final static String ACCESS_TOKEN_KEY = "wechat:access_token_"; + + private final static String JSAPI_TICKET_KEY = "wechat:jsapi_ticket_"; + + private final static String CARDAPI_TICKET_KEY = "wechat:cardapi_ticket_"; + + private final RedisTemplate redisTemplate; + + private String accessTokenKey; + + private String jsapiTicketKey; + + private String cardapiTicketKey; + + public WxMpInRedisConfigStorage(RedisTemplate redisTemplate) { + this.redisTemplate = redisTemplate; + } + + /** + * 每个公众号生成独有的存储key + * + * @param appId + */ + @Override + public void setAppId(String appId) { + super.setAppId(appId); + this.accessTokenKey = ACCESS_TOKEN_KEY.concat(appId); + this.jsapiTicketKey = JSAPI_TICKET_KEY.concat(appId); + this.cardapiTicketKey = CARDAPI_TICKET_KEY.concat(appId); + } + + @Override + public String getAccessToken() { + return redisTemplate.opsForValue().get(this.accessTokenKey); + } + + @Override + public boolean isAccessTokenExpired() { + return redisTemplate.getExpire(accessTokenKey) < 2L; + } + + @Override + public synchronized void updateAccessToken(String accessToken, int expiresInSeconds) { + redisTemplate.opsForValue().set(accessTokenKey, accessToken, expiresInSeconds - 200, TimeUnit.SECONDS); + } + + @Override + public void expireAccessToken() { + redisTemplate.expire(this.accessTokenKey, 0, TimeUnit.SECONDS); + } + + @Override + public String getJsapiTicket() { + return redisTemplate.opsForValue().get(this.jsapiTicketKey); + } + + + @Override + public String getCardApiTicket() { + return redisTemplate.opsForValue().get(cardapiTicketKey); + } + + + @Override + public String getTicket(TicketType type) { + return redisTemplate.opsForValue().get(getTicketRedisKey(type)); + } + + @Override + public boolean isTicketExpired(TicketType type) { + return redisTemplate.getExpire(this.getTicketRedisKey(type)) < 2; + } + + @Override + public synchronized void updateTicket(TicketType type, String jsapiTicket, int expiresInSeconds) { + redisTemplate.opsForValue().set(getTicketRedisKey(type), jsapiTicket, expiresInSeconds - 200, TimeUnit.SECONDS); + } + + @Override + public void expireTicket(TicketType type) { + redisTemplate.expire(getTicketRedisKey(type), 0, TimeUnit.SECONDS); + } + + private String getTicketRedisKey(TicketType type) { + return String.format("wechat:ticket:key:%s:%s", this.appId, type.getCode()); + } + +} diff --git a/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/controller/WxAccountController.java b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/controller/WxAccountController.java new file mode 100755 index 000000000..e6806732e --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/controller/WxAccountController.java @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2018-2025, lengleng All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the pig4cloud.com developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: lengleng (wangiegie@gmail.com) + */ +package com.pig4cloud.pigx.mp.controller; + +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.common.log.annotation.SysLog; +import com.pig4cloud.pigx.mp.config.WxMpConfiguration; +import com.pig4cloud.pigx.mp.entity.WxAccount; +import com.pig4cloud.pigx.mp.service.WxAccountService; +import lombok.AllArgsConstructor; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + + +/** + * 公众号账户 + * + * @author lengleng + * @date 2019-03-26 22:07:53 + */ +@RestController +@AllArgsConstructor +@RequestMapping("/wxaccount") +public class WxAccountController { + private final WxMpConfiguration wxMpConfiguration; + private final WxAccountService wxAccountService; + + /** + * 分页查询 + * + * @param page 分页对象 + * @param wxAccount 公众号账户 + * @return + */ + @GetMapping("/page") + public R getWxAccountPage(Page page, WxAccount wxAccount) { + return new R<>(wxAccountService.page(page, Wrappers.query(wxAccount))); + } + + + /** + * 通过id查询公众号账户 + * + * @param id id + * @return R + */ + @GetMapping("/{id}") + public R getById(@PathVariable("id") Integer id) { + return new R<>(wxAccountService.getById(id)); + } + + /** + * 新增公众号账户 + * + * @param wxAccount 公众号账户 + * @return R + */ + @SysLog("新增公众号账户") + @PostMapping + @PreAuthorize("@pms.hasPermission('mp_wxaccount_add')") + public R save(@RequestBody WxAccount wxAccount) { + wxAccountService.save(wxAccount); + wxMpConfiguration.initServices(); + return new R<>(); + } + + /** + * 修改公众号账户 + * + * @param wxAccount 公众号账户 + * @return R + */ + @SysLog("修改公众号账户") + @PutMapping + @PreAuthorize("@pms.hasPermission('mp_wxaccount_edit')") + public R updateById(@RequestBody WxAccount wxAccount) { + wxAccountService.updateById(wxAccount); + wxMpConfiguration.initServices(); + return new R<>(); + } + + /** + * 通过id删除公众号账户 + * + * @param id id + * @return R + */ + @SysLog("删除公众号账户") + @DeleteMapping("/{id}") + @PreAuthorize("@pms.hasPermission('mp_wxaccount_del')") + public R removeById(@PathVariable Integer id) { + wxAccountService.removeById(id); + wxMpConfiguration.initServices(); + return new R<>(); + } + + /** + * 生成公众号二维码 + * + * @param appId + * @return + */ + @SysLog("生成公众号二维码") + @PostMapping("/qr/{appId}") + @PreAuthorize("@pms.hasPermission('mp_wxaccount_add')") + public R qr(@PathVariable String appId) { + return wxAccountService.generateQr(appId); + } + + /** + * 获取公众号列表 + * + * @return + */ + @GetMapping("/list") + public R list() { + return new R<>(wxAccountService.list()); + } + + /** + * 获取公众号接口数据 + * + * @param appId 公众号 + * @param interval 时间间隔 + * @return + */ + @GetMapping("/statistics") + public R statistics(String appId, String interval) { + return wxAccountService.statistics(appId, interval); + } +} diff --git a/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/controller/WxAccountFansController.java b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/controller/WxAccountFansController.java new file mode 100755 index 000000000..5ec3ec169 --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/controller/WxAccountFansController.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2018-2025, lengleng All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the pig4cloud.com developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: lengleng (wangiegie@gmail.com) + */ +package com.pig4cloud.pigx.mp.controller; + +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.common.log.annotation.SysLog; +import com.pig4cloud.pigx.mp.entity.WxAccountFans; +import com.pig4cloud.pigx.mp.service.WxAccountFansService; +import lombok.AllArgsConstructor; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + + +/** + * 微信公众号粉丝管理 + * + * @author lengleng + * @date 2019-03-26 22:08:08 + */ +@RestController +@AllArgsConstructor +@RequestMapping("/wxaccountfans") +public class WxAccountFansController { + + private final WxAccountFansService wxAccountFansService; + + /** + * 分页查询 + * + * @param page 分页对象 + * @param wxAccountFans 微信公众号粉丝 + * @return + */ + @GetMapping("/page") + public R getWxAccountFansPage(Page page, WxAccountFans wxAccountFans) { + return new R<>(wxAccountFansService.page(page, Wrappers.query(wxAccountFans))); + } + + + /** + * 通过id查询微信公众号粉丝 + * + * @param id id + * @return R + */ + @GetMapping("/{id}") + public R getById(@PathVariable("id") Integer id) { + return new R<>(wxAccountFansService.getById(id)); + } + + /** + * 新增微信公众号粉丝 + * + * @param wxAccountFans 微信公众号粉丝 + * @return R + */ + @SysLog("新增微信公众号粉丝") + @PostMapping + @PreAuthorize("@pms.hasPermission('mp_wxaccountfans_add')") + public R save(@RequestBody WxAccountFans wxAccountFans) { + return new R<>(wxAccountFansService.save(wxAccountFans)); + } + + /** + * 修改微信公众号粉丝 + * + * @param wxAccountFans 微信公众号粉丝 + * @return R + */ + @SysLog("修改微信公众号粉丝") + @PutMapping + @PreAuthorize("@pms.hasPermission('mp_wxaccountfans_edit')") + public R updateById(@RequestBody WxAccountFans wxAccountFans) { + return new R<>(wxAccountFansService.updateById(wxAccountFans)); + } + + /** + * 通过id删除微信公众号粉丝 + * + * @param id id + * @return R + */ + @SysLog("删除微信公众号粉丝") + @DeleteMapping("/{id}") + @PreAuthorize("@pms.hasPermission('mp_wxaccountfans_del')") + public R removeById(@PathVariable Integer id) { + return new R<>(wxAccountFansService.removeById(id)); + } + + /** + * 同步粉丝 + * + * @param appId + * @return + */ + @PostMapping("/sync/{appId}") + public R sync(@PathVariable String appId) { + return new R(wxAccountFansService.syncAccountFans(appId)); + } + +} diff --git a/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/controller/WxFansMsgController.java b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/controller/WxFansMsgController.java new file mode 100755 index 000000000..d1200085c --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/controller/WxFansMsgController.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2018-2025, lengleng All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the pig4cloud.com developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: lengleng (wangiegie@gmail.com) + */ +package com.pig4cloud.pigx.mp.controller; + +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.common.log.annotation.SysLog; +import com.pig4cloud.pigx.mp.entity.WxFansMsg; +import com.pig4cloud.pigx.mp.service.WxFansMsgService; +import lombok.AllArgsConstructor; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + + +/** + * 微信粉丝消息管理 + * + * @author lengleng + * @date 2019-03-27 20:45:27 + */ +@RestController +@AllArgsConstructor +@RequestMapping("/wxfansmsg") +public class WxFansMsgController { + + private final WxFansMsgService wxFansMsgService; + + /** + * 分页查询 + * + * @param page 分页对象 + * @param wxFansMsg 消息 + * @return + */ + @GetMapping("/page") + public R getWxFansMsgPage(Page page, WxFansMsg wxFansMsg) { + return new R<>(wxFansMsgService.page(page, Wrappers.query(wxFansMsg))); + } + + + /** + * 通过id查询消息 + * + * @param id id + * @return R + */ + @GetMapping("/{id}") + public R getById(@PathVariable("id") Integer id) { + return new R<>(wxFansMsgService.getById(id)); + } + + /** + * 新增消息 + * + * @param wxFansMsg 消息 + * @return R + */ + @SysLog("新增消息") + @PostMapping + @PreAuthorize("@pms.hasPermission('mp_wxfansmsg_add')") + public R save(@RequestBody WxFansMsg wxFansMsg) { + return new R<>(wxFansMsgService.save(wxFansMsg)); + } + + /** + * 修改消息 + * + * @param wxFansMsg 消息 + * @return R + */ + @SysLog("修改消息") + @PutMapping + @PreAuthorize("@pms.hasPermission('mp_wxfansmsg_edit')") + public R updateById(@RequestBody WxFansMsg wxFansMsg) { + return new R<>(wxFansMsgService.updateById(wxFansMsg)); + } + + /** + * 通过id删除消息 + * + * @param id id + * @return R + */ + @SysLog("删除消息") + @DeleteMapping("/{id}") + @PreAuthorize("@pms.hasPermission('mp_wxfansmsg_del')") + public R removeById(@PathVariable Integer id) { + return new R<>(wxFansMsgService.removeById(id)); + } + +} diff --git a/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/controller/WxFansMsgResController.java b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/controller/WxFansMsgResController.java new file mode 100755 index 000000000..9213af46f --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/controller/WxFansMsgResController.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2018-2025, lengleng All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the pig4cloud.com developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: lengleng (wangiegie@gmail.com) + */ +package com.pig4cloud.pigx.mp.controller; + +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.common.log.annotation.SysLog; +import com.pig4cloud.pigx.mp.entity.WxFansMsgRes; +import com.pig4cloud.pigx.mp.service.WxFansMsgResService; +import lombok.AllArgsConstructor; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + + +/** + * 微信粉丝消息回复管理 + * + * @author lengleng + * @date 2019-03-27 20:45:48 + */ +@RestController +@AllArgsConstructor +@RequestMapping("/wxfansmsgres") +public class WxFansMsgResController { + + private final WxFansMsgResService wxFansMsgResService; + + /** + * 分页查询 + * + * @param page 分页对象 + * @param wxFansMsgRes 回复 + * @return + */ + @GetMapping("/page") + public R getWxFansMsgResPage(Page page, WxFansMsgRes wxFansMsgRes) { + return new R<>(wxFansMsgResService.page(page, Wrappers.query(wxFansMsgRes))); + } + + + /** + * 通过id查询回复 + * + * @param id id + * @return R + */ + @GetMapping("/{id}") + public R getById(@PathVariable("id") Integer id) { + return new R<>(wxFansMsgResService.getById(id)); + } + + /** + * 新增回复 + * + * @param wxFansMsgRes 回复 + * @return R + */ + @SysLog("新增回复") + @PostMapping + @PreAuthorize("@pms.hasPermission('mp_wxfansmsgres_add')") + public R save(@RequestBody WxFansMsgRes wxFansMsgRes) { + return wxFansMsgResService.saveAndSend(wxFansMsgRes); + } + + /** + * 修改回复 + * + * @param wxFansMsgRes 回复 + * @return R + */ + @SysLog("修改回复") + @PutMapping + @PreAuthorize("@pms.hasPermission('mp_wxfansmsgres_edit')") + public R updateById(@RequestBody WxFansMsgRes wxFansMsgRes) { + return new R<>(wxFansMsgResService.updateById(wxFansMsgRes)); + } + + /** + * 通过id删除回复 + * + * @param id id + * @return R + */ + @SysLog("删除回复") + @DeleteMapping("/{id}") + @PreAuthorize("@pms.hasPermission('mp_wxfansmsgres_del')") + public R removeById(@PathVariable Integer id) { + return new R<>(wxFansMsgResService.removeById(id)); + } + +} diff --git a/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/controller/WxMenuController.java b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/controller/WxMenuController.java new file mode 100755 index 000000000..978264153 --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/controller/WxMenuController.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2018-2025, lengleng All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the pig4cloud.com developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: lengleng (wangiegie@gmail.com) + */ +package com.pig4cloud.pigx.mp.controller; + +import cn.hutool.json.JSONObject; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.common.log.annotation.SysLog; +import com.pig4cloud.pigx.mp.entity.WxMpMenu; +import com.pig4cloud.pigx.mp.service.WxMenuService; +import lombok.AllArgsConstructor; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + + +/** + * 微信菜单管理 + * + * @author lengleng + * @date 2019-03-27 20:45:18 + */ +@RestController +@AllArgsConstructor +@RequestMapping("/wxmenu") +public class WxMenuController { + + private final WxMenuService wxMenuService; + + /** + * 分页查询 + * + * @param page 分页对象 + * @param WxMpMenu lengleng + * @return + */ + @GetMapping("/page") + public R getWxMpMenuPage(Page page, WxMpMenu WxMpMenu) { + return new R<>(wxMenuService.page(page, Wrappers.query(WxMpMenu))); + } + + + /** + * 通过appid查询微信菜单 + * + * @param appId 公众号 + * @return R + */ + @GetMapping("/{appId}") + public R getById(@PathVariable("appId") String appId) { + return wxMenuService.getByAppId(appId); + } + + /** + * 新增微信菜单 + * + * @param WxMpMenus 微信菜单列表 + * @return R + */ + @SysLog("新增微信菜单") + @PostMapping("/{appId}") + @PreAuthorize("@pms.hasPermission('mp_wxmenu_add')") + public R save(@RequestBody JSONObject WxMpMenus, @PathVariable String appId) { + return new R(wxMenuService.save(WxMpMenus, appId)); + } + + /** + * 发布微信菜单 + * + * @param appId 公众号 + * @return R + */ + @SysLog("发布微信菜单") + @PutMapping("/{appId}") + @PreAuthorize("@pms.hasPermission('mp_wxmenu_push')") + public R updateById(@PathVariable String appId) { + return wxMenuService.push(appId); + } + +} diff --git a/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/controller/WxPortalController.java b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/controller/WxPortalController.java new file mode 100755 index 000000000..583f530d5 --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/controller/WxPortalController.java @@ -0,0 +1,123 @@ +package com.pig4cloud.pigx.mp.controller; + +import cn.hutool.core.util.StrUtil; +import com.pig4cloud.pigx.common.core.constant.SecurityConstants; +import com.pig4cloud.pigx.mp.config.WxMpConfiguration; +import com.pig4cloud.pigx.mp.config.WxMpContextHolder; +import lombok.extern.slf4j.Slf4j; +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.springframework.web.bind.annotation.*; + +/** + * @author Binary Wang + * @author lengleng + *

+ * 微信接入入口 + */ +@Slf4j +@RestController +@RequestMapping("/{appId}/portal") +public class WxPortalController { + + /** + * 微信接入校验处理 + * + * @param appId 多公众号标志位 + * @param signature 微信签名 + * @param timestamp 时间戳 + * @param nonce 随机数 + * @param echostr 随机字符串 + * @return + */ + @GetMapping(produces = "text/plain;charset=utf-8") + public String authGet(@PathVariable("appId") 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) { + + log.info("接收到来自微信服务器的认证消息:[{}, {}, {}, {}]", signature, timestamp, nonce, echostr); + + if (StringUtils.isAnyBlank(signature, timestamp, nonce, echostr)) { + throw new IllegalArgumentException("请求参数非法,请核实!"); + } + + final WxMpService wxService = WxMpConfiguration.getMpServices().get(appId); + + if (wxService == null) { + throw new IllegalArgumentException(String.format("未找到对应appid=[%d]的配置,请核实!", appId)); + } + + if (wxService.checkSignature(timestamp, nonce, signature)) { + return echostr; + } + + return "非法请求"; + } + + /** + * 微信消息处理 + * + * @param appId 多公众号标志位 + * @param requestBody 请求报文体 + * @param signature 微信签名 + * @param encType 加签方式 + * @param msgSignature 微信签名 + * @param timestamp 时间戳 + * @param nonce 随机数 + * @return + */ + @PostMapping(produces = "application/xml; charset=UTF-8") + public String post(@PathVariable("appId") 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) { + + WxMpContextHolder.setAppId(appId); + final WxMpService wxService = WxMpConfiguration.getMpServices().get(appId); + + log.info("接收微信请求:[openid=[{}], [signature=[{}], encType=[{}], msgSignature=[{}]," + + " timestamp=[{}], nonce=[{}], requestBody=[{}] ", + openid, signature, encType, msgSignature, timestamp, nonce, requestBody); + + if (!wxService.checkSignature(timestamp, nonce, signature)) { + throw new IllegalArgumentException("非法请求,可能属于伪造的请求!"); + } + + String out = null; + + // 明文模式 + if (StrUtil.isBlank(encType)) { + WxMpXmlMessage inMessage = WxMpXmlMessage.fromXml(requestBody); + WxMpXmlOutMessage outMessage = WxMpConfiguration.getRouters().get(appId).route(inMessage); + if (outMessage != null) { + out = outMessage.toXml(); + } + } + + // aes加密模式 + if (SecurityConstants.AES.equalsIgnoreCase(encType)) { + WxMpXmlMessage inMessage = WxMpXmlMessage.fromEncryptedXml(requestBody, wxService.getWxMpConfigStorage(), + timestamp, nonce, msgSignature); + + log.debug("消息解密后内容为:{} ", inMessage.toString()); + + WxMpXmlOutMessage outMessage = WxMpConfiguration.getRouters().get(appId).route(inMessage); + if (outMessage != null) { + out = outMessage.toEncryptedXml(wxService.getWxMpConfigStorage()); + } + } + + log.debug("组装回复信息:{}", out); + WxMpContextHolder.clear(); + return out; + } + +} diff --git a/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/controller/WxRedirectController.java b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/controller/WxRedirectController.java new file mode 100755 index 000000000..e0c48c36b --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/controller/WxRedirectController.java @@ -0,0 +1,37 @@ +package com.pig4cloud.pigx.mp.controller; + +import com.pig4cloud.pigx.mp.config.WxMpConfiguration; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken; +import me.chanjar.weixin.mp.bean.result.WxMpUser; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +/** + * @author Edward + */ +@Controller +@RequestMapping("/wx/redirect/{appid}") +public class WxRedirectController { + + + @RequestMapping("/greet") + public String greetUser(@PathVariable String appid, @RequestParam String code, ModelMap map) { + + WxMpService mpService = WxMpConfiguration.getMpServices().get(appid); + + try { + WxMpOAuth2AccessToken accessToken = mpService.oauth2getAccessToken(code); + WxMpUser user = mpService.oauth2getUserInfo(accessToken, null); + map.put("user", user); + } catch (WxErrorException e) { + e.printStackTrace(); + } + + return "greet_user"; + } +} diff --git a/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/entity/WxAccount.java b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/entity/WxAccount.java new file mode 100755 index 000000000..76b94ca73 --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/entity/WxAccount.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2018-2025, lengleng All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the pig4cloud.com developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: lengleng (wangiegie@gmail.com) + */ +package com.pig4cloud.pigx.mp.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.time.LocalDateTime; + +/** + * 公众号账户 + * + * @author lengleng + * @date 2019-03-26 22:07:53 + */ +@Data +@TableName("t_wx_account") +@EqualsAndHashCode(callSuper = true) +public class WxAccount extends Model { + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId + private Integer id; + /** + * 公众号名称 + */ + private String name; + /** + * 公众号账户 + */ + private String account; + /** + * 公众号appid + */ + private String appid; + /** + * 公众号密钥 + */ + private String appsecret; + /** + * 公众号url + */ + private String url; + /** + * 公众号token + */ + private String token; + /** + * 加密密钥 + */ + private String aeskey; + /** + * 二维码图片URL + */ + private String qrUrl; + /** + * 创建时间 + */ + private LocalDateTime createTime; + /** + * 更新时间 + */ + private LocalDateTime updateTime; + + /** + * 是否删除 -1:已删除 0:正常 + */ + @TableLogic + private String delFlag; + + /** + * 租户 + */ + private Integer tenantId; +} diff --git a/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/entity/WxAccountFans.java b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/entity/WxAccountFans.java new file mode 100755 index 000000000..a6da434e1 --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/entity/WxAccountFans.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2018-2025, lengleng All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the pig4cloud.com developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: lengleng (wangiegie@gmail.com) + */ +package com.pig4cloud.pigx.mp.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.time.LocalDateTime; + +/** + * 微信公众号粉丝 + * + * @author lengleng + * @date 2019-03-26 22:08:08 + */ +@Data +@TableName("t_wx_account_fans") +@EqualsAndHashCode(callSuper = true) +public class WxAccountFans extends Model { + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId + private Integer id; + /** + * 用户标识 + */ + private String openid; + /** + * 订阅状态,0未关注,1已关注 + */ + private String subscribeStatus; + /** + * 订阅时间 + */ + private LocalDateTime subscribeTime; + /** + * 昵称 + */ + private String nickname; + /** + * 性别,1男,2女,0未知 + */ + private String gender; + /** + * 语言 + */ + private String language; + /** + * 国家 + */ + private String country; + /** + * 省份 + */ + private String province; + /** + * 城市 + */ + private String city; + /** + * 头像地址 + */ + private String headimgUrl; + /** + * 备注 + */ + private String remark; + /** + * 微信公众号ID + */ + private Integer wxAccountId; + /** + * 微信公众号appid + */ + private String wxAccountAppid; + + /** + * 微信公众号名 + */ + private String wxAccountName; + /** + * 创建时间 + */ + private LocalDateTime createTime; + /** + * 更新时间 + */ + private LocalDateTime updateTime; + /** + * 是否删除 -1:已删除 0:正常 + */ + @TableLogic + private String delFlag; + +} diff --git a/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/entity/WxFansMsg.java b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/entity/WxFansMsg.java new file mode 100755 index 000000000..e892019c5 --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/entity/WxFansMsg.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2018-2025, lengleng All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the pig4cloud.com developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: lengleng (wangiegie@gmail.com) + */ +package com.pig4cloud.pigx.mp.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.time.LocalDateTime; + +/** + * 微信消息 + * + * @author lengleng + * @date 2019-03-27 20:45:27 + */ +@Data +@TableName("t_wx_fans_msg") +@EqualsAndHashCode(callSuper = true) +public class WxFansMsg extends Model { + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId + private Integer id; + /** + * 用户标识 + */ + private String openid; + /** + * 昵称 + */ + private String nickname; + /** + * 头像地址 + */ + private String headimgUrl; + /** + * 微信账号ID + */ + private Integer wxAccountId; + + /** + * 微信公众号appid + */ + private String wxAccountAppid; + + /** + * 微信公众号名 + */ + private String wxAccountName; + + /** + * 消息ID + */ + private Long msgId; + + /** + * 消息类型 + */ + private String msgType; + /** + * 内容 + */ + private String content; + /** + * 最近一条回复内容 + */ + private String resContent; + /** + * 是否已回复 + */ + private String isRes; + /** + * 微信素材ID + */ + private String mediaId; + /** + * 微信图片URL + */ + private String picUrl; + /** + * 本地图片路径 + */ + private String picPath; + /** + * 创建时间 + */ + private LocalDateTime createTime; + /** + * 更新时间 + */ + private LocalDateTime updateTime; + + /** + * 是否删除 -1:已删除 0:正常 + */ + @TableLogic + private String delFlag; + + /** + * 租户 + */ + private Integer tenantId; + +} diff --git a/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/entity/WxFansMsgRes.java b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/entity/WxFansMsgRes.java new file mode 100755 index 000000000..31e853e91 --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/entity/WxFansMsgRes.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2018-2025, lengleng All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the pig4cloud.com developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: lengleng (wangiegie@gmail.com) + */ +package com.pig4cloud.pigx.mp.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.time.LocalDateTime; + +/** + * 微信粉丝消息回复表 + * + * @author lengleng + * @date 2019-03-27 20:45:48 + */ +@Data +@TableName("t_wx_fans_msg_res") +@EqualsAndHashCode(callSuper = true) +public class WxFansMsgRes extends Model { + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId + private Integer id; + /** + * 粉丝消息ID + */ + private Integer fansMsgId; + /** + * 回复内容 + */ + private String resContent; + /** + * 用户ID + */ + private Integer userId; + /** + * 用户名 + */ + private String userName; + /** + * 创建时间 + */ + private LocalDateTime createTime; + /** + * 更新时间 + */ + private LocalDateTime updateTime; + +} diff --git a/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/entity/WxMpMenu.java b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/entity/WxMpMenu.java new file mode 100755 index 000000000..97fbd79fc --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/entity/WxMpMenu.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2018-2025, lengleng All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the pig4cloud.com developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: lengleng (wangiegie@gmail.com) + */ +package com.pig4cloud.pigx.mp.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.time.LocalDateTime; + +/** + * 微信菜单表 + * + * @author lengleng + * @date 2019-03-27 20:45:18 + */ +@Data +@TableName("t_wx_menu") +@EqualsAndHashCode(callSuper = true) +public class WxMpMenu extends Model { + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId + private Integer id; + + /** + * 菜单 + */ + private String menu; + + /** + * 微信公众号ID + */ + private Integer wxAccountId; + /** + * 微信公众号appid + */ + private String wxAccountAppid; + + /** + * 微信公众号名 + */ + private String wxAccountName; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + /** + * 更新时间 + */ + private LocalDateTime updateTime; + + /** + * 是否删除 -1:已删除 0:正常 + */ + @TableLogic + private String delFlag; + + /** + * 是否发布 0 未发布 1 已发布 + */ + private String pubFlag; + +} diff --git a/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/handler/AbstractHandler.java b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/handler/AbstractHandler.java new file mode 100755 index 000000000..c59c54c4e --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/handler/AbstractHandler.java @@ -0,0 +1,9 @@ +package com.pig4cloud.pigx.mp.handler; + +import me.chanjar.weixin.mp.api.WxMpMessageHandler; + +/** + * @author Binary Wang(https://github.com/binarywang) + */ +public abstract class AbstractHandler implements WxMpMessageHandler { +} diff --git a/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/handler/KfSessionHandler.java b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/handler/KfSessionHandler.java new file mode 100755 index 000000000..a6792b40c --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/handler/KfSessionHandler.java @@ -0,0 +1,24 @@ +package com.pig4cloud.pigx.mp.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(https://github.com/binarywang) + */ +@Component +public class KfSessionHandler extends AbstractHandler { + + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, + Map context, WxMpService wxMpService, + WxSessionManager sessionManager) { + return null; + } + +} diff --git a/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/handler/LocationHandler.java b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/handler/LocationHandler.java new file mode 100755 index 000000000..76c442ce0 --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/handler/LocationHandler.java @@ -0,0 +1,34 @@ +package com.pig4cloud.pigx.mp.handler; + +import com.pig4cloud.pigx.mp.builder.TextBuilder; +import lombok.extern.slf4j.Slf4j; +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(https://github.com/binarywang) + */ +@Slf4j +@Component +public class LocationHandler extends AbstractHandler { + + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, + Map context, WxMpService wxMpService, + WxSessionManager sessionManager) { + //上报地理位置事件 + log.info("上报地理位置,纬度 : {},经度 : {},精度 : {}", + wxMessage.getLatitude(), wxMessage.getLongitude(), wxMessage.getPrecision()); + + //TODO 可以将用户地理位置信息保存到本地数据库,以便以后使用 + + String content = "感谢反馈,您的的地理位置已收到!"; + return new TextBuilder().build(content, wxMessage, null); + } + +} diff --git a/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/handler/LogHandler.java b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/handler/LogHandler.java new file mode 100755 index 000000000..f5d65d103 --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/handler/LogHandler.java @@ -0,0 +1,62 @@ +package com.pig4cloud.pigx.mp.handler; + +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.pig4cloud.pigx.mp.entity.WxAccount; +import com.pig4cloud.pigx.mp.entity.WxFansMsg; +import com.pig4cloud.pigx.mp.service.WxAccountService; +import com.pig4cloud.pigx.mp.service.WxFansMsgService; +import lombok.AllArgsConstructor; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +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.bean.result.WxMpUser; +import org.springframework.stereotype.Component; + +import java.util.Map; + +/** + * @author lengleng + *

+ * 保存微信消息 + */ +@Slf4j +@Component +@AllArgsConstructor +public class LogHandler extends AbstractHandler { + private final WxFansMsgService wxFansMsgService; + private final WxAccountService wxAccountService; + + @Override + @SneakyThrows + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, + Map context, WxMpService wxMpService, + WxSessionManager sessionManager) { + log.debug("接收到请求消息,内容:{}", wxMessage.getContent()); + + WxAccount wxAccount = wxAccountService.getOne(Wrappers.lambdaQuery() + .eq(WxAccount::getAccount, wxMessage.getToUser())); + + + WxMpUser wxmpUser = wxMpService.getUserService() + .userInfo(wxMessage.getFromUser()); + + WxFansMsg wxFansMsg = new WxFansMsg(); + wxFansMsg.setOpenid(wxmpUser.getOpenId()); + wxFansMsg.setNickname(wxmpUser.getNickname()); + wxFansMsg.setHeadimgUrl(wxmpUser.getHeadImgUrl()); + wxFansMsg.setWxAccountId(wxAccount.getId()); + wxFansMsg.setWxAccountName(wxAccount.getName()); + wxFansMsg.setWxAccountAppid(wxAccount.getAppid()); + wxFansMsg.setMsgType(wxMessage.getMsgType()); + wxFansMsg.setMsgId(wxMessage.getMsgId()); + wxFansMsg.setContent(wxMessage.getContent()); + wxFansMsg.setTenantId(wxAccount.getTenantId()); + wxFansMsgService.save(wxFansMsg); + + log.debug("保存微信用户信息成功 {}", wxFansMsg); + return null; + } +} diff --git a/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/handler/MenuHandler.java b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/handler/MenuHandler.java new file mode 100755 index 000000000..630c33535 --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/handler/MenuHandler.java @@ -0,0 +1,36 @@ +package com.pig4cloud.pigx.mp.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.MenuButtonType; + +/** + * @author Binary Wang(https://github.com/binarywang) + */ +@Component +public class MenuHandler extends AbstractHandler { + + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, + Map context, WxMpService weixinService, + WxSessionManager sessionManager) { + + String msg = String.format("type:%s, event:%s, key:%s", + wxMessage.getMsgType(), wxMessage.getEvent(), + wxMessage.getEventKey()); + if (MenuButtonType.VIEW.equals(wxMessage.getEvent())) { + return null; + } + + return WxMpXmlOutMessage.TEXT().content(msg) + .fromUser(wxMessage.getToUser()).toUser(wxMessage.getFromUser()) + .build(); + } + +} diff --git a/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/handler/MsgHandler.java b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/handler/MsgHandler.java new file mode 100755 index 000000000..21feece52 --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/handler/MsgHandler.java @@ -0,0 +1,49 @@ +package com.pig4cloud.pigx.mp.handler; + +import com.pig4cloud.pigx.mp.builder.TextBuilder; +import lombok.SneakyThrows; +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.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Component; + +import java.util.Map; + +import static me.chanjar.weixin.common.api.WxConsts.XmlMsgType; + +/** + * @author Binary Wang(https://github.com/binarywang) + */ +@Component +public class MsgHandler extends AbstractHandler { + + @Override + @SneakyThrows + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, + Map context, WxMpService weixinService, + WxSessionManager sessionManager) { + + if (!wxMessage.getMsgType().equals(XmlMsgType.EVENT)) { + //TODO 可以选择将消息保存到本地 + } + + //当用户输入关键词如“你好”,“客服”等,并且有客服在线时,把消息转发给在线客服 + if (StringUtils.startsWithAny(wxMessage.getContent(), "你好", "客服") + && weixinService.getKefuService().kfOnlineList() + .getKfOnlineList().size() > 0) { + return WxMpXmlOutMessage.TRANSFER_CUSTOMER_SERVICE() + .fromUser(wxMessage.getToUser()) + .toUser(wxMessage.getFromUser()).build(); + } + + + //TODO 组装回复消息 + String content = "收到信息内容:" + wxMessage.getContent(); + + return new TextBuilder().build(content, wxMessage, weixinService); + + } + +} diff --git a/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/handler/NullHandler.java b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/handler/NullHandler.java new file mode 100755 index 000000000..5f961b871 --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/handler/NullHandler.java @@ -0,0 +1,24 @@ +package com.pig4cloud.pigx.mp.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(https://github.com/binarywang) + */ +@Component +public class NullHandler extends AbstractHandler { + + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, + Map context, WxMpService wxMpService, + WxSessionManager sessionManager) { + return null; + } + +} diff --git a/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/handler/ScanHandler.java b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/handler/ScanHandler.java new file mode 100755 index 000000000..0173764f6 --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/handler/ScanHandler.java @@ -0,0 +1,24 @@ +package com.pig4cloud.pigx.mp.handler; + +import me.chanjar.weixin.common.error.WxErrorException; +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(https://github.com/binarywang) + */ +@Component +public class ScanHandler extends AbstractHandler { + + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMpXmlMessage, Map map, + WxMpService wxMpService, WxSessionManager wxSessionManager) throws WxErrorException { + // 扫码事件处理 + return null; + } +} diff --git a/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/handler/StoreCheckNotifyHandler.java b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/handler/StoreCheckNotifyHandler.java new file mode 100755 index 000000000..1d75ea153 --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/handler/StoreCheckNotifyHandler.java @@ -0,0 +1,27 @@ +package com.pig4cloud.pigx.mp.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(https://github.com/binarywang) + */ +@Component +public class StoreCheckNotifyHandler extends AbstractHandler { + + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, + Map context, WxMpService wxMpService, + WxSessionManager sessionManager) { + // TODO 处理门店审核事件 + return null; + } + +} diff --git a/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/handler/SubscribeHandler.java b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/handler/SubscribeHandler.java new file mode 100755 index 000000000..a90c174d3 --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/handler/SubscribeHandler.java @@ -0,0 +1,72 @@ +package com.pig4cloud.pigx.mp.handler; + +import com.pig4cloud.pigx.mp.builder.TextBuilder; +import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.common.error.WxErrorException; +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.bean.result.WxMpUser; +import org.springframework.stereotype.Component; + +import java.util.Map; + +/** + * @author Binary Wang(https://github.com/binarywang) + */ +@Slf4j +@Component +public class SubscribeHandler extends AbstractHandler { + + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, + Map context, WxMpService weixinService, + WxSessionManager sessionManager) throws WxErrorException { + + log.info("新关注用户 OPENID: " + wxMessage.getFromUser()); + + // 获取微信用户基本信息 + try { + WxMpUser userWxInfo = weixinService.getUserService() + .userInfo(wxMessage.getFromUser(), null); + if (userWxInfo != null) { + // TODO 可以添加关注用户到本地数据库 + } + } catch (WxErrorException e) { + if (e.getError().getErrorCode() == 48001) { + log.info("该公众号没有获取用户信息权限!"); + } + } + + + WxMpXmlOutMessage responseResult = null; + try { + responseResult = this.handleSpecial(wxMessage); + } catch (Exception e) { + log.error(e.getMessage(), e); + } + + if (responseResult != null) { + return responseResult; + } + + try { + return new TextBuilder().build("感谢关注", wxMessage, weixinService); + } catch (Exception e) { + log.error(e.getMessage(), e); + } + + return null; + } + + /** + * 处理特殊请求,比如如果是扫码进来的,可以做相应处理 + */ + private WxMpXmlOutMessage handleSpecial(WxMpXmlMessage wxMessage) + throws Exception { + //TODO + return null; + } + +} diff --git a/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/handler/UnsubscribeHandler.java b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/handler/UnsubscribeHandler.java new file mode 100755 index 000000000..7dde34f32 --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/handler/UnsubscribeHandler.java @@ -0,0 +1,29 @@ +package com.pig4cloud.pigx.mp.handler; + +import lombok.extern.slf4j.Slf4j; +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(https://github.com/binarywang) + */ +@Slf4j +@Component +public class UnsubscribeHandler extends AbstractHandler { + + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, + Map context, WxMpService wxMpService, + WxSessionManager sessionManager) { + String openId = wxMessage.getFromUser(); + log.info("取消关注用户 OPENID: " + openId); + // TODO 可以更新本地数据库为取消关注状态 + return null; + } + +} diff --git a/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/mapper/WxAccountFansMapper.java b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/mapper/WxAccountFansMapper.java new file mode 100755 index 000000000..010329ea7 --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/mapper/WxAccountFansMapper.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2018-2025, lengleng All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the pig4cloud.com developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: lengleng (wangiegie@gmail.com) + */ +package com.pig4cloud.pigx.mp.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.pig4cloud.pigx.mp.entity.WxAccountFans; + +/** + * 微信公众号粉丝 + * + * @author lengleng + * @date 2019-03-26 22:08:08 + */ +public interface WxAccountFansMapper extends BaseMapper { + +} diff --git a/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/mapper/WxAccountMapper.java b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/mapper/WxAccountMapper.java new file mode 100755 index 000000000..899c95124 --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/mapper/WxAccountMapper.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2018-2025, lengleng All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the pig4cloud.com developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: lengleng (wangiegie@gmail.com) + */ +package com.pig4cloud.pigx.mp.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.pig4cloud.pigx.mp.entity.WxAccount; + +/** + * 公众号账户 + * + * @author lengleng + * @date 2019-03-26 22:07:53 + */ +public interface WxAccountMapper extends BaseMapper { + +} diff --git a/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/mapper/WxFansMsgMapper.java b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/mapper/WxFansMsgMapper.java new file mode 100755 index 000000000..2719ed380 --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/mapper/WxFansMsgMapper.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2018-2025, lengleng All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the pig4cloud.com developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: lengleng (wangiegie@gmail.com) + */ +package com.pig4cloud.pigx.mp.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.pig4cloud.pigx.mp.entity.WxFansMsg; + +/** + * lengleng + * + * @author pigx code generator + * @date 2019-03-27 20:45:27 + */ +public interface WxFansMsgMapper extends BaseMapper { + +} diff --git a/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/mapper/WxFansMsgResMapper.java b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/mapper/WxFansMsgResMapper.java new file mode 100755 index 000000000..c6f790868 --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/mapper/WxFansMsgResMapper.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2018-2025, lengleng All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the pig4cloud.com developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: lengleng (wangiegie@gmail.com) + */ +package com.pig4cloud.pigx.mp.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.pig4cloud.pigx.mp.entity.WxFansMsgRes; + +/** + * lengleng + * + * @author pigx code generator + * @date 2019-03-27 20:45:48 + */ +public interface WxFansMsgResMapper extends BaseMapper { + +} diff --git a/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/mapper/WxMenuMapper.java b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/mapper/WxMenuMapper.java new file mode 100755 index 000000000..7013f4fbd --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/mapper/WxMenuMapper.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2018-2025, lengleng All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the pig4cloud.com developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: lengleng (wangiegie@gmail.com) + */ +package com.pig4cloud.pigx.mp.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.pig4cloud.pigx.mp.entity.WxMpMenu; + +/** + * lengleng + * + * @author pigx code generator + * @date 2019-03-27 20:45:18 + */ +public interface WxMenuMapper extends BaseMapper { + +} diff --git a/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/service/WxAccountFansService.java b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/service/WxAccountFansService.java new file mode 100755 index 000000000..5094ba7dd --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/service/WxAccountFansService.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2018-2025, lengleng All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the pig4cloud.com developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: lengleng (wangiegie@gmail.com) + */ +package com.pig4cloud.pigx.mp.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.pig4cloud.pigx.mp.entity.WxAccountFans; + +/** + * 微信公众号粉丝 + * + * @author lengleng + * @date 2019-03-26 22:08:08 + */ +public interface WxAccountFansService extends IService { + + /** + * 同步指定公众号粉丝 + * + * @param appId + * @return + */ + Boolean syncAccountFans(String appId); +} diff --git a/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/service/WxAccountService.java b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/service/WxAccountService.java new file mode 100755 index 000000000..ab59a9601 --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/service/WxAccountService.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2018-2025, lengleng All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the pig4cloud.com developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: lengleng (wangiegie@gmail.com) + */ +package com.pig4cloud.pigx.mp.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.mp.entity.WxAccount; + +/** + * 公众号账户 + * + * @author lengleng + * @date 2019-03-26 22:07:53 + */ +public interface WxAccountService extends IService { + + /** + * 生成公众号二维码 + * + * @param appId + * @return + */ + R generateQr(String appId); + + /** + * 获取公众号统计数据 + * + * @param appId + * @param interval + * @return + */ + R statistics(String appId, String interval); +} diff --git a/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/service/WxFansMsgResService.java b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/service/WxFansMsgResService.java new file mode 100755 index 000000000..6b28b69fc --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/service/WxFansMsgResService.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2018-2025, lengleng All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the pig4cloud.com developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: lengleng (wangiegie@gmail.com) + */ +package com.pig4cloud.pigx.mp.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.mp.entity.WxFansMsgRes; + +/** + * 微信消息回复业务 + * + * @author lengleng + * @date 2019-03-27 20:45:48 + */ +public interface WxFansMsgResService extends IService { + + /** + * 保存并发送回复 + * + * @param wxFansMsgRes + * @return + */ + R saveAndSend(WxFansMsgRes wxFansMsgRes); +} diff --git a/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/service/WxFansMsgService.java b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/service/WxFansMsgService.java new file mode 100755 index 000000000..b3aa4b860 --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/service/WxFansMsgService.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2018-2025, lengleng All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the pig4cloud.com developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: lengleng (wangiegie@gmail.com) + */ +package com.pig4cloud.pigx.mp.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.pig4cloud.pigx.mp.entity.WxFansMsg; + +/** + * 微信消息业务 + * + * @author lengleng + * @date 2019-03-27 20:45:27 + */ +public interface WxFansMsgService extends IService { + +} diff --git a/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/service/WxMenuService.java b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/service/WxMenuService.java new file mode 100755 index 000000000..967ac499e --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/service/WxMenuService.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2018-2025, lengleng All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the pig4cloud.com developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: lengleng (wangiegie@gmail.com) + */ +package com.pig4cloud.pigx.mp.service; + +import cn.hutool.json.JSONObject; +import com.baomidou.mybatisplus.extension.service.IService; +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.mp.entity.WxMpMenu; + +/** + * 微信菜单业务 + * + * @author lengleng + * @date 2019-03-27 20:45:18 + */ +public interface WxMenuService extends IService { + + /** + * 新增微信公众号按钮 + * + * @param wxMenus json + * @param appId 公众号信息 + * @return + */ + Boolean save(JSONObject wxMenus, String appId); + + /** + * 发布到微信 + * + * @param appId 公众号信息 + * @return + */ + R push(String appId); + + /** + * 通过appid 查询菜单信息 + * + * @param appId + * @return + */ + R getByAppId(String appId); +} diff --git a/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/service/impl/WxAccountFansServiceImpl.java b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/service/impl/WxAccountFansServiceImpl.java new file mode 100755 index 000000000..494b7daf9 --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/service/impl/WxAccountFansServiceImpl.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2018-2025, lengleng All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the pig4cloud.com developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: lengleng (wangiegie@gmail.com) + */ +package com.pig4cloud.pigx.mp.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.pig4cloud.pigx.mp.config.WxMpConfiguration; +import com.pig4cloud.pigx.mp.entity.WxAccount; +import com.pig4cloud.pigx.mp.entity.WxAccountFans; +import com.pig4cloud.pigx.mp.mapper.WxAccountFansMapper; +import com.pig4cloud.pigx.mp.mapper.WxAccountMapper; +import com.pig4cloud.pigx.mp.service.WxAccountFansService; +import lombok.AllArgsConstructor; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +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.WxMpUserList; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.List; + +/** + * @author lengleng + * @date 2019-03-26 22:08:08 + *

+ * 微信公众号粉丝 + */ +@Slf4j +@Service +@AllArgsConstructor +public class WxAccountFansServiceImpl extends ServiceImpl implements WxAccountFansService { + private static final int SIZE = 100; + private final WxAccountMapper wxAccountMapper; + + /** + * 获取公众号粉丝,生产建议异步 + * + * @param appId + * @return + */ + @Async + @Override + @SneakyThrows + @Transactional(rollbackFor = Exception.class) + public Boolean syncAccountFans(String appId) { + WxAccount wxAccount = wxAccountMapper + .selectOne(Wrappers.query().lambda() + .eq(WxAccount::getAppid, appId)); + + WxMpService wxMpService = WxMpConfiguration.getMpServices().get(appId); + WxMpUserService wxMpUserService = wxMpService.getUserService(); + fetchUser(null, wxAccount, wxMpUserService); + return Boolean.TRUE; + } + + /** + * 获取微信用户 + * + * @param nextOpenid + * @param wxAccount + * @param wxMpUserService + * @throws WxErrorException + */ + private void fetchUser(String nextOpenid, WxAccount wxAccount, WxMpUserService wxMpUserService) throws WxErrorException { + WxMpUserList wxMpUserList = wxMpUserService.userList(nextOpenid); + + // openId 分组 每组 100个 openid + CollUtil.split(wxMpUserList.getOpenids(), SIZE) + .stream().filter(CollUtil::isNotEmpty) + .forEach(openIdList -> { + log.info("开始批量获取用户信息 {}", openIdList); + List wxAccountFansList = new ArrayList<>(); + try { + wxMpUserService.userInfoList(openIdList).forEach(wxMpUser -> { + WxAccountFans wxAccountFans = baseMapper + .selectOne(Wrappers.query().lambda() + .eq(WxAccountFans::getOpenid, wxMpUser.getOpenId())); + // 为空初始化一个新的对象 + if (wxAccountFans == null) { + wxAccountFans = new WxAccountFans(); + } + + wxAccountFans.setOpenid(wxMpUser.getOpenId()); + wxAccountFans.setSubscribeStatus(wxMpUser.getSubscribe() ? "1" : "0"); + wxAccountFans.setSubscribeTime(LocalDateTime + .ofInstant(Instant.ofEpochMilli(wxMpUser.getSubscribeTime() * 1000L) + , ZoneId.systemDefault())); + wxAccountFans.setNickname(wxMpUser.getNickname()); + wxAccountFans.setGender(String.valueOf(wxMpUser.getSex())); + wxAccountFans.setLanguage(wxMpUser.getLanguage()); + wxAccountFans.setCountry(wxMpUser.getCountry()); + wxAccountFans.setProvince(wxMpUser.getProvince()); + wxAccountFans.setCity(wxMpUser.getCity()); + wxAccountFans.setHeadimgUrl(wxMpUser.getHeadImgUrl()); + wxAccountFans.setRemark(wxMpUser.getRemark()); + wxAccountFans.setWxAccountId(wxAccount.getId()); + wxAccountFans.setWxAccountAppid(wxAccount.getAppid()); + wxAccountFans.setWxAccountName(wxAccount.getName()); + wxAccountFansList.add(wxAccountFans); + }); + this.saveOrUpdateBatch(wxAccountFansList); + log.info("批量插入用户信息完成 {}", openIdList); + } catch (WxErrorException e) { + log.error("批量同步粉丝失败", e); + } + }); + + // 如果nextOpenId 不为空,则继续获取 + if (StrUtil.isNotBlank(wxMpUserList.getNextOpenid())) { + fetchUser(wxMpUserList.getNextOpenid(), wxAccount, wxMpUserService); + } + + log.info("批量同步微信用户信息完成"); + } +} diff --git a/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/service/impl/WxAccountServiceImpl.java b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/service/impl/WxAccountServiceImpl.java new file mode 100755 index 000000000..1f9b6bbb6 --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/service/impl/WxAccountServiceImpl.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2018-2025, lengleng All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the pig4cloud.com developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: lengleng (wangiegie@gmail.com) + */ +package com.pig4cloud.pigx.mp.service.impl; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.pig4cloud.pigx.common.core.constant.CommonConstants; +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.mp.config.WxMpConfiguration; +import com.pig4cloud.pigx.mp.entity.WxAccount; +import com.pig4cloud.pigx.mp.mapper.WxAccountMapper; +import com.pig4cloud.pigx.mp.service.WxAccountService; +import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.api.WxMpDataCubeService; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.datacube.WxDataCubeArticleResult; +import me.chanjar.weixin.mp.bean.datacube.WxDataCubeInterfaceResult; +import me.chanjar.weixin.mp.bean.datacube.WxDataCubeMsgResult; +import me.chanjar.weixin.mp.bean.datacube.WxDataCubeUserCumulate; +import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 公众号账户 + * + * @author lengleng + * @date 2019-03-26 22:07:53 + */ +@Slf4j +@Service +public class WxAccountServiceImpl extends ServiceImpl implements WxAccountService { + + /** + * 生成公众号二维码 + * + * @param appId + * @return + */ + + @Override + public R generateQr(String appId) { + WxMpService wxMpService = WxMpConfiguration.getMpServices().get(appId); + try { + WxMpQrCodeTicket ticket = wxMpService.getQrcodeService().qrCodeCreateLastTicket(1); + String url = wxMpService.getQrcodeService().qrCodePictureUrl(ticket.getTicket()); + + WxAccount wxAccount = baseMapper + .selectOne(Wrappers.query().lambda() + .eq(WxAccount::getAppid, appId)); + wxAccount.setQrUrl(url); + baseMapper.updateById(wxAccount); + } catch (WxErrorException e) { + log.error(" 获取公众号二维码失败", e); + return R.builder().code(CommonConstants.FAIL).msg("更新公众号二维码失败").build(); + } + + return R.builder().build(); + } + + /** + * 获取公众号统计数据 + * + * @param appId 公众号信息 + * @param interval 时间间隔 + * @return + */ + @Override + public R statistics(String appId, String interval) { + String[] split = interval.split(StrUtil.DASHED); + Date start = new Date(Long.parseLong(split[0])); + Date end = new Date(Long.parseLong(split[1])); + + WxMpService wxMpService = WxMpConfiguration.getMpServices().get(appId); + WxMpDataCubeService cubeService = wxMpService.getDataCubeService(); + + List> result = new ArrayList<>(); + try { + // 获取累计用户数据 + List cumulateList = cubeService.getUserCumulate(start, end).stream() + .map(WxDataCubeUserCumulate::getCumulateUser) + .collect(Collectors.toList()); + result.add(cumulateList); + + // 获取用户分享数据 + List shareList = cubeService.getUserShare(start, end).stream() + .map(WxDataCubeArticleResult::getShareCount) + .collect(Collectors.toList()); + result.add(shareList); + + // 获取消息发送概况数据 + List upstreamList = cubeService.getUpstreamMsg(start, end).stream() + .map(WxDataCubeMsgResult::getMsgCount) + .collect(Collectors.toList()); + result.add(upstreamList); + + // 获取接口调用概况数据 + List interfaceSummaryList = cubeService.getInterfaceSummary(start, end); + List interfaceList = interfaceSummaryList.stream() + .map(WxDataCubeInterfaceResult::getCallbackCount) + .collect(Collectors.toList()); + result.add(interfaceList); + + // 接口日期保存 + List dateList = interfaceSummaryList.stream() + .map(WxDataCubeInterfaceResult::getRefDate) + .collect(Collectors.toList()); + result.add(dateList); + } catch (WxErrorException e) { + log.error(" 获取公众号统计数据报错", e); + return R.builder().code(CommonConstants.FAIL).msg("获取公众号数据失败:" + e.getError().getErrorMsg()).build(); + } + + return R.builder().data(result).build(); + } +} diff --git a/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/service/impl/WxFansMsgResServiceImpl.java b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/service/impl/WxFansMsgResServiceImpl.java new file mode 100755 index 000000000..45407f946 --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/service/impl/WxFansMsgResServiceImpl.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2018-2025, lengleng All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the pig4cloud.com developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: lengleng (wangiegie@gmail.com) + */ +package com.pig4cloud.pigx.mp.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.pig4cloud.pigx.common.core.constant.CommonConstants; +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.common.security.service.PigxUser; +import com.pig4cloud.pigx.common.security.util.SecurityUtils; +import com.pig4cloud.pigx.mp.config.WxMpConfiguration; +import com.pig4cloud.pigx.mp.entity.WxFansMsg; +import com.pig4cloud.pigx.mp.entity.WxFansMsgRes; +import com.pig4cloud.pigx.mp.mapper.WxFansMsgMapper; +import com.pig4cloud.pigx.mp.mapper.WxFansMsgResMapper; +import com.pig4cloud.pigx.mp.service.WxFansMsgResService; +import lombok.AllArgsConstructor; +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.kefu.WxMpKefuMessage; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +/** + * 微信消息回复业务 + * + * @author lengleng + * @date 2019-03-27 20:45:48 + */ +@Slf4j +@Service +@AllArgsConstructor +public class WxFansMsgResServiceImpl extends ServiceImpl implements WxFansMsgResService { + private final WxFansMsgMapper wxFansMsgMapper; + + + /** + * 保存并发送回复 + *

+ * 1. 根据消息ID 查询消息的所属 公众号信息 + * 2. 构建文本客服消息并发送 + * 3. 完善回复消息并保存 + * 4. 更新微信消息为已回复 + * + * @param wxFansMsgRes + * @return + */ + @Override + @Transactional(rollbackFor = Exception.class) + public R saveAndSend(WxFansMsgRes wxFansMsgRes) { + WxFansMsg wxFansMsg = wxFansMsgMapper.selectById(wxFansMsgRes.getFansMsgId()); + + String wxAccountAppid = wxFansMsg.getWxAccountAppid(); + WxMpService wxMpService = WxMpConfiguration.getMpServices().get(wxAccountAppid); + + try { + wxMpService.getKefuService().sendKefuMessage(WxMpKefuMessage + .TEXT() + .toUser(wxFansMsg.getOpenid()) + .content(wxFansMsgRes.getResContent()) + .build()); + } catch (WxErrorException e) { + log.error("发送客服消息失败 ", e); + return R.builder().code(CommonConstants.FAIL).msg(e.getError().getErrorMsg()).build(); + } + + PigxUser user = SecurityUtils.getUser(); + wxFansMsgRes.setUserId(user.getId()); + wxFansMsgRes.setUserName(user.getUsername()); + baseMapper.insert(wxFansMsgRes); + + wxFansMsg.setIsRes("1"); + wxFansMsgMapper.updateById(wxFansMsg); + return R.builder().build(); + } +} diff --git a/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/service/impl/WxFansMsgServiceImpl.java b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/service/impl/WxFansMsgServiceImpl.java new file mode 100755 index 000000000..73c701f0d --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/service/impl/WxFansMsgServiceImpl.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2018-2025, lengleng All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the pig4cloud.com developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: lengleng (wangiegie@gmail.com) + */ +package com.pig4cloud.pigx.mp.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.pig4cloud.pigx.mp.entity.WxFansMsg; +import com.pig4cloud.pigx.mp.mapper.WxFansMsgMapper; +import com.pig4cloud.pigx.mp.service.WxFansMsgService; +import org.springframework.stereotype.Service; + +/** + * 微信消息业务 + * + * @author lengleng + * @date 2019-03-27 20:45:27 + */ +@Service +public class WxFansMsgServiceImpl extends ServiceImpl implements WxFansMsgService { + +} diff --git a/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/service/impl/WxMenuServiceImpl.java b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/service/impl/WxMenuServiceImpl.java new file mode 100755 index 000000000..b78b8e8ef --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/service/impl/WxMenuServiceImpl.java @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2018-2025, lengleng All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the pig4cloud.com developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: lengleng (wangiegie@gmail.com) + */ +package com.pig4cloud.pigx.mp.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.json.JSONObject; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.pig4cloud.pigx.common.core.constant.CommonConstants; +import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.mp.config.WxMpConfiguration; +import com.pig4cloud.pigx.mp.entity.WxAccount; +import com.pig4cloud.pigx.mp.entity.WxMpMenu; +import com.pig4cloud.pigx.mp.mapper.WxAccountMapper; +import com.pig4cloud.pigx.mp.mapper.WxMenuMapper; +import com.pig4cloud.pigx.mp.service.WxMenuService; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.api.WxMpMenuService; +import me.chanjar.weixin.mp.api.WxMpService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * 微信菜单业务 + * + * @author lengleng + * @date 2019-03-27 20:45:18 + */ +@Slf4j +@Service +@AllArgsConstructor +public class WxMenuServiceImpl extends ServiceImpl implements WxMenuService { + private static final String PUB_ED = "1"; + private final WxAccountMapper wxAccountMapper; + + /** + * 新增微信公众号按钮 + * + * @param wxMenus json + * @param appId 公众号 + * @return + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean save(JSONObject wxMenus, String appId) { + baseMapper.delete(Wrappers.lambdaQuery() + .eq(WxMpMenu::getWxAccountAppid, appId)); + + WxAccount wxAccount = wxAccountMapper + .selectOne(Wrappers.lambdaQuery() + .eq(WxAccount::getAppid, appId)); + WxMpMenu wxMpMenu = new WxMpMenu(); + wxMpMenu.setMenu(wxMenus.toStringPretty()); + wxMpMenu.setWxAccountId(wxAccount.getId()); + wxMpMenu.setWxAccountAppid(wxAccount.getAppid()); + wxMpMenu.setWxAccountName(wxAccount.getName()); + baseMapper.insert(wxMpMenu); + return Boolean.TRUE; + } + + /** + * 发布到微信 + * + * @param appId 公众号信息 + * @return + */ + @Override + public R push(String appId) { + List wxMpMenuList = baseMapper.selectList(Wrappers.lambdaQuery() + .eq(WxMpMenu::getWxAccountAppid, appId)); + + if (CollUtil.isEmpty(wxMpMenuList)) { + return R.builder() + .code(CommonConstants.FAIL) + .msg("微信菜单配置未保存,不能发布").build(); + } + WxMpMenu wxMpMenu = wxMpMenuList.get(0); + // 判断是否发布 + if (PUB_ED.equals(wxMpMenu.getPubFlag())) { + return R.builder() + .code(CommonConstants.FAIL) + .msg("微信菜单配置已发布,不要重复发布").build(); + } + WxMpService wxMpService = WxMpConfiguration.getMpServices().get(appId); + WxMpMenuService menuService = wxMpService.getMenuService(); + + // 给数据库保存的加一层 + try { + menuService.menuCreate(wxMpMenu.getMenu()); + } catch (WxErrorException e) { + log.error("发布微信菜单失败", e.getError().getErrorMsg()); + return R.builder() + .code(CommonConstants.FAIL) + .msg(e.getError().getErrorMsg()).build(); + } + + //更新菜单发布标志 + wxMpMenu.setPubFlag(PUB_ED); + baseMapper.updateById(wxMpMenu); + return R.builder().build(); + } + + /** + * 通过appid 查询菜单信息 + * + * @param appId + * @return + */ + @Override + public R getByAppId(String appId) { + List wxMpMenuList = baseMapper.selectList(Wrappers.lambdaQuery() + .eq(WxMpMenu::getWxAccountAppid, appId)); + + if (CollUtil.isEmpty(wxMpMenuList)) { + return R.builder().build(); + } + return R.builder().data(wxMpMenuList.get(0).getMenu()).build(); + } +} diff --git a/pigx-visual/pigx-mp-manager/src/main/resources/bootstrap.yml b/pigx-visual/pigx-mp-manager/src/main/resources/bootstrap.yml new file mode 100644 index 000000000..672fc6f1f --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/resources/bootstrap.yml @@ -0,0 +1,25 @@ +server: + port: 6000 + +spring: + application: + name: @artifactId@ + #配置中心 + cloud: + config: + fail-fast: true + name: ${spring.application.name} + profile: ${spring.profiles.active} + discovery: + enabled: true + service-id: pigx-config + profiles: + active: dev + +# 注册中心配置 +eureka: + instance: + prefer-ip-address: true + client: + service-url: + defaultZone: http://pig:pig@pigx-eureka:8761/eureka/ diff --git a/pigx-visual/pigx-mp-manager/src/main/resources/mapper/WxAccountFansMapper.xml b/pigx-visual/pigx-mp-manager/src/main/resources/mapper/WxAccountFansMapper.xml new file mode 100755 index 000000000..834219ace --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/resources/mapper/WxAccountFansMapper.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pigx-visual/pigx-mp-manager/src/main/resources/mapper/WxAccountMapper.xml b/pigx-visual/pigx-mp-manager/src/main/resources/mapper/WxAccountMapper.xml new file mode 100755 index 000000000..a5aba8ec8 --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/resources/mapper/WxAccountMapper.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pigx-visual/pigx-mp-manager/src/main/resources/mapper/WxFansMsgMapper.xml b/pigx-visual/pigx-mp-manager/src/main/resources/mapper/WxFansMsgMapper.xml new file mode 100755 index 000000000..5bcded334 --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/resources/mapper/WxFansMsgMapper.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pigx-visual/pigx-mp-manager/src/main/resources/mapper/WxFansMsgResMapper.xml b/pigx-visual/pigx-mp-manager/src/main/resources/mapper/WxFansMsgResMapper.xml new file mode 100755 index 000000000..4ebb02559 --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/resources/mapper/WxFansMsgResMapper.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + diff --git a/pigx-visual/pigx-mp-manager/src/main/resources/mapper/WxMenuMapper.xml b/pigx-visual/pigx-mp-manager/src/main/resources/mapper/WxMenuMapper.xml new file mode 100755 index 000000000..3bc199fcd --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/resources/mapper/WxMenuMapper.xml @@ -0,0 +1,26 @@ + + + + + + + + + diff --git a/pigx-visual/pigx-sso-client-demo/pom.xml b/pigx-visual/pigx-sso-client-demo/pom.xml index 4df1a5d21..6fc917786 100644 --- a/pigx-visual/pigx-sso-client-demo/pom.xml +++ b/pigx-visual/pigx-sso-client-demo/pom.xml @@ -29,7 +29,7 @@ com.pig4cloud pigx-visual - 2.7.0 + 2.8.0 diff --git a/pigx-visual/pigx-tx-manager/pom.xml b/pigx-visual/pigx-tx-manager/pom.xml index fe695de20..f94cdc2de 100644 --- a/pigx-visual/pigx-tx-manager/pom.xml +++ b/pigx-visual/pigx-tx-manager/pom.xml @@ -5,7 +5,7 @@ com.pig4cloud pigx-visual - 2.7.0 + 2.8.0 pigx-tx-manager diff --git a/pigx-visual/pigx-zipkin/pom.xml b/pigx-visual/pigx-zipkin/pom.xml index 9aab28503..a70d40d5a 100644 --- a/pigx-visual/pigx-zipkin/pom.xml +++ b/pigx-visual/pigx-zipkin/pom.xml @@ -22,7 +22,7 @@ pigx-visual com.pig4cloud - 2.7.0 + 2.8.0 4.0.0 diff --git a/pigx-visual/pom.xml b/pigx-visual/pom.xml index c8e5d4ad7..d6b1bbc4a 100644 --- a/pigx-visual/pom.xml +++ b/pigx-visual/pom.xml @@ -24,7 +24,7 @@ com.pig4cloud pigx - 2.7.0 + 2.8.0 pigx-visual @@ -37,6 +37,7 @@ pigx-daemon-elastic-job pigx-daemon-quartz pigx-monitor + pigx-mp-manager pigx-sso-client-demo pigx-tx-manager pigx-zipkin diff --git a/pom.xml b/pom.xml index 6a61426be..0aaa086db 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ com.pig4cloud pigx - 2.7.0 + 2.8.0 ${project.artifactId} pom @@ -42,14 +42,14 @@ - 2.1.3.RELEASE + 2.1.4.RELEASE Greenwich.SR1 - Cairo-SR7 + Cairo-SR8 UTF-8 1.8 1.8 2.1.3 - 4.4.5 + 4.5.3 0.0.9 2.9.2 2.10.0 @@ -57,7 +57,7 @@ 4.1.0 2.1.1 2.10.2 - 6.0.2 + 6.0.4 2.1.5 2.3.5.RELEASE 2.1.2.RELEASE