参考文档

短信服务首页:https://help.aliyun.com/product/44282.html?spm=a2c4g.11174283.6.540.76d22c429dLh6Q

阿里云短信服务文档使用指引:https://help.aliyun.com/document_detail/59210.html?spm=a2c4g.11174283.4.1.76d22c429dLh6Q

安装Java SDK:https://help.aliyun.com/document_detail/112148.html?spm=a2c4g.11186623.6.646.73df50a4ldAjRC

API自动生成:https://api.aliyun.com/?spm=a2c4g.11186623.2.17.5dac60e2EGbsmB#/?product=Dysmsapi&lang=JAVA

使用指南

使用“阿里云短信服务文档使用指引”文档做好准备工作后,再使用“API自动生成”生成相应的API就可用使用了。

对于频繁使用的测试手机号码,可用设置白名单:https://dysms.console.aliyun.com/dysms.htm?spm=5176.12818093.recent.ddysms.488716d0UWJE0c#/system/setting/safe

 短信发送(SendSms)开发代码

使用此代码的时候,直接复制WxLoginSendMessageImpl(微信登录的短信验证码)类,然后修改信息即可。

请求信息类,用来请求短信发送(SendSms)接口的返回json。

import lombok.Builder;
import lombok.Data;

import java.io.Serializable;

/**
 * 短信验证码的code
 *
 * @author shuaige.zheng
 */
@Builder
@Data
public class SmsTemplateParam implements Serializable {

    private static final long serialVersionUID = 7693125133210884584L;
    /**
     * 验证码code
     */
    private String code;

}

返回信息类,用来接收请求短信发送(SendSms)接口的返回json。

import lombok.Data;

@Data
public class SmsDataModel {
    /**
     * 状态码的描述
     */
    private String message;
    /**
     * 请求状态码
     */
    private String code;
    /**
     * 发送id
     */
    private String requestId;
    /**
     * 发送回执ID,可根据该ID在接口QuerySendDetails中查询具体的发送状态。
     */
    private String bizId;
}

保存日志的po

import lombok.Data;
import tk.mybatis.mapper.annotation.KeySql;

import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.Table;
import java.io.Serializable;
import java.time.LocalDateTime;

/**
 * @author shuaige
 */
@Data
@Table(name = "push_short_message_log")
public class PushShortMessageLogDO implements Serializable {
    private static final long serialVersionUID = -70489226920770339L;
    /**
     * 主键
     */
    @Id
    @Column(name = "`id`")
    @KeySql(useGeneratedKeys = true)
    private Long id;

    /**
     * 1 发送微信小程序登录码
     */
    private Integer sendType;

    /**
     * 用户id
     */
    private Long userId;

    /**
     * 状态码的描述
     */
    private String message;

    /**
     * 发送id
     */
    private String requestId;

    /**
     * 发送回执id,可根据该id在接口querysenddetails中查询具体的发送状态。
     */
    private String bizId;

    /**
     * 请求状态码
     */
    private String code;

    /**
     * 创建时间
     */
    private LocalDateTime createTime;

}

日志mapper

import com.anchi.car.coresystem.consumer.dao.entity.PushShortMessageLogDO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Component;

import java.util.Map;

@Component
@Mapper
public interface PushShortMessageLogMapper extends tk.mybatis.mapper.common.Mapper<PushShortMessageLogDO> {

}

请求方法

  /**
     * 发送短信
     *
     * @param phoneNumbers  接收短信的手机号码。
     *                      格式:
     *                      <p>
     *                      国内短信:11位手机号码,例如15951955195。
     *                      国际/港澳台消息:国际区号+号码,例如85200000000。
     *                      支持对多个手机号码发送短信,手机号码之间以英文逗号(,)分隔。上限为1000个手机号码。批量调用相对于单条调用及时性稍有延迟。
     * @param signName      短信签名名称。
     * @param templateCode  短信模板ID。
     * @param templateParam 短信模板变量对应的实际值,JSON格式
     * @return
     */
    public SmsDataModel sendSms(String phoneNumbers, String signName, String templateCode, String templateParam) {
        DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", "LTAI21dsfiHfTI", "zoasdFsdfsdsdfsgpfUQzQjbx2");
        IAcsClient client = new DefaultAcsClient(profile);
        CommonRequest request = new CommonRequest();
        request.setMethod(MethodType.POST);
        request.setDomain("dysmsapi.aliyuncs.com");
        request.setVersion("2017-05-25");
        // 调用SendSms发送短信。
        request.setAction("SendSms");
        request.putQueryParameter("RegionId", "cn-hangzhou");
        request.putQueryParameter("PhoneNumbers", phoneNumbers);
        request.putQueryParameter("SignName", signName);
        request.putQueryParameter("TemplateCode", templateCode);
        request.putQueryParameter("TemplateParam", templateParam);
        try {
            CommonResponse response = client.getCommonResponse(request);
            String data = response.getData();
            if (StringUtils.isNotBlank(data)) {
                SmsDataModel smsDataModel = JSON.parseObject(data, SmsDataModel.class);
                if (smsDataModel != null && "OK".equalsIgnoreCase(smsDataModel.getCode())) {
                    logger.info("send success");
                    return smsDataModel;
                }
            }
        } catch (ClientException e) {
            logger.error("sms response error", e);
        }
        return null;
    }

构建发送短信的模板基础类

import com.anchi.car.coresystem.consumer.dao.entity.PushShortMessageLogDO;
import com.anchi.car.coresystem.consumer.dao.mapper.PushShortMessageLogMapper;
import com.anchi.car.coresystem.consumer.service.shortmessage.aliyun.SmsDataModel;
import com.anchi.car.coresystem.consumer.service.shortmessage.aliyun.SmsFactory;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Service
@Data
public abstract class AbstractSendMessage<T> {

    @Autowired
    private SmsFactory smsFactory;
    @Resource
    private PushShortMessageLogMapper pushShortMessageLogMapper;

    /**
     * 中文签名
     */
    protected static final String ZH_CN_SIGN_NAME = "常州安驰汽车租赁有限公司";
    /**
     * 英文签名
     */
    protected static final String EN_SIGN_NAME = "AmyExpress";

    /**
     * 获取模板参数
     */
    abstract String getTemplateParam(T templateParam);

    /**
     * 获取模板编号
     */
    abstract String getTemplateCode();

    /**
     * 获取模板签名
     *
     * @param isabroad 是否国外
     */
    private String getSignName(boolean isabroad) {
        if (isabroad) {
            return EN_SIGN_NAME;
        } else {
            return ZH_CN_SIGN_NAME;
        }
    }

    /**
     * 模板
     *
     * @param phones        接收短信的手机号码。
     *                      格式:
     *                      <p>
     *                      国内短信:11位手机号码,例如15951955195。
     *                      国际/港澳台消息:国际区号+号码,例如85200000000。
     *                      支持对多个手机号码发送短信,手机号码之间以英文逗号(,)分隔。上限为1000个手机号码。批量调用相对于单条调用及时性稍有延迟。
     * @param isabroad      是否国外
     * @param templateParam 短信模板变量对应的实际值,JSON格式
     * @param sendType      1 登录 2 注册
     */
    public boolean sendMessage(String phones, boolean isabroad, T templateParam, int sendType, long userId) {
        // 发送短信
        SmsDataModel smsDataModel = smsFactory.sendSms(phones, getSignName(isabroad), getTemplateCode(), getTemplateParam(templateParam));
        if (smsDataModel != null) {
            // 记录发送记录
            PushShortMessageLogDO messageLog = new PushShortMessageLogDO();
            messageLog.setSendType(sendType);
            messageLog.setUserId(userId);
            messageLog.setMessage(smsDataModel.getMessage());
            messageLog.setRequestId(smsDataModel.getRequestId());
            messageLog.setBizId(smsDataModel.getBizId());
            messageLog.setCode(smsDataModel.getCode());
            pushShortMessageLogMapper.insertSelective(messageLog);
            return true;
        }
        return false;
    }

}

微信登录的短信验证码

import com.alibaba.fastjson.JSON;
import org.springframework.stereotype.Service;

/**
 * 微信登录的短信模板
 *
 * @author shaoshuai.zheng
 */
@Service
public class WxLoginSendMessageImpl extends AbstractSendMessage<String> {

    @Override
    String getTemplateParam(String code) {
        // 构建参数
        SmsTemplateParam build = SmsTemplateParam
                .builder()
                .code(code)
                .build();
        // 返回
        return JSON.toJSONString(build);
    }

    @Override
    String getTemplateCode() {
        return "SMS_153915225";
    }

}

发送代码

// 发送验证码
boolean sendMessage = wxLoginSendMessage.sendMessage("13212345678,12012345678", false, "1234",1, 120);