品優購項目記錄:day14

進入目標:

(1)掌握Spring Boot 框架的搭建方法

(2)能夠使用阿里大於發送短信

(3)運用 Spring Boot、阿里大於和ActiveMQ 開發短信微服務

(4)完成品優購用戶註冊功能(短信驗證碼認證)

 

目錄

1、短信微服務

1.1 需求分析

1.2 搭建工程

2、用戶註冊

2.1 需求分析

2.2 工程搭建(參考其他服務層工程和WEB層)

2.3 基本註冊功能實現

2.4 用戶註冊-發送短信驗證碼

2.5 用戶註冊-校驗短信驗證碼


 

1、短信微服務

 

1.1 需求分析

構建一個通用的短信發送服務(獨立於品優購的單獨工程),接收activeMQ的消息(MAP類型)  消息包括手機號(mobile)、短信模板號(template_code)、簽名(sign_name)、參數字符串(param)

 

1.2 搭建工程

(1)創建spring boot工程,並引入相關依賴

<?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.xushuai</groupId>
    <artifactId>sms-service</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.4.0.RELEASE</version>
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-activemq</artifactId>
        </dependency>
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>aliyun-java-sdk-dysmsapi</artifactId>
            <version>1.0.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>aliyun-java-sdk-core</artifactId>
            <version>3.2.5</version>
        </dependency>

    </dependencies>

</project>

(2)創建引導類

package com.xushuai.sms;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * 短信服務 引導類
 * Author xushuai
 * Description
 */
@SpringBootApplication
public class Application {

    public static void main(String[] args){
        SpringApplication.run(Application.class, args);
    }
}

(3)創建配置文件(application.properties),填入accessKey的相關信息

server.port=9003
spring.activemq.broker-url=tcp://192.168.25.170:61616
accessKeyId=accessKeyId
accessKeySecret=accessKeySecret

(4)複製阿里大於的API Demo工程中的SmsDemo,然後進行修改

package com.xushuai.sms.util;

import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.QuerySendDetailsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.QuerySendDetailsResponse;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.dysmsapi.transform.v20170525.SendSmsResponseUnmarshaller;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.http.FormatType;
import com.aliyuncs.http.HttpResponse;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;

/**
 * 短信API產品的DEMO程序,工程中包含了一個SmsDemo類,直接通過
 * 執行main函數即可體驗短信產品API功能(只需要將AK替換成開通了雲通信-短信產品功能的AK即可)
 * 工程依賴了2個jar包(存放在工程的libs目錄下)
 * 1:aliyun-java-sdk-core.jar
 * 2:aliyun-java-sdk-dysmsapi.jar
 *
 * 備註:Demo工程編碼採用UTF-8
 * 國際短信發送請勿參照此DEMO
 */
@Component
public class SmsUtil {

    //產品名稱:雲通信短信API產品,開發者無需替換
    static final String product = "Dysmsapi";
    //產品域名,開發者無需替換
    static final String domain = "dysmsapi.aliyuncs.com";

    // TODO 此處需要替換成開發者自己的AK(在阿里雲訪問控制檯尋找)
    @Autowired
    private Environment env;

    public SendSmsResponse sendSms(String mobile, String templateCode, String signName, String param) throws ClientException {
        // 獲取AK
        String accessKeyId = env.getProperty("accessKeyId");
        String accessKeySecret = env.getProperty("accessKeySecret");
        //可自助調整超時時間
        System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
        System.setProperty("sun.net.client.defaultReadTimeout", "10000");

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

        //組裝請求對象-具體描述見控制檯-文檔部分內容
        SendSmsRequest request = new SendSmsRequest();
        //必填:待發送手機號
        request.setPhoneNumbers(mobile);
        //必填:短信簽名-可在短信控制檯中找到
        request.setSignName(signName);
        //必填:短信模板-可在短信控制檯中找到
        request.setTemplateCode(templateCode);
        //可選:模板中的變量替換JSON串,如模板內容爲"親愛的${name},您的驗證碼爲${code}"時,此處的值爲
        request.setTemplateParam(param);

        //選填-上行短信擴展碼(無特殊需求用戶請忽略此字段)
        //request.setSmsUpExtendCode("90997");

        //可選:outId爲提供給業務方擴展字段,最終在短信回執消息中將此值帶回給調用者
        request.setOutId("yourOutId");

        //hint 此處可能會拋出異常,注意catch
        SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);

