新增微信模块

This commit is contained in:
wanggeng888 2021-04-28 12:02:39 +08:00
parent c670823d4c
commit e0532a7028
10 changed files with 444 additions and 0 deletions

22
module-wechat/pom.xml Normal file
View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>wg-basic</artifactId>
<groupId>ink.wgink</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>module-wechat</artifactId>
<dependencies>
<dependency>
<groupId>ink.wgink</groupId>
<artifactId>common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,50 @@
package ink.wgink.module.wechat.enums;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: ErrorMsgEnums
* @Description:
* @Author: wanggeng
* @Date: 2021/4/28 6:08 上午
* @Version: 1.0
*/
public enum ErrorMsgEnum {
SYSTEM_BUSY(-1, "系统繁忙,此时请开发者稍候再试"),
SUCCESS(0, "请求成功"),
ERROR_40001(40001, "AppSecret错误或者AppSecret不属于这个公众号请开发者确认AppSecret的正确性"),
ERROR_40002(40002, "请确保grant_type字段值为client_credential"),
ERROR_40164(40164, "调用接口的IP地址不在白名单中请在接口IP白名单中进行设置。小程序及小游戏调用不要求IP地址在白名单内。"),
ERROR_89503(89503, "此IP调用需要管理员确认,请联系管理员"),
ERROR_89501(89501, "此IP正在等待管理员确认,请联系管理员"),
ERROR_89506(89506, "24小时内该IP被管理员拒绝调用两次24小时内不可再使用该IP调用"),
ERROR_89507(89507, "1小时内该IP被管理员拒绝调用一次1小时内不可再使用该IP调用");
private int errCode;
private String errMsg;
ErrorMsgEnum(int errCode, String errMsg) {
this.errCode = errCode;
this.errMsg = errMsg;
}
public int getErrCode() {
return errCode;
}
public String getErrMsg() {
return errMsg == null ? "" : errMsg;
}
public static String getErrMsg(int errCode) {
ErrorMsgEnum[] errorMsgEnums = values();
for (ErrorMsgEnum errorMsgEnum : errorMsgEnums) {
if (errorMsgEnum.errCode == errCode) {
return errorMsgEnum.getErrMsg();
}
}
return null;
}
}

View File

@ -0,0 +1,59 @@
package ink.wgink.module.wechat.official.account.manager;
import ink.wgink.module.wechat.official.account.pojo.OfficialAccountAccessToken;
import ink.wgink.module.wechat.official.account.request.AccessTokenRestTemplate;
import ink.wgink.properties.wechat.official.account.OfficialAccountProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: AccessTokenManager
* @Description: access_token控制器
* @Author: wanggeng
* @Date: 2021/4/27 5:19 下午
* @Version: 1.0
*/
public class OfficialAccountAccessTokenManager {
private static final Logger LOG = LoggerFactory.getLogger(OfficialAccountAccessTokenManager.class);
/**
* 最大过期毫秒
*/
private static long MAXIMUM_EXPIRE_MILLISECOND = 5400000;
private static OfficialAccountAccessTokenManager officialAccountAccessTokenManager = AccessTokenManagerFactory.officialAccountAccessTokenManager;
private OfficialAccountAccessToken officialAccountAccessToken;
private OfficialAccountAccessTokenManager() {
}
public static OfficialAccountAccessTokenManager getInstance() {
return officialAccountAccessTokenManager;
}
/**
* 刷新access_token
*/
public void refreshAccessToken(OfficialAccountProperties officialAccountProperties) {
long currentTime = System.currentTimeMillis();
if (officialAccountAccessToken != null && (currentTime - this.officialAccountAccessToken.getLastUpdated()) < MAXIMUM_EXPIRE_MILLISECOND) {
return;
}
LOG.debug("刷新公众号 AccessToken 开始");
AccessTokenRestTemplate accessTokenRestTemplate = new AccessTokenRestTemplate(officialAccountProperties);
accessTokenRestTemplate.post(officialAccountProperties.getAccessTokenUrl());
LOG.debug("accessToken: {}", this.officialAccountAccessToken);
LOG.debug("刷新公众号 AccessToken 结束");
}
public void setAccessToken(OfficialAccountAccessToken officialAccountAccessToken) {
this.officialAccountAccessToken = officialAccountAccessToken;
}
private static class AccessTokenManagerFactory {
public static OfficialAccountAccessTokenManager officialAccountAccessTokenManager = new OfficialAccountAccessTokenManager();
}
}

