Spring Boot(十一):整合RabbitMQ消息中間件與阿里雲發送手機驗證碼

上篇博文具體講了RabbitMQ的知識,這篇博文就實際應用一下RabbitMQ,並藉助阿里雲進行發送短信驗證碼的功能。

註冊阿里雲短信服務

如果要使用阿里雲的短信服務,就需要在阿里雲的官網上申請。
首先登錄阿里雲,支付寶或者淘寶登錄即可。

登錄完就是上面這個界面,然後在產品與服務中找到雲通信下面的短信服務。

如果沒有開通,直接點擊開通,因爲博主已經開通了,所以進來就是這個界面。

框框中的東西"簽名管理",“模板管理”,需要根據自己的情況自己申請的,然後等系統通過即可。

當然,阿里雲還提供了發送短信的代碼Demo,這個讀者可以自行查閱。

代碼實現

需求:用戶通過手機號註冊,需要手機發送驗證碼。填寫正確的驗證碼,就可以完成註冊。
此項目還是基於另一篇博文:《SpringBoot中使用RabbitMQ消息中間件
因爲這裏還是要使用消息中間件,所以,先導入Maven依賴。

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>aliyun-java-sdk-core</artifactId>
            <version>4.1.0</version>
        </dependency>

要用到阿里雲,所以也要將依賴導入。

然後修改配置文件。

spring:
  # 配置rabbitmq
  rabbitmq:
    host: 127.0.0.1
    port: 5672
    username: guest
    password: guest


# 阿里雲相關配置
aliyun:
  sms:
    accessKeyId: 
    accessKeySecret: 
    signName1: 
    templateCode1: 

上面是RabbitMQ的配置,下面是阿里雲的配置,accessKeyId和accessKeySecret如圖所示。

通過這裏點進去就能看到。下面兩個自定義配置就是剛纔需要申請的"簽名管理",“模板管理”,只有申請通過之後,才能使用。

創建生產者,發送短信驗證碼。
因爲要與數據庫交互,博主這裏使用了MySQL數據庫,使用JPA來操作,同時這裏還使用了Redis。
如果使用其他數據庫或者其他ORM框架的讀者,需要使用博主的例子修改的話,也沒有什麼影響!

創建一個實體類,User

@Data
@Entity
@Table(name = "qf_user")
@ApiModel(value = "User", description = "用戶")
public class User implements Serializable {

    @Id
    @ApiModelProperty(value = "主鍵")
    private String id;

    @ApiModelProperty(value = "手機")
    private String mobile;

    @ApiModelProperty(value = "密碼")
    private String password;

    @ApiModelProperty(value = "鹽值")
    private String salt;

    @Column(name = "nick_name")
    @ApiModelProperty(value = "暱稱")
    private String nickName;

    @ApiModelProperty(value = "性別")
    private String sex;

    @ApiModelProperty(value = "生日")
    private Date birthday;

    @ApiModelProperty(value = "頭像")
    private String avatar;

    @ApiModelProperty(value = "郵箱")
    private String email;

    @Column(name = "reg_date")
    @ApiModelProperty(value = "註冊日期")
    private Date regDate;

    @Column(name = "update_date")
    @ApiModelProperty(value = "修改日期")
    private Date updateDate;

    @Column(name = "last_date")
    @ApiModelProperty(value = "最後登錄日期")
    private Date lastDate;
}

因爲這是博主項目中的一部分,爲了方便,我就直接拷貝過來了。
關於dao層的部分就不上代碼了,就一個增刪改查而已。下面是service層

@Service
@Slf4j
@Transactional(rollbackFor = Exception.class)
public class UserService {

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Value("${spring.redis.key.mobile}")
    private String verifyCodeKey;

    public void save(User user) {
        user.setRegDate(new Date());
        user.setUpdateDate(new Date());
        user.setLastDate(new Date());
        userRepository.save(user);
    }

    /**
     *發送短信
     */
    public void sendMobileMessage(String mobile) {
        //生成六位隨機數
        String verifyCode = RandomStringUtils.randomNumeric(6);
        //寫入redis緩存
        redisTemplate.opsForValue().set(verifyCodeKey + mobile, verifyCode, 5, TimeUnit.MINUTES);
        //發給用戶
        Map<String, String> stringMap = Maps.newHashMap();
        stringMap.put("mobile", mobile);
        stringMap.put("verifyCode", verifyCode);
        //使用了direct模式
        rabbitTemplate.convertAndSend(RabbitConstant.MOBILE_ROUTING_KEY, stringMap);
        //記錄到日誌中
        boolean enabled = log.isDebugEnabled();
        if (enabled) {
            log.debug("mobile:[{}],verifyCode:[{}]", mobile, verifyCode);
        }
    }

    /**
     *註冊
     */
    public ResultBean register(User user, String code) {
        //判斷redis中是否存在
        String verifyCode = redisTemplate.opsForValue().get(verifyCodeKey + user.getMobile());
        if (StringUtils.isEmpty(verifyCode)) {
            return new ResultBean(new CustomerException("短信驗證碼爲空"), -1);
        }
        if (!verifyCode.equals(code)) {
            return new ResultBean(new CustomerException("驗證碼錯誤!"), 100);
        }
        save(user);
        return new ResultBean();
    }
}

