短信发送项目

前提:在阿里云或腾讯云购买短信,填写相关信息,准备好模板参数等等。

思路:将需要发送的短信保存到数据库,短信发送项目从数据库获取需要发送的短信,用线程的形式,循环读取数据库内容并发送,读取一次睡眠3秒,也就是每3秒执行一次。

可能用到的mysql的表:

待发送短信列表 message

CREATE TABLE `message` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
  `message_type` tinyint unsigned NOT NULL COMMENT '类型 1验证码 2通知',
  `send_platform` tinyint unsigned NOT NULL COMMENT '发送平台 1阿里云 2 阿里云批量 3腾讯云',
  `sign_name` varchar(256) NOT NULL COMMENT '短信签名',
  `template_code` varchar(225) NOT NULL COMMENT '短信模板编码',
  `template_params` varchar(256) NOT NULL COMMENT '短信模板参数',
  `tels` varchar(1100) NOT NULL COMMENT '手机号码,多个用,隔开,腾讯的前面加+86',
  `template_content` varchar(256) NOT NULL COMMENT '短信模板内容',
  `gmt_create` datetime NOT NULL COMMENT '创建时间',
  `status` tinyint unsigned NOT NULL COMMENT '发送状态 0待发 1发送中 2已发',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=93 DEFAULT CHARSET=utf8 COMMENT='待发送短信列表';

示例
在这里插入图片描述

已发送短信列表 message_sent

