Commit 3f6e750108dde9281ddfcb70a0409eee00d877d6

Authored by xp.Huang
2 parents 98345048 80521719

Merge branch 'weixin_message' into 'CommonTenant'

feat:企业微信通知

See merge request yunteng/thingskit!386
  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 3 import com.fasterxml.jackson.annotation.JsonSubTypes;
4 4 import com.fasterxml.jackson.annotation.JsonTypeInfo;
5 5 import org.thingsboard.server.common.data.yunteng.config.dingtalk.DingTalkSmsProviderConfiguration;
  6 +import org.thingsboard.server.common.data.yunteng.config.enterpriseWeChat.EnterpriseWeChatConfiguration;
6 7 import org.thingsboard.server.common.data.yunteng.config.message.ali.AliSmsProviderConfiguration;
7 8 import org.thingsboard.server.common.data.yunteng.config.message.tencent.TencentSmsProviderConfiguration;
8 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 14 @JsonSubTypes.Type(value = AliSmsProviderConfiguration.class, name = "ALI_CLOUD"),
14 15 @JsonSubTypes.Type(value = TencentSmsProviderConfiguration.class, name = "TENCENT_CLOUD"),
15 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 20 public interface MessageProviderConfiguration {
19 21
... ...
1 1 package org.thingsboard.server.common.data.yunteng.config.message;
2   -
3 2 import java.util.LinkedHashMap;
4 3
5 4 public interface MessageSender {
... ...
... ... @@ -3,6 +3,8 @@ package org.thingsboard.server.common.data.yunteng.config.message;
3 3 import org.springframework.stereotype.Component;
4 4 import org.thingsboard.server.common.data.yunteng.config.dingtalk.DingTalkSmsProviderConfiguration;
5 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 8 import org.thingsboard.server.common.data.yunteng.config.message.ali.AliSmsProviderConfiguration;
7 9 import org.thingsboard.server.common.data.yunteng.config.message.ali.AliSmsSender;
8 10 import org.thingsboard.server.common.data.yunteng.config.message.tencent.TencentSmsProviderConfiguration;
... ... @@ -42,6 +44,11 @@ public class TkDefaultMessageSenderFactory implements MessageSenderFactory {
42 44 (DingTalkSmsProviderConfiguration) config);
43 45 smsSenderMap.put(key,dingTalkSmsSender);
44 46 return dingTalkSmsSender;
  47 + case ENTERPRISE_WECHAT:
  48 + EnterpriseWeChatSmsSender enterpriseWeChatSmsSender = new EnterpriseWeChatSmsSender(
  49 + (EnterpriseWeChatConfiguration) config);
  50 + smsSenderMap.put(key,enterpriseWeChatSmsSender);
  51 + return enterpriseWeChatSmsSender;
45 52 case ALI_VOICE:
46 53 return new AliVoiceSmsSender(
47 54 (AliVoiceSmsProviderConfiguration) config);
... ...
... ... @@ -5,5 +5,6 @@ public enum MessageProviderTypeEnum {
5 5 ALI_CLOUD,
6 6 TENCENT_CLOUD,
7 7 DING_TALK,
  8 + ENTERPRISE_WECHAT,
8 9 ALI_VOICE
9 10 }
... ...
... ... @@ -6,5 +6,6 @@ public enum MessageTypeEnum {
6 6 PHONE_MESSAGE,
7 7 DING_TALK_MESSAGE,
8 8 WECHAT_MESSAGE,
  9 + ENTERPRISE_WECHAT_MESSAGE,
9 10 VOICE_MESSAGE
10 11 }
... ...
... ... @@ -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 102 || null == configJsonNode.get("clientSecret"))) {
103 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 111 else if (platForm.equals(MessageProviderTypeEnum.ALI_VOICE.name())
106 112 && (null == configJsonNode.get("accessKeyId")
107 113 || null == configJsonNode.get("accessKeySecret"))) {
... ... @@ -117,6 +123,12 @@ public class TkMessageServiceImpl implements TkMessageService {
117 123 keyList.add(configJsonNode.get("clientSecret").toString());
118 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 132 MessageProviderConfiguration smsProviderConfiguration =
121 133 JacksonUtil.convertValue(configObjectNode, MessageProviderConfiguration.class);
122 134 if (null != smsProviderConfiguration) {
... ...
... ... @@ -153,6 +153,14 @@ public class TkNoticeServiceImpl implements TkNoticeService {
153 153 organization,
154 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 164 if (messageCode.contains(MessageTypeEnum.VOICE_MESSAGE.name())
157 165 && templatesMap.containsKey(MessageTypeEnum.VOICE_MESSAGE.name())) {
158 166 aLiVoice4Alarm(
... ... @@ -268,6 +276,37 @@ public class TkNoticeServiceImpl implements TkNoticeService {
268 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 *
... ...