Showing
10 changed files
with
219 additions
and
11 deletions
1 | +package org.thingsboard.server.common.data.yunteng.config.enterpriseWeChat; | ||
2 | + | ||
3 | +import lombok.Data; | ||
4 | +import org.thingsboard.server.common.data.yunteng.config.message.MessageProviderConfiguration; | ||
5 | +import org.thingsboard.server.common.data.yunteng.enums.MessageProviderTypeEnum; | ||
6 | + | ||
7 | +@Data | ||
8 | +public class EnterpriseWeChatConfiguration implements MessageProviderConfiguration { | ||
9 | + | ||
10 | + /** 企业id */ | ||
11 | + private String corpId; | ||
12 | + | ||
13 | + /** 应用id */ | ||
14 | + private Long agentId; | ||
15 | + | ||
16 | + /** 企业微信应用Secret */ | ||
17 | + private String corpSecret; | ||
18 | + | ||
19 | + @Override | ||
20 | + public MessageProviderTypeEnum getType() { | ||
21 | + return MessageProviderTypeEnum.ENTERPRISE_WECHAT; | ||
22 | + } | ||
23 | +} |
1 | +package org.thingsboard.server.common.data.yunteng.config.enterpriseWeChat; | ||
2 | +import com.fasterxml.jackson.databind.JsonNode; | ||
3 | +import lombok.extern.slf4j.Slf4j; | ||
4 | +import org.apache.commons.lang3.StringUtils; | ||
5 | +import org.thingsboard.server.common.data.yunteng.config.message.AbstractMessageSender; | ||
6 | +import org.thingsboard.server.common.data.yunteng.core.exception.TkDataValidationException; | ||
7 | +import org.thingsboard.server.common.data.yunteng.core.message.ErrorMessage; | ||
8 | +import org.thingsboard.server.common.data.yunteng.enums.ResponseCodeEnum; | ||
9 | +import org.thingsboard.server.common.data.yunteng.utils.HttpClientUtils; | ||
10 | +import org.thingsboard.server.common.data.yunteng.utils.JacksonUtil; | ||
11 | +import java.util.ArrayList; | ||
12 | +import java.util.Date; | ||
13 | +import java.util.LinkedHashMap; | ||
14 | +import java.util.List; | ||
15 | + | ||
16 | +@Slf4j | ||
17 | +public class EnterpriseWeChatSmsSender extends AbstractMessageSender { | ||
18 | + | ||
19 | + /** 钉钉参数配置 */ | ||
20 | + private final EnterpriseWeChatConfiguration config; | ||
21 | + | ||
22 | + private String accessToken; | ||
23 | + | ||
24 | + private String url = "https://qyapi.weixin.qq.com/cgi-bin"; | ||
25 | + | ||
26 | + private Long expirationTime; | ||
27 | +// | ||
28 | +// private static final String smsText="{\n" + | ||
29 | +// " \"touser\": \"%s\",\n" + | ||
30 | +// " \"msgtype\": \"textcard\",\n" + | ||
31 | +// " \"agentid\": %s,\n" + | ||
32 | +// " \"textcard\": {\n" + | ||
33 | +// "\"title\": \"平台告警通知\",\n" + | ||
34 | +// "\"description\": \"<div class=\\\"normal\\\">设备所属组织:%s</div>" + | ||
35 | +// "<div class=\\\"normal\\\">设备名称:%s</div>" + | ||
36 | +// "<div class=\\\"normal\\\">告警等级:%s</div>" + | ||
37 | +// "<div class=\\\"normal\\\">告警类型:%s</div>" + | ||
38 | +// "<div class=\\\"normal\\\">触发值:%s</div>" + | ||
39 | +// "<div class=\\\"normal\\\">告警时间:%s</div>\",\n" + | ||
40 | +// " \"url\": \" \",\n" + | ||
41 | +// " \"btntxt\": \"详情\"\n" + | ||
42 | +// " },\n" + | ||
43 | +// " \"enable_id_trans\": 0,\n" + | ||
44 | +// " \"enable_duplicate_check\": 0,\n" + | ||
45 | +// " \"duplicate_check_interval\": 1800\n" + | ||
46 | +// "}"; | ||
47 | + | ||
48 | + private static final String smsText="{\n" + | ||
49 | + " \"touser\" : \"%s\",\n" + | ||
50 | + " \"msgtype\" : \"text\",\n" + | ||
51 | + " \"agentid\" : %s,\n" + | ||
52 | + " \"text\" : {\n" + | ||
53 | + " \"content\" : \"平台告警通知\n设备所属组织:%s\n设备名称:%s\n告警等级:%s\n告警类型:%s\n触发值:%s\n告警时间:%s\n\"\n" + | ||
54 | + " },\n" + | ||
55 | + " \"safe\":0,\n" + | ||
56 | + " \"enable_id_trans\": 0,\n" + | ||
57 | + " \"enable_duplicate_check\": 0,\n" + | ||
58 | + " \"duplicate_check_interval\": 1800\n" + | ||
59 | + "}"; | ||
60 | + | ||
61 | + | ||
62 | + | ||
63 | + public EnterpriseWeChatSmsSender(EnterpriseWeChatConfiguration config) { | ||
64 | + if (StringUtils.isEmpty(config.getCorpId()) | ||
65 | + || StringUtils.isEmpty(config.getCorpSecret())) { | ||
66 | + throw new TkDataValidationException(ErrorMessage.INVALID_PARAMETER.getMessage()); | ||
67 | + } | ||
68 | + this.config = config; | ||
69 | + getAccessToken(); | ||
70 | + } | ||
71 | + | ||
72 | + /** 初始化token */ | ||
73 | + private void getAccessToken() { | ||
74 | + if(expirationTime!=null){ | ||
75 | + Date now = new Date(); | ||
76 | + if(now.getTime()>expirationTime){ | ||
77 | + getAccessTokenByUrl(); | ||
78 | + } | ||
79 | + }else{ | ||
80 | + getAccessTokenByUrl(); | ||
81 | + } | ||
82 | + } | ||
83 | + private void getAccessTokenByUrl() { | ||
84 | + try { | ||
85 | + String response = HttpClientUtils.sendGet(url+"/gettoken?"+"corpid="+config.getCorpId()+"&corpsecret="+config.getCorpSecret()); | ||
86 | + JsonNode jsonNode = JacksonUtil.toJsonNode(response); | ||
87 | + this.accessToken = jsonNode.path("access_token").asText(); | ||
88 | + this.expirationTime = new Date().getTime()+5400*1000; | ||
89 | + } catch (Exception e) { | ||
90 | + e.printStackTrace(); | ||
91 | + throw new TkDataValidationException(ErrorMessage.OPERATION_FAILED.getMessage()); | ||
92 | + } | ||
93 | + } | ||
94 | + | ||
95 | + | ||
96 | + private String getUserId(String phone) { | ||
97 | + List<String> numbers = new ArrayList<>(); | ||
98 | + String [] phones = phone.split(","); | ||
99 | + for(String onePhone: phones){ | ||
100 | + try { | ||
101 | + String payload ="{\"mobile\":\""+onePhone+"\"}"; | ||
102 | + String response = HttpClientUtils.sendPOST(url+"/user/getuserid?access_token="+accessToken,payload); | ||
103 | + JsonNode jsonNode = JacksonUtil.toJsonNode(response); | ||
104 | + if(jsonNode.path("userid").asText().isEmpty()){ | ||
105 | + continue; | ||
106 | + } | ||
107 | + numbers.add(jsonNode.path("userid").asText()); | ||
108 | + } catch (Exception e) { | ||
109 | + e.printStackTrace(); | ||
110 | + } | ||
111 | + } | ||
112 | + return String.join("|",numbers); | ||
113 | + } | ||
114 | + | ||
115 | + @Override | ||
116 | + public String sendSms( | ||
117 | + String phone, String templateCode, LinkedHashMap<String, Object> param, String signName) { | ||
118 | + try{ | ||
119 | + getAccessToken(); | ||
120 | + String payload = String.format(smsText,getUserId(phone),config.getAgentId(),param.get("organization"),param.get("deviceName"), | ||
121 | + param.get("severity"),param.get("type"),param.get("triggerValue"),param.get("createTime")); | ||
122 | + String response = HttpClientUtils.sendPOST( | ||
123 | + url +"/message/send?"+"access_token="+accessToken,payload); | ||
124 | + JsonNode jsonNode = JacksonUtil.toJsonNode(response); | ||
125 | + return jsonNode.path("error-msg").asText().equalsIgnoreCase(ResponseCodeEnum.OK.name()) | ||
126 | + ? ResponseCodeEnum.SUCCESS.name() | ||
127 | + : jsonNode.path("error-msg").asText(); | ||
128 | + } catch (Exception e) { | ||
129 | + e.printStackTrace(); | ||
130 | + return e.getMessage(); | ||
131 | + } | ||
132 | + } | ||
133 | +} |
@@ -3,6 +3,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore; | @@ -3,6 +3,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore; | ||
3 | import com.fasterxml.jackson.annotation.JsonSubTypes; | 3 | import com.fasterxml.jackson.annotation.JsonSubTypes; |
4 | import com.fasterxml.jackson.annotation.JsonTypeInfo; | 4 | import com.fasterxml.jackson.annotation.JsonTypeInfo; |
5 | import org.thingsboard.server.common.data.yunteng.config.dingtalk.DingTalkSmsProviderConfiguration; | 5 | import org.thingsboard.server.common.data.yunteng.config.dingtalk.DingTalkSmsProviderConfiguration; |
6 | +import org.thingsboard.server.common.data.yunteng.config.enterpriseWeChat.EnterpriseWeChatConfiguration; | ||
6 | import org.thingsboard.server.common.data.yunteng.config.message.ali.AliSmsProviderConfiguration; | 7 | import org.thingsboard.server.common.data.yunteng.config.message.ali.AliSmsProviderConfiguration; |
7 | import org.thingsboard.server.common.data.yunteng.config.message.tencent.TencentSmsProviderConfiguration; | 8 | import org.thingsboard.server.common.data.yunteng.config.message.tencent.TencentSmsProviderConfiguration; |
8 | import org.thingsboard.server.common.data.yunteng.config.voice.AliVoiceSmsProviderConfiguration; | 9 | import org.thingsboard.server.common.data.yunteng.config.voice.AliVoiceSmsProviderConfiguration; |
@@ -13,7 +14,8 @@ import org.thingsboard.server.common.data.yunteng.enums.MessageProviderTypeEnum; | @@ -13,7 +14,8 @@ import org.thingsboard.server.common.data.yunteng.enums.MessageProviderTypeEnum; | ||
13 | @JsonSubTypes.Type(value = AliSmsProviderConfiguration.class, name = "ALI_CLOUD"), | 14 | @JsonSubTypes.Type(value = AliSmsProviderConfiguration.class, name = "ALI_CLOUD"), |
14 | @JsonSubTypes.Type(value = TencentSmsProviderConfiguration.class, name = "TENCENT_CLOUD"), | 15 | @JsonSubTypes.Type(value = TencentSmsProviderConfiguration.class, name = "TENCENT_CLOUD"), |
15 | @JsonSubTypes.Type(value = DingTalkSmsProviderConfiguration.class, name = "DING_TALK"), | 16 | @JsonSubTypes.Type(value = DingTalkSmsProviderConfiguration.class, name = "DING_TALK"), |
16 | - @JsonSubTypes.Type(value = AliVoiceSmsProviderConfiguration.class, name = "ALI_VOICE") | 17 | + @JsonSubTypes.Type(value = AliVoiceSmsProviderConfiguration.class, name = "ALI_VOICE"), |
18 | + @JsonSubTypes.Type(value = EnterpriseWeChatConfiguration.class, name = "ENTERPRISE_WECHAT") | ||
17 | }) | 19 | }) |
18 | public interface MessageProviderConfiguration { | 20 | public interface MessageProviderConfiguration { |
19 | 21 |
@@ -3,6 +3,8 @@ package org.thingsboard.server.common.data.yunteng.config.message; | @@ -3,6 +3,8 @@ package org.thingsboard.server.common.data.yunteng.config.message; | ||
3 | import org.springframework.stereotype.Component; | 3 | import org.springframework.stereotype.Component; |
4 | import org.thingsboard.server.common.data.yunteng.config.dingtalk.DingTalkSmsProviderConfiguration; | 4 | import org.thingsboard.server.common.data.yunteng.config.dingtalk.DingTalkSmsProviderConfiguration; |
5 | import org.thingsboard.server.common.data.yunteng.config.dingtalk.DingTalkSmsSender; | 5 | import org.thingsboard.server.common.data.yunteng.config.dingtalk.DingTalkSmsSender; |
6 | +import org.thingsboard.server.common.data.yunteng.config.enterpriseWeChat.EnterpriseWeChatConfiguration; | ||
7 | +import org.thingsboard.server.common.data.yunteng.config.enterpriseWeChat.EnterpriseWeChatSmsSender; | ||
6 | import org.thingsboard.server.common.data.yunteng.config.message.ali.AliSmsProviderConfiguration; | 8 | import org.thingsboard.server.common.data.yunteng.config.message.ali.AliSmsProviderConfiguration; |
7 | import org.thingsboard.server.common.data.yunteng.config.message.ali.AliSmsSender; | 9 | import org.thingsboard.server.common.data.yunteng.config.message.ali.AliSmsSender; |
8 | import org.thingsboard.server.common.data.yunteng.config.message.tencent.TencentSmsProviderConfiguration; | 10 | import org.thingsboard.server.common.data.yunteng.config.message.tencent.TencentSmsProviderConfiguration; |
@@ -42,6 +44,11 @@ public class TkDefaultMessageSenderFactory implements MessageSenderFactory { | @@ -42,6 +44,11 @@ public class TkDefaultMessageSenderFactory implements MessageSenderFactory { | ||
42 | (DingTalkSmsProviderConfiguration) config); | 44 | (DingTalkSmsProviderConfiguration) config); |
43 | smsSenderMap.put(key,dingTalkSmsSender); | 45 | smsSenderMap.put(key,dingTalkSmsSender); |
44 | return dingTalkSmsSender; | 46 | return dingTalkSmsSender; |
47 | + case ENTERPRISE_WECHAT: | ||
48 | + EnterpriseWeChatSmsSender enterpriseWeChatSmsSender = new EnterpriseWeChatSmsSender( | ||
49 | + (EnterpriseWeChatConfiguration) config); | ||
50 | + smsSenderMap.put(key,enterpriseWeChatSmsSender); | ||
51 | + return enterpriseWeChatSmsSender; | ||
45 | case ALI_VOICE: | 52 | case ALI_VOICE: |
46 | return new AliVoiceSmsSender( | 53 | return new AliVoiceSmsSender( |
47 | (AliVoiceSmsProviderConfiguration) config); | 54 | (AliVoiceSmsProviderConfiguration) config); |
@@ -48,14 +48,5 @@ public class HttpClientUtils { | @@ -48,14 +48,5 @@ public class HttpClientUtils { | ||
48 | 48 | ||
49 | } | 49 | } |
50 | 50 | ||
51 | - public static void main(String[] args) throws IOException { | ||
52 | -// String url = "https://open.ys7.com/api/lapp/token/get?appKey=0cf3f1753e6941e3b5dfe3c00162924e&appSecret=cbe2f41bebee529fde568143109a9903"; | ||
53 | -// String param = "{\"appKey\":\"0cf3f1753e6941e3b5dfe3c00162924e\",\"appSecret\":\"cbe2f41bebee529fde568143109a9903\"}"; | ||
54 | -// String response = sendPOST(url,param);System.out.println(response); | ||
55 | - String url2 = "https://open.ys7.com/api/lapp/v2/live/address/get?accessToken=at.cm82uxq261a7ji0xcf32z4su2f5vc066-2krkymy3is-1of7jb5-v1jamwzxw" + | ||
56 | - "&deviceSerial=E53165567&protocol=4"; | ||
57 | - String response = sendPOST(url2,""); | ||
58 | - System.out.println(response); | ||
59 | - } | ||
60 | 51 | ||
61 | } | 52 | } |
@@ -102,6 +102,12 @@ public class TkMessageServiceImpl implements TkMessageService { | @@ -102,6 +102,12 @@ public class TkMessageServiceImpl implements TkMessageService { | ||
102 | || null == configJsonNode.get("clientSecret"))) { | 102 | || null == configJsonNode.get("clientSecret"))) { |
103 | isMatch = false; | 103 | isMatch = false; |
104 | } | 104 | } |
105 | + else if (platForm.equals(MessageProviderTypeEnum.ENTERPRISE_WECHAT.name()) | ||
106 | + && (null == configJsonNode.get("corpId") | ||
107 | + || null == configJsonNode.get("agentId") | ||
108 | + || null == configJsonNode.get("corpSecret"))) { | ||
109 | + isMatch = false; | ||
110 | + } | ||
105 | else if (platForm.equals(MessageProviderTypeEnum.ALI_VOICE.name()) | 111 | else if (platForm.equals(MessageProviderTypeEnum.ALI_VOICE.name()) |
106 | && (null == configJsonNode.get("accessKeyId") | 112 | && (null == configJsonNode.get("accessKeyId") |
107 | || null == configJsonNode.get("accessKeySecret"))) { | 113 | || null == configJsonNode.get("accessKeySecret"))) { |
@@ -117,6 +123,12 @@ public class TkMessageServiceImpl implements TkMessageService { | @@ -117,6 +123,12 @@ public class TkMessageServiceImpl implements TkMessageService { | ||
117 | keyList.add(configJsonNode.get("clientSecret").toString()); | 123 | keyList.add(configJsonNode.get("clientSecret").toString()); |
118 | keyList.add(messageConfig.getTenantId()); | 124 | keyList.add(messageConfig.getTenantId()); |
119 | } | 125 | } |
126 | + else if(isMatch&&platForm.equals(MessageProviderTypeEnum.ENTERPRISE_WECHAT.name())){ | ||
127 | + keyList.add(configJsonNode.get("corpId").toString()); | ||
128 | + keyList.add(configJsonNode.get("agentId").toString()); | ||
129 | + keyList.add(configJsonNode.get("corpSecret").toString()); | ||
130 | + keyList.add(messageConfig.getTenantId()); | ||
131 | + } | ||
120 | MessageProviderConfiguration smsProviderConfiguration = | 132 | MessageProviderConfiguration smsProviderConfiguration = |
121 | JacksonUtil.convertValue(configObjectNode, MessageProviderConfiguration.class); | 133 | JacksonUtil.convertValue(configObjectNode, MessageProviderConfiguration.class); |
122 | if (null != smsProviderConfiguration) { | 134 | if (null != smsProviderConfiguration) { |
@@ -153,6 +153,14 @@ public class TkNoticeServiceImpl implements TkNoticeService { | @@ -153,6 +153,14 @@ public class TkNoticeServiceImpl implements TkNoticeService { | ||
153 | organization, | 153 | organization, |
154 | contacts); | 154 | contacts); |
155 | } | 155 | } |
156 | + if (messageCode.contains(MessageTypeEnum.ENTERPRISE_WECHAT_MESSAGE.name()) | ||
157 | + && templatesMap.containsKey(MessageTypeEnum.ENTERPRISE_WECHAT_MESSAGE.name())) { | ||
158 | + enterpriseWeChat4Alarm( | ||
159 | + alarmInfo, | ||
160 | + templatesMap.get(MessageTypeEnum.ENTERPRISE_WECHAT_MESSAGE.name()), | ||
161 | + organization, | ||
162 | + contacts); | ||
163 | + } | ||
156 | if (messageCode.contains(MessageTypeEnum.VOICE_MESSAGE.name()) | 164 | if (messageCode.contains(MessageTypeEnum.VOICE_MESSAGE.name()) |
157 | && templatesMap.containsKey(MessageTypeEnum.VOICE_MESSAGE.name())) { | 165 | && templatesMap.containsKey(MessageTypeEnum.VOICE_MESSAGE.name())) { |
158 | aLiVoice4Alarm( | 166 | aLiVoice4Alarm( |
@@ -268,6 +276,37 @@ public class TkNoticeServiceImpl implements TkNoticeService { | @@ -268,6 +276,37 @@ public class TkNoticeServiceImpl implements TkNoticeService { | ||
268 | smsService.sendSms(info); | 276 | smsService.sendSms(info); |
269 | } | 277 | } |
270 | 278 | ||
279 | + /** | ||
280 | + * 企业微信通知设备告警信息 | ||
281 | + * | ||
282 | + * @param alarmInfo 告警信息 | ||
283 | + * @param templateId 告警模板主键 | ||
284 | + * @param organization 设备所属组织 | ||
285 | + */ | ||
286 | + private void enterpriseWeChat4Alarm( | ||
287 | + AlarmInfoDTO alarmInfo, | ||
288 | + String templateId, | ||
289 | + TkOrganizationEntity organization, | ||
290 | + List<TkAlarmContactEntity> contacts) { | ||
291 | + // TODO 推送企业微信通知 | ||
292 | + SmsReqDTO info = new SmsReqDTO(); | ||
293 | + info.setId(templateId); | ||
294 | + info.setParams(setAliAlarmParams(alarmInfo, organization)); | ||
295 | + info.setTemplatePurpose(MsgTemplatePurposeEnum.FOR_ALARM_NOTICE.name()); | ||
296 | + List<String> phones = new ArrayList<>(); | ||
297 | + contacts.stream() | ||
298 | + .parallel() | ||
299 | + .forEach( | ||
300 | + item -> { | ||
301 | + if (StringUtils.isEmpty(item.getWechat())&&StringUtils.isEmpty(item.getPhone())) { | ||
302 | + return; | ||
303 | + } | ||
304 | + phones.add(item.getWechat()==null?item.getPhone():item.getWechat()); | ||
305 | + }); | ||
306 | + String phone = String.join(",",phones); | ||
307 | + info.setPhoneNumbers(phone); | ||
308 | + smsService.sendSms(info); | ||
309 | + } | ||
271 | /** | 310 | /** |
272 | * 微信通知设备告警信息 | 311 | * 微信通知设备告警信息 |
273 | * | 312 | * |