diff --git a/jetlinks-components/notify-component/notify-sms/pom.xml b/jetlinks-components/notify-component/notify-sms/pom.xml
index 02ffeaa9..f416b7c5 100644
--- a/jetlinks-components/notify-component/notify-sms/pom.xml
+++ b/jetlinks-components/notify-component/notify-sms/pom.xml
@@ -17,6 +17,12 @@
hsweb-easy-orm-rdb
+
+ com.aliyun
+ aliyun-java-sdk-core
+ 4.5.2
+
+
org.hswebframework.web
hsweb-starter
diff --git a/jetlinks-components/notify-component/notify-sms/src/main/java/org/jetlinks/community/notify/sms/provider/PlainTextSmsTemplate.java b/jetlinks-components/notify-component/notify-sms/src/main/java/org/jetlinks/community/notify/sms/PlainTextSmsTemplate.java
similarity index 96%
rename from jetlinks-components/notify-component/notify-sms/src/main/java/org/jetlinks/community/notify/sms/provider/PlainTextSmsTemplate.java
rename to jetlinks-components/notify-component/notify-sms/src/main/java/org/jetlinks/community/notify/sms/PlainTextSmsTemplate.java
index bd78c1dd..9f9e20b1 100644
--- a/jetlinks-components/notify-component/notify-sms/src/main/java/org/jetlinks/community/notify/sms/provider/PlainTextSmsTemplate.java
+++ b/jetlinks-components/notify-component/notify-sms/src/main/java/org/jetlinks/community/notify/sms/PlainTextSmsTemplate.java
@@ -1,4 +1,4 @@
-package org.jetlinks.community.notify.sms.provider;
+package org.jetlinks.community.notify.sms;
import lombok.Getter;
import lombok.Setter;
diff --git a/jetlinks-components/notify-component/notify-sms/src/main/java/org/jetlinks/community/notify/sms/SmsProvider.java b/jetlinks-components/notify-component/notify-sms/src/main/java/org/jetlinks/community/notify/sms/SmsProvider.java
new file mode 100644
index 00000000..41f89cea
--- /dev/null
+++ b/jetlinks-components/notify-component/notify-sms/src/main/java/org/jetlinks/community/notify/sms/SmsProvider.java
@@ -0,0 +1,20 @@
+package org.jetlinks.community.notify.sms;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import org.jetlinks.community.notify.Provider;
+
+@Getter
+@AllArgsConstructor
+public enum SmsProvider implements Provider {
+
+ aliyunSms("阿里云短信服务")
+ ;
+ private final String name;
+
+ @Override
+ public String getId() {
+ return name();
+ }
+
+}
diff --git a/jetlinks-components/notify-component/notify-sms/src/main/java/org/jetlinks/community/notify/sms/provider/TestSmsProvider.java b/jetlinks-components/notify-component/notify-sms/src/main/java/org/jetlinks/community/notify/sms/TestSmsProvider.java
similarity index 89%
rename from jetlinks-components/notify-component/notify-sms/src/main/java/org/jetlinks/community/notify/sms/provider/TestSmsProvider.java
rename to jetlinks-components/notify-component/notify-sms/src/main/java/org/jetlinks/community/notify/sms/TestSmsProvider.java
index 48348e57..c51dffed 100644
--- a/jetlinks-components/notify-component/notify-sms/src/main/java/org/jetlinks/community/notify/sms/provider/TestSmsProvider.java
+++ b/jetlinks-components/notify-component/notify-sms/src/main/java/org/jetlinks/community/notify/sms/TestSmsProvider.java
@@ -1,10 +1,10 @@
-package org.jetlinks.community.notify.sms.provider;
+package org.jetlinks.community.notify.sms;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
+import org.jetlinks.community.notify.*;
import org.jetlinks.core.Values;
import org.jetlinks.core.metadata.ConfigMetadata;
-import org.jetlinks.community.notify.*;
import org.jetlinks.community.notify.template.Template;
import org.jetlinks.community.notify.template.TemplateManager;
import org.jetlinks.community.notify.template.TemplateProperties;
@@ -54,7 +54,7 @@ public class TestSmsProvider extends AbstractNotifier impl
@Nonnull
@Override
public Mono send(@Nonnull PlainTextSmsTemplate template, @Nonnull Values context) {
- return Mono.fromRunnable(() -> log.info("send sms [{}] message:{}", template.getSendTo(context.getAllValues()), template.getTextSms(context.getAllValues())));
+ return Mono.fromRunnable(() -> log.info("send sms {} message:{}", template.getSendTo(context.getAllValues()), template.getTextSms(context.getAllValues())));
}
@Nonnull
@@ -71,7 +71,7 @@ public class TestSmsProvider extends AbstractNotifier impl
@Override
public String getNotifierId() {
- return "test-sms-notify";
+ return "test-sms-sender";
}
@Override
diff --git a/jetlinks-components/notify-component/notify-sms/src/main/java/org/jetlinks/community/notify/sms/aliyun/AliyunSmsNotifier.java b/jetlinks-components/notify-component/notify-sms/src/main/java/org/jetlinks/community/notify/sms/aliyun/AliyunSmsNotifier.java
new file mode 100644
index 00000000..74da0174
--- /dev/null
+++ b/jetlinks-components/notify-component/notify-sms/src/main/java/org/jetlinks/community/notify/sms/aliyun/AliyunSmsNotifier.java
@@ -0,0 +1,115 @@
+package org.jetlinks.community.notify.sms.aliyun;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.aliyuncs.CommonRequest;
+import com.aliyuncs.CommonResponse;
+import com.aliyuncs.DefaultAcsClient;
+import com.aliyuncs.IAcsClient;
+import com.aliyuncs.http.MethodType;
+import com.aliyuncs.profile.DefaultProfile;
+import com.aliyuncs.profile.IClientProfile;
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
+import org.hswebframework.web.exception.BusinessException;
+import org.hswebframework.web.logger.ReactiveLogger;
+import org.jetlinks.community.notify.*;
+import org.jetlinks.community.notify.sms.SmsProvider;
+import org.jetlinks.core.Values;
+import org.jetlinks.community.notify.template.TemplateManager;
+import reactor.core.publisher.Mono;
+import reactor.core.scheduler.Schedulers;
+
+import javax.annotation.Nonnull;
+import java.util.Map;
+import java.util.Objects;
+
+@Slf4j
+public class AliyunSmsNotifier extends AbstractNotifier {
+
+ private final IAcsClient client;
+ private final int connectTimeout = 1000;
+ private final int readTimeout = 5000;
+
+ @Getter
+ private String notifierId;
+
+ private String domain = "dysmsapi.aliyuncs.com";
+ private String regionId = "cn-hangzhou";
+
+ public AliyunSmsNotifier(NotifierProperties profile, TemplateManager templateManager) {
+ super(templateManager);
+ Map config = profile.getConfiguration();
+ DefaultProfile defaultProfile = DefaultProfile.getProfile(
+ this.regionId = (String) Objects.requireNonNull(config.get("regionId"), "regionId不能为空"),
+ (String) Objects.requireNonNull(config.get("accessKeyId"), "accessKeyId不能为空"),
+ (String) Objects.requireNonNull(config.get("secret"), "secret不能为空")
+ );
+ this.client = new DefaultAcsClient(defaultProfile);
+ this.domain = (String) config.getOrDefault("domain", domain);
+ this.notifierId = profile.getId();
+ }
+
+ public AliyunSmsNotifier(IClientProfile profile, TemplateManager templateManager) {
+ this(new DefaultAcsClient(profile), templateManager);
+ }
+
+ public AliyunSmsNotifier(IAcsClient client, TemplateManager templateManager) {
+ super(templateManager);
+ this.client = client;
+ }
+
+ @Override
+ @Nonnull
+ public NotifyType getType() {
+ return DefaultNotifyType.sms;
+ }
+
+ @Nonnull
+ @Override
+ public Provider getProvider() {
+ return SmsProvider.aliyunSms;
+ }
+
+ @Override
+ @Nonnull
+ public Mono send(@Nonnull AliyunSmsTemplate template, @Nonnull Values context) {
+
+ return Mono.defer(() -> {
+ try {
+ CommonRequest request = new CommonRequest();
+ request.setSysMethod(MethodType.POST);
+ request.setSysDomain(domain);
+ request.setSysVersion("2017-05-25");
+ request.setSysAction("SendSms");
+ request.setSysConnectTimeout(connectTimeout);
+ request.setSysReadTimeout(readTimeout);
+ request.putQueryParameter("RegionId", regionId);
+ request.putQueryParameter("PhoneNumbers", template.getPhoneNumber());
+ request.putQueryParameter("SignName", template.getSignName());
+ request.putQueryParameter("TemplateCode", template.getCode());
+ request.putQueryParameter("TemplateParam", template.createTtsParam(context.getAllValues()));
+
+ CommonResponse response = client.getCommonResponse(request);
+
+ log.info("发送短信通知完成 {}:{}", response.getHttpResponse().getStatus(), response.getData());
+
+ JSONObject json = JSON.parseObject(response.getData());
+ if (!"ok".equalsIgnoreCase(json.getString("Code"))) {
+ return Mono.error(new BusinessException(json.getString("Message"), json.getString("Code")));
+ }
+ } catch (Exception e) {
+ return Mono.error(e);
+ }
+ return Mono.empty();
+ }).doOnEach(ReactiveLogger.onError(err -> {
+ log.info("发送短信通知失败", err);
+ })).subscribeOn(Schedulers.elastic());
+ }
+
+ @Override
+ @Nonnull
+ public Mono close() {
+ return Mono.fromRunnable(client::shutdown);
+ }
+}
diff --git a/jetlinks-components/notify-component/notify-sms/src/main/java/org/jetlinks/community/notify/sms/aliyun/AliyunSmsNotifierProvider.java b/jetlinks-components/notify-component/notify-sms/src/main/java/org/jetlinks/community/notify/sms/aliyun/AliyunSmsNotifierProvider.java
new file mode 100644
index 00000000..6dea3459
--- /dev/null
+++ b/jetlinks-components/notify-component/notify-sms/src/main/java/org/jetlinks/community/notify/sms/aliyun/AliyunSmsNotifierProvider.java
@@ -0,0 +1,78 @@
+package org.jetlinks.community.notify.sms.aliyun;
+
+import com.alibaba.fastjson.JSON;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.hswebframework.web.validator.ValidatorUtils;
+import org.jetlinks.community.notify.*;
+import org.jetlinks.community.notify.sms.SmsProvider;
+import org.jetlinks.core.metadata.ConfigMetadata;
+import org.jetlinks.core.metadata.DefaultConfigMetadata;
+import org.jetlinks.core.metadata.types.StringType;
+import org.jetlinks.community.notify.template.TemplateManager;
+import org.jetlinks.community.notify.template.TemplateProperties;
+import org.jetlinks.community.notify.template.TemplateProvider;
+import org.springframework.stereotype.Component;
+import reactor.core.publisher.Mono;
+
+import javax.annotation.Nonnull;
+
+/**
+ * 阿里云短信通知服务
+ *
+ *
+ * @author zhouhao
+ * @since 1.3
+ */
+@Component
+@Slf4j
+@AllArgsConstructor
+public class AliyunSmsNotifierProvider implements NotifierProvider, TemplateProvider {
+
+ private final TemplateManager templateManager;
+
+ @Nonnull
+ @Override
+ public Provider getProvider() {
+ return SmsProvider.aliyunSms;
+ }
+
+ public static final DefaultConfigMetadata templateConfig = new DefaultConfigMetadata("阿里云短信模版",
+ "https://help.aliyun.com/document_detail/108086.html")
+ .add("signName", "签名", "", new StringType())
+ .add("code", "模版编码", "", new StringType())
+ .add("phoneNumber", "收信人", "", new StringType());
+
+ public static final DefaultConfigMetadata notifierConfig = new DefaultConfigMetadata("阿里云API配置"
+ ,"https://help.aliyun.com/document_detail/101300.html")
+ .add("regionId", "regionId", "regionId", new StringType())
+ .add("accessKeyId", "accessKeyId", "", new StringType())
+ .add("secret", "secret", "", new StringType());
+
+ @Override
+ public ConfigMetadata getTemplateConfigMetadata() {
+ return templateConfig;
+ }
+
+ @Override
+ public ConfigMetadata getNotifierConfigMetadata() {
+ return notifierConfig;
+ }
+
+ @Override
+ public Mono createTemplate(TemplateProperties properties) {
+ return Mono.fromCallable(() -> ValidatorUtils.tryValidate(JSON.parseObject(properties.getTemplate(), AliyunSmsTemplate.class)));
+ }
+
+ @Nonnull
+ @Override
+ public NotifyType getType() {
+ return DefaultNotifyType.sms;
+ }
+
+ @Nonnull
+ @Override
+ public Mono createNotifier(@Nonnull NotifierProperties properties) {
+ return Mono.fromSupplier(() -> new AliyunSmsNotifier(properties, templateManager));
+ }
+}
diff --git a/jetlinks-components/notify-component/notify-sms/src/main/java/org/jetlinks/community/notify/sms/aliyun/AliyunSmsTemplate.java b/jetlinks-components/notify-component/notify-sms/src/main/java/org/jetlinks/community/notify/sms/aliyun/AliyunSmsTemplate.java
new file mode 100644
index 00000000..8c3e0646
--- /dev/null
+++ b/jetlinks-components/notify-component/notify-sms/src/main/java/org/jetlinks/community/notify/sms/aliyun/AliyunSmsTemplate.java
@@ -0,0 +1,37 @@
+package org.jetlinks.community.notify.sms.aliyun;
+
+import com.alibaba.fastjson.JSON;
+import lombok.Getter;
+import lombok.Setter;
+import org.jetlinks.community.notify.template.Template;
+
+import javax.validation.constraints.NotBlank;
+import java.util.Map;
+
+/**
+ * 阿里云短信模版
+ *
+ * @since 1.3
+ */
+@Getter
+@Setter
+public class AliyunSmsTemplate implements Template {
+
+ //签名名称
+ @NotBlank(message = "[signName]不能为空")
+ private String signName;
+
+ //模版编码
+ @NotBlank(message = "[code]不能为空")
+ private String code;
+
+ @NotBlank(message = "[phoneNumber]不能为空")
+ private String phoneNumber;
+
+ private Map param;
+
+ public String createTtsParam(Map ctx) {
+
+ return JSON.toJSONString(ctx);
+ }
+}
diff --git a/jetlinks-components/notify-component/notify-sms/src/main/java/org/jetlinks/community/notify/sms/provider/Hy2046SmsSenderProvider.java b/jetlinks-components/notify-component/notify-sms/src/main/java/org/jetlinks/community/notify/sms/provider/Hy2046SmsSenderProvider.java
deleted file mode 100644
index a468c3e7..00000000
--- a/jetlinks-components/notify-component/notify-sms/src/main/java/org/jetlinks/community/notify/sms/provider/Hy2046SmsSenderProvider.java
+++ /dev/null
@@ -1,172 +0,0 @@
-package org.jetlinks.community.notify.sms.provider;
-
-import com.alibaba.fastjson.JSON;
-import lombok.Getter;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.codec.digest.DigestUtils;
-import org.jetlinks.core.Values;
-import org.jetlinks.core.metadata.ConfigMetadata;
-import org.jetlinks.core.metadata.DefaultConfigMetadata;
-import org.jetlinks.core.metadata.types.PasswordType;
-import org.jetlinks.core.metadata.types.StringType;
-import org.jetlinks.community.notify.*;
-import org.jetlinks.community.notify.template.Template;
-import org.jetlinks.community.notify.template.TemplateManager;
-import org.jetlinks.community.notify.template.TemplateProperties;
-import org.jetlinks.community.notify.template.TemplateProvider;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.context.annotation.Profile;
-import org.springframework.http.MediaType;
-import org.springframework.stereotype.Component;
-import org.springframework.util.Assert;
-import org.springframework.util.LinkedMultiValueMap;
-import org.springframework.util.MultiValueMap;
-import org.springframework.web.reactive.function.BodyInserters;
-import org.springframework.web.reactive.function.client.WebClient;
-import reactor.core.publisher.Mono;
-
-import javax.annotation.Nonnull;
-import java.time.LocalDateTime;
-import java.time.format.DateTimeFormatter;
-import java.util.Map;
-
-@Component
-@Slf4j
-@Profile({"dev","test"})
-public class Hy2046SmsSenderProvider implements NotifierProvider, TemplateProvider, Provider {
-
-
- private WebClient webClient = WebClient.builder()
- .baseUrl("http://sms10692.com/v2sms.aspx")
- .build();
-
- @Autowired
- private TemplateManager templateManager;
-
- @Nonnull
- @Override
- public NotifyType getType() {
- return DefaultNotifyType.sms;
- }
-
- @Nonnull
- @Override
- public Provider getProvider() {
- return this;
- }
-
- static DefaultConfigMetadata notifierConfig = new DefaultConfigMetadata("宏衍2046短信配置", "")
- .add("userId", "userId", "用户ID", new StringType())
- .add("username", "用户名", "用户名", new StringType())
- .add("password", "密码", "密码", new PasswordType());
-
- @Override
- public ConfigMetadata getNotifierConfigMetadata() {
- return notifierConfig;
- }
-
- @Override
- public ConfigMetadata getTemplateConfigMetadata() {
- return PlainTextSmsTemplate.templateConfig;
- }
-
- @Override
- public Mono extends Template> createTemplate(TemplateProperties properties) {
- return Mono.fromSupplier(() -> JSON.parseObject(properties.getTemplate(), PlainTextSmsTemplate.class));
- }
-
- @Nonnull
- @Override
- public Mono createNotifier(@Nonnull NotifierProperties properties) {
- return Mono.defer(() -> {
- String userId = (String) properties.getConfigOrNull("userId");
- String username = (String) properties.getConfigOrNull("username");
- String password = (String) properties.getConfigOrNull("password");
- Assert.hasText(userId, "短信配置错误,缺少userId");
- Assert.hasText(username, "短信配置错误,缺少username");
- Assert.hasText(password, "短信配置错误,缺少password");
- return Mono.just(new Hy2046SmsSender(properties.getId(),userId, username, password));
- });
- }
-
- @Override
- public String getId() {
- return "hy2046";
- }
-
- @Override
- public String getName() {
- return "宏衍2046";
- }
-
- class Hy2046SmsSender extends AbstractNotifier {
-
- String userId;
- String username;
- String password;
- @Getter
- private final String notifierId;
-
- public Hy2046SmsSender(String id,String userId, String username, String password) {
- super(templateManager);
- this.userId = userId;
- this.notifierId = id;
- this.username = username;
- this.password = password;
- }
-
- @Nonnull
- @Override
- public NotifyType getType() {
- return DefaultNotifyType.sms;
- }
-
- @Nonnull
- @Override
- public Provider getProvider() {
- return Hy2046SmsSenderProvider.this;
- }
-
- @Nonnull
- @Override
- public Mono close() {
- return Mono.empty();
- }
-
-
- @Nonnull
- @Override
- public Mono send(@Nonnull PlainTextSmsTemplate template, @Nonnull Values context) {
- return Mono.defer(() -> {
- String ts = DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(LocalDateTime.now());
- String sign = DigestUtils.md5Hex(username.concat(password).concat(ts));
- String[] sendTo = template.getSendTo(context.getAllValues());
-
- String mobile = String.join(",", sendTo);
- MultiValueMap formData = new LinkedMultiValueMap<>();
- formData.add("userid", userId);
- formData.add("timestamp", ts);
- formData.add("sign", sign);
- formData.add("mobile", mobile);
- formData.add("content", template.getTextSms(context.getAllValues()));
- formData.add("action", "send");
- formData.add("rt", "json");
-
- return webClient.post()
- .contentType(MediaType.APPLICATION_FORM_URLENCODED)
- .body(BodyInserters.fromFormData(formData))
- .retrieve()
- .bodyToMono(Map.class)
- .map(map -> {
- if (Integer.valueOf(sendTo.length).equals(map.get("SuccessCounts"))) {
- return true;
- }
- throw new RuntimeException("发送短信失败:" + map.get("Message"));
- });
-
- }).then();
- }
-
- }
-}
-