裏面有很多變量,博主都提取出來了,不可能將所有代碼都放入,如果不明白的讀者,可以給博主留言,博主一定會回答。

基本上生產者就完成了。執行上面的代碼,就將驗證碼放入Redis緩存中,將手機號和驗證碼封裝成Map放入消息隊列中,可以作爲一個僞發送短信的功能,只有等到發送短息的服務中的消費者來消費隊列中的消息時,才能真正的發送驗證碼。

接着,將創建消息的消費者。實際上,這裏需要提取出另一個服務,專門發送手機短信的服務。博主這裏將其提取出來並封裝了發送短信的工具類。

/**
 * @ClassName: SmsUtil
 * @Author: 清風一陣吹我心
 * @Description: TODO 阿里雲發送短信驗證碼的工具類
 * @Date: 2019/10/26 13:37
 * @Version 1.0
 **/
@Component
public class SmsUtil {

    private static final String regionId = "cn-hangzhou";

    /**
     * 產品域名
     */
    private static final String DOMAIN = "dysmsapi.aliyuncs.com";
    /**
     * 系統規定參數。取值:SendSms
     */
    private static final String ACTION = "SendSms";

    /**
     * 可以得到當前配置文件中所有的信息
     */
    @Autowired
    private Environment environment;

    /**
     * //TODO
     * 發送短信
     *
     * @param phoneNumbers  手機號
     * @param signName      短信簽名名稱
     * @param templateCode  短信模板ID
     * @param templateParam 參數
     * @return com.aliyuncs.CommonResponse
     */
    public CommonResponse sendSms(String phoneNumbers, String signName, String templateCode, String templateParam) {
        String accessKeyId = environment.getProperty("aliyun.sms.accessKeyId");
        String accessKeySecret = environment.getProperty("aliyun.sms.accessKeySecret");
        //調整超時時間
        System.setProperty("sun.net.client.defaultConnectTimeout", "5000");
        System.setProperty("sun.net.client.defaultReadTimeout", "5000");

        DefaultProfile profile = DefaultProfile.getProfile(regionId, accessKeyId, accessKeySecret);
        IAcsClient client = new DefaultAcsClient(profile);

        CommonRequest request = new CommonRequest();
        request.setMethod(MethodType.POST);
        request.setDomain(DOMAIN);
        request.setVersion("2017-05-25");
        request.setAction(ACTION);
        //待發送手機號
        request.putQueryParameter("PhoneNumbers", phoneNumbers);
        //短信簽名
        request.putQueryParameter("SignName", signName);
        //短信模板Id
        request.putQueryParameter("TemplateCode", templateCode);
        //短信模板變量對應的實際值,JSON格式。如果JSON中需要帶換行符,請參照標準的JSON協議處理。
        request.putQueryParameter("TemplateParam", templateParam);
        //上行短信擴展碼,無特殊需要此字段的用戶請忽略此字段。
        //request.putQueryParameter("SmsUpExtendCode", "0000");
        //外部流水擴展字段
        //request.putQueryParameter("OutId", "0000");

        CommonResponse commonResponse = null;
        try {
            commonResponse = client.getCommonResponse(request);
        } catch (ClientException e) {
            e.printStackTrace();
        }
        return commonResponse;
    }
}

上面的代碼在阿里雲提供的文檔中都有詳細介紹,博主這裏只是做了簡單的修改。
發送短信的工具類完成後,需要用到RabbitMQ了,將消息隊列中的消息消費掉,發送真正的短信到用戶的手機上。

@Slf4j
@Component
@RabbitListener(queues = RabbitConstant.MOBILE_ROUTING_KEY)
public class MobileMessageListener {

    @Autowired
    private SmsUtil smsUtil;

    @Value("${aliyun.sms.signName1}")
    private String signName1;

    @Value("${aliyun.sms.templateCode1}")
    private String templateCode1;

    @RabbitHandler
    public void messageHandler(Map<String, String> map) {
        String mobile = map.get("mobile");
        String verifyCode = map.get("verifyCode");
        boolean debugEnabled = log.isDebugEnabled();
        if (debugEnabled) {
            log.debug("手機號:[{}],驗證碼:[{}]", mobile, verifyCode);
        }
        String templateParam = "{" + "code" + ":" + verifyCode + "}";
        smsUtil.sendSms(mobile, signName1, templateCode1, templateParam);
    }
}

基本上發送短信的功能就完成了,下面就可以啓動服務測試了。

因爲功能並不複雜,通過文檔就能夠實現的。博主這裏只是做一個簡單的講解。

技術之外

昨天博主看騰訊視頻,發現《烈火英雄》可以看了,以前本來想去電影院看的,但是都沒時間去,主要是因爲“一個人不想出去”,emmmm~ 然後博主就借來一個騰訊視頻的會員,把電影看了一遍。基本上,全程都是揪着心看的。覺得這個電影拍的太好了。真的覺得"人名英雄"太偉大了。心中也與那句“此生無悔入華夏,來生願在種花家”,產生了共鳴。

千言萬語都沒有看一遍來的實際,如果有讀者讀到這裏,並且還沒有看過《烈火英雄》的,博主強烈建議大家去看呢,但是,首先要做好心理準備啊。

努力不一定成功,但不努力一定不成功

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章