From aedaa54341a4f720d997a3141ccb84baf55c0fd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=86=B7=E5=86=B7?= Date: Wed, 27 Mar 2019 00:17:35 +0800 Subject: [PATCH] =?UTF-8?q?:sparkles:=20=E6=B7=BB=E5=8A=A0=E6=96=B0?= =?UTF-8?q?=E7=89=B9=E6=80=A7=E3=80=82=20=E5=A4=9A=E5=85=AC=E4=BC=97?= =?UTF-8?q?=E5=8F=B7=E7=AE=A1=E7=90=86=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pigx-common/pigx-common-bom/pom.xml | 12 ++ .../core/constant/SecurityConstants.java | 4 + .../resources/config/pigx-codegen-dev.yml | 2 +- .../resources/config/pigx-mp-manager-dev.yml | 31 ++++ .../service/impl/SysMenuServiceImpl.java | 2 +- .../com/pig4cloud/pigx/admin/BitMapTest.java | 86 ++++++++++ pigx-visual/pigx-mp-manager/Dockerfile | 15 ++ pigx-visual/pigx-mp-manager/pom.xml | 85 ++++++++++ .../pigx/mp/PigxMpManagerApplication.java | 40 +++++ .../pigx/mp/builder/AbstractBuilder.java | 21 +++ .../pigx/mp/builder/ImageBuilder.java | 24 +++ .../pigx/mp/builder/TextBuilder.java | 22 +++ .../pigx/mp/config/WxMpConfiguration.java | 149 ++++++++++++++++++ .../mp/config/WxMpInRedisConfigStorage.java | 120 ++++++++++++++ .../mp/controller/WxAccountController.java | 126 +++++++++++++++ .../controller/WxAccountFansController.java | 106 +++++++++++++ .../mp/controller/WxPortalController.java | 119 ++++++++++++++ .../mp/controller/WxRedirectController.java | 37 +++++ .../pig4cloud/pigx/mp/entity/WxAccount.java | 92 +++++++++++ .../pigx/mp/entity/WxAccountFans.java | 111 +++++++++++++ .../pigx/mp/handler/AbstractHandler.java | 9 ++ .../pigx/mp/handler/KfSessionHandler.java | 24 +++ .../pigx/mp/handler/LocationHandler.java | 34 ++++ .../pig4cloud/pigx/mp/handler/LogHandler.java | 26 +++ .../pigx/mp/handler/MenuHandler.java | 36 +++++ .../pig4cloud/pigx/mp/handler/MsgHandler.java | 49 ++++++ .../pigx/mp/handler/NullHandler.java | 24 +++ .../pigx/mp/handler/ScanHandler.java | 24 +++ .../mp/handler/StoreCheckNotifyHandler.java | 27 ++++ .../pigx/mp/handler/SubscribeHandler.java | 72 +++++++++ .../pigx/mp/handler/UnsubscribeHandler.java | 29 ++++ .../pigx/mp/mapper/WxAccountFansMapper.java | 30 ++++ .../pigx/mp/mapper/WxAccountMapper.java | 30 ++++ .../pigx/mp/service/WxAccountFansService.java | 30 ++++ .../pigx/mp/service/WxAccountService.java | 38 +++++ .../impl/WxAccountFansServiceImpl.java | 34 ++++ .../mp/service/impl/WxAccountServiceImpl.java | 69 ++++++++ .../src/main/resources/bootstrap.yml | 25 +++ .../resources/mapper/WxAccountFansMapper.xml | 45 ++++++ .../main/resources/mapper/WxAccountMapper.xml | 40 +++++ pigx-visual/pom.xml | 1 + 41 files changed, 1898 insertions(+), 2 deletions(-) create mode 100644 pigx-config/src/main/resources/config/pigx-mp-manager-dev.yml create mode 100644 pigx-upms/pigx-upms-biz/src/test/java/com/pig4cloud/pigx/admin/BitMapTest.java create mode 100644 pigx-visual/pigx-mp-manager/Dockerfile create mode 100755 pigx-visual/pigx-mp-manager/pom.xml create mode 100755 pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/PigxMpManagerApplication.java create mode 100755 pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/builder/AbstractBuilder.java create mode 100755 pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/builder/ImageBuilder.java create mode 100755 pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/builder/TextBuilder.java create mode 100755 pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/config/WxMpConfiguration.java create mode 100644 pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/config/WxMpInRedisConfigStorage.java create mode 100755 pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/controller/WxAccountController.java create mode 100755 pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/controller/WxAccountFansController.java create mode 100755 pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/controller/WxPortalController.java create mode 100755 pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/controller/WxRedirectController.java create mode 100755 pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/entity/WxAccount.java create mode 100755 pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/entity/WxAccountFans.java create mode 100755 pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/handler/AbstractHandler.java create mode 100755 pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/handler/KfSessionHandler.java create mode 100755 pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/handler/LocationHandler.java create mode 100755 pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/handler/LogHandler.java create mode 100755 pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/handler/MenuHandler.java create mode 100755 pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/handler/MsgHandler.java create mode 100755 pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/handler/NullHandler.java create mode 100755 pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/handler/ScanHandler.java create mode 100755 pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/handler/StoreCheckNotifyHandler.java create mode 100755 pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/handler/SubscribeHandler.java create mode 100755 pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/handler/UnsubscribeHandler.java create mode 100755 pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/mapper/WxAccountFansMapper.java create mode 100755 pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/mapper/WxAccountMapper.java create mode 100755 pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/service/WxAccountFansService.java create mode 100755 pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/service/WxAccountService.java create mode 100755 pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/service/impl/WxAccountFansServiceImpl.java create mode 100755 pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/service/impl/WxAccountServiceImpl.java create mode 100644 pigx-visual/pigx-mp-manager/src/main/resources/bootstrap.yml create mode 100755 pigx-visual/pigx-mp-manager/src/main/resources/mapper/WxAccountFansMapper.xml create mode 100755 pigx-visual/pigx-mp-manager/src/main/resources/mapper/WxAccountMapper.xml diff --git a/pigx-common/pigx-common-bom/pom.xml b/pigx-common/pigx-common-bom/pom.xml index ba9003c6d..f1dae42c6 100644 --- a/pigx-common/pigx-common-bom/pom.xml +++ b/pigx-common/pigx-common-bom/pom.xml @@ -19,6 +19,7 @@ 2.6.0 3.1.0 8.0.13 + 3.3.0 @@ -92,6 +93,17 @@ mysql-connector-java ${mysql.connector.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/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-config/src/main/resources/config/pigx-codegen-dev.yml b/pigx-config/src/main/resources/config/pigx-codegen-dev.yml index 47d1fcfce..6e3d9f3e1 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,6 @@ 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/ 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..d25267789 --- /dev/null +++ b/pigx-config/src/main/resources/config/pigx-mp-manager-dev.yml @@ -0,0 +1,31 @@ +## 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 + 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-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysMenuServiceImpl.java b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysMenuServiceImpl.java index d0c86958d..fb4ec98c3 100644 --- a/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysMenuServiceImpl.java +++ b/pigx-upms/pigx-upms-biz/src/main/java/com/pig4cloud/pigx/admin/service/impl/SysMenuServiceImpl.java @@ -52,7 +52,7 @@ public class SysMenuServiceImpl extends ServiceImpl impl private final SysRoleMenuMapper sysRoleMenuMapper; @Override - @Cacheable(value = "menu_details#2000", key = "#roleId + '_menu'") + @Cacheable(value = "menu_details", key = "#roleId + '_menu'") public List findMenuByRoleId(Integer roleId) { return baseMapper.listMenusByRoleId(roleId); } 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-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..cb9b513c3 --- /dev/null +++ b/pigx-visual/pigx-mp-manager/pom.xml @@ -0,0 +1,85 @@ + + + 4.0.0 + + + com.pig4cloud + pigx-visual + 2.6.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/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..322d0dc9b --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/controller/WxAccountController.java @@ -0,0 +1,126 @@ +/* + * 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); + } + +} 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..550ca3d80 --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/controller/WxAccountFansController.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.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)); + } + +} 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..a9afd103c --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/controller/WxPortalController.java @@ -0,0 +1,119 @@ +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 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) { + 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); + 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..76623d276 --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/entity/WxAccount.java @@ -0,0 +1,92 @@ +/* + * 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; + +} 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..a2ec8af50 --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/entity/WxAccountFans.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.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 String wxAccountId; + /** + * 微信公众号appid + */ + private String wxAccountAppid; + /** + * 创建时间 + */ + 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/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..0294e435c --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/handler/LogHandler.java @@ -0,0 +1,26 @@ +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 LogHandler extends AbstractHandler { + @Override + public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, + Map context, WxMpService wxMpService, + WxSessionManager sessionManager) { + log.info("接收到请求消息,内容:{}", wxMessage.getContent()); + 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/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..e0c374795 --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/service/WxAccountFansService.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.WxAccountFans; + +/** + * 微信公众号粉丝 + * + * @author lengleng + * @date 2019-03-26 22:08:08 + */ +public interface WxAccountFansService extends IService { + +} 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..926091d84 --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/service/WxAccountService.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.WxAccount; + +/** + * 公众号账户 + * + * @author lengleng + * @date 2019-03-26 22:07:53 + */ +public interface WxAccountService extends IService { + + /** + * 生成公众号二维码 + * + * @param appId + * @return + */ + R generateQr(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..45b45fc99 --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/service/impl/WxAccountFansServiceImpl.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.WxAccountFans; +import com.pig4cloud.pigx.mp.mapper.WxAccountFansMapper; +import com.pig4cloud.pigx.mp.service.WxAccountFansService; +import org.springframework.stereotype.Service; + +/** + * 微信公众号粉丝 + * + * @author lengleng + * @date 2019-03-26 22:08:08 + */ +@Service +public class WxAccountFansServiceImpl extends ServiceImpl implements WxAccountFansService { + +} 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..d5cbe95e3 --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/java/com/pig4cloud/pigx/mp/service/impl/WxAccountServiceImpl.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.service.impl; + +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.WxMpService; +import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket; +import org.springframework.stereotype.Service; + +/** + * 公众号账户 + * + * @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(); + } +} 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..347559fab --- /dev/null +++ b/pigx-visual/pigx-mp-manager/src/main/resources/mapper/WxAccountFansMapper.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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/pom.xml b/pigx-visual/pom.xml index 9661d6c4d..d397cab3a 100644 --- a/pigx-visual/pom.xml +++ b/pigx-visual/pom.xml @@ -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