        return sendSmsResponse;
    }


    public QuerySendDetailsResponse querySendDetails(String mobile, String bizId) throws ClientException {
        // 獲取AK
        String accessKeyId = env.getProperty("accessKeyId");
        String accessKeySecret = env.getProperty("accessKeySecret");
        //可自助調整超時時間
        System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
        System.setProperty("sun.net.client.defaultReadTimeout", "10000");

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

        //組裝請求對象
        QuerySendDetailsRequest request = new QuerySendDetailsRequest();
        //必填-號碼
        request.setPhoneNumber(mobile);
        //可選-流水號
        request.setBizId(bizId);
        //必填-發送日期 支持30天內記錄查詢,格式yyyyMMdd
        SimpleDateFormat ft = new SimpleDateFormat("yyyyMMdd");
        request.setSendDate(ft.format(new Date()));
        //必填-頁大小
        request.setPageSize(10L);
        //必填-當前頁碼從1開始計數
        request.setCurrentPage(1L);

        //hint 此處可能會拋出異常,注意catch
        QuerySendDetailsResponse querySendDetailsResponse = acsClient.getAcsResponse(request);

        return querySendDetailsResponse;
    }
}

(5)編寫 activeMQ監聽器類

package com.xushuai.sms.listener;

import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
import com.xushuai.sms.util.SmsUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;

import java.util.Map;

/**
 * 發送短信監聽器
 * Author xushuai
 * Description
 */
@Component
public class SmsListener {

    @Autowired
    private SmsUtil smsUtil;

    @JmsListener(destination = "sms")
    public void sendSms(Map<String, String> map) {
        try {
            SendSmsResponse response = smsUtil.sendSms(map.get("mobile"),
                    map.get("templateCode"),
                    map.get("SignName"),
                    map.get("param"));
            System.out.println(response.getCode());
            System.out.println(response.getMessage());
        } catch (ClientException e) {
            e.printStackTrace();
        }
    }
}

 

 

 

 

 

2、用戶註冊

 

2.1 需求分析

完成用戶註冊功能

 

 

2.2 工程搭建(參考其他服務層工程和WEB層)

(1)分別爲:pinyougou-user-interface、pinyougou-user-service和pinyougou-user-web

 

 

 

2.3 基本註冊功能實現

(1)後端:服務層實現,修改UserServicceImpl中的add方法的邏輯

	/**
	 * 增加
	 */
	@Override
	public void add(TbUser user) {
		// 補全數據
		// 創建和更新時間
		user.setCreated(new Date());
		user.setUpdated(new Date());
		// 註冊來源
		user.setSourceType(TbUser.SOURCE_TYPE_PC);
		// 對密碼進行加密
		String md5Hex = DigestUtils.md5Hex(user.getPassword());
		user.setPassword(md5Hex);

		userMapper.insert(user);		
	}

(2)前端:引入JS文件和基礎指令

(3)前端:在userController.js中新增方法

    // 註冊方法
    $scope.reg = function () {
        if ($scope.entity == null || $scope.entity.username == null || $scope.entity.username.trim() == '' ||
            $scope.entity.password == null || $scope.entity.password.trim() == '' || $scope.entity.phone == null ||
            $scope.entity.phone.trim() == '') {
            alert("請完成填寫您的資料");
            return ;
        }

        if ($scope.entity.password != $scope.password) {
            alert("兩次輸入的密碼不一致!");
            return ;
        }
        // alert(JSON.stringify($scope.entity));
        userService.add($scope.entity).success(
            function (rtn) {
                alert(rtn.message);
            }
        );
    }

 

(4)前端:頁面綁定變量和單擊事件

 

 

 

2.4 用戶註冊-發送短信驗證碼

(1)實現思路

點擊頁面上的”獲取短信驗證碼”連接,向後端傳遞手機號。後端隨機生成6位數字作爲短信驗證碼,將其保存在redis中(手機號作爲KEY),併發送到短信網關。

