feat: 添加企业微信通知器
This commit is contained in:
parent
a088d6440e
commit
f69eeb502c
@ -8,8 +8,8 @@ package com.cicdi.notify;
|
|||||||
public enum DefaultNotifyType implements NotifyType {
|
public enum DefaultNotifyType implements NotifyType {
|
||||||
|
|
||||||
email("邮件"),
|
email("邮件"),
|
||||||
sms("短信")
|
sms("短信"),
|
||||||
;
|
wechat("微信");
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
|
|
||||||
|
44
notify-wechat/pom.xml
Normal file
44
notify-wechat/pom.xml
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<?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>notify</artifactId>
|
||||||
|
<groupId>com.cicdi</groupId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>notify-wechat</artifactId>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.cicdi</groupId>
|
||||||
|
<artifactId>notify-core</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||||
|
<version>2.3.11.RELEASE</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba</groupId>
|
||||||
|
<artifactId>fastjson</artifactId>
|
||||||
|
<version>1.2.73</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<version>4.12</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>8</maven.compiler.source>
|
||||||
|
<maven.compiler.target>8</maven.compiler.target>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
</project>
|
@ -0,0 +1,24 @@
|
|||||||
|
package com.cicdi.notify.wechat;
|
||||||
|
|
||||||
|
public class WechatCorpProperties {
|
||||||
|
|
||||||
|
private String corpId;
|
||||||
|
|
||||||
|
private String corpSecret;
|
||||||
|
|
||||||
|
public String getCorpId() {
|
||||||
|
return corpId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCorpId(String corpId) {
|
||||||
|
this.corpId = corpId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCorpSecret() {
|
||||||
|
return corpSecret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCorpSecret(String corpSecret) {
|
||||||
|
this.corpSecret = corpSecret;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,137 @@
|
|||||||
|
package com.cicdi.notify.wechat;
|
||||||
|
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.cicdi.notify.template.Template;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
import org.springframework.web.reactive.function.BodyInserters;
|
||||||
|
import org.springframework.web.util.UriComponentsBuilder;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class WechatMessageTemplate implements Template {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用ID
|
||||||
|
*/
|
||||||
|
private String agentId;
|
||||||
|
|
||||||
|
private String toUser;
|
||||||
|
|
||||||
|
private String toParty;
|
||||||
|
|
||||||
|
private String toTag;
|
||||||
|
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
public String getAgentId() {
|
||||||
|
return agentId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAgentId(String agentId) {
|
||||||
|
this.agentId = agentId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getToUser() {
|
||||||
|
return toUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setToUser(String toUser) {
|
||||||
|
this.toUser = toUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getToParty() {
|
||||||
|
return toParty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setToParty(String toParty) {
|
||||||
|
this.toParty = toParty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getToTag() {
|
||||||
|
return toTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setToTag(String toTag) {
|
||||||
|
this.toTag = toTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMessage(String message) {
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BodyInserters.FormInserter<String> createFormInserter(BodyInserters.FormInserter<String> inserter, Map<String, Object> context) {
|
||||||
|
inserter.with("agentid", this.getAgentId())
|
||||||
|
.with("msgtype","text")
|
||||||
|
.with("text",this.createMessage(context));
|
||||||
|
if (StringUtils.hasText(toUser)) {
|
||||||
|
inserter.with("touser", this.createUserIdList(context));
|
||||||
|
}
|
||||||
|
if (StringUtils.hasText(toParty)) {
|
||||||
|
inserter.with("toparty", this.createDepartmentIdList(context));
|
||||||
|
}
|
||||||
|
return inserter;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public String createJsonRequest(Map<String, Object> context){
|
||||||
|
JSONObject json=new JSONObject();
|
||||||
|
json.put("agentid",getAgentId());
|
||||||
|
json.put("msgtype","text");
|
||||||
|
// TODO
|
||||||
|
// json.put("text",Collections.singletonMap("content",ExpressionUtils.analytical(message, context.getAllValues(), "spel")));
|
||||||
|
json.put("text",Collections.singletonMap("content", message));
|
||||||
|
|
||||||
|
if (StringUtils.hasText(toUser)) {
|
||||||
|
json.put("touser", this.createUserIdList(context));
|
||||||
|
}
|
||||||
|
if (StringUtils.hasText(toParty)) {
|
||||||
|
json.put("toparty", this.createDepartmentIdList(context));
|
||||||
|
}
|
||||||
|
|
||||||
|
return json.toJSONString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public UriComponentsBuilder createUriParameter(UriComponentsBuilder builder, Map<String, Object> context){
|
||||||
|
builder.queryParam("agentid", this.getAgentId())
|
||||||
|
.queryParam("msgtype","text")
|
||||||
|
.queryParam("text",this.createMessage(context));
|
||||||
|
if (StringUtils.hasText(toUser)) {
|
||||||
|
builder.queryParam("touser", this.createUserIdList(context));
|
||||||
|
}
|
||||||
|
if (StringUtils.hasText(toParty)) {
|
||||||
|
builder.queryParam("toparty", this.createDepartmentIdList(context));
|
||||||
|
}
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String createUserIdList(Map<String, Object> context) {
|
||||||
|
if (StringUtils.isEmpty(toUser)) {
|
||||||
|
return toUser;
|
||||||
|
}
|
||||||
|
return toUser;
|
||||||
|
// return ExpressionUtils.analytical(toUser, context.getAllValues(), "spel");
|
||||||
|
}
|
||||||
|
|
||||||
|
public String createDepartmentIdList(Map<String, Object> context) {
|
||||||
|
if (StringUtils.isEmpty(toParty)) {
|
||||||
|
return toParty;
|
||||||
|
}
|
||||||
|
return toParty;
|
||||||
|
// return ExpressionUtils.analytical(toParty, context.getAllValues(), "spel");
|
||||||
|
}
|
||||||
|
|
||||||
|
public String createMessage(Map<String, Object> context) {
|
||||||
|
JSONObject json = new JSONObject();
|
||||||
|
json.put("content", message);
|
||||||
|
// json.put("content", ExpressionUtils.analytical(message, context.getAllValues(), "spel"));
|
||||||
|
return json.toJSONString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,67 @@
|
|||||||
|
package com.cicdi.notify.wechat;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.cicdi.notify.*;
|
||||||
|
import com.cicdi.notify.template.TemplateManager;
|
||||||
|
import com.cicdi.notify.template.TemplateProperties;
|
||||||
|
import com.cicdi.notify.template.TemplateProvider;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class WechatNotifierProvider implements NotifierProvider, TemplateProvider {
|
||||||
|
|
||||||
|
private final TemplateManager templateManager;
|
||||||
|
|
||||||
|
public WechatNotifierProvider(TemplateManager templateManager) {
|
||||||
|
this.templateManager = templateManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
// public static final DefaultConfigMetadata notifierConfig = new DefaultConfigMetadata("通知配置", "")
|
||||||
|
// .add("corpId", "corpId", "", new StringType().expand(ConfigMetadataConstants.required.value(true)))
|
||||||
|
// .add("corpSecret", "corpSecret", "", new StringType());
|
||||||
|
//
|
||||||
|
// public static final DefaultConfigMetadata templateConfig = new DefaultConfigMetadata("模版配置", "")
|
||||||
|
// .add("agentId", "应用ID", "", new StringType().expand(ConfigMetadataConstants.required.value(true)))
|
||||||
|
// .add("toUser", "收信人ID", "与部门ID不能同时为空", new StringType())
|
||||||
|
// .add("toParty", "收信部门ID", "与收信人ID不能同时为空", new StringType())
|
||||||
|
// .add("toTag", "按标签推送", "", new StringType())
|
||||||
|
// .add("message", "内容", "最大不超过500字", new StringType().expand(ConfigMetadataConstants.maxLength.value(500L)));
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NotifyType getType() {
|
||||||
|
return DefaultNotifyType.wechat;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Provider getProvider() {
|
||||||
|
return WechatProvider.corpMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WechatMessageTemplate createTemplate(TemplateProperties properties) {
|
||||||
|
return JSON.parseObject(properties.getTemplate(), WechatMessageTemplate.class);
|
||||||
|
// return Mono.fromSupplier(() -> ValidatorUtils.tryValidate(JSON.parseObject(properties.getTemplate(), org.jetlinks.community.notify.wechat.WechatMessageTemplate.class)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WeixinCorpNotifier createNotifier(NotifierProperties properties) {
|
||||||
|
// WechatCorpProperties wechatCorpProperties = FastBeanCopier.copy(properties.getConfiguration(), new WechatCorpProperties());
|
||||||
|
Map<String, Object> config = properties.getConfiguration();
|
||||||
|
WechatCorpProperties wechatCorpProperties = new WechatCorpProperties();
|
||||||
|
wechatCorpProperties.setCorpId((String) config.get("corpId"));
|
||||||
|
wechatCorpProperties.setCorpSecret((String) config.get("corpSecret"));
|
||||||
|
return new WeixinCorpNotifier(properties.getId(), wechatCorpProperties, templateManager);
|
||||||
|
// return Mono.just(new WeixinCorpNotifier(properties.getId(), client, ValidatorUtils.tryValidate(wechatCorpProperties), templateManager));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Override
|
||||||
|
// public ConfigMetadata getNotifierConfigMetadata() {
|
||||||
|
// return notifierConfig;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public ConfigMetadata getTemplateConfigMetadata() {
|
||||||
|
// return templateConfig;
|
||||||
|
// }
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
package com.cicdi.notify.wechat;
|
||||||
|
|
||||||
|
import com.cicdi.notify.Provider;
|
||||||
|
|
||||||
|
public enum WechatProvider implements Provider {
|
||||||
|
corpMessage("微信企业消息通知");
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
WechatProvider(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getId() {
|
||||||
|
return name();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,124 @@
|
|||||||
|
package com.cicdi.notify.wechat;
|
||||||
|
|
||||||
|
|
||||||
|
import com.cicdi.notify.AbstractNotifier;
|
||||||
|
import com.cicdi.notify.DefaultNotifyType;
|
||||||
|
import com.cicdi.notify.NotifyType;
|
||||||
|
import com.cicdi.notify.Provider;
|
||||||
|
import com.cicdi.notify.template.TemplateManager;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.web.reactive.function.BodyInserters;
|
||||||
|
import org.springframework.web.reactive.function.client.ClientResponse;
|
||||||
|
import org.springframework.web.reactive.function.client.WebClient;
|
||||||
|
import org.springframework.web.util.UriComponentsBuilder;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
|
public class WeixinCorpNotifier extends AbstractNotifier<WechatMessageTemplate> {
|
||||||
|
|
||||||
|
private final AtomicReference<String> accessToken = new AtomicReference<>();
|
||||||
|
|
||||||
|
private long refreshTokenTime;
|
||||||
|
|
||||||
|
private final long tokenTimeOut = Duration.ofSeconds(7000).toMillis();
|
||||||
|
|
||||||
|
private static final String tokenApi = "https://qyapi.weixin.qq.com/cgi-bin/gettoken";
|
||||||
|
|
||||||
|
private static final String notify = "https://qyapi.weixin.qq.com/cgi-bin/message/send";
|
||||||
|
|
||||||
|
private final WechatCorpProperties properties;
|
||||||
|
|
||||||
|
private final String notifierId;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getNotifierId() {
|
||||||
|
return notifierId;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public WeixinCorpNotifier(String id, WechatCorpProperties properties, TemplateManager templateManager) {
|
||||||
|
super(templateManager);
|
||||||
|
this.properties = properties;
|
||||||
|
this.notifierId = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NotifyType getType() {
|
||||||
|
return DefaultNotifyType.wechat;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Provider getProvider() {
|
||||||
|
return WechatProvider.corpMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void send(WechatMessageTemplate template, Map<String, Object> context) {
|
||||||
|
String token1 = getToken();
|
||||||
|
WebClient.create().post()
|
||||||
|
.uri(UriComponentsBuilder.fromUriString(notify).queryParam("access_token", token1).toUriString())
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
|
.body(BodyInserters.fromValue(template.createJsonRequest(context)))
|
||||||
|
.exchange()
|
||||||
|
.flatMap(clientResponse -> clientResponse.bodyToMono(HashMap.class))
|
||||||
|
.as(this::checkResult)
|
||||||
|
.then();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Mono<HashMap> checkResult(Mono<HashMap> msg) {
|
||||||
|
return msg.doOnNext(map -> {
|
||||||
|
String code = String.valueOf(map.get("errcode"));
|
||||||
|
if ("0".equals(code)) {
|
||||||
|
// log.info("发送微信企业通知成功");
|
||||||
|
} else {
|
||||||
|
// log.warn("发送微信企业通知失败:{}", map);
|
||||||
|
// throw new BusinessException("发送微信企业通知失败:" + map.get("errmsg"), code);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getToken() {
|
||||||
|
if (System.currentTimeMillis() - refreshTokenTime > tokenTimeOut || accessToken.get() == null) {
|
||||||
|
return requestToken();
|
||||||
|
}
|
||||||
|
return accessToken.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String requestToken() {
|
||||||
|
Mono<ClientResponse> responseMono = WebClient.create().get()
|
||||||
|
.uri(UriComponentsBuilder.fromUriString(tokenApi)
|
||||||
|
.queryParam("corpId", properties.getCorpId())
|
||||||
|
.queryParam("corpSecret", properties.getCorpSecret())
|
||||||
|
.build().toUri())
|
||||||
|
.exchange();
|
||||||
|
|
||||||
|
responseMono.flatMap(resp -> {
|
||||||
|
System.out.println(resp);
|
||||||
|
return resp.bodyToMono(HashMap.class);
|
||||||
|
})
|
||||||
|
.map(map -> {
|
||||||
|
if (map.containsKey("access_token")) {
|
||||||
|
return map.get("access_token");
|
||||||
|
}
|
||||||
|
// TODO 自定义异常
|
||||||
|
// throw new BusinessException("获取Token失败:" + map.get("errmsg"), String.valueOf(map.get("errcode")));
|
||||||
|
return Mono.empty();
|
||||||
|
})
|
||||||
|
.cast(String.class)
|
||||||
|
.doOnNext(r -> {
|
||||||
|
refreshTokenTime = System.currentTimeMillis();
|
||||||
|
accessToken.set(r);
|
||||||
|
});
|
||||||
|
return accessToken.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
accessToken.set(null);
|
||||||
|
refreshTokenTime = 0;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,72 @@
|
|||||||
|
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 org.junit.Test;
|
||||||
|
import reactor.core.publisher.Hooks;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author xueye
|
||||||
|
*/
|
||||||
|
public class WechatTest {
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
Hooks.onOperatorDebug();
|
||||||
|
// 通知器配置管理器
|
||||||
|
NotifyConfigManager notifyConfigManager = new NotifyConfigManager() {
|
||||||
|
@Override
|
||||||
|
public NotifierProperties getNotifyConfig(NotifyType notifyType, String 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 DefaultNotifierManager(notifyConfigManager);
|
||||||
|
|
||||||
|
// register
|
||||||
|
WechatNotifierProvider provider = new WechatNotifierProvider(templateManager);
|
||||||
|
notifierManager.registerProvider(provider);
|
||||||
|
templateManager.register(provider);
|
||||||
|
|
||||||
|
Notifier<Template> notifier = notifierManager.getNotifier(DefaultNotifyType.wechat, "123");
|
||||||
|
notifier.send(templateManager.getTemplate(DefaultNotifyType.wechat, "124"), new HashMap<>());
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user