CREATE TABLE `message_sent` (
  `id` bigint unsigned NOT NULL COMMENT 'id',
  `message_type` tinyint unsigned NOT NULL COMMENT '类型 1验证码 2通知',
  `send_platform` tinyint unsigned NOT NULL COMMENT '发送平台 1阿里云 2 阿里云批量 3腾讯云',
  `sign_name` varchar(256) NOT NULL COMMENT '短信签名',
  `template_code` varchar(225) NOT NULL COMMENT '短信模板编码',
  `template_params` varchar(256) NOT NULL COMMENT '短信模板参数',
  `tels` varchar(1100) NOT NULL COMMENT '手机号码,多个用,隔开,腾讯的前面加+86',
  `template_content` varchar(256) NOT NULL COMMENT '短信模板内容',
  `request_id` varchar(225) DEFAULT NULL COMMENT '返回msgId',
  `status` tinyint unsigned NOT NULL COMMENT '发送结果 0待定 1成功 2失败',
  `gmt_create` datetime NOT NULL COMMENT '创建时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='已发送短信列表';

短信模板 message_template

CREATE TABLE `message_template` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
  `message_key` varchar(256) DEFAULT NULL COMMENT '短信key',
  `message_name` varchar(256) DEFAULT NULL COMMENT '短信名称',
  `platform` tinyint unsigned NOT NULL COMMENT '短信平台 1阿里云 3腾讯云',
  `is_enable` tinyint unsigned NOT NULL DEFAULT '1' COMMENT '启用状态,0停用 1启用',
  `sign_name` varchar(256) NOT NULL COMMENT '短信签名',
  `template_code` varchar(225) NOT NULL COMMENT '短信模板编码',
  `template_content` varchar(256) NOT NULL COMMENT '短信模板内容',
  `gmt_create` datetime NOT NULL COMMENT '创建时间',
  `creator` varchar(16) DEFAULT NULL COMMENT '创建人',
  `gmt_modified` datetime DEFAULT NULL COMMENT '更新时间',
  `modifier` varchar(16) DEFAULT NULL COMMENT '更新人',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 COMMENT='短信模板';

示例:
在这里插入图片描述

搭建项目

idea新建maven项目,去除其他目录结构。如下图:
在这里插入图片描述

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>com.uwa.srm</groupId>
    <artifactId>srm-sms-task</artifactId>
    <description>这里集成短信发送</description>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.17</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.49</version>
        </dependency>

        <!--  阿里云短信  -->
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>aliyun-java-sdk-core</artifactId>
            <version>4.5.3</version>
        </dependency>

        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>aliyun-java-sdk-dysmsapi</artifactId>
            <version>1.1.0</version>
        </dependency>

        <!--  腾讯云短信  -->
        <dependency>
            <groupId>com.tencentcloudapi</groupId>
            <artifactId>tencentcloud-sdk-java</artifactId>
            <version>3.1.62</version><!-- 注:这里只是示例版本号,请获取并替换为 最新的版本号 -->
        </dependency>


    </dependencies>

    <build>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <configuration>
                    <archive>
                        <manifest>
                            <mainClass>com.uwa.srm.task.SrmSmsTask</mainClass>
                        </manifest>
                    </archive>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                </configuration>
                <executions>
                    <execution>
                        <id>make-assembly</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

核心代码

AliSmsConfig.java

/**
 * 阿里云短信发送--配置
 */
public class AliSmsConfig {

    public static String ACCESS_KEY_ID = "xxxx";
    public static String ACCESS_KEY_SECRET = "xxxxx";
}

AliSmsUtil.java


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.dysmsapi.model.v20170525.SendBatchSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendBatchSmsResponse;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.uwa.srm.task.message.Message;

/**
 * 阿里云短信发送
 */
public class AliSmsUtil {

    public static final String CODE_SUCCESS = "OK";

    //产品名称:云通信短信API产品,开发者无需替换
    static final String product = "Dysmsapi";
    //产品域名,开发者无需替换
    static final String domain = "dysmsapi.aliyuncs.com";


    /*
    *--返回代码
        {
            "Message":"OK",
                "RequestId":"2184201F-BFB3-446B-B1F2-C746B7BF0657",
                "BizId":"197703245997295588^0",
                "Code":"OK"
        }*/
    public static SendSmsResponse sendSms(Message msg) throws ClientException {

        //可自助调整超时时间
        System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
        System.setProperty("sun.net.client.defaultReadTimeout", "10000");

        //初始化acsClient,暂不支持region化
        IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", AliSmsConfig.ACCESS_KEY_ID, AliSmsConfig.ACCESS_KEY_SECRET);
        DefaultProfile.addEndpoint("cn-hangzhou", product, domain);
        IAcsClient acsClient = new DefaultAcsClient(profile);

        //组装请求对象-具体描述见控制台-文档部分内容
        SendSmsRequest request = new SendSmsRequest();
        //必填:待发送手机号
        request.setPhoneNumbers(msg.getTels());
        //必填:短信签名-可在短信控制台中找到
        request.setSignName(msg.getSignName());
        //必填:短信模板-可在短信控制台中找到
        request.setTemplateCode(msg.getTemplateCode());
        //模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为"{\"name\":\"Tom\", \"code\":\"123\"}"
        request.setTemplateParam(msg.getTemplateParams());

        //hint 此处可能会抛出异常,注意catch
        SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);

        return sendSmsResponse;
    }

    public static SendBatchSmsResponse SendBatchSms(Message msg) throws ClientException {

        //可自助调整超时时间
        System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
        System.setProperty("sun.net.client.defaultReadTimeout", "10000");

        //初始化acsClient,暂不支持region化
        IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", AliSmsConfig.ACCESS_KEY_ID, AliSmsConfig.ACCESS_KEY_SECRET);
        DefaultProfile.addEndpoint("cn-hangzhou", product, domain);
        IAcsClient acsClient = new DefaultAcsClient(profile);

        //组装请求对象
        SendBatchSmsRequest request = new SendBatchSmsRequest();
        //使用post提交
        //必填:待发送手机号。支持JSON格式的批量调用,批量上限为100个手机号码,批量调用相对于单条调用及时性稍有延迟,验证码类型的短信推荐使用单条调用的方式
        //"[\"1500000000\",\"1500000001\"]"
        request.setPhoneNumberJson(JSONObject.toJSONString(msg.getTels().split(",")));
        //必填:短信签名-支持不同的号码发送不同的短信签名
        //"[\"云通信\",\"云通信\"]"
        request.setSignNameJson(JSONObject.toJSONString(msg.getSignName().split(",")));
        //必填:短信模板-可在短信控制台中找到
        request.setTemplateCode(msg.getTemplateCode());
        //必填:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为
        //友情提示:如果JSON中需要带换行符,请参照标准的JSON协议对换行符的要求,比如短信内容中包含\r\n的情况在JSON中需要表示成\\r\\n,否则会导致JSON在服务端解析失败
        //"[{\"name\":\"Tom\", \"code\":\"123\"},{\"name\":\"Jack\", \"code\":\"456\"}]"
        request.setTemplateParamJson(msg.getTemplateParams());
        //可选-上行短信扩展码(扩展码字段控制在7位或以下,无特殊需求用户请忽略此字段)
        //request.setSmsUpExtendCodeJson("[\"90997\",\"90998\"]");
        //请求失败这里会抛ClientException异常
        SendBatchSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);

        return sendSmsResponse;
    }
}

MessageSent.java


