refactor: 添加微信公众号消息通知模块

This commit is contained in:
椰子 2021-07-05 17:43:42 +08:00
parent 9e22765147
commit a62daf4ee0
10 changed files with 436 additions and 40 deletions

View File

@ -1,5 +1,4 @@
package com.cicdi.notify.wechat; package com.cicdi.notify.wechat.corp;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
@ -8,6 +7,7 @@ import com.cicdi.notify.DefaultNotifyType;
import com.cicdi.notify.NotifyType; import com.cicdi.notify.NotifyType;
import com.cicdi.notify.Provider; import com.cicdi.notify.Provider;
import com.cicdi.notify.template.TemplateManager; import com.cicdi.notify.template.TemplateManager;
import com.cicdi.notify.wechat.WechatProvider;
import org.apache.http.NameValuePair; import org.apache.http.NameValuePair;
import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpGet;
@ -25,7 +25,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
public class WeixinCorpNotifier extends AbstractNotifier<WechatMessageTemplate> { public class WechatCorpNotifier extends AbstractNotifier<WechatCorpTemplate> {
private String accessToken; private String accessToken;
@ -41,18 +41,17 @@ public class WeixinCorpNotifier extends AbstractNotifier<WechatMessageTemplate>
private final String notifierId; private final String notifierId;
@Override public WechatCorpNotifier(String id, WechatCorpProperties properties, TemplateManager templateManager) {
public String getNotifierId() {
return notifierId;
}
public WeixinCorpNotifier(String id, WechatCorpProperties properties, TemplateManager templateManager) {
super(templateManager); super(templateManager);
this.properties = properties; this.properties = properties;
this.notifierId = id; this.notifierId = id;
} }
@Override
public String getNotifierId() {
return notifierId;
}
@Override @Override
public NotifyType getType() { public NotifyType getType() {
return DefaultNotifyType.wechat; return DefaultNotifyType.wechat;
@ -64,7 +63,7 @@ public class WeixinCorpNotifier extends AbstractNotifier<WechatMessageTemplate>
} }
@Override @Override
public void send(WechatMessageTemplate template, Map<String, Object> context) { public void send(WechatCorpTemplate template, Map<String, Object> context) {
CloseableHttpClient httpClient = HttpClientBuilder.create().build(); CloseableHttpClient httpClient = HttpClientBuilder.create().build();
HttpPost httpPost = new HttpPost(notifyApi + "?access_token=" + getToken()); HttpPost httpPost = new HttpPost(notifyApi + "?access_token=" + getToken());
httpPost.setHeader("Content-Type", "application/json;charset=utf8"); httpPost.setHeader("Content-Type", "application/json;charset=utf8");

View File

@ -1,18 +1,20 @@
package com.cicdi.notify.wechat; package com.cicdi.notify.wechat.corp;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.cicdi.notify.*; import com.cicdi.notify.*;
import com.cicdi.notify.template.Template;
import com.cicdi.notify.template.TemplateManager; import com.cicdi.notify.template.TemplateManager;
import com.cicdi.notify.template.TemplateProperties; import com.cicdi.notify.template.TemplateProperties;
import com.cicdi.notify.template.TemplateProvider; import com.cicdi.notify.template.TemplateProvider;
import com.cicdi.notify.wechat.WechatProvider;
import java.util.Map; import java.util.Map;
public class WechatNotifierProvider implements NotifierProvider, TemplateProvider { public class WechatCorpNotifierProvider implements NotifierProvider, TemplateProvider {
private final TemplateManager templateManager; private final TemplateManager templateManager;
public WechatNotifierProvider(TemplateManager templateManager) { public WechatCorpNotifierProvider(TemplateManager templateManager) {
this.templateManager = templateManager; this.templateManager = templateManager;
} }
@ -38,21 +40,17 @@ public class WechatNotifierProvider implements NotifierProvider, TemplateProvide
} }
@Override @Override
public WechatMessageTemplate createTemplate(TemplateProperties properties) { public Template createTemplate(TemplateProperties properties) {
return JSON.parseObject(properties.getTemplate(), WechatMessageTemplate.class); return JSON.parseObject(properties.getTemplate(), WechatCorpTemplate.class);
// return Mono.fromSupplier(() -> ValidatorUtils.tryValidate(JSON.parseObject(properties.getTemplate(), org.jetlinks.community.notify.wechat.WechatMessageTemplate.class)));
} }
@Override @Override
public WeixinCorpNotifier createNotifier(NotifierProperties properties) { public WechatCorpNotifier createNotifier(NotifierProperties properties) {
// WechatCorpProperties wechatCorpProperties = FastBeanCopier.copy(properties.getConfiguration(), new WechatCorpProperties());
Map<String, Object> config = properties.getConfiguration(); Map<String, Object> config = properties.getConfiguration();
WechatCorpProperties wechatCorpProperties = new WechatCorpProperties(); WechatCorpProperties wechatCorpProperties = new WechatCorpProperties();
wechatCorpProperties.setCorpId((String) config.get("corpId")); wechatCorpProperties.setCorpId((String) config.get("corpId"));
wechatCorpProperties.setCorpSecret((String) config.get("corpSecret")); wechatCorpProperties.setCorpSecret((String) config.get("corpSecret"));
return new WeixinCorpNotifier(properties.getId(), wechatCorpProperties, templateManager); return new WechatCorpNotifier(properties.getId(), wechatCorpProperties, templateManager);
// return Mono.just(new WeixinCorpNotifier(properties.getId(), client, ValidatorUtils.tryValidate(wechatCorpProperties), templateManager));
} }
// @Override // @Override

View File

@ -1,4 +1,4 @@
package com.cicdi.notify.wechat; package com.cicdi.notify.wechat.corp;
public class WechatCorpProperties { public class WechatCorpProperties {

View File

@ -1,5 +1,4 @@
package com.cicdi.notify.wechat; package com.cicdi.notify.wechat.corp;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.cicdi.notify.template.Template; import com.cicdi.notify.template.Template;
@ -8,7 +7,7 @@ import org.apache.commons.lang.StringUtils;
import java.util.Collections; import java.util.Collections;
import java.util.Map; import java.util.Map;
public class WechatMessageTemplate implements Template { public class WechatCorpTemplate implements Template {
/** /**
* 应用ID * 应用ID
@ -67,8 +66,6 @@ public class WechatMessageTemplate implements Template {
JSONObject json = new JSONObject(); JSONObject json = new JSONObject();
json.put("agentid", getAgentId()); json.put("agentid", getAgentId());
json.put("msgtype", "text"); json.put("msgtype", "text");
// TODO
// json.put("text",Collections.singletonMap("content",ExpressionUtils.analytical(message, context.getAllValues(), "spel")));
json.put("text", Collections.singletonMap("content", message)); json.put("text", Collections.singletonMap("content", message));
if (StringUtils.isNotBlank(toUser)) { if (StringUtils.isNotBlank(toUser)) {
@ -86,7 +83,6 @@ public class WechatMessageTemplate implements Template {
return toUser; return toUser;
} }
return toUser; return toUser;
// return ExpressionUtils.analytical(toUser, context.getAllValues(), "spel");
} }
public String createDepartmentIdList(Map<String, Object> context) { public String createDepartmentIdList(Map<String, Object> context) {
@ -94,13 +90,11 @@ public class WechatMessageTemplate implements Template {
return toParty; return toParty;
} }
return toParty; return toParty;
// return ExpressionUtils.analytical(toParty, context.getAllValues(), "spel");
} }
public String createMessage(Map<String, Object> context) { public String createMessage(Map<String, Object> context) {
JSONObject json = new JSONObject(); JSONObject json = new JSONObject();
json.put("content", message); json.put("content", message);
// json.put("content", ExpressionUtils.analytical(message, context.getAllValues(), "spel"));
return json.toJSONString(); return json.toJSONString();
} }

View File

@ -0,0 +1,150 @@
package com.cicdi.notify.wechat.subscription;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.support.hsf.HSFJSONUtils;
import com.cicdi.notify.*;
import com.cicdi.notify.template.TemplateManager;
import com.cicdi.notify.wechat.WechatProvider;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.time.Duration;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
/**
* 微信公众号消息通知器
*
* @author xueye
*/
public class WechatSubscriptionNotifier extends AbstractNotifier<WechatSubscriptionTemplate> {
/**
* 通知器配置信息
*/
private final NotifierProperties properties;
/**
* 全局唯一接口调用凭证
*/
private final AtomicReference<String> accessToken = new AtomicReference<>();
/**
* 获取凭证的Api
*/
private static final String tokenApi = "https://api.weixin.qq.com/cgi-bin/token";
/**
* 发送消息通知的Api
*/
private static final String notifyApi = " https://api.weixin.qq.com/cgi-bin/message/template/send";
/**
* 凭证有效时间
*/
private static final long tokenTimeOut = Duration.ofSeconds(7000).toMillis();
/**
* 凭据刷新时间
* <p>一般接口对凭证的获取会有次数限制记录上一次获取凭证的时间每次发送通知的时候配合凭证有效时间来判断是否重新获取</p>
*/
private long refreshTokenTime;
private final CloseableHttpClient httpClient;
public WechatSubscriptionNotifier(NotifierProperties properties, TemplateManager templateManager) {
super(templateManager);
this.properties = properties;
this.httpClient = HttpClientBuilder.create().build();
}
@Override
public String getNotifierId() {
return properties.getId();
}
@Override
public NotifyType getType() {
return DefaultNotifyType.wechat;
}
@Override
public Provider getProvider() {
// return WechatProvider.subscription;
return null;
}
@Override
public void send(WechatSubscriptionTemplate template, Map<String, Object> context) {
try {
URI sendMessageURI = new URIBuilder(notifyApi)
.addParameter("access_token", getToken())
.build();
HttpPost httpPost = new HttpPost(sendMessageURI);
httpPost.setHeader("Content-Type", "application/json;charset=utf8");
StringEntity requestBody = new StringEntity(template.createJsonRequest());
httpPost.setEntity(requestBody);
CloseableHttpResponse response = httpClient.execute(httpPost);
JSONObject responseJson = JSON.parseObject(EntityUtils.toString(response.getEntity()));
if (!"0".equals(responseJson.get("errcode"))) {
throw new RuntimeException(responseJson.get("errmsg").toString());
}
} catch (URISyntaxException | IOException e) {
e.printStackTrace();
}
}
@Override
public void close() {
accessToken.set(null);
refreshTokenTime = 0;
try {
httpClient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private String getToken() {
if (System.currentTimeMillis() - refreshTokenTime > tokenTimeOut || accessToken.get() == null) {
refreshToken();
}
return accessToken.get();
}
/**
* 刷新接口访问凭证
*/
private void refreshToken() {
WechatSubscriptionProperties config = new JSONObject(properties.getConfiguration()).toJavaObject(WechatSubscriptionProperties.class);
try {
URI getTokenURI = new URIBuilder(tokenApi)
.addParameter("grant_type", config.getGrantType())
.addParameter("appid", config.getAppId())
.addParameter("secret", config.getSecret())
.build();
HttpGet httpGet = new HttpGet(getTokenURI);
CloseableHttpResponse response = httpClient.execute(httpGet);
String responseString = EntityUtils.toString(response.getEntity());
JSONObject responseJson = JSON.parseObject(responseString);
if (responseJson.containsKey("access_token")) {
accessToken.set(responseJson.get("access_token").toString());
} else if (responseJson.containsKey("errcode")) {
throw new RuntimeException(responseJson.get("errmsg").toString());
}
} catch (URISyntaxException | IOException e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,35 @@
package com.cicdi.notify.wechat.subscription;
import com.alibaba.fastjson.JSON;
import com.cicdi.notify.*;
import com.cicdi.notify.template.Template;
import com.cicdi.notify.template.TemplateProperties;
import com.cicdi.notify.template.TemplateProvider;
import com.cicdi.notify.wechat.WechatProvider;
/**
* 微信公众号通知器提供商
*
* @author xueye
*/
public class WechatSubscriptionNotifierProvider implements NotifierProvider, TemplateProvider {
@Override
public NotifyType getType() {
return DefaultNotifyType.wechat;
}
@Override
public Provider getProvider() {
return WechatProvider.corpMessage;
}
@Override
public Template createTemplate(TemplateProperties properties) {
return JSON.parseObject(String.valueOf(properties), WechatSubscriptionTemplate.class);
}
@Override
public Notifier<? extends Template> createNotifier(NotifierProperties properties) {
return null;
}
}

View File

@ -0,0 +1,50 @@
package com.cicdi.notify.wechat.subscription;
import com.cicdi.notify.NotifierProperties;
/**
* 微信公众号通知器配置信息
*
* @author xueye
*/
public class WechatSubscriptionProperties extends NotifierProperties {
/**
* 获取access_token填写client_credential
*/
private String grantType;
/**
* 第三方用户唯一凭证
*/
private String appId;
/**
* 第三方用户唯一凭证密钥即appsecret
*/
private String secret;
public String getGrantType() {
return grantType;
}
public void setGrantType(String grantType) {
this.grantType = grantType;
}
public String getAppId() {
return appId;
}
public void setAppId(String appId) {
this.appId = appId;
}
public String getSecret() {
return secret;
}
public void setSecret(String secret) {
this.secret = secret;
}
}

View File

@ -0,0 +1,100 @@
package com.cicdi.notify.wechat.subscription;
import com.alibaba.fastjson.JSONObject;
import com.cicdi.notify.template.Template;
import java.util.Map;
/**
* 微信公众号消息模板
*
* @author xueye
*/
public class WechatSubscriptionTemplate implements Template {
/**
* 接收者openid
*/
private String toUser;
/**
* 模板ID
*/
private String templateId;
/**
* 模板跳转链接海外帐号没有跳转能力
*/
private String url;
/**
* 跳小程序所需数据不需跳小程序可不用传该数据
* <ul>
* <li>appid所需跳转到的小程序appid该小程序appid必须与发模板消息的公众号是绑定关联关系暂不支持小游戏</li>
* <li>pagepath所需跳转到小程序的具体页面路径支持带参数,示例index?foo=bar要求该小程序已发布暂不支持小游戏</li>
* </ul>
*/
private Map<String, Object> miniProgram;
/**
* 模板数据
* <ul>
* <li>keyword模板数据名称</li>
* <ul>
* <li>value模板数据值</li>
* <li>color模板内容字体颜色不填默认为黑色</li>
* </ul>
* </ul>
*/
private Map<String, Object> data;
public String createJsonRequest() {
JSONObject json = new JSONObject();
json.put("touser", toUser);
json.put("template_id", templateId);
json.put("url", url);
json.put("miniprogram", miniProgram);
json.put("data", data);
return json.toJSONString();
}
public String getToUser() {
return toUser;
}
public void setToUser(String toUser) {
this.toUser = toUser;
}
public String getTemplateId() {
return templateId;
}
public void setTemplateId(String templateId) {
this.templateId = templateId;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public Map<String, Object> getMiniProgram() {
return miniProgram;
}
public void setMiniProgram(Map<String, Object> miniProgram) {
this.miniProgram = miniProgram;
}
public Map<String, Object> getData() {
return data;
}
public void setData(Map<String, Object> data) {
this.data = data;
}
}

View File

@ -0,0 +1,68 @@
package com.cicdi.notify.wechat;
import com.alibaba.fastjson.JSONObject;
import com.cicdi.notify.*;
import com.cicdi.notify.template.AbstractTemplateManager;
import com.cicdi.notify.template.Template;
import com.cicdi.notify.template.TemplateManager;
import com.cicdi.notify.template.TemplateProperties;
import com.cicdi.notify.wechat.corp.WechatCorpNotifierProvider;
import org.junit.Test;
import java.util.HashMap;
import java.util.Map;
/**
* @author xueye
*/
public class WechatSubscriptionTest {
@Test
public void test() {
// 通知器配置管理器
NotifyConfigManager notifyConfigManager = (notifyType, configId) -> {
NotifierProperties notifierProperties = new NotifierProperties();
notifierProperties.setType(DefaultNotifyType.wechat.getId());
notifierProperties.setProvider(WechatProvider.corpMessage.getId());
notifierProperties.setId("12");
Map<String, Object> config = new HashMap<>();
config.put("corpId", "wwbd49ae2419a55a9f");
config.put("corpSecret", "TXDRQw_H8gpVKX0E01EmwMXJ4VooXmj65I-mDe0wQ1k");
notifierProperties.setConfiguration(config);
return notifierProperties;
};
// 模板管理器
TemplateManager templateManager = new AbstractTemplateManager() {
@Override
protected TemplateProperties getProperties(NotifyType type, String id) {
TemplateProperties templateProperties = new TemplateProperties();
templateProperties.setType(DefaultNotifyType.wechat.getId());
templateProperties.setProvider(WechatProvider.corpMessage.getId());
JSONObject jsonObject = new JSONObject();
jsonObject.put("agentId", "3010084");
jsonObject.put("toUser", "XueYe");
jsonObject.put("toParty", "");
jsonObject.put("toTag", "");
jsonObject.put("message", "Hello");
// templateProperties.setTemplate(jsonObject.toJSONString());
return templateProperties;
}
};
NotifierManager notifierManager = new AbstractNotifierManager(notifyConfigManager){};
// register
WechatCorpNotifierProvider provider = new WechatCorpNotifierProvider(templateManager);
notifierManager.register(provider);
templateManager.register(provider);
Notifier<Template> notifier = notifierManager.getNotifier(DefaultNotifyType.wechat, "123");
notifier.send(templateManager.getTemplate(DefaultNotifyType.wechat, "124"), new HashMap<>());
}
}

View File

@ -1,11 +1,13 @@
package com.cicdi.notify.wechat; package com.cicdi.notify.wechat;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSON;
import com.cicdi.notify.*; import com.cicdi.notify.*;
import com.cicdi.notify.template.AbstractTemplateManager; import com.cicdi.notify.template.AbstractTemplateManager;
import com.cicdi.notify.template.Template; import com.cicdi.notify.template.Template;
import com.cicdi.notify.template.TemplateManager; import com.cicdi.notify.template.TemplateManager;
import com.cicdi.notify.template.TemplateProperties; import com.cicdi.notify.template.TemplateProperties;
import com.cicdi.notify.wechat.corp.WechatCorpNotifierProvider;
import com.cicdi.notify.wechat.corp.WechatCorpTemplate;
import org.junit.Test; import org.junit.Test;
import java.util.HashMap; import java.util.HashMap;
@ -41,14 +43,14 @@ public class WechatTest {
templateProperties.setType(DefaultNotifyType.wechat.getId()); templateProperties.setType(DefaultNotifyType.wechat.getId());
templateProperties.setProvider(WechatProvider.corpMessage.getId()); templateProperties.setProvider(WechatProvider.corpMessage.getId());
JSONObject jsonObject = new JSONObject(); WechatCorpTemplate template = new WechatCorpTemplate();
jsonObject.put("agentId", "3010084"); template.setAgentId("3010084");
jsonObject.put("toUser", "XueYe"); template.setToUser("XueYe");
jsonObject.put("toParty", ""); template.setToParty("");
jsonObject.put("toTag", ""); template.setToTag("");
jsonObject.put("message", "Hello"); template.setMessage("Hello");
templateProperties.setTemplate(jsonObject.toJSONString()); templateProperties.setTemplate(JSON.toJSONString(template));
return templateProperties; return templateProperties;
} }
@ -57,7 +59,7 @@ public class WechatTest {
NotifierManager notifierManager = new AbstractNotifierManager(notifyConfigManager){}; NotifierManager notifierManager = new AbstractNotifierManager(notifyConfigManager){};
// register // register
WechatNotifierProvider provider = new WechatNotifierProvider(templateManager); WechatCorpNotifierProvider provider = new WechatCorpNotifierProvider(templateManager);
notifierManager.register(provider); notifierManager.register(provider);
templateManager.register(provider); templateManager.register(provider);