公众号绑定和关注事件
This commit is contained in:
parent
2b7d5f3121
commit
9d7b8407d9
@ -24,6 +24,7 @@ public class OfficialAccountProperties {
|
|||||||
private String appId;
|
private String appId;
|
||||||
private String appSecret;
|
private String appSecret;
|
||||||
private String grantType;
|
private String grantType;
|
||||||
|
private String configToken;
|
||||||
|
|
||||||
public Boolean getApiCrossOrigin() {
|
public Boolean getApiCrossOrigin() {
|
||||||
return apiCrossOrigin;
|
return apiCrossOrigin;
|
||||||
@ -80,4 +81,12 @@ public class OfficialAccountProperties {
|
|||||||
public void setGrantType(String grantType) {
|
public void setGrantType(String grantType) {
|
||||||
this.grantType = 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_40001(40001, "AppSecret错误或者AppSecret不属于这个公众号,请开发者确认AppSecret的正确性"),
|
||||||
ERROR_40002(40002, "请确保grant_type字段值为client_credential"),
|
ERROR_40002(40002, "请确保grant_type字段值为client_credential"),
|
||||||
ERROR_40164(40164, "调用接口的IP地址不在白名单中,请在接口IP白名单中进行设置。(小程序及小游戏调用不要求IP地址在白名单内。)"),
|
ERROR_40164(40164, "调用接口的IP地址不在白名单中,请在接口IP白名单中进行设置。(小程序及小游戏调用不要求IP地址在白名单内。)"),
|
||||||
|
ERROR_41002(41002, "appid为空"),
|
||||||
ERROR_89503(89503, "此IP调用需要管理员确认,请联系管理员"),
|
ERROR_89503(89503, "此IP调用需要管理员确认,请联系管理员"),
|
||||||
ERROR_89501(89501, "此IP正在等待管理员确认,请联系管理员"),
|
ERROR_89501(89501, "此IP正在等待管理员确认,请联系管理员"),
|
||||||
ERROR_89506(89506, "24小时内该IP被管理员拒绝调用两次,24小时内不可再使用该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.pojo.OfficialAccountAccessToken;
|
||||||
import ink.wgink.module.wechat.official.account.request.AccessTokenRestTemplate;
|
import ink.wgink.module.wechat.request.AccessTokenRestTemplate;
|
||||||
import ink.wgink.properties.wechat.official.account.OfficialAccountProperties;
|
import ink.wgink.properties.wechat.official.account.OfficialAccountProperties;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@ -43,7 +43,7 @@ public class OfficialAccountAccessTokenManager {
|
|||||||
}
|
}
|
||||||
LOG.debug("刷新公众号 AccessToken 开始");
|
LOG.debug("刷新公众号 AccessToken 开始");
|
||||||
AccessTokenRestTemplate accessTokenRestTemplate = new AccessTokenRestTemplate(officialAccountProperties);
|
AccessTokenRestTemplate accessTokenRestTemplate = new AccessTokenRestTemplate(officialAccountProperties);
|
||||||
accessTokenRestTemplate.post(officialAccountProperties.getAccessTokenUrl());
|
accessTokenRestTemplate.get(accessTokenRestTemplate.getAccessTokenUrl());
|
||||||
LOG.debug("accessToken: {}", this.officialAccountAccessToken);
|
LOG.debug("accessToken: {}", this.officialAccountAccessToken);
|
||||||
LOG.debug("刷新公众号 AccessToken 结束");
|
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
|
* 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.enums.ErrorMsgEnum;
|
||||||
import ink.wgink.module.wechat.official.account.manager.OfficialAccountAccessTokenManager;
|
import ink.wgink.module.wechat.manager.OfficialAccountAccessTokenManager;
|
||||||
import ink.wgink.module.wechat.official.account.pojo.OfficialAccountAccessToken;
|
import ink.wgink.module.wechat.pojo.OfficialAccountAccessToken;
|
||||||
import ink.wgink.module.wechat.official.account.result.AccessTokenResult;
|
import ink.wgink.module.wechat.result.AccessTokenResult;
|
||||||
import ink.wgink.properties.wechat.official.account.OfficialAccountProperties;
|
import ink.wgink.properties.wechat.official.account.OfficialAccountProperties;
|
||||||
import ink.wgink.util.request.AbstractRestTemplate;
|
import ink.wgink.util.request.AbstractRestTemplate;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.util.LinkedMultiValueMap;
|
||||||
|
import org.springframework.util.MultiValueMap;
|
||||||
import org.springframework.web.client.HttpClientErrorException;
|
import org.springframework.web.client.HttpClientErrorException;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -24,7 +26,7 @@ import java.util.concurrent.TimeUnit;
|
|||||||
* @Date: 2021/4/28 5:31 上午
|
* @Date: 2021/4/28 5:31 上午
|
||||||
* @Version: 1.0
|
* @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 static final Logger LOG = LoggerFactory.getLogger(AccessTokenRestTemplate.class);
|
||||||
private OfficialAccountProperties officialAccountProperties;
|
private OfficialAccountProperties officialAccountProperties;
|
||||||
|
|
||||||
@ -33,12 +35,12 @@ public class AccessTokenRestTemplate extends AbstractRestTemplate<AccessTokenRes
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, Object> postBody() {
|
public MultiValueMap postBody() {
|
||||||
Map<String, Object> params = new HashMap<>(6);
|
MultiValueMap multiValueMap = new LinkedMultiValueMap<>();
|
||||||
params.put("grant_type", officialAccountProperties.getGrantType());
|
multiValueMap.add("grant_type", officialAccountProperties.getGrantType());
|
||||||
params.put("appid", officialAccountProperties.getAppId());
|
multiValueMap.add("appid", officialAccountProperties.getAppId());
|
||||||
params.put("secret", officialAccountProperties.getAppSecret());
|
multiValueMap.add("secret", officialAccountProperties.getAppSecret());
|
||||||
return params;
|
return multiValueMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -62,7 +64,7 @@ public class AccessTokenRestTemplate extends AbstractRestTemplate<AccessTokenRes
|
|||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
LOG.error(e.getMessage(), e);
|
LOG.error(e.getMessage(), e);
|
||||||
}
|
}
|
||||||
this.post(officialAccountProperties.getAccessTokenUrl());
|
this.get(getAccessTokenUrl());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
LOG.error(ErrorMsgEnum.getErrMsg(result.getErrcode()));
|
LOG.error(ErrorMsgEnum.getErrMsg(result.getErrcode()));
|
||||||
@ -73,4 +75,17 @@ public class AccessTokenRestTemplate extends AbstractRestTemplate<AccessTokenRes
|
|||||||
LOG.error(error.getMessage(), error);
|
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;
|
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
|
* 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 上午
|
* @Date: 2021/4/28 11:20 上午
|
||||||
* @Version: 1.0
|
* @Version: 1.0
|
||||||
*/
|
*/
|
||||||
public class OfficialAccountEvent {
|
public class OfficialAccountEventResult {
|
||||||
|
|
||||||
private String toUserName;
|
private String toUserName;
|
||||||
private String fromUserName;
|
private String fromUserName;
|
||||||
private String createTime;
|
private String createTime;
|
||||||
private String msgType;
|
private String msgType;
|
||||||
private String event;
|
private String event;
|
||||||
|
private String eventKey;
|
||||||
|
|
||||||
public String getToUserName() {
|
public String getToUserName() {
|
||||||
return toUserName == null ? "" : toUserName;
|
return toUserName == null ? "" : toUserName;
|
||||||
@ -58,6 +59,14 @@ public class OfficialAccountEvent {
|
|||||||
this.event = event;
|
this.event = event;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getEventKey() {
|
||||||
|
return eventKey == null ? "" : eventKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEventKey(String eventKey) {
|
||||||
|
this.eventKey = eventKey;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
final StringBuilder sb = new StringBuilder("{");
|
final StringBuilder sb = new StringBuilder("{");
|
||||||
@ -71,6 +80,8 @@ public class OfficialAccountEvent {
|
|||||||
.append(msgType).append('\"');
|
.append(msgType).append('\"');
|
||||||
sb.append(",\"event\":\"")
|
sb.append(",\"event\":\"")
|
||||||
.append(event).append('\"');
|
.append(event).append('\"');
|
||||||
|
sb.append(",\"eventKey\":\"")
|
||||||
|
.append(eventKey).append('\"');
|
||||||
sb.append('}');
|
sb.append('}');
|
||||||
return sb.toString();
|
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;
|
package ink.wgink.module.wechat.startup;
|
||||||
|
|
||||||
import ink.wgink.module.wechat.official.account.manager.OfficialAccountAccessTokenManager;
|
import ink.wgink.module.wechat.manager.OfficialAccountAccessTokenManager;
|
||||||
import ink.wgink.module.wechat.official.account.pojo.OfficialAccountEvent;
|
|
||||||
import ink.wgink.properties.wechat.official.account.OfficialAccountProperties;
|
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.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.ApplicationArguments;
|
import org.springframework.boot.ApplicationArguments;
|
||||||
import org.springframework.boot.ApplicationRunner;
|
import org.springframework.boot.ApplicationRunner;
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.io.StringReader;
|
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When you feel like quitting. Think about why you started
|
* When you feel like quitting. Think about why you started
|
||||||
@ -37,9 +29,10 @@ public class WechatStartUp implements ApplicationRunner {
|
|||||||
@Override
|
@Override
|
||||||
public void run(ApplicationArguments args) throws Exception {
|
public void run(ApplicationArguments args) throws Exception {
|
||||||
|
|
||||||
|
new Thread(() -> refreshOfficialAccountAccessToken()).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Scheduled(cron = "0 0/5 * * * ? *")
|
@Scheduled(cron = "0 0/5 * * * ?")
|
||||||
public void refreshOfficialAccountAccessToken() {
|
public void refreshOfficialAccountAccessToken() {
|
||||||
OfficialAccountAccessTokenManager.getInstance().refreshAccessToken(officialAccountProperties);
|
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