import java.sql.Timestamp;
import java.io.Serializable;


public class MessageSent implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * id
     */
    private Long id;

    /**
     * 类型 1验证码 2通知
     */
    private Integer messageType;

    /**
     * 发送平台 1阿里云 2腾讯云
     */
    private Integer sendPlatform;

    /**
     * 短信签名
     */
    private String signName;

    /**
     * 短信模板编码
     */
    private String templateCode;

    /**
     * 短信模板参数
     */
    private String templateParams;

    /**
     * 手机号码,多个用,隔开
     */
    private String tels;

    /**
     * 短信模板内容
     */
    private String templateContent;

    /**
     * 返回msgId
     */
    private String requestId;

    /**
     * 发送结果 0待定 1成功 2失败
     */
    private Integer status;

    /**
     * 创建时间
     */
    private Timestamp gmtCreate;
    //......
 }

SendScheduler.java


import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.dysmsapi.model.v20170525.SendBatchSmsResponse;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.tencentcloudapi.sms.v20190711.models.SendStatus;
import com.uwa.srm.task.config.Conn;
import com.uwa.srm.task.dysmsapi.AliSmsUtil;
import com.uwa.srm.task.tencentapi.TencentSmsUtil;
import jdk.nashorn.internal.runtime.logging.Logger;

import java.sql.Connection;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@Logger
public class SendScheduler extends Thread {

    protected final ThreadPoolExecutor executor;
    protected transient boolean alive = true;
    private MessageRepository msgRep;
    private Connection conn;

    public SendScheduler() {
        executor = new ThreadPoolExecutor(10, 50, 30, TimeUnit.SECONDS,
                new LinkedBlockingQueue<Runnable>());
        msgRep = new MessageRepository();
        conn = Conn.getConn();
    }

    public void halt() {
        alive = false;
        try {
            executor.shutdownNow();
        } finally {
            this.interrupt();
        }

    }

    @Override
    public void run() {
        while (alive) {
            List<Message> list = msgRep.getUnredMessage(conn);

            if (list != null && list.size() > 0) {
                Runner runner = new Runner(list);
                executor.submit(runner);
            }
            try {
                sleep(3000);
            } catch (InterruptedException e) {
                alive = false;
                break;
            }
        }
    }

    protected class Runner implements Runnable {
        protected List<Message> list;

        public Runner(List<Message> list) {
            this.list = list;
        }

        public void send(Message msg) {
            int status = 2;
            String requestId = "";
            try {

                //判断平台
                if (msg.getSendPlatform() == 1) {
                    SendSmsResponse response = AliSmsUtil.sendSms(msg);
                    System.out.println("阿里云-发送短信返回值:" + JSONObject.toJSONString(response));
                    if (response != null) {
                        requestId = response.getRequestId();
                        if (AliSmsUtil.CODE_SUCCESS.equals(response.getCode())) {
                            //成功
                            status = 1;
                        } else {
                            //失败
                            status = 2;
                        }
                    } else {
                        //异常其它
                        status = 3;
                    }
                } else if (msg.getSendPlatform() == 2) {
                    SendBatchSmsResponse response = AliSmsUtil.SendBatchSms(msg);
                    System.out.println("阿里云-发送短信返回值:" + JSONObject.toJSONString(response));
                    if (response != null) {
                        requestId = response.getRequestId();
                        if (AliSmsUtil.CODE_SUCCESS.equals(response.getCode())) {
                            //成功
                            status = 1;
                        } else {
                            //失败
                            status = 2;
                        }
                    } else {
                        //异常其它
                        status = 3;
                    }

                } else if (msg.getSendPlatform() == 3) {
                    com.tencentcloudapi.sms.v20190711.models.SendSmsResponse response = TencentSmsUtil.sendSms(msg);
                    System.out.println("腾讯云-发送短信返回值:" + JSONObject.toJSONString(response));
                    if (response != null) {
                        boolean isAllFail = true;
                        requestId = response.getRequestId();
                        for (SendStatus sendStatus : response.getSendStatusSet()) {
                            if (sendStatus != null && TencentSmsUtil.CODE_SUCCESS.equals(sendStatus.getCode())) {
                                isAllFail = false;
                                break;
                            }
                        }
                        if (!isAllFail) {
                            status = 1;
                        } else {
                            status = 2;
                        }
                    } else {
                        //异常其它
                        status = 3;
                    }
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            }

            msg.setStatus(status);
            msg.setRequestId(requestId);


            try {
                msgRep.copyMessage(conn, msg);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }

        public void run() {
            if (list == null || list.size() == 0) {
                return;
            }
            int len = list.size();
            for (int i = 0; i < len; i++) {
                send(list.get(i));
            }
        }
    }

}

TencentSmsConfig.java


import com.aliyuncs.exceptions.ClientException;
import com.tencentcloudapi.sms.v20190711.models.SendSmsResponse;
import com.uwa.srm.task.message.Message;

/**
 * 腾讯云短信发送--配置
 */
public class TencentSmsConfig {