用戶註冊時,後端根據手機號查詢redis中的驗證碼與用戶填寫的驗證碼是否相同,如果不同則提示用戶不能註冊。

 

(2)後端:服務層接口,在UserService中新增方法

	/**
	 * 發送短信驗證碼
	 * 
	 * @param phone 接收驗證碼的手機號
	 */
	void sendSmsCode(String phone);

(3)後端:服務層實現,在UserServiceImpl中實現

    @Override
    public void sendSmsCode(final String phone) {
        // 生成6位數字驗證碼
        final String code = String.valueOf((long) (Math.random() * 1000000));
        // 將驗證碼放入redis緩存,以手機號爲key
        redisTemplate.boundHashOps("smsCode").put(phone, code);
        // 發送短信消息
        System.out.println("驗證碼:" + code);
        jmsTemplate.send(smsDestination, new MessageCreator() {
            @Override
            public Message createMessage(Session session) throws JMSException {
                MapMessage message = session.createMapMessage();
                message.setString("mobile", phone);
                message.setString("templateCode", templateCode);
                message.setString("signName",signName);
                // 設置替換參數
                Map<String, String> map = new HashMap<>();
                map.put("code", code);
                message.setString("param", JSON.toJSONString(map));

                return message;
            }
        });
    }

注意:需要配置常量到properties配置文件

(4)後端:控制層,在UserController中新增方法

    /**
     * 發送短信驗證碼
     */
    @RequestMapping("/sendCode")
    public Result sendCode(String phone) {
        try {
            // 校驗phone是否合法
            if (!PhoneFormatCheckUtils.isPhoneLegal(phone)) {
                return Result.error("手機號格式不正確");
            }
            userService.sendSmsCode(phone);
            return Result.success("發送成功");
        }catch (Exception e){
            e.printStackTrace();
            return Result.error("驗證碼發送異常");
        }
    }

(5)前端:userService.js中新增方法

	// 發送短信驗證碼
	this.sendCode = function (phone) {
		return $http.get('../user/sendCode.do?phone=' + phone);
    }

(6)前端:userController.js新增方法

    // 發送短信驗證碼
    $scope.sendCode = function () {
        if ($scope.entity.phone == null || $scope.entity.phone.trim() == "") {
            alert("請正確填寫手機號!");
            return ;
        }
        userService.sendCode($scope.entity.phone).success(
            function (rtn) {
                alert(rtn.message);
            }
        );
    }

(7)頁面綁定單擊事件

 

 

2.5 用戶註冊-校驗短信驗證碼

(1)後端:服務層接口,UserService中新增方法

    /**
     * 判斷用戶輸入的驗證碼是否正確
     *
     * @param phone 接收短信的手機號
     * @param code  用戶輸入的驗證碼
     * @return boolean
     */
    boolean checkSmsCode(String phone, String code);

(2)後端:服務層實現,UserServiceImpl實現

    @Override
    public boolean checkSmsCode(String phone, String code) {
	    // 通過手機號,從redis中獲取驗證碼
        String smsCode = (String) redisTemplate.boundHashOps("smsCode").get(phone);
        if (smsCode == null || smsCode.trim().equals("")) {
            return false;
        }
        // 判斷驗證碼是否正確
        return code.equals(smsCode);
    }

(3)後端:控制層,修改UserController中的add方法

    /**
     * 增加
     *
     * @param user    用戶資料
     * @param smsCode 驗證碼
     * @return
     */
    @RequestMapping("/add")
    public Result add(@RequestBody TbUser user, String smsCode) {
        try {
            // 校驗短信驗證碼
            if (!userService.checkSmsCode(user.getPhone(), smsCode)) {
                return Result.error("驗證碼錯誤!");
            }
            userService.add(user);
            return new Result(true, "註冊成功");
        } catch (Exception e) {
            e.printStackTrace();
            return new Result(false, "註冊失敗");
        }
    }

(4)前端:修改userService.js中的add方法

	//增加
	this.add=function(entity,smsCode){
		return  $http.post('../user/add.do?smsCode=' + smsCode,entity );
	}

(5)前端:修改userController.js中的reg方法

(6)前端:頁面綁定變量

 

 

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