教你几步实现短信通知

教你几步完成短信通知

前言

Image.png

在日常工作中,我们经常会遇到通知类型的场景,常见的一般为短信通知和邮件通知,这里我们单独将短信通知拎出来跟大家讨论一下。

各个大厂基本都与三大运营商有合作,并拥有自己独立的Sms服务,但是如果我们要集成到我们的系统中,每个厂的代码都不太一样,难不成我们要一个一个的集成进来吗?有没有更简单便捷的方式呢?

答案是有的,接下来就让我给大家介绍一下今天的主角:Sms4j

摘自Sms4j官网: 在日常的开发过程中,短信的发送经常使用(尤其是中小型的外包公司),毕竟不是每个公司都有阿里腾讯一样的实力, 也不是每个都像银行联通等公司一样有内部的短信规程。第三方的短信往往是最常见的解决方案,但是市面上第三方短信服务商众多, 各家都有不同的方式和标准,每次需要使用时候,都需要花费时间去阅读文档和编写相应的工具,为一个短信浪费了太多的精力和时间。 同时我们还兼容了多厂商共用,以及动态配置切换,让您可以方便的使用多个厂商或者更换厂商进行短信发送。

现支持的厂商有:

  • 合一短信
  • 云片短信
  • 天翼云短信
  • 网易云短信
  • 阿里云国内短信
  • 腾讯云国内短信
  • 华为云国内短信
  • 京东云国内短信
  • 容联云国内短信
  • 亿美软通国内短信

配置与使用

引入依赖

首先我们要先引入sms4j的依赖,目前最新版本为2.2.0

1
2
3
4
5
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>

配置

image.png

暂时来说sms4j支持的配置方式有:配置文件、配置类、数据库和Nacos等, 听作者说后续更新配置方式会不太一样,在这里我们先使用yml配置文件来演示,其支持很多厂商,我们在这里使用阿里云的sms服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
sms:
alibaba:
# 阿里云的accessKey
accessKeyId: 您的accessKey
# 阿里云的accessKeySecret
accessKeySecret: 您的accessKeySecret
# 短信签名
signature: 测试签名
# 模板ID 用于发送固定模板短信使用
templateId: 您的模板ID
# 模板变量 上述模板的变量
templateName: code
# 请求地址默认为 dysmsapi.aliyuncs.com 如无特殊改变可以不用设置
requestUrl: dysmsapi.aliyuncs.com
# 接口方法默认为 SendSms 如无特殊改变可以不用设置
action: SendSms
# 接口版本号默认为 2017-05-25 如无特殊改变可以不用设置
version: 2017-05-25
# 地域信息默认为 cn-hangzhou 如无特殊改变可以不用设置
regionId: cn-hangzhou

解读

单租户与多租户

其中我们首先要先通过SmsFactory来创建我们需要的sms服务,在2.2.0版本中支持以多租户的方式来创建,代码如下:

1
2
3
4
5
6
7
/** 获取单租户模式实例*/
private final SmsBlend aliSms = SmsFactory.createSmsBlend(SupplierType.ALIBABA);
/** 获取多租户模式实例
* 如果要获取一个多租户实例,则需要将配置信息传递到第二个参数中,这种情况下,框架将不再持有这个配置对象和所获取的实例对象
* 需要用户自己去持有,单租户和多租户并不冲突,可以同时使用
* */
private final SmsBlend aliSms = SmsFactory.createSmsBlend(SupplierType.ALIBABA,aliConfig);

我们在使用单租户的时候可以直接通过框架内提供的枚举来创建我们需要的sms服务,而在多租户的模式下可以传入枚举和各个租户的单独配置来实现多租户的消息发送。

消息发送

其中框架内提供了多种消息发送的方法,我们来一一解读都是什么样的作用

单发短信

发送固定模板短信

1
SmsResponse sendMessage(String phone,String message);

我们在yml中配置的 templateId 就是用在此处,这里通常用于验证码的发送或只需要传入一个参数的模板,验证码只需要传入一个参数,在该方法中 phone 代表了我们要给谁的手机号发短信,而 message 表示了我们要传入的验证码的值

发送自定义模板短信

