From 23a6451c3be917789fc85bfbb87b9748f6958180 Mon Sep 17 00:00:00 2001
From: zhizhi wu <2377881365@qq.com>
Date: Thu, 10 Mar 2022 18:27:36 +0800
Subject: [PATCH] =?UTF-8?q?=E7=94=9F=E6=88=90=E4=BA=8C=E7=BB=B4=E7=A0=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../java/com/ccsens/util/JacksonUtilTest.java | 23 +++++
.../test/java/com/ccsens/util/NoticeDto.java | 86 +++++++++++++++++++
wechatutil/pom.xml | 4 +-
.../wechatutil/WechatutilApplication.java | 20 ++---
.../wechatutil/bean/dto/wxmini/NoticeDto.java | 6 ++
.../bean/dto/wxofficial/WxQrCodeDto.java | 54 ++++++++++++
.../bean/vo/wxofficial/WxQrCodeVo.java | 25 ++++++
.../wechatutil/util/WeiXinPropUtil.java | 26 ++++++
.../ccsens/wechatutil/util/WxConstant.java | 30 +++++--
.../wxofficial/OfficialQrCodeUtil.java | 62 +++++++++++++
10 files changed, 318 insertions(+), 18 deletions(-)
create mode 100644 util/src/test/java/com/ccsens/util/JacksonUtilTest.java
create mode 100644 util/src/test/java/com/ccsens/util/NoticeDto.java
create mode 100644 wechatutil/src/main/java/com/ccsens/wechatutil/bean/dto/wxofficial/WxQrCodeDto.java
create mode 100644 wechatutil/src/main/java/com/ccsens/wechatutil/bean/vo/wxofficial/WxQrCodeVo.java
create mode 100644 wechatutil/src/main/java/com/ccsens/wechatutil/util/WeiXinPropUtil.java
create mode 100644 wechatutil/src/main/java/com/ccsens/wechatutil/wxofficial/OfficialQrCodeUtil.java
diff --git a/util/src/test/java/com/ccsens/util/JacksonUtilTest.java b/util/src/test/java/com/ccsens/util/JacksonUtilTest.java
new file mode 100644
index 0000000..148c306
--- /dev/null
+++ b/util/src/test/java/com/ccsens/util/JacksonUtilTest.java
@@ -0,0 +1,23 @@
+package com.ccsens.util;
+
+import org.junit.Test;
+
+import java.io.IOException;
+
+/**
+ * @description:
+ * @author: whj
+ * @time: 2022/3/9 11:36
+ */
+public class JacksonUtilTest {
+
+ @Test
+ public void test01() throws IOException {
+
+ String xml = "1646796877";
+
+
+ System.out.println(JacksonUtil.xmlToJson(xml));
+ System.out.println(JacksonUtil.xmlToBean(xml, NoticeDto.Notice.class));
+ }
+}
diff --git a/util/src/test/java/com/ccsens/util/NoticeDto.java b/util/src/test/java/com/ccsens/util/NoticeDto.java
new file mode 100644
index 0000000..3dc68f5
--- /dev/null
+++ b/util/src/test/java/com/ccsens/util/NoticeDto.java
@@ -0,0 +1,86 @@
+package com.ccsens.util;
+
+import cn.hutool.core.util.ArrayUtil;
+import com.ccsens.util.enterprisewx.SHA1;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
+import lombok.Data;
+
+import javax.validation.constraints.NotEmpty;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+
+/**
+ * @description:
+ * @author: whj
+ * @time: 2021/10/21 15:51
+ */
+public class NoticeDto {
+
+ /**
+ * 微信小程序通知校验
+ */
+ @Data
+ public static class ValidMsg{
+ @NotEmpty
+ private String signature;
+ @NotEmpty
+ private String timestamp;
+ @NotEmpty
+ private String nonce;
+ @NotEmpty
+ private String echostr;
+
+
+ public boolean check(String token) throws NoSuchAlgorithmException {
+ String[] dict = {token, timestamp, nonce};
+ Arrays.sort(dict);
+ String str = ArrayUtil.join(dict, "");
+ String shaStr = SHA1.getSha1(str);
+ return signature.equals(shaStr);
+ }
+ }
+
+ @Data
+ @JacksonXmlRootElement(localName = "xml")
+ public static class Notice {
+ /**
+ * 小程序的原始ID
+ */
+ @JacksonXmlProperty(localName = "ToUserName")
+ private String ToUserName;
+ /**
+ * 发送者的openid
+ */
+ @JacksonXmlProperty(localName = "FromUserName")
+ private String FromUserName;
+ @JacksonXmlProperty(localName = "CreateTime")
+ private String CreateTime;
+ /**
+ * text: 文本 Content
+ * image:PicUrl MediaId
+ * miniprogrampage: 小程序卡片 Title AppId PagePath ThumbUrl ThumbMediaId
+ */
+ private String MsgType;
+ private String Event;
+ private String SessionFrom;
+ private String Content;
+ private String MsgId;
+ private String PicUrl;
+
+ /**事件KEY值,qrscene_为前缀,后面为二维码的参数值*/
+ private String EventKey;
+ /**二维码的ticket,可用来换取二维码图片*/
+ private String Ticket;
+
+ /**
+ * 图片消息媒体id,可以调用[获取临时素材]((getTempMedia)接口拉取数据。
+ */
+ private String MediaId;
+ private String Title;
+ private String AppId;
+ private String PagePath;
+ private String ThumbUrl;
+ private String ThumbMediaId;
+ }
+}
diff --git a/wechatutil/pom.xml b/wechatutil/pom.xml
index ee55e01..ffc039f 100644
--- a/wechatutil/pom.xml
+++ b/wechatutil/pom.xml
@@ -16,11 +16,11 @@
-
+
util
diff --git a/wechatutil/src/main/java/com/ccsens/wechatutil/WechatutilApplication.java b/wechatutil/src/main/java/com/ccsens/wechatutil/WechatutilApplication.java
index a2d5472..e44b726 100644
--- a/wechatutil/src/main/java/com/ccsens/wechatutil/WechatutilApplication.java
+++ b/wechatutil/src/main/java/com/ccsens/wechatutil/WechatutilApplication.java
@@ -1,15 +1,15 @@
package com.ccsens.wechatutil;
-import com.ccsens.cloudutil.ribbon.RibbonConfiguration;
-import org.mybatis.spring.annotation.MapperScan;
-import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.boot.web.servlet.ServletComponentScan;
-import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
-import org.springframework.cloud.openfeign.EnableFeignClients;
-import org.springframework.context.annotation.ComponentScan;
-import org.springframework.context.annotation.FilterType;
-import org.springframework.scheduling.annotation.EnableAsync;
+//import com.ccsens.cloudutil.ribbon.RibbonConfiguration;
+//import org.mybatis.spring.annotation.MapperScan;
+//import org.springframework.boot.SpringApplication;
+//import org.springframework.boot.autoconfigure.SpringBootApplication;
+//import org.springframework.boot.web.servlet.ServletComponentScan;
+//import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
+//import org.springframework.cloud.openfeign.EnableFeignClients;
+//import org.springframework.context.annotation.ComponentScan;
+//import org.springframework.context.annotation.FilterType;
+//import org.springframework.scheduling.annotation.EnableAsync;
/**
* @author 逗
diff --git a/wechatutil/src/main/java/com/ccsens/wechatutil/bean/dto/wxmini/NoticeDto.java b/wechatutil/src/main/java/com/ccsens/wechatutil/bean/dto/wxmini/NoticeDto.java
index 629efc8..dcb275f 100644
--- a/wechatutil/src/main/java/com/ccsens/wechatutil/bean/dto/wxmini/NoticeDto.java
+++ b/wechatutil/src/main/java/com/ccsens/wechatutil/bean/dto/wxmini/NoticeDto.java
@@ -62,6 +62,12 @@ public class NoticeDto {
private String Content;
private String MsgId;
private String PicUrl;
+
+ /**事件KEY值,qrscene_为前缀,后面为二维码的参数值*/
+ private String EventKey;
+ /**二维码的ticket,可用来换取二维码图片*/
+ private String Ticket;
+
/**
* 图片消息媒体id,可以调用[获取临时素材]((getTempMedia)接口拉取数据。
*/
diff --git a/wechatutil/src/main/java/com/ccsens/wechatutil/bean/dto/wxofficial/WxQrCodeDto.java b/wechatutil/src/main/java/com/ccsens/wechatutil/bean/dto/wxofficial/WxQrCodeDto.java
new file mode 100644
index 0000000..8a35e43
--- /dev/null
+++ b/wechatutil/src/main/java/com/ccsens/wechatutil/bean/dto/wxofficial/WxQrCodeDto.java
@@ -0,0 +1,54 @@
+package com.ccsens.wechatutil.bean.dto.wxofficial;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * @description:
+ * @author: whj
+ * @time: 2022/3/7 9:09
+ */
+public class WxQrCodeDto {
+
+ @Data
+ @ApiModel("生成带参数的二维码-公众号")
+ public static class Create{
+
+ @ApiModelProperty("该二维码有效时间,以秒为单位。 最大不超过2592000(即30天),此字段如果不填,则默认有效期为60秒。")
+ private Long expire_seconds;
+ @ApiModelProperty("二维码类型,QR_SCENE为临时的整型参数值,QR_STR_SCENE为临时的字符串参数值,QR_LIMIT_SCENE为永久的整型参数值,QR_LIMIT_STR_SCENE为永久的字符串参数值")
+ private String action_name;
+ @ApiModelProperty
+ private ActionInfo action_info;
+ public Create(){}
+
+ public Create(Long expire_seconds, String action_name, Integer scene_id, String scene_str) {
+ this.expire_seconds = expire_seconds;
+ this.action_name = action_name;
+ this.action_info = new ActionInfo();
+ Scene scene = new Scene();
+ scene.setScene_id(scene_id);
+ scene.setScene_str(scene_str);
+ this.action_info.setScene(scene);
+ }
+ }
+
+
+ @Data
+ @ApiModel("生成带参数的二维码场景值1-公众号")
+ public static class ActionInfo {
+ private Scene scene;
+ }
+
+ @Data
+ @ApiModel("生成带参数的二维码场景值2-公众号")
+ public static class Scene {
+ @ApiModelProperty("场景值ID,临时二维码时为32位非0整型,永久二维码时最大值为100000(目前参数只支持1--100000)")
+ private Integer scene_id;
+ @ApiModelProperty("场景值ID(字符串形式的ID),字符串类型,长度限制为1到64")
+ private String scene_str;
+
+ }
+
+}
diff --git a/wechatutil/src/main/java/com/ccsens/wechatutil/bean/vo/wxofficial/WxQrCodeVo.java b/wechatutil/src/main/java/com/ccsens/wechatutil/bean/vo/wxofficial/WxQrCodeVo.java
new file mode 100644
index 0000000..9eba5d4
--- /dev/null
+++ b/wechatutil/src/main/java/com/ccsens/wechatutil/bean/vo/wxofficial/WxQrCodeVo.java
@@ -0,0 +1,25 @@
+package com.ccsens.wechatutil.bean.vo.wxofficial;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * @description:
+ * @author: whj
+ * @time: 2022/3/7 9:52
+ */
+public class WxQrCodeVo {
+
+ @Data
+ @ApiModel("生成带参数的二维码-公众号返回")
+ public static class QrCodeUrl{
+ @ApiModelProperty("获取的二维码ticket,凭借此ticket可以在有效时间内换取二维码")
+ private String ticket;
+ @ApiModelProperty("该二维码有效时间,以秒为单位。 最大不超过2592000(即30天)")
+ private Long expire_seconds;
+ @ApiModelProperty("二维码图片解析后的地址,开发者可根据该地址自行生成需要的二维码图片")
+ private String url;
+ }
+
+}
diff --git a/wechatutil/src/main/java/com/ccsens/wechatutil/util/WeiXinPropUtil.java b/wechatutil/src/main/java/com/ccsens/wechatutil/util/WeiXinPropUtil.java
new file mode 100644
index 0000000..94c642e
--- /dev/null
+++ b/wechatutil/src/main/java/com/ccsens/wechatutil/util/WeiXinPropUtil.java
@@ -0,0 +1,26 @@
+package com.ccsens.wechatutil.util;
+
+import com.ccsens.wechatutil.wxofficial.OfficialAccountSigninUtil;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+/**
+ * @description:
+ * @author: whj
+ * @time: 2022/3/4 17:22
+ */
+@Component
+public class WeiXinPropUtil {
+ public static String appIdOfficial;
+ public static String secretOfficial;
+
+ @Value("${official.appId:}")
+ public void setAppIdOfficial(String appIdOfficial) {
+ WeiXinPropUtil.appIdOfficial = appIdOfficial;
+ }
+ @Value("${official.secret:}")
+ public void setApplication(String secretOfficial) {
+ WeiXinPropUtil.secretOfficial = secretOfficial;
+ }
+
+}
diff --git a/wechatutil/src/main/java/com/ccsens/wechatutil/util/WxConstant.java b/wechatutil/src/main/java/com/ccsens/wechatutil/util/WxConstant.java
index 3c4acb8..45ba859 100644
--- a/wechatutil/src/main/java/com/ccsens/wechatutil/util/WxConstant.java
+++ b/wechatutil/src/main/java/com/ccsens/wechatutil/util/WxConstant.java
@@ -1,5 +1,11 @@
package com.ccsens.wechatutil.util;
+import cn.hutool.core.util.StrUtil;
+import com.ccsens.util.JacksonUtil;
+import com.ccsens.util.exception.BaseException;
+import com.ccsens.wechatutil.bean.po.WxBaseEntity;
+
+import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
@@ -12,10 +18,16 @@ public class WxConstant {
public static final String ANYRING = "anyring";
- /*** 小程序登录路径 */
- public static final String MINI_PROGRAM_LOGIN = "https://api.weixin.qq.com/sns/jscode2session?appid=%1$s&secret=%2$s&js_code=%3$s&grant_type=%4$s";
/*** 公众号获取accessToken */
public static final String URL_GET_OAUTH2_ACCESS_TOKEN = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%1$s&secret=%2$s&code=%3$s&grant_type=authorization_code";
+ /*** 公众号发送订阅消息 */
+ public static final String MESSAGE_TEMPLATE_SEND = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=%1$s";
+ /** 创建二维码 */
+ public static final String QR_CODE_CREATE = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token={}";
+
+
+ /*** 小程序登录路径 */
+ public static final String MINI_PROGRAM_LOGIN = "https://api.weixin.qq.com/sns/jscode2session?appid=%1$s&secret=%2$s&js_code=%3$s&grant_type=%4$s";
/*** 通过网页授权和openId获取用户信息 */
public static final String URL_GET_OAUTH2_USER_INFO = "https://api.weixin.qq.com/sns/userinfo?access_token=%1$s&openid=%2$s";
/*** 获取小程序码A */
@@ -26,16 +38,12 @@ public class WxConstant {
public static final String URL_GET_WX_CODE_C = "https://api.weixin.qq.com/cgi-bin/wxaapp/createwxaqrcode?access_token=%1$s";
/*** 小程序获取accessToken */
public static final String URL_GET_ACCESS_TOKEN = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%1$s&secret=%2$s";
- /*** 公众号发送订阅消息 */
- public static final String MESSAGE_TEMPLATE_SEND = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=%1$s";
/*** 小程序发送订阅消息 */
public static final String URL_SEND_SUBSCRIBE_MESSAGE = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=%1$s";
-
/*** 小程序消息模板--支付 */
public static String SUBSCRIBE_MSG_ID_BUY = "bqdx4FW51G-JLU6HjL6LyvUbjpo4rFK6CPor2-w3VwM";
/*** 小程序消息模板--订单发送 */
public static String SUBSCRIBE_MSG_ID_ORDERSEND = "5-rhM8h3x1W82tHCt18g9iXyGELyUKQtBDZiFjgItOo";
-
/*** 小程序登录路径内的type */
public static final String GRANT_TYPE = "authorization_code";
@@ -106,4 +114,14 @@ public class WxConstant {
}
+ public static void pageResult(String result) {
+ try {
+ if (StrUtil.isEmpty(result) || null == JacksonUtil.jsonToBean(result, WxBaseEntity.class)) {
+ throw new BaseException(WxCodeError.WX_HTTP_ERROR);
+ }
+ } catch (IOException e) {
+ throw new BaseException(e.getMessage());
+ }
+ }
+
}
diff --git a/wechatutil/src/main/java/com/ccsens/wechatutil/wxofficial/OfficialQrCodeUtil.java b/wechatutil/src/main/java/com/ccsens/wechatutil/wxofficial/OfficialQrCodeUtil.java
new file mode 100644
index 0000000..818675f
--- /dev/null
+++ b/wechatutil/src/main/java/com/ccsens/wechatutil/wxofficial/OfficialQrCodeUtil.java
@@ -0,0 +1,62 @@
+package com.ccsens.wechatutil.wxofficial;
+
+import cn.hutool.core.util.StrUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.ccsens.util.RestTemplateUtil;
+import com.ccsens.wechatutil.bean.dto.wxofficial.WxQrCodeDto;
+import com.ccsens.wechatutil.bean.vo.wxofficial.WxQrCodeVo;
+import com.ccsens.wechatutil.util.WeiXinPropUtil;
+import com.ccsens.wechatutil.util.WxConstant;
+import com.ccsens.wechatutil.wxcommon.WxCommonUtil;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * @description:
+ * @author: whj
+ * @time: 2022/3/4 17:14
+ */
+@Slf4j
+public class OfficialQrCodeUtil {
+ /**临时的整型参数值*/
+ public static final String QR_SCENE = "QR_SCENE";
+ /**临时的字符串参数值*/
+ public static final String QR_STR_SCENE = "QR_STR_SCENE";
+ /**永久的整型参数值*/
+ public static final String QR_LIMIT_SCENE = "QR_LIMIT_SCENE";
+ /**永久的字符串参数值*/
+ public static final String QR_LIMIT_STR_SCENE = "QR_LIMIT_STR_SCENE";
+
+
+ /**
+ * 生成带参数的二维码
+ * @param expire_seconds 有效时间
+ * @param action_name 应用名
+ * @param scene_id 场景值ID,临时二维码时为32位非0整型,永久二维码时最大值为100000
+ * @param scene_str 场景值ID(字符串形式的ID),字符串类型,长度限制为1到64
+ * @return 二维码路径
+ */
+ public static WxQrCodeVo.QrCodeUrl send (Long expire_seconds, String action_name, Integer scene_id, String scene_str){
+ WxQrCodeDto.Create create = new WxQrCodeDto.Create(expire_seconds, action_name, scene_id, scene_str);
+ String url = String.format(WxConstant.QR_CODE_CREATE, WxCommonUtil.getAccessToken(WeiXinPropUtil.appIdOfficial, WeiXinPropUtil.secretOfficial));
+ String response = RestTemplateUtil.postBody(url, create);
+ log.info("url: {}\nresponse: {}", url, response);
+ WxConstant.pageResult(response);
+ return JSONObject.parseObject(response, WxQrCodeVo.QrCodeUrl.class);
+ }
+
+
+ /**
+ * 生成带参数的二维码
+ * @param create 二维码参数
+ * @param appIdOfficia appId
+ * @param secretOfficial secret
+ * @return 二维码路径
+ */
+ public static WxQrCodeVo.QrCodeUrl send (WxQrCodeDto.Create create, String appIdOfficia, String secretOfficial){
+ String url = StrUtil.format(WxConstant.QR_CODE_CREATE, WxCommonUtil.getAccessToken(appIdOfficia,secretOfficial));
+ String response = RestTemplateUtil.postBody(url, create);
+ log.info("url: {}\nresponse: {}", url, response);
+ WxConstant.pageResult(response);
+ return JSONObject.parseObject(response, WxQrCodeVo.QrCodeUrl.class);
+ }
+}