    public static String ACCESS_KEY_ID = "AKIDqSpyAp5gfWCdgXHeBIXVXJcAUYLsPJSM";

    public static String ACCESS_KEY_SECRET = "6zqYI8nv0rX8k9MKRAhaEAuQ8aJmyylI";

    /* 填充请求参数,这里 request 对象的成员变量即对应接口的入参
     * 您可以通过官网接口文档或跳转到 request 对象的定义处查看请求参数的定义
     * 基本类型的设置:
     * 帮助链接:
     * 短信控制台:https://console.cloud.tencent.com/smsv2
     * sms helper:https://cloud.tencent.com/document/product/382/3773 */
    /* 短信应用 ID: 在 [短信控制台] 添加应用后生成的实际 SDKAppID,例如1400006666 */

    public static String APP_ID = "1400475158";

}

TencentSmsUtil.java


import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile;
import com.tencentcloudapi.sms.v20190711.SmsClient;
import com.tencentcloudapi.sms.v20190711.models.SendSmsRequest;
import com.tencentcloudapi.sms.v20190711.models.SendSmsResponse;
import com.uwa.srm.task.message.Message;

/**
 * 腾讯云短信发送
 */
public class TencentSmsUtil {

    public static final String CODE_SUCCESS = "Ok";
    /*
       *--返回代码
        {
            "Response": {
            "SendStatusSet": [
            {
                "SerialNo": "5000:1045710669157053657849499619",
                    "PhoneNumber": "+8618511122233",
                    "Fee": 1,
                    "SessionContext": "test",
                    "Code": "Ok",
                    "Message": "send success",
                    "IsoCode": "CN"
            },
            {
                "SerialNo": "5000:104571066915705365784949619",
                    "PhoneNumber": "+8618511122266",
                    "Fee": 1,
                    "SessionContext": "test",
                    "Code": "Ok",
                    "Message": "send success",
                    "IsoCode": "CN"
            }
        ],
            "RequestId": "a0aabda6-cf91-4f3e-a81f-9198114a2279"
        }
        }*/
    public static SendSmsResponse sendSms(Message msg) throws TencentCloudSDKException {

        Credential cred = new Credential(TencentSmsConfig.ACCESS_KEY_ID, TencentSmsConfig.ACCESS_KEY_SECRET);

        // 实例化一个 http 选项,可选,无特殊需求时可以跳过
        HttpProfile httpProfile = new HttpProfile();

        /* SDK 会自动指定域名,通常无需指定域名,但访问金融区的服务时必须手动指定域名 */
        httpProfile.setEndpoint("sms.tencentcloudapi.com");

        /* 非必要步骤:
         * 实例化一个客户端配置对象,可以指定超时时间等配置 */
        ClientProfile clientProfile = new ClientProfile();
        clientProfile.setSignMethod("HmacSHA256");
        clientProfile.setHttpProfile(httpProfile);

        //地域信息,可以直接填写字符串 ap-guangzhou,或者引用预设的常量
        String region = "ap-guangzhou";

        SmsClient client = new SmsClient(cred, region, clientProfile);

        SendSmsRequest req = new SendSmsRequest();
        req.setSmsSdkAppid(TencentSmsConfig.APP_ID);
        req.setSign(msg.getSignName());
        req.setTemplateID(msg.getTemplateCode());
        /* 下发手机号码,"+8621212313123", "+8612345678902", "+8612345678903"*/
        req.setPhoneNumberSet(msg.getTels().split(","));
        if (msg.getTemplateParams() != null) {
            req.setTemplateParamSet(msg.getTemplateParams().split(","));
        }

        SendSmsResponse sendSmsResponse = client.SendSms(req);


        return sendSmsResponse;

    }

}

SrmSmsTask .java

import com.uwa.srm.task.message.SendScheduler;

public class SrmSmsTask {

    public static void main(String[] args){
        new SendScheduler().start();
    }
}

数据库操作部分自己清楚,项目完成。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值