From d209bd327775161df6b433ab6848eb31f29e8287 Mon Sep 17 00:00:00 2001 From: lwqzz <62584513+lwqzz@users.noreply.github.com> Date: Thu, 18 Apr 2024 17:20:39 +0800 Subject: [PATCH] Added the function of sending SMS messages through Alibaba Cloud. (#1768) Co-authored-by: Logic --- common/pom.xml | 4 + .../common/config/CommonProperties.java | 82 ++++++++++++ .../common/service/AliYunSmsClient.java | 119 ++++++++++++++++++ .../common/util/AliYunSendSmsUtil.java | 52 ++++++++ .../impl/AliYunAlertNotifyHandlerImpl.java | 69 ++++++++++ pom.xml | 6 + 6 files changed, 332 insertions(+) create mode 100644 common/src/main/java/org/apache/hertzbeat/common/service/AliYunSmsClient.java create mode 100644 common/src/main/java/org/apache/hertzbeat/common/util/AliYunSendSmsUtil.java create mode 100644 manager/src/main/java/org/apache/hertzbeat/manager/component/alerter/impl/AliYunAlertNotifyHandlerImpl.java diff --git a/common/pom.xml b/common/pom.xml index e7327529fb5..3de933d2359 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -97,6 +97,10 @@ com.tencentcloudapi tencentcloud-sdk-java-sms + + com.aliyun + dysmsapi20170525 + com.github.ben-manes.caffeine diff --git a/common/src/main/java/org/apache/hertzbeat/common/config/CommonProperties.java b/common/src/main/java/org/apache/hertzbeat/common/config/CommonProperties.java index 59425468958..d92fb8c332f 100644 --- a/common/src/main/java/org/apache/hertzbeat/common/config/CommonProperties.java +++ b/common/src/main/java/org/apache/hertzbeat/common/config/CommonProperties.java @@ -150,7 +150,10 @@ public void setAlertsDataTopic(String alertsDataTopic) { * sms properties */ public static class SmsProperties { + //Tencent cloud SMS configuration private TencentSmsProperties tencent; + //Ali cloud SMS configuration + private AliYunSmsProperties aliYun; public TencentSmsProperties getTencent() { return tencent; @@ -159,6 +162,14 @@ public TencentSmsProperties getTencent() { public void setTencent(TencentSmsProperties tencent) { this.tencent = tencent; } + + public AliYunSmsProperties getAliYun() { + return aliYun; + } + + public void setAliYun(AliYunSmsProperties aliYun) { + this.aliYun = aliYun; + } } /** @@ -231,4 +242,75 @@ public void setTemplateId(String templateId) { this.templateId = templateId; } } + + /** + * aliYun sms properties + */ + public static class AliYunSmsProperties { + + /** + * Aliyun account access key id + */ + private String secretId; + + /** + * Ali Cloud account access key + */ + private String secretKey; + + /** + * SMS app id + */ + private String appId; + + /** + * SMS signature + */ + private String signName; + + /** + * ID of the SMS template + */ + private String templateId; + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getSecretId() { + return secretId; + } + + public void setSecretId(String secretId) { + this.secretId = secretId; + } + + public String getSecretKey() { + return secretKey; + } + + public void setSecretKey(String secretKey) { + this.secretKey = secretKey; + } + + public String getSignName() { + return signName; + } + + public void setSignName(String signName) { + this.signName = signName; + } + + public String getTemplateId() { + return templateId; + } + + public void setTemplateId(String templateId) { + this.templateId = templateId; + } + } } diff --git a/common/src/main/java/org/apache/hertzbeat/common/service/AliYunSmsClient.java b/common/src/main/java/org/apache/hertzbeat/common/service/AliYunSmsClient.java new file mode 100644 index 00000000000..161dcec32be --- /dev/null +++ b/common/src/main/java/org/apache/hertzbeat/common/service/AliYunSmsClient.java @@ -0,0 +1,119 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hertzbeat.common.service; + +import com.aliyun.dysmsapi20170525.models.SendSmsResponse; +import com.tencentcloudapi.common.Credential; +import com.tencentcloudapi.sms.v20210111.SmsClient; +import com.tencentcloudapi.sms.v20210111.models.SendSmsRequest; +import lombok.extern.slf4j.Slf4j; +import org.apache.hertzbeat.common.config.CommonProperties; +import org.apache.hertzbeat.common.support.exception.SendMessageException; +import org.apache.hertzbeat.common.util.AliYunSendSmsUtil; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.HashMap; +import java.util.Map; + +/** + * sms service client for aliyun cloud + */ +@Component +@ConditionalOnProperty("common.sms.aliyun.app-id") +@Slf4j +public class AliYunSmsClient { + + private static final String RESPONSE_OK = "OK"; + private static final String REGION = "ap-guangzhou"; + + private SmsClient smsClient; + private String appId; + private String signName; + private String templateId; + private String secretId; + private String secretKey; + + public AliYunSmsClient(CommonProperties properties) { + if (properties == null || properties.getSms() == null || properties.getSms().getTencent() == null) { + log.error("init error, please config TencentSmsClient props in application.yml"); + throw new IllegalArgumentException("please config TencentSmsClient props"); + } + initSmsClient(properties.getSms().getAliYun()); + } + + private void initSmsClient(CommonProperties.AliYunSmsProperties tencent) { + this.appId = tencent.getAppId(); + this.signName = tencent.getSignName(); + this.templateId = tencent.getTemplateId(); + this.secretId = tencent.getSecretId(); + this.secretKey = tencent.getSecretKey(); + Credential cred = new Credential(tencent.getSecretId(), tencent.getSecretKey()); + smsClient = new SmsClient(cred, REGION); + } + + /** + * Alibaba cloud sends SMS messages + * @param appId appId + * @param signName sign name + * @param templateId template id + * @param templateValues template values + * @param phones phones num + */ + public void sendMessage(String appId, String signName, String templateId, String secretId, String secretKey, + String[] templateValues, String[] phones){ + + LocalDateTime dateTime = LocalDateTime.now(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + SendSmsRequest req = new SendSmsRequest(); + req.setSmsSdkAppId(appId); + req.setSignName(signName); + req.setTemplateId(templateId); + req.setTemplateParamSet(templateValues); + req.setPhoneNumberSet(phones); + try { + Map param = new HashMap<>(); + // taskName: monitoring name, alert: alarm level, message: alarm content, sysTime:system time + param.put("taskName", templateValues[0]); + param.put("alert", templateValues[1]); + param.put("message", templateValues[2]); + param.put("sysTime", dateTime.format(formatter)); + SendSmsResponse smsResponse = AliYunSendSmsUtil.send(param, signName, templateId, phones[0], secretId, secretKey); + String code = smsResponse.body.code; + if (!RESPONSE_OK.equals(code)) { + throw new SendMessageException(code + ":" + smsResponse.body.message); + } + } catch (Exception e) { + log.warn(e.getMessage()); + throw new SendMessageException(e.getMessage()); + } + } + + /** + * Send a text message + * @param templateValues template values + * @param phones phones num + */ + public void sendMessage(String[] templateValues, String[] phones) { + sendMessage(this.appId, this.signName, this.templateId, this.secretId, this.secretKey, templateValues, phones); + } + + +} diff --git a/common/src/main/java/org/apache/hertzbeat/common/util/AliYunSendSmsUtil.java b/common/src/main/java/org/apache/hertzbeat/common/util/AliYunSendSmsUtil.java new file mode 100644 index 00000000000..fe718cb00c8 --- /dev/null +++ b/common/src/main/java/org/apache/hertzbeat/common/util/AliYunSendSmsUtil.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hertzbeat.common.util; + +import com.aliyun.dysmsapi20170525.models.SendSmsRequest; +import com.aliyun.dysmsapi20170525.models.SendSmsResponse; +import com.aliyun.teaopenapi.models.Config; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.Map; + +/** + * Alibaba cloud send SMS util + */ +public class AliYunSendSmsUtil { + + public static com.aliyun.dysmsapi20170525.Client createClient(String accessKeyId, String accessKeySecret) throws Exception { + Config config = new Config(); + config.accessKeyId = accessKeyId; + config.accessKeySecret = accessKeySecret; + return new com.aliyun.dysmsapi20170525.Client(config); + } + + /** + * Method for sending SMS messages: Enter the map format + */ + public static SendSmsResponse send(Map map, String singName, String templateCode, String phone, String accessKeyId, String accessKeySecret) throws Exception { + com.aliyun.dysmsapi20170525.Client client = AliYunSendSmsUtil.createClient(accessKeyId, accessKeySecret); + SendSmsRequest sendReq = new SendSmsRequest() + .setPhoneNumbers(phone)//The phone number that received the text message + .setSignName(singName)//SMS signature + .setTemplateCode(templateCode)//SMS Template Code + .setTemplateParam(new ObjectMapper().writeValueAsString(map)); //The actual value of the SMS template variable + SendSmsResponse sendResp = client.sendSms(sendReq); + return sendResp; + + } +} \ No newline at end of file diff --git a/manager/src/main/java/org/apache/hertzbeat/manager/component/alerter/impl/AliYunAlertNotifyHandlerImpl.java b/manager/src/main/java/org/apache/hertzbeat/manager/component/alerter/impl/AliYunAlertNotifyHandlerImpl.java new file mode 100644 index 00000000000..af4a82ce678 --- /dev/null +++ b/manager/src/main/java/org/apache/hertzbeat/manager/component/alerter/impl/AliYunAlertNotifyHandlerImpl.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hertzbeat.manager.component.alerter.impl; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.hertzbeat.common.constants.CommonConstants; +import org.apache.hertzbeat.common.entity.alerter.Alert; +import org.apache.hertzbeat.common.entity.manager.NoticeReceiver; +import org.apache.hertzbeat.common.entity.manager.NoticeTemplate; +import org.apache.hertzbeat.common.service.AliYunSmsClient; +import org.apache.hertzbeat.common.util.ResourceBundleUtil; +import org.apache.hertzbeat.manager.support.exception.AlertNoticeException; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.stereotype.Component; + +import java.util.ResourceBundle; + +/** + * Send alarm information through Alibaba Cloud SMS + */ +@Component +@RequiredArgsConstructor +@Slf4j +@ConditionalOnProperty("common.sms.aliyun.app-id") +final class AliYunAlertNotifyHandlerImpl extends AbstractAlertNotifyHandlerImpl { + + private final AliYunSmsClient aliYunSmsClient; + + private final ResourceBundle bundle = ResourceBundleUtil.getBundle("alerter"); + + @Override + public void send(NoticeReceiver receiver, NoticeTemplate noticeTemplate, Alert alert) { + // SMS notification + try { + String monitorName = null; + if (alert.getTags() != null) { + monitorName = alert.getTags().get(CommonConstants.TAG_MONITOR_NAME); + } + String[] params = new String[3]; + params[0] = monitorName == null ? alert.getTarget() : monitorName; + params[1] = bundle.getString("alerter.priority." + alert.getPriority()); + params[2] = alert.getContent(); + aliYunSmsClient.sendMessage(params, new String[]{receiver.getPhone()}); + } catch (Exception e) { + throw new AlertNoticeException("[Sms Notify Error] " + e.getMessage()); + } + } + + @Override + public byte type() { + return 0; + } +} diff --git a/pom.xml b/pom.xml index 7c762d01b04..a9501972479 100644 --- a/pom.xml +++ b/pom.xml @@ -112,6 +112,7 @@ 32.1.2-jre 3.19.6 3.1.648 + 2.0.24 2.9.3 4.5.14 @@ -340,6 +341,11 @@ tencentcloud-sdk-java-sms ${tencentcloud-sdk-java-sms.version} + + com.aliyun + dysmsapi20170525 + ${aliYun-sdk-java-sms.version} + com.squareup.okhttp3