巴拉巴拉
小魔仙

操碎心的AliyunSMS,短信通知推送

原本一个很简单的短信推送,被自己作死搞的好复杂,不过主要是在加强java的学习和aliyun的一些服务学习吧。

这次也是用了自定义注解,并且利用了fastjson过滤器。

!!!!!!注意注意⚠️,新版阿里云短信mns版本博客已经更新,本博客只做技术分享,如果你是想看阿里云短信相关内容,可以查看

阿里云短信升级篇-mns

这篇博客

如果你是想学习反射,自定义注解,fastjson的过滤器,可以看本文博客。

使用的jar包:

aliyun-java-sdk-core-3.0.8.jar

aliyun-java-sdk-sms-3.0.0-rc1.jar

fastjson-1.2.4.jar

com.againfly.util.aliyun
    ├─annotation
    │   └SmsParame.java             --一个短信注解
    ├─sms
    │   ├filter
    │   │   └SmsParameFilter.java   --fastjson短信模版字段过滤器
    │   │
    │   ├template
    │   │   ├SmsTemplate.java       --模版接口,定义的短信模版需要实现该接口
    │   │   └VerificationTemplate.java--验证码模版
    │   ├SmsResponse.java           --短信推送的返回值
    │   └SmsUtil.java               --外部调用的工具类
    └AliyunConst.java               --阿里云服务配置变量值

 

首先我们要先知道阿里的短信推送,他们需要什么:

  1. 自己在阿里云控制台开通短信推送服务。
  2. 知道自己阿里云的ACCESS_KEY和ACCESS_SECRET
  3. 申请签名
  4. 申请短信模版

只有当签名和短信模版都审核通过后才能使用,短信模版有一个唯一码,SMS_CODE,短信模版当中会设置若干参数,例如${time},${name}。比如我这里的短信模版内容是:

尊敬的${name},您的验证码为:${code},请在${time}内使用。

官方实例很简单,但是也够用了,如果你只是想发送短信,那就直接看官方的文档吧。

本文纯粹是瞎操心,简单的东西复杂化,旨在提高java的了解。

上一篇文章已经说过了自定义注解,对fastjson也做了一个过滤器的说明,如果是想了解fastjson的话可以访问这篇文章

注解代码:里面什么都没有,纯粹只是为了标记某个字段是不是被本注解标记了。

package com.againfly.util.aliyun.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @Target(ElementType.FIELD):该注解只能注解在字段上
 * @Retention(RetentionPolicy.RUNTIME):该注解可以保留到运行期,可以通过反射找到本注解值
 * @Documented:表明这个注解应该被 javadoc工具记录
 * @author Jecced
 * 本注解用在阿里短信模版参数注释,被标记则为模版参数
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SmsParame {
}

fastjson过滤器类:实现了静态内部类的单例模式,以及利用反射,来确定一个字段是否拥有上面的SmsParame注解,如果有则返回true。

package com.againfly.util.aliyun.sms.filter;

import java.lang.reflect.Field;

import com.againfly.util.aliyun.annotation.SmsParame;
import com.alibaba.fastjson.serializer.PropertyFilter;

public class SmsParameFilter implements PropertyFilter{
    private static class SingletonHolder{
        private static final PropertyFilter INSTANCE = new SmsParameFilter();
    }
    
    public static PropertyFilter getInstance(){
        return SingletonHolder.INSTANCE;
    }
    
    @Override
    public boolean apply(Object object, String name, Object value) {
        Class<? extends Object> clazz = object.getClass();
        try {
            Field field = clazz.getDeclaredField(name);
            SmsParame annotation = field.getAnnotation(SmsParame.class);
            if(null != annotation) return true;
        } catch (NoSuchFieldException | SecurityException e) {
            return false;
        }
        return false;
    }

}

短信模版抽象类:具体实现了一个parameJson的方法,并且禁止让子类重写。并且定义了两个方法,分别是获取这个短信模版使用的SMS_CODE和应用签名。这两个基本上在申请短信模版的时候就固定了,所以让子类实现这两个方法,让他们分别返回这两个字段即可。

package com.againfly.util.aliyun.sms.template;

import com.againfly.util.aliyun.sms.filter.SmsParameFilter;
import com.alibaba.fastjson.JSON;

public abstract class SmsTemplate {

    public final String paramJson() {
        return JSON.toJSONString(this, SmsParameFilter.getInstance());
    }
    
    public abstract String getTemplateCode();
    public abstract String getSmsSignName();
}

现在我们申请了一个短信验证码的短信模版:让他继承短信模版抽象类,并实现抽象类中的两个方法。

