优化短信通知,增加阿里云短信通知
This commit is contained in:
parent
0fa4e606a5
commit
011f56a7ce
|
|
@ -17,6 +17,12 @@
|
|||
<artifactId>hsweb-easy-orm-rdb</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.aliyun</groupId>
|
||||
<artifactId>aliyun-java-sdk-core</artifactId>
|
||||
<version>4.5.2</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hswebframework.web</groupId>
|
||||
<artifactId>hsweb-starter</artifactId>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package org.jetlinks.community.notify.sms.provider;
|
||||
package org.jetlinks.community.notify.sms;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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<PlainTextSmsTemplate> impl
|
|||
@Nonnull
|
||||
@Override
|
||||
public Mono<Void> 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<PlainTextSmsTemplate> impl
|
|||
|
||||
@Override
|
||||
public String getNotifierId() {
|
||||
return "test-sms-notify";
|
||||
return "test-sms-sender";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -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<AliyunSmsTemplate> {
|
||||
|
||||
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<String, Object> 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<Void> send(@Nonnull AliyunSmsTemplate template, @Nonnull Values context) {
|
||||
|
||||
return Mono.<Void>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<Void> close() {
|
||||
return Mono.fromRunnable(client::shutdown);
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
/**
|
||||
* 阿里云短信通知服务
|
||||
* </a>
|
||||
*
|
||||
* @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<AliyunSmsTemplate> 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<AliyunSmsNotifier> createNotifier(@Nonnull NotifierProperties properties) {
|
||||
return Mono.fromSupplier(() -> new AliyunSmsNotifier(properties, templateManager));
|
||||
}
|
||||
}
|
||||
|
|
@ -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<String, String> param;
|
||||
|
||||
public String createTtsParam(Map<String, Object> ctx) {
|
||||
|
||||
return JSON.toJSONString(ctx);
|
||||
}
|
||||
}
|
||||
|
|
@ -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<Hy2046SmsSender> 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<PlainTextSmsTemplate> {
|
||||
|
||||
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<Void> close() {
|
||||
return Mono.empty();
|
||||
}
|
||||
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Mono<Void> 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<String, String> 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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue