一、简要说明

        在当今数字化时代,手机验证码作为一种普遍的身份验证手段,保障了用户账户安全。像阿里云、腾讯云、华为云短信服务等第三方服务简化了与运营商的对接过程,通过提供API接口,允许开发者轻松地集成短信发送功能。然而,这些服务通常不是免费的。在本例中,我们将专注于如何利用设计模式中的模板方法模式,以统一和定制化的方式实现与阿里云短信服务的集成,确保系统的灵活性和可扩展性。

二、使用操作

①阿里云操作:

1.打开阿里云网址https://www.aliyun.com/,进行登录(刚使用aliyun的可以注册一个)

2.点击右上角的控制台,在搜索框输入“短信服务”,来到概览界面(我之前买过短信,所以会有相应的数据,一开始数量都是为0的):

3.在左侧栏选择“国内消息”,点击“添加签名”,对里面的信息进行填写(若没有资质需要添加一个,需要上传身份证等信息,审核时长大约1小时):

注:审核状态必须为通过才可以。

4.点击“模板管理”,来到“添加模板”,再对里面的信息进行填写(关联签名可为你刚刚添加的签名模板;可根据常用模板推荐选择合适的模板内容;手机验证码一般都是数字所以我这里选择的比那辆属性是仅数字):

5.添加后,也是需要等待审核成功才行。审核成功后后有一个模板CODE,这个必须要记下来,后面写程序会用到:

6.点击上面的“费用”,为了测试只充值1元即可:

7.搜索栏输入“RAM访问控制”,然后左侧栏点击“用户”,并创建用户:

注:一定要勾选OpenAPI调用访问!

8.用户创建成功后,会有一个AccessKeyIDAccessKeySecret,这两个值也必须保存下来。建议把这两个值放在一个文件上,因为界面关闭后AccessKeySecret不再出现。

9.点击“添加权限”,添加:

  • AliyunRDSFullAccess (管理云数据库服务(RDS)的权限)
  • AliyunOSSReadOnlyAccess (只读访问对象存储服务(OSS)的权限)

②程序操作:

1.pom.xml导入相关依赖:

<!--短信验证码(阿里云)-->
    <dependency>
      <groupId>com.aliyun</groupId>
      <artifactId>aliyun-java-sdk-core</artifactId>
      <version>4.1.0</version>
    </dependency>

    <!--JSON-->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>fastjson</artifactId>
      <version>1.2.45</version>
    </dependency>

模板方法模式:定义一个操作中算法的框架,而将一些步骤延迟到子类中。模板方法模式使得子类不改变一个算法的结构即可重定义该算法的某些特定步骤。

模板方法模式的实现:

  • 模板方法 (Template Method)
  • 基本方法 (Primitive Method)

2.创建模板方法:

import java.util.HashMap;
import java.util.Map;

public abstract class SendValidateCodeTemplate {
    protected static Map<String, Object> map = new HashMap<>();
    public abstract void init();
    public abstract Map<String, Object> send(String value);
    public Map<String, Object> getMap() {
        return map;
    }
}

3.创建基本方法(目前只用一个阿里云,也可以用腾讯云、华为云方法去继承SendValidateCodeTemplate):

import com.alibaba.fastjson.JSONObject;
import com.aliyun.oss.ClientException;
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 java.util.Map;
import java.util.Random;

public class SendValidateCodeAliyun extends SendValidateCodeTemplate{
    @Override
    public void init() {
        // 生成随机4位验证码
        Random random = new Random();
        StringBuilder code = new StringBuilder();
        for (int i = 0; i < 4; i++) {
            code.append(random.nextInt(10)); // 生成0-9之间的随机数
        }

        map.put("code", code.toString());
    }

    @Override
    public Map<String, Object> send(String value) {
        DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou",
                "/*你的Access Key Id*/", "/*你的Access Secret*/");
        IAcsClient client = new DefaultAcsClient(profile);

        CommonRequest request = new CommonRequest();

        request.setMethod(MethodType.POST);
        request.setDomain("dysmsapi.aliyuncs.com");
        request.setVersion("2017-05-25");
        request.setAction("SendSms");
        request.putQueryParameter("PhoneNumbers",value );
        request.putQueryParameter("SignName", "/*你的签名名称*/");
        request.putQueryParameter("TemplateCode", "/*你的模板Code*/");
        init();
        System.out.println(map.get("code"));
        request.putQueryParameter("TemplateParam", JSONObject.toJSONString(map));

        try {
            CommonResponse response = client.getCommonResponse(request);
            System.out.println(response.getData());
        } catch (ClientException | com.aliyuncs.exceptions.ClientException e) {
            e.printStackTrace();
        }
        return map;
    }
}
public class SendValidateCodeFactory {
    public static SendValidateCodeTemplate createSendValidateCodeTemplate(String type) {
        if ("aliyun".equalsIgnoreCase(type)) {
            return new SendValidateCodeAliyun();
        }else if ("tengxunyun".equalsIgnoreCase(type)){
            return new SendValidateCodeTengxunyun();//SendValidateCodeTengxunyun()没写
        }
         //else if ......
        else {
            throw new IllegalArgumentException("Invalid type: " + type);
        }
    }
}

4.写控制类去测试,这里顺便写一个注册方法(我这里用postman):

注:有关userService的根据用户名查询信息、注册方法省略。

//发送验证码
    @PostMapping("/send")
    public Result send(String value){
        if (value.equals("/*你自己注册的手机号码*/")){
            SendValidateCodeFactory.createSendValidateCodeTemplate("aliyun")
                    .send(value);
        }
        return Result.success();
    }
@PostMapping("/register")
    public Result register(@Pattern(regexp ="^\\S{5,16}$" ) String username, @Pattern(regexp ="^\\S{5,16}$" ) String password,String validate
    ) {
            //先查,没有就注册

        User u = userService.findByUserName(username);
            if (u == null && validate.equals(SendValidateCodeFactory.createSendValidateCodeTemplate("aliyun").getMap().get("code"))) {
                System.out.println(SendValidateCodeFactory.createSendValidateCodeTemplate("aliyun").getMap().get("code"));
                userService.register(username, password);
                return Result.success();
            } else {
                return Result.error("用户名已被占用或验证码有误");
            }
    }

 

//统一响应结果
@NoArgsConstructor
@AllArgsConstructor
@Data
public class Result<T> {
    private Integer code;//业务状态码  0-成功  1-失败
    private String message;//提示信息
    private T data;//响应数据

    //快速返回操作成功响应结果(带响应数据)
    public static <E> Result<E> success(E data) {
        return new Result<>(0, "操作成功", data);
    }

    //快速返回操作成功响应结果
    public static Result success() {
        return new Result(0, "操作成功", null);
    }

    public static Result error(String message) {
        return new Result(1, message, null);
    }
}

5.测试:

发送验证码:

先输入一个错误的验证码:

再输入一个正确的,查看数据库是否添加上去(密码已经过md5加密了):

到此,整个阿里云手机验证码注册的教程已结束!

Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