在这个模版中我们可以定义若干个自定义字段,这些字段分别代表着短信模版中定义的字段名称,并且这些字段是需要使用@SmsParmae注解标注,这些标注可以让抽象类中那个具体实现的方法获取他们,并且返回json字符串。

我申请的短信模版内容是:尊敬的${name},您的验证码为:${code},请在${time}内使用。

所以验证码模版中有name字段,code字段,time字段三个,并且使用了@SmsParmae注解

package com.againfly.util.aliyun.sms.template;

import com.againfly.util.aliyun.annotation.SmsParame;

public class VerificationTemplate extends SmsTemplate{
    
    public static final String SMS_TEMPLATE_CODE = "/****you sms code****/";
    public static final String SMS_SIGN_NAME = "/****you sign name****/";

    @SmsParame
    private String name;

    @SmsParame
    private String code;

    @SmsParame
    private String time;

    public VerificationTemplate(String name, String code) {
        this.name = name;
        this.code = code;
        this.time = "30分钟";
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getTime() {
        return time;
    }

    public void setTime(String time) {
        this.time = time;
    }

    @Override
    public String toString() {
        return "VerificationTemplate [name=" + name + ", code=" + code + ", time=" + time + ", paramJson()="
                + paramJson() + "]";
    }
    
    public static void main(String[] args) {
        SmsTemplate template = new VerificationTemplate("ankaang", "12312");
        System.out.println(template);
    }

    @Override
    public String getTemplateCode() {
        return VerificationTemplate.SMS_TEMPLATE_CODE;
    }

    @Override
    public String getSmsSignName() {
        return VerificationTemplate.SMS_SIGN_NAME;
    }

}

短信内容返回类:

package com.againfly.util.aliyun.sms;

import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.sms.model.v20160927.SingleSendSmsResponse;

public class SmsResponse {
    private boolean success;
    private String requestId;
    private String errCode;
    private String errMsg;
    private String model;

    public SmsResponse(ClientException e) {
        requestId = e.getRequestId();
        errCode = e.getErrCode();
        errMsg = e.getErrMsg();
        success = false;
    }

    public SmsResponse(SingleSendSmsResponse r) {
        requestId = r.getRequestId();
        model = r.getModel();
        success = true;
    }

    /**此处省略get和set方法**/

    @Override
    public String toString() {
        return "SmsResponse [success=" + success + ", requestId=" + requestId + ", errCode=" + errCode + ", errMsg="
                + errMsg + ", model=" + model + "]";
    }

}

真正被外部使用的SMSUtil

package com.againfly.util.aliyun.sms;

import com.againfly.util.aliyun.AliyunConst;
import com.againfly.util.aliyun.sms.template.SmsTemplate;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.exceptions.ServerException;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.aliyuncs.sms.model.v20160927.SingleSendSmsRequest;
import com.aliyuncs.sms.model.v20160927.SingleSendSmsResponse;

public class SmsUtil {

    /**
     * 发送短信
     * @param template 短信模版,模版code,签名,模版参数都在模版中,模版需要继承抽象类:SmsTemplate
     * @param mobile 手机号码,可以是多个手机号码,但是手机号码需要使用英文半角逗号隔开;手机号数量不能超过100,需要控制
     * @author Jecced
     * @return
     */
    public static SmsResponse SendSms(SmsTemplate template, String mobile) {
        IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", AliyunConst.ACCESS_KEY,
                AliyunConst.ACCESS_SECRET);
        try {
            DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", "Sms", "sms.aliyuncs.com");
            IAcsClient client = new DefaultAcsClient(profile);
            SingleSendSmsRequest request = new SingleSendSmsRequest();
            request.setSignName(template.getSmsSignName());
            request.setTemplateCode(template.getTemplateCode());
            request.setParamString(template.paramJson());
            request.setRecNum(mobile);
            SingleSendSmsResponse httpResponse = client.getAcsResponse(request);
            return new SmsResponse(httpResponse);
        } catch (ServerException e) {
            return new SmsResponse(e);
        } catch (ClientException e) {
            return new SmsResponse(e);
        }
    }
}

阿里云服务需要的一些权限KEY存放的静态字段类:

package com.againfly.util.aliyun;

public class AliyunConst {
    public static final String ACCESS_KEY = "/****you access key****/";
    public static final String ACCESS_SECRET = "/****you access secret****/";
}

==============================================

最后当然是要来看使用效果的。。。对吧,这个不能忘。

SmsUtil.SendSms(new VerificationTemplate("ankang", "1212"), "155xxxxxxx");

img_0768

赞(0) 打赏
如果文章对你有帮助,欢迎你来评价反馈。AgainFly » 操碎心的AliyunSMS,短信通知推送
标签:

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
  • Q Q(选填)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