公众号绑定和关注事件
This commit is contained in:
parent
2b7d5f3121
commit
9d7b8407d9
@ -24,6 +24,7 @@ public class OfficialAccountProperties {
|
||||
private String appId;
|
||||
private String appSecret;
|
||||
private String grantType;
|
||||
private String configToken;
|
||||
|
||||
public Boolean getApiCrossOrigin() {
|
||||
return apiCrossOrigin;
|
||||
@ -80,4 +81,12 @@ public class OfficialAccountProperties {
|
||||
public void setGrantType(String grantType) {
|
||||
this.grantType = grantType;
|
||||
}
|
||||
|
||||
public String getConfigToken() {
|
||||
return configToken == null ? "" : configToken;
|
||||
}
|
||||
|
||||
public void setConfigToken(String configToken) {
|
||||
this.configToken = configToken;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,113 @@
|
||||
package ink.wgink.module.wechat.controller.official.account;
|
||||
|
||||
import ink.wgink.common.base.DefaultBaseController;
|
||||
import ink.wgink.exceptions.ParamsException;
|
||||
import ink.wgink.interfaces.consts.ISystemConstant;
|
||||
import ink.wgink.module.wechat.enums.XmlEventTypeEnum;
|
||||
import ink.wgink.module.wechat.enums.XmlMsgTypeEnum;
|
||||
import ink.wgink.module.wechat.pojo.vos.official.account.OfficialAccountUserPO;
|
||||
import ink.wgink.module.wechat.result.OfficialAccountEventResult;
|
||||
import ink.wgink.module.wechat.service.official.account.IOfficialAccountCheckService;
|
||||
import ink.wgink.module.wechat.service.official.account.IOfficialAccountUserService;
|
||||
import ink.wgink.util.xml.XMLUtil;
|
||||
import io.swagger.annotations.Api;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.servlet.AsyncContext;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
* When you feel like quitting. Think about why you started
|
||||
* 当你想要放弃的时候,想想当初你为何开始
|
||||
*
|
||||
* @ClassName: OfficialAccountWechatController
|
||||
* @Description: 微信公众号
|
||||
* @Author: wanggeng
|
||||
* @Date: 2021/4/28 3:15 下午
|
||||
* @Version: 1.0
|
||||
*/
|
||||
@Api(tags = ISystemConstant.API_TAGS_WECHAT_PREFIX + "微信公众号")
|
||||
@RestController
|
||||
@RequestMapping(ISystemConstant.WECHAT_PREFIX + "/official/account")
|
||||
public class OfficialAccountWechatController extends DefaultBaseController {
|
||||
|
||||
@Autowired
|
||||
private IOfficialAccountCheckService officialAccountCheckService;
|
||||
@Autowired
|
||||
private IOfficialAccountUserService officialAccountUserService;
|
||||
|
||||
@RequestMapping("event")
|
||||
public void event(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
|
||||
// 处理认证
|
||||
if (StringUtils.equalsIgnoreCase(HttpMethod.GET.toString(), request.getMethod())) {
|
||||
officialAccountCheckService.checkSignature(request, response);
|
||||
return;
|
||||
}
|
||||
// 处理事件
|
||||
if (StringUtils.equalsIgnoreCase(HttpMethod.POST.toString(), request.getMethod())) {
|
||||
AsyncContext asyncContext = request.startAsync();
|
||||
CompletableFuture.runAsync(() -> {
|
||||
handleMsgType(asyncContext, request, response);
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理消息类型
|
||||
*
|
||||
* @param asyncContext
|
||||
* @param request
|
||||
* @param response
|
||||
*/
|
||||
private void handleMsgType(AsyncContext asyncContext, HttpServletRequest request, HttpServletResponse response) {
|
||||
OfficialAccountEventResult officialAccountEventResult = getEventResult(request);
|
||||
if (officialAccountEventResult == null) {
|
||||
throw new ParamsException("事件错误");
|
||||
}
|
||||
if (StringUtils.equalsIgnoreCase(XmlMsgTypeEnum.EVENT.getValue(), officialAccountEventResult.getMsgType())) {
|
||||
handleEvent(officialAccountEventResult, asyncContext, request, response);
|
||||
}
|
||||
}
|
||||
|
||||
// 处理事件
|
||||
private void handleEvent(OfficialAccountEventResult officialAccountEventResult, AsyncContext asyncContext, HttpServletRequest request, HttpServletResponse response) {
|
||||
if (StringUtils.equalsIgnoreCase(XmlEventTypeEnum.SUBSCRIBE.getType(), officialAccountEventResult.getEvent())) {
|
||||
OfficialAccountUserPO officialAccountUserPO = new OfficialAccountUserPO();
|
||||
officialAccountUserPO.setOpenId(officialAccountEventResult.getFromUserName());
|
||||
officialAccountUserService.save(officialAccountUserPO);
|
||||
} else if(StringUtils.equalsIgnoreCase(XmlEventTypeEnum.UNSUBSCRIBE.getType(), officialAccountEventResult.getEvent())) {
|
||||
officialAccountUserService.updateStatus(officialAccountEventResult.getFromUserName(), XmlEventTypeEnum.UNSUBSCRIBE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 事件结果
|
||||
*
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
private OfficialAccountEventResult getEventResult(HttpServletRequest request) {
|
||||
try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(request.getInputStream()))) {
|
||||
StringBuilder content = new StringBuilder();
|
||||
for (String line; (line = bufferedReader.readLine()) != null; ) {
|
||||
content.append(line);
|
||||
}
|
||||
return XMLUtil.xml2SampleBean(content.toString(), OfficialAccountEventResult.class);
|
||||
} catch (Exception e) {
|
||||
LOG.error(e.getMessage(), e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
package ink.wgink.module.wechat.dao.official.account;
|
||||
|
||||
import ink.wgink.exceptions.RemoveException;
|
||||
import ink.wgink.exceptions.SaveException;
|
||||
import ink.wgink.exceptions.SearchException;
|
||||
import ink.wgink.exceptions.UpdateException;
|
||||
import ink.wgink.module.wechat.pojo.dtos.official.account.OfficialAccountUserDTO;
|
||||
import ink.wgink.module.wechat.pojo.vos.official.account.OfficialAccountUserPO;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* When you feel like quitting. Think about why you started
|
||||
* 当你想要放弃的时候,想想当初你为何开始
|
||||
*
|
||||
* @ClassName: IAccountOfficialUserDao
|
||||
* @Description: 公众号用户
|
||||
* @Author: wanggeng
|
||||
* @Date: 2021/4/28 6:42 下午
|
||||
* @Version: 1.0
|
||||
*/
|
||||
@Repository
|
||||
public interface IOfficialAccountUserDao {
|
||||
|
||||
/**
|
||||
* 建表
|
||||
*
|
||||
* @throws UpdateException
|
||||
*/
|
||||
void createTable() throws UpdateException;
|
||||
|
||||
/**
|
||||
* 新增
|
||||
*
|
||||
* @param params
|
||||
* @throws SaveException
|
||||
*/
|
||||
void save(Map<String, Object> params) throws SaveException;
|
||||
|
||||
/**
|
||||
* 修改
|
||||
*
|
||||
* @param params
|
||||
* @throws UpdateException
|
||||
*/
|
||||
void update(Map<String, Object> params) throws UpdateException;
|
||||
|
||||
/**
|
||||
* 删除
|
||||
*
|
||||
* @param params
|
||||
* @throws RemoveException
|
||||
*/
|
||||
void remove(Map<String, Object> params) throws RemoveException;
|
||||
|
||||
/**
|
||||
* 详情
|
||||
*
|
||||
* @param params
|
||||
* @return
|
||||
* @throws SearchException
|
||||
*/
|
||||
OfficialAccountUserDTO get(Map<String, Object> params) throws SearchException;
|
||||
|
||||
/**
|
||||
* 详情
|
||||
*
|
||||
* @param params
|
||||
* @return
|
||||
* @throws SearchException
|
||||
*/
|
||||
OfficialAccountUserPO getPO(Map<String, Object> params) throws SearchException;
|
||||
|
||||
/**
|
||||
* 列表
|
||||
*
|
||||
* @param params
|
||||
* @return
|
||||
* @throws SearchException
|
||||
*/
|
||||
List<OfficialAccountUserDTO> list(Map<String, Object> params) throws SearchException;
|
||||
|
||||
/**
|
||||
* 列表
|
||||
*
|
||||
* @param params
|
||||
* @return
|
||||
* @throws SearchException
|
||||
*/
|
||||
List<OfficialAccountUserPO> listPO(Map<String, Object> params) throws SearchException;
|
||||
|
||||
}
|
@ -17,6 +17,7 @@ public enum ErrorMsgEnum {
|
||||
ERROR_40001(40001, "AppSecret错误或者AppSecret不属于这个公众号,请开发者确认AppSecret的正确性"),
|
||||
ERROR_40002(40002, "请确保grant_type字段值为client_credential"),
|
||||
ERROR_40164(40164, "调用接口的IP地址不在白名单中,请在接口IP白名单中进行设置。(小程序及小游戏调用不要求IP地址在白名单内。)"),
|
||||
ERROR_41002(41002, "appid为空"),
|
||||
ERROR_89503(89503, "此IP调用需要管理员确认,请联系管理员"),
|
||||
ERROR_89501(89501, "此IP正在等待管理员确认,请联系管理员"),
|
||||
ERROR_89506(89506, "24小时内该IP被管理员拒绝调用两次,24小时内不可再使用该IP调用"),
|
||||
|
@ -0,0 +1,34 @@
|
||||
package ink.wgink.module.wechat.enums;
|
||||
|
||||
/**
|
||||
* When you feel like quitting. Think about why you started
|
||||
* 当你想要放弃的时候,想想当初你为何开始
|
||||
*
|
||||
* @ClassName: EventTypeEnum
|
||||
* @Description: 事件类型
|
||||
* @Author: wanggeng
|
||||
* @Date: 2021/4/28 6:19 下午
|
||||
* @Version: 1.0
|
||||
*/
|
||||
public enum XmlEventTypeEnum {
|
||||
|
||||
SUBSCRIBE("subscribe", "订阅"),
|
||||
UNSUBSCRIBE("unsubscribe", "取消订阅");
|
||||
|
||||
|
||||
private String type;
|
||||
private String describe;
|
||||
|
||||
XmlEventTypeEnum(String type, String describe) {
|
||||
this.type = type;
|
||||
this.describe = describe;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type == null ? "" : type;
|
||||
}
|
||||
|
||||
public String getDescribe() {
|
||||
return describe == null ? "" : describe;
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package ink.wgink.module.wechat.enums;
|
||||
|
||||
/**
|
||||
* When you feel like quitting. Think about why you started
|
||||
* 当你想要放弃的时候,想想当初你为何开始
|
||||
*
|
||||
* @ClassName: XMLMsgTypeEnum
|
||||
* @Description: xml消息类型
|
||||
* @Author: wanggeng
|
||||
* @Date: 2021/4/28 6:20 下午
|
||||
* @Version: 1.0
|
||||
*/
|
||||
public enum XmlMsgTypeEnum {
|
||||
|
||||
EVENT("event");
|
||||
|
||||
private String value;
|
||||
|
||||
XmlMsgTypeEnum(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value == null ? "" : value;
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
package ink.wgink.module.wechat.official.account.manager;
|
||||
package ink.wgink.module.wechat.manager;
|
||||
|
||||
import ink.wgink.module.wechat.official.account.pojo.OfficialAccountAccessToken;
|
||||
import ink.wgink.module.wechat.official.account.request.AccessTokenRestTemplate;
|
||||
import ink.wgink.module.wechat.pojo.OfficialAccountAccessToken;
|
||||
import ink.wgink.module.wechat.request.AccessTokenRestTemplate;
|
||||
import ink.wgink.properties.wechat.official.account.OfficialAccountProperties;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@ -43,7 +43,7 @@ public class OfficialAccountAccessTokenManager {
|
||||
}
|
||||
LOG.debug("刷新公众号 AccessToken 开始");
|
||||
AccessTokenRestTemplate accessTokenRestTemplate = new AccessTokenRestTemplate(officialAccountProperties);
|
||||
accessTokenRestTemplate.post(officialAccountProperties.getAccessTokenUrl());
|
||||
accessTokenRestTemplate.get(accessTokenRestTemplate.getAccessTokenUrl());
|
||||
LOG.debug("accessToken: {}", this.officialAccountAccessToken);
|
||||
LOG.debug("刷新公众号 AccessToken 结束");
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package ink.wgink.module.wechat.official.account.pojo;
|
||||
package ink.wgink.module.wechat.pojo;
|
||||
|
||||
/**
|
||||
* When you feel like quitting. Think about why you started
|
@ -0,0 +1,14 @@
|
||||
package ink.wgink.module.wechat.pojo.dtos.official.account;
|
||||
|
||||
/**
|
||||
* When you feel like quitting. Think about why you started
|
||||
* 当你想要放弃的时候,想想当初你为何开始
|
||||
*
|
||||
* @ClassName: OfficialAccountUserDTO
|
||||
* @Description: 公众号用户
|
||||
* @Author: wanggeng
|
||||
* @Date: 2021/4/28 6:46 下午
|
||||
* @Version: 1.0
|
||||
*/
|
||||
public class OfficialAccountUserDTO {
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
package ink.wgink.module.wechat.pojo.pos.official.account;
|
||||
|
||||
/**
|
||||
* When you feel like quitting. Think about why you started
|
||||
* 当你想要放弃的时候,想想当初你为何开始
|
||||
*
|
||||
* @ClassName: OfficialAccountUserVO
|
||||
* @Description: 公众号用户
|
||||
* @Author: wanggeng
|
||||
* @Date: 2021/4/28 6:10 下午
|
||||
* @Version: 1.0
|
||||
*/
|
||||
public class OfficialAccountUserVO {
|
||||
|
||||
private String appId;
|
||||
private String openId;
|
||||
private String userId;
|
||||
private String userCode;
|
||||
private Integer isInitAccount;
|
||||
|
||||
public String getAppId() {
|
||||
return appId == null ? "" : appId;
|
||||
}
|
||||
|
||||
public void setAppId(String appId) {
|
||||
this.appId = appId;
|
||||
}
|
||||
|
||||
public String getOpenId() {
|
||||
return openId == null ? "" : openId;
|
||||
}
|
||||
|
||||
public void setOpenId(String openId) {
|
||||
this.openId = openId;
|
||||
}
|
||||
|
||||
public String getUserId() {
|
||||
return userId == null ? "" : userId;
|
||||
}
|
||||
|
||||
public void setUserId(String userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public String getUserCode() {
|
||||
return userCode == null ? "" : userCode;
|
||||
}
|
||||
|
||||
public void setUserCode(String userCode) {
|
||||
this.userCode = userCode;
|
||||
}
|
||||
|
||||
public Integer getIsInitAccount() {
|
||||
return isInitAccount == null ? 0 : isInitAccount;
|
||||
}
|
||||
|
||||
public void setIsInitAccount(Integer isInitAccount) {
|
||||
this.isInitAccount = isInitAccount;
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
package ink.wgink.module.wechat.pojo.vos.official.account;
|
||||
|
||||
/**
|
||||
* When you feel like quitting. Think about why you started
|
||||
* 当你想要放弃的时候,想想当初你为何开始
|
||||
*
|
||||
* @ClassName: OfficialAccountUserPO
|
||||
* @Description: 公众号用户
|
||||
* @Author: wanggeng
|
||||
* @Date: 2021/4/28 6:13 下午
|
||||
* @Version: 1.0
|
||||
*/
|
||||
public class OfficialAccountUserPO {
|
||||
|
||||
private String appId;
|
||||
private String openId;
|
||||
private String userId;
|
||||
private String userCode;
|
||||
private Integer isInitAccount;
|
||||
private String gmtCreate;
|
||||
|
||||
public String getAppId() {
|
||||
return appId == null ? "" : appId;
|
||||
}
|
||||
|
||||
public void setAppId(String appId) {
|
||||
this.appId = appId;
|
||||
}
|
||||
|
||||
public String getOpenId() {
|
||||
return openId == null ? "" : openId;
|
||||
}
|
||||
|
||||
public void setOpenId(String openId) {
|
||||
this.openId = openId;
|
||||
}
|
||||
|
||||
public String getUserId() {
|
||||
return userId == null ? "" : userId;
|
||||
}
|
||||
|
||||
public void setUserId(String userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public String getUserCode() {
|
||||
return userCode == null ? "" : userCode;
|
||||
}
|
||||
|
||||
public void setUserCode(String userCode) {
|
||||
this.userCode = userCode;
|
||||
}
|
||||
|
||||
public Integer getIsInitAccount() {
|
||||
return isInitAccount == null ? 0 : isInitAccount;
|
||||
}
|
||||
|
||||
public void setIsInitAccount(Integer isInitAccount) {
|
||||
this.isInitAccount = isInitAccount;
|
||||
}
|
||||
|
||||
public String getGmtCreate() {
|
||||
return gmtCreate == null ? "" : gmtCreate;
|
||||
}
|
||||
|
||||
public void setGmtCreate(String gmtCreate) {
|
||||
this.gmtCreate = gmtCreate;
|
||||
}
|
||||
}
|
@ -1,13 +1,15 @@
|
||||
package ink.wgink.module.wechat.official.account.request;
|
||||
package ink.wgink.module.wechat.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.module.wechat.manager.OfficialAccountAccessTokenManager;
|
||||
import ink.wgink.module.wechat.pojo.OfficialAccountAccessToken;
|
||||
import ink.wgink.module.wechat.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.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.client.HttpClientErrorException;
|
||||
|
||||
import java.util.HashMap;
|
||||
@ -24,7 +26,7 @@ import java.util.concurrent.TimeUnit;
|
||||
* @Date: 2021/4/28 5:31 上午
|
||||
* @Version: 1.0
|
||||
*/
|
||||
public class AccessTokenRestTemplate extends AbstractRestTemplate<AccessTokenResult, Map<String, Object>> {
|
||||
public class AccessTokenRestTemplate extends AbstractRestTemplate<AccessTokenResult, MultiValueMap> {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AccessTokenRestTemplate.class);
|
||||
private OfficialAccountProperties officialAccountProperties;
|
||||
|
||||
@ -33,12 +35,12 @@ public class AccessTokenRestTemplate extends AbstractRestTemplate<AccessTokenRes
|
||||
}
|
||||
|
||||
@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;
|
||||
public MultiValueMap postBody() {
|
||||
MultiValueMap multiValueMap = new LinkedMultiValueMap<>();
|
||||
multiValueMap.add("grant_type", officialAccountProperties.getGrantType());
|
||||
multiValueMap.add("appid", officialAccountProperties.getAppId());
|
||||
multiValueMap.add("secret", officialAccountProperties.getAppSecret());
|
||||
return multiValueMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -62,7 +64,7 @@ public class AccessTokenRestTemplate extends AbstractRestTemplate<AccessTokenRes
|
||||
} catch (InterruptedException e) {
|
||||
LOG.error(e.getMessage(), e);
|
||||
}
|
||||
this.post(officialAccountProperties.getAccessTokenUrl());
|
||||
this.get(getAccessTokenUrl());
|
||||
return;
|
||||
}
|
||||
LOG.error(ErrorMsgEnum.getErrMsg(result.getErrcode()));
|
||||
@ -73,4 +75,17 @@ public class AccessTokenRestTemplate extends AbstractRestTemplate<AccessTokenRes
|
||||
LOG.error(error.getMessage(), error);
|
||||
}
|
||||
|
||||
/**
|
||||
* access_token路径
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getAccessTokenUrl() {
|
||||
return String.format("%s?grant_type=%s&appid=%s&secret=%s",
|
||||
officialAccountProperties.getAccessTokenUrl(),
|
||||
officialAccountProperties.getGrantType(),
|
||||
officialAccountProperties.getAppId(),
|
||||
officialAccountProperties.getAppSecret());
|
||||
}
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package ink.wgink.module.wechat.official.account.result;
|
||||
package ink.wgink.module.wechat.result;
|
||||
|
||||
import ink.wgink.module.wechat.result.BaseWechatResult;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package ink.wgink.module.wechat.official.account.pojo;
|
||||
package ink.wgink.module.wechat.result;
|
||||
|
||||
/**
|
||||
* When you feel like quitting. Think about why you started
|
||||
@ -10,13 +10,14 @@ package ink.wgink.module.wechat.official.account.pojo;
|
||||
* @Date: 2021/4/28 11:20 上午
|
||||
* @Version: 1.0
|
||||
*/
|
||||
public class OfficialAccountEvent {
|
||||
public class OfficialAccountEventResult {
|
||||
|
||||
private String toUserName;
|
||||
private String fromUserName;
|
||||
private String createTime;
|
||||
private String msgType;
|
||||
private String event;
|
||||
private String eventKey;
|
||||
|
||||
public String getToUserName() {
|
||||
return toUserName == null ? "" : toUserName;
|
||||
@ -58,6 +59,14 @@ public class OfficialAccountEvent {
|
||||
this.event = event;
|
||||
}
|
||||
|
||||
public String getEventKey() {
|
||||
return eventKey == null ? "" : eventKey;
|
||||
}
|
||||
|
||||
public void setEventKey(String eventKey) {
|
||||
this.eventKey = eventKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder("{");
|
||||
@ -71,6 +80,8 @@ public class OfficialAccountEvent {
|
||||
.append(msgType).append('\"');
|
||||
sb.append(",\"event\":\"")
|
||||
.append(event).append('\"');
|
||||
sb.append(",\"eventKey\":\"")
|
||||
.append(eventKey).append('\"');
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package ink.wgink.module.wechat.service.official.account;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* When you feel like quitting. Think about why you started
|
||||
* 当你想要放弃的时候,想想当初你为何开始
|
||||
*
|
||||
* @ClassName: IOfficialAccountBindService
|
||||
* @Description: 公众号绑定
|
||||
* @Author: wanggeng
|
||||
* @Date: 2021/4/28 3:19 下午
|
||||
* @Version: 1.0
|
||||
*/
|
||||
public interface IOfficialAccountCheckService {
|
||||
/**
|
||||
* 校验签名
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
*/
|
||||
void checkSignature(HttpServletRequest request, HttpServletResponse response) throws IOException;
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package ink.wgink.module.wechat.service.official.account;
|
||||
|
||||
import ink.wgink.module.wechat.enums.XmlEventTypeEnum;
|
||||
import ink.wgink.module.wechat.pojo.vos.official.account.OfficialAccountUserPO;
|
||||
|
||||
/**
|
||||
* When you feel like quitting. Think about why you started
|
||||
* 当你想要放弃的时候,想想当初你为何开始
|
||||
*
|
||||
* @ClassName: IOfficialAccountUserService
|
||||
* @Description: 公众号用户
|
||||
* @Author: wanggeng
|
||||
* @Date: 2021/4/28 6:15 下午
|
||||
* @Version: 1.0
|
||||
*/
|
||||
public interface IOfficialAccountUserService {
|
||||
|
||||
/**
|
||||
* 新增用户
|
||||
*
|
||||
* @param officialAccountUserPO
|
||||
*/
|
||||
void save(OfficialAccountUserPO officialAccountUserPO);
|
||||
|
||||
/**
|
||||
* 修改状态
|
||||
*
|
||||
* @param fromUserName
|
||||
* @param unsubscribe
|
||||
*/
|
||||
void updateStatus(String fromUserName, XmlEventTypeEnum unsubscribe);
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
package ink.wgink.module.wechat.service.official.account.impl;
|
||||
|
||||
import ink.wgink.common.base.DefaultBaseService;
|
||||
import ink.wgink.exceptions.ParamsException;
|
||||
import ink.wgink.module.wechat.service.official.account.IOfficialAccountCheckService;
|
||||
import ink.wgink.properties.wechat.official.account.OfficialAccountProperties;
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* When you feel like quitting. Think about why you started
|
||||
* 当你想要放弃的时候,想想当初你为何开始
|
||||
*
|
||||
* @ClassName: OfficialAccountBindServiceImpl
|
||||
* @Description: 公众号绑定
|
||||
* @Author: wanggeng
|
||||
* @Date: 2021/4/28 3:20 下午
|
||||
* @Version: 1.0
|
||||
*/
|
||||
@Service
|
||||
public class OfficialAccountCheckServiceImpl extends DefaultBaseService implements IOfficialAccountCheckService {
|
||||
|
||||
@Autowired
|
||||
private OfficialAccountProperties officialAccountProperties;
|
||||
|
||||
@Override
|
||||
public void checkSignature(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
String signatureParameter = request.getParameter("signature");
|
||||
String timestampParameter = request.getParameter("timestamp");
|
||||
String nonceParameter = request.getParameter("nonce");
|
||||
String echostrParameter = request.getParameter("echostr");
|
||||
boolean isWechatConfig = !org.springframework.util.StringUtils.isEmpty(signatureParameter)
|
||||
&& !org.springframework.util.StringUtils.isEmpty(timestampParameter)
|
||||
&& !org.springframework.util.StringUtils.isEmpty(nonceParameter)
|
||||
&& !StringUtils.isEmpty(echostrParameter);
|
||||
if (!isWechatConfig) {
|
||||
throw new ParamsException("参数缺失");
|
||||
}
|
||||
if (!isWechatOfficialAccountConfigRequest(signatureParameter, timestampParameter, nonceParameter, echostrParameter)) {
|
||||
throw new ParamsException("非公众号账号配置请求");
|
||||
}
|
||||
PrintWriter writer = response.getWriter();
|
||||
writer.write(echostrParameter);
|
||||
writer.flush();
|
||||
writer.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param signature
|
||||
* @param timestamp
|
||||
* @param nonce
|
||||
* @param echostr
|
||||
* @return
|
||||
*/
|
||||
private boolean isWechatOfficialAccountConfigRequest(String signature, String timestamp, String nonce, String echostr) {
|
||||
List<String> sortList = new ArrayList<>();
|
||||
sortList.add(officialAccountProperties.getConfigToken());
|
||||
sortList.add(timestamp);
|
||||
sortList.add(nonce);
|
||||
Collections.sort(sortList);
|
||||
StringBuilder newSignature = new StringBuilder();
|
||||
sortList.forEach(str -> {
|
||||
newSignature.append(str);
|
||||
});
|
||||
|
||||
if (!StringUtils.equals(signature, DigestUtils.sha1Hex(newSignature.toString()))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package ink.wgink.module.wechat.service.official.account.impl;
|
||||
|
||||
import ink.wgink.common.base.DefaultBaseService;
|
||||
import ink.wgink.module.wechat.dao.official.account.IOfficialAccountUserDao;
|
||||
import ink.wgink.module.wechat.enums.XmlEventTypeEnum;
|
||||
import ink.wgink.module.wechat.pojo.vos.official.account.OfficialAccountUserPO;
|
||||
import ink.wgink.module.wechat.service.official.account.IOfficialAccountUserService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* When you feel like quitting. Think about why you started
|
||||
* 当你想要放弃的时候,想想当初你为何开始
|
||||
*
|
||||
* @ClassName: OfficialAccountUserServiceImpl
|
||||
* @Description: 公众号用户
|
||||
* @Author: wanggeng
|
||||
* @Date: 2021/4/28 6:15 下午
|
||||
* @Version: 1.0
|
||||
*/
|
||||
@Service
|
||||
public class OfficialAccountUserServiceImpl extends DefaultBaseService implements IOfficialAccountUserService {
|
||||
|
||||
@Autowired
|
||||
private IOfficialAccountUserDao officialAccountUserDao;
|
||||
|
||||
@Override
|
||||
public void save(OfficialAccountUserPO officialAccountUserPO) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateStatus(String fromUserName, XmlEventTypeEnum unsubscribe) {
|
||||
|
||||
}
|
||||
}
|
@ -1,23 +1,15 @@
|
||||
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.module.wechat.manager.OfficialAccountAccessTokenManager;
|
||||
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;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
|
||||
/**
|
||||
* When you feel like quitting. Think about why you started
|
||||
@ -37,9 +29,10 @@ public class WechatStartUp implements ApplicationRunner {
|
||||
@Override
|
||||
public void run(ApplicationArguments args) throws Exception {
|
||||
|
||||
new Thread(() -> refreshOfficialAccountAccessToken()).start();
|
||||
}
|
||||
|
||||
@Scheduled(cron = "0 0/5 * * * ? *")
|
||||
@Scheduled(cron = "0 0/5 * * * ?")
|
||||
public void refreshOfficialAccountAccessToken() {
|
||||
OfficialAccountAccessTokenManager.getInstance().refreshAccessToken(officialAccountProperties);
|
||||
}
|
||||
|
@ -0,0 +1,75 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="ink.wgink.login.wechat.dao.user.IMiniAppUserDao">
|
||||
|
||||
<cache flushInterval="3600000"/>
|
||||
|
||||
<resultMap id="miniAppUserPO" type="ink.wgink.login.wechat.pojo.pos.user.MiniAppUserPO">
|
||||
<result column="app_id" property="appId"/>
|
||||
<result column="open_id" property="openId"/>
|
||||
<result column="user_id" property="userId"/>
|
||||
<result column="is_init_account" property="isInitAccount"/>
|
||||
<result column="gmt_create" property="gmtCreate"/>
|
||||
</resultMap>
|
||||
|
||||
<!-- 建表 -->
|
||||
<update id="createTable">
|
||||
CREATE TABLE IF NOT EXISTS `wechat_mini_app_user` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`app_id` varchar(255) DEFAULT NULL COMMENT 'appid',
|
||||
`open_id` varchar(255) DEFAULT NULL COMMENT 'openid',
|
||||
`user_id` varchar(255) DEFAULT NULL COMMENT '用户ID',
|
||||
`is_init_account` int(1) DEFAULT '0' COMMENT '是否初始化账户',
|
||||
`gmt_create` datetime DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `app_id` (`app_id`) USING BTREE,
|
||||
KEY `open_id` (`open_id`) USING BTREE,
|
||||
KEY `user_id` (`user_id`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='小程序用户';
|
||||
</update>
|
||||
|
||||
<!-- 保存 -->
|
||||
<insert id="save" parameterType="map">
|
||||
INSERT INTO wechat_mini_app_user(
|
||||
app_id,
|
||||
open_id,
|
||||
user_id,
|
||||
is_init_account,
|
||||
gmt_create
|
||||
) VALUES(
|
||||
#{appId},
|
||||
#{openId},
|
||||
#{userId},
|
||||
#{isInitAccount},
|
||||
#{gmtCreate}
|
||||
)
|
||||
</insert>
|
||||
|
||||
<!-- 详情 -->
|
||||
<select id="getPO" parameterType="map" resultMap="miniAppUserPO" useCache="true">
|
||||
SELECT
|
||||
app_id,
|
||||
open_id,
|
||||
user_id,
|
||||
is_init_account,
|
||||
gmt_create
|
||||
FROM
|
||||
wechat_mini_app_user
|
||||
<where>
|
||||
<if test="appId != null and appId != ''">
|
||||
app_id = #{appId}
|
||||
</if>
|
||||
<if test="openId != '' and openId != ''">
|
||||
AND
|
||||
open_id = #{openId}
|
||||
</if>
|
||||
<if test="userId != null and userId != ''">
|
||||
AND
|
||||
user_id = #{userId}
|
||||
</if>
|
||||
</where>
|
||||
</select>
|
||||
|
||||
|
||||
|
||||
</mapper>
|
Loading…
Reference in New Issue
Block a user