1
SmsResponse sendMessage(String phone, String templateId, LinkedHashMap<String,String> messages);

在这里我们将不使用在yml中配置的 templateId 来发消息,而是将传入一个templateId供我们使用,其中 messages 的数据类型为 LinkedHashMap,这个map里存的就是我们模板中的变量,其中变量名为key,变量值为value。例如模板为:

1
2
欢迎你,${name}!
你是今天第${num}位注册的用户

在这个模板中就存在 namenum 两个变量,而我们在使用该模板发消息时,messages 可以存:

1
2
messages.put("name","张三");
messages.put("num","123")

以这种形式来传递参数,并且该方法支持没有模板变量、只有一个模板变量和多个模板变量的形式来发送,当没有模板变量时我们传入一个空的LinkedHashMap即可。

群发短信

群发固定模板短信

1
SmsResponse massTexting(List<String> phones, String message);

其中 phones 为以list形式存储的手机号集合,message为模板变量的值,这里使用的同样是在配置中写的变量名

群发自定义模板短信

1
SmsResponse massTexting(List<String> phones,String templateId, LinkedHashMap<String, String> messages);

这里的说明同上面的发送自定义模板消息,phones 为以list形式存储的手机号集合

异步短信

异步发送固定模板短信

1
void sendMessageAsync(String phone, String message, CallBack callBack);

这里的方法与上述方法略有不同,其中上述返回的SmsResponse 在这里为void,并且多了一个CallBack 函数,该函数用于方法后的回调,可以用于接收发送结果,接收类型为SmsResponse,如果对结果不关心也可以不接收,使用方法如下:

1
aliSms.sendMessageAsync(phone,message, c->log.info(c.toString()));

异步发送自定义模板短信

1
void sendMessageAsync(String phone, String templateId, LinkedHashMap<String,String> messages, CallBack callBack);

参数说明基本同上述的发送自定义模板消息和异步发送固定模板消息,这里不过多赘述

延时短信

延时发送固定模板短信

1
void delayedMessage(String phone ,String message,Long delayedTime);

其中delayedTime 为需要延迟多久发送,单位:毫秒

延时发送自定义模板短信

1
void delayedMessage(String phone ,String templateId, LinkedHashMap<String,String> messages,Long delayedTime);

延时群发固定模板短信

1
void delayMassTexting(List<String> phones, String message,Long delayedTime);

延时群发自定义模板短信

1
void delayMassTexting(List<String> phones,String templateId, LinkedHashMap<String, String> messages,Long delayedTime);

使用

我们配置完成之后,可以先写个示例来测试一下,这里只举例单发消息的情况,关于其他短信可以参考上述解读中的消息发送来编写相关代码。

注意:作者在写本篇文档时使用的是阿里云sms服务测试签名与测试模板,由于测试用的自定义通知模板无法添加模板变量,所以这里作者直接传入了一个空的 LinkedHashMap,各位小伙伴可以根据各自的实际情况来修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import org.dromara.sms4j.api.SmsBlend;
import org.dromara.sms4j.api.entity.SmsResponse;
import org.dromara.sms4j.core.factory.SmsFactory;
import org.dromara.sms4j.provider.enumerate.SupplierType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.LinkedHashMap;

/**
* @author Bummon
* @description Sms短信服务
* @date 2023-07-17 09:05
*/
@RestController
public class SmsController {

private final SmsBlend aliSms = SmsFactory.createSmsBlend(SupplierType.ALIBABA);

@GetMapping("/send")
public SmsResponse send(String phone, String templateId) {
return aliSms.sendMessage(phone, templateId, new LinkedHashMap<>());
}

@GetMapping("/sendByTemplate")
public SmsResponse sendByTemplate(String phone) {
String code = "123456";
return aliSms.sendMessage(phone, code);
}

}

测试

这里我们使用 Postman 来测试,首先是发送固定模板短信

image.png

8b44cf8a8b98c118168d31baff6b96d.png

发送成功,接下来我们来测试一下发送自定义模板短信

image.png

可以看到返回结果中已经发送成功了,接下来我们看下手机是否有相关短信

ba0a84d3c3b6c401c3aae486c47173a.png

也收到了相关短信,表示我们发送成功!

本文结束!