View File

@ -0,0 +1,44 @@
package ink.wgink.module.wechat.official.account.pojo;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: AccessToken
* @Description:
* @Author: wanggeng
* @Date: 2021/4/28 5:29 上午
* @Version: 1.0
*/
public class OfficialAccountAccessToken {
private String accessToken;
private long lastUpdated;
public String getAccessToken() {
return accessToken == null ? "" : accessToken;
}
public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}
public long getLastUpdated() {
return lastUpdated;
}
public void setLastUpdated(long lastUpdated) {
this.lastUpdated = lastUpdated;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("{");
sb.append("\"accessToken\":\"")
.append(accessToken).append('\"');
sb.append(",\"lastUpdated\":")
.append(lastUpdated);
sb.append('}');
return sb.toString();
}
}

View File

@ -0,0 +1,77 @@
package ink.wgink.module.wechat.official.account.pojo;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: AttentionCancel
* @Description: 公众号事件
* @Author: wanggeng
* @Date: 2021/4/28 11:20 上午
* @Version: 1.0
*/
public class OfficialAccountEvent {
private String toUserName;
private String fromUserName;
private String createTime;
private String msgType;
private String event;
public String getToUserName() {
return toUserName == null ? "" : toUserName;
}
public void setToUserName(String toUserName) {
this.toUserName = toUserName;
}
public String getFromUserName() {
return fromUserName == null ? "" : fromUserName;
}
public void setFromUserName(String fromUserName) {
this.fromUserName = fromUserName;
}
public String getCreateTime() {
return createTime == null ? "" : createTime;
}
public void setCreateTime(String createTime) {
this.createTime = createTime;
}
public String getMsgType() {
return msgType == null ? "" : msgType;
}
public void setMsgType(String msgType) {
this.msgType = msgType;
}
public String getEvent() {
return event == null ? "" : event;
}
public void setEvent(String event) {
this.event = event;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("{");
sb.append("\"toUserName\":\"")
.append(toUserName).append('\"');
sb.append(",\"fromUserName\":\"")
.append(fromUserName).append('\"');
sb.append(",\"createTime\":\"")
.append(createTime).append('\"');
sb.append(",\"msgType\":\"")
.append(msgType).append('\"');
sb.append(",\"event\":\"")
.append(event).append('\"');
sb.append('}');
return sb.toString();
}
}

View File

@ -0,0 +1,76 @@
package ink.wgink.module.wechat.official.account.request;
import ink.wgink.module.wechat.enums.ErrorMsgEnum;
import ink.wgink.module.wechat.official.account.manager.OfficialAccountAccessTokenManager;
import ink.wgink.module.wechat.official.account.pojo.OfficialAccountAccessToken;
import ink.wgink.module.wechat.official.account.result.AccessTokenResult;
import ink.wgink.properties.wechat.official.account.OfficialAccountProperties;
import ink.wgink.util.request.AbstractRestTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.client.HttpClientErrorException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: AccessTokenRestTemplate
* @Description:
* @Author: wanggeng
* @Date: 2021/4/28 5:31 上午
* @Version: 1.0
*/
public class AccessTokenRestTemplate extends AbstractRestTemplate<AccessTokenResult, Map<String, Object>> {
private static final Logger LOG = LoggerFactory.getLogger(AccessTokenRestTemplate.class);
private OfficialAccountProperties officialAccountProperties;
public AccessTokenRestTemplate(OfficialAccountProperties officialAccountProperties) {
this.officialAccountProperties = officialAccountProperties;
}
@Override
public Map<String, Object> postBody() {
Map<String, Object> params = new HashMap<>(6);
params.put("grant_type", officialAccountProperties.getGrantType());
params.put("appid", officialAccountProperties.getAppId());
params.put("secret", officialAccountProperties.getAppSecret());
return params;
}
@Override
public Class<AccessTokenResult> successResultType() {
return AccessTokenResult.class;
}
@Override
public void success200(AccessTokenResult result) {
if (result.getErrcode() == ErrorMsgEnum.SUCCESS.getErrCode()) {
OfficialAccountAccessToken officialAccountAccessToken = new OfficialAccountAccessToken();
officialAccountAccessToken.setAccessToken(result.getAccess_token());
officialAccountAccessToken.setLastUpdated(System.currentTimeMillis());
OfficialAccountAccessTokenManager.getInstance().setAccessToken(officialAccountAccessToken);
return;
}
if (result.getErrcode() == ErrorMsgEnum.SYSTEM_BUSY.getErrCode()) {
LOG.error("系统繁忙3s后重试");
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
LOG.error(e.getMessage(), e);
}
this.post(officialAccountProperties.getAccessTokenUrl());
return;
}
LOG.error(ErrorMsgEnum.getErrMsg(result.getErrcode()));
}
@Override
public void error400(HttpClientErrorException error) {
LOG.error(error.getMessage(), error);
}
}

View File

@ -0,0 +1,35 @@
package ink.wgink.module.wechat.official.account.result;
import ink.wgink.module.wechat.result.BaseWechatResult;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: AccessTokenResult
* @Description:
* @Author: wanggeng
* @Date: 2021/4/28 6:00 上午
* @Version: 1.0
*/
public class AccessTokenResult extends BaseWechatResult {
private String access_token;
private Long expires_in;
public String getAccess_token() {
return access_token == null ? "" : access_token;
}
public void setAccess_token(String access_token) {
this.access_token = access_token;
}
public Long getExpires_in() {
return expires_in == null ? 0 : expires_in;
}
public void setExpires_in(Long expires_in) {
this.expires_in = expires_in;
}
}

View File

@ -0,0 +1,33 @@
package ink.wgink.module.wechat.result;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: BaseWechatResult
* @Description: 微信基础返回类
* @Author: wanggeng
* @Date: 2021/4/28 5:59 上午
* @Version: 1.0
*/
public class BaseWechatResult {
private Integer errcode;
private String errmsg;
public Integer getErrcode() {
return errcode == null ? 0 : errcode;
}
public void setErrcode(Integer errcode) {
this.errcode = errcode;
}
public String getErrmsg() {
return errmsg == null ? "" : errmsg;
}
public void setErrmsg(String errmsg) {
this.errmsg = errmsg;
}
}

View File

@ -0,0 +1,47 @@
package ink.wgink.module.wechat.startup;
import ink.wgink.module.wechat.official.account.manager.OfficialAccountAccessTokenManager;
import ink.wgink.module.wechat.official.account.pojo.OfficialAccountEvent;
import ink.wgink.properties.wechat.official.account.OfficialAccountProperties;
import ink.wgink.util.xml.XMLUtil;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.io.ByteArrayInputStream;
import java.io.StringReader;
import java.nio.charset.StandardCharsets;
import java.util.List;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: WechatStartUp
* @Description: 微信启动
* @Author: wanggeng
* @Date: 2021/4/28 6:40 上午
* @Version: 1.0
*/
@Component
public class WechatStartUp implements ApplicationRunner {
@Autowired
private OfficialAccountProperties officialAccountProperties;
@Override
public void run(ApplicationArguments args) throws Exception {
}
@Scheduled(cron = "0 0/5 * * * ? *")
public void refreshOfficialAccountAccessToken() {
OfficialAccountAccessTokenManager.getInstance().refreshAccessToken(officialAccountProperties);
}
}

View File

@ -30,6 +30,7 @@
<module>login-wechat</module> <module>login-wechat</module>
<module>basic-properties</module> <module>basic-properties</module>
<module>module-article</module> <module>module-article</module>
<module>module-wechat</module>
</modules> </modules>
<packaging>pom</packaging> <packaging>pom</packaging>