package cn.itcast.sms;
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.exceptions.ClientException;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
@Component
public class SmsUtil {
//産品名稱:雲通信短信API産品,開發者無需替換
static final String product = "Dysmsapi";
//産品域名,開發者無需替換
static final String domain = "dysmsapi.aliyuncs.com";
@Autowired
private Environment env;
// TODO 此處需要替換成開發者自己的AK(在阿裡雲通路控制台尋找)
public SendSmsResponse sendSms(String mobile,String template_code,String sign_name,String param) throws ClientException {
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(sign_name);
//必填:短信模闆-可在短信控制台中找到
request.setTemplateCode(template_code);
//可選:模闆中的變量替換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 {
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;
}
}
3.2.3消息監聽類
建立SmsListener.java
package cn.itcast.sms; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jms.annotation.JmsListener; import org.springframework.stereotype.Component; import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse; import com.aliyuncs.exceptions.ClientException; @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("template_code"), map.get("sign_name"), map.get("param") ); System.out.println("Code=" + response.getCode()); System.out.println("Message=" + response.getMessage()); System.out.println("RequestId=" + response.getRequestId()); System.out.println("BizId=" + response.getBizId()); } catch (ClientException e) { e.printStackTrace(); } } } |
3.3代碼測試
修改springboot-demo 的QueueController.java
@RequestMapping("/sendsms") public void sendSms(){ Map map=new HashMap<>(); map.put("mobile", "13900001111"); map.put("template_code", "SMS_85735065"); map.put("sign_name", "黑馬"); map.put("param", "{\"number\":\"102931\"}"); jmsMessagingTemplate.convertAndSend("sms",map); } |
啟動itcast_sms
啟動springboot-demo
位址欄輸入:http://localhost:8088/sendsms.do
觀察控制台輸出
随後短信也成功發送到你的手機上
4.使用者注冊
4.1需求分析
完成使用者注冊功能
4.2工程搭建
4.2.1使用者服務接口層
(1)建立pinyougou-user-interface(jar)
(2)引入pojo依賴
4.2.2使用者服務實作層
(1)建立pinyougou-user-service(war)
(2)引入spring dubbox activeMQ相關依賴,引入依賴( pinyougou-user-interface pinyougou-dao pinyougou-common),運作端口為9006
(3)添加web.xml
(4)建立Spring 配置檔案applicationContext-service.xml 和applicationContent-tx.xml
<dubbo:protocol name="dubbo" port="20886" /> <dubbo:annotation package="com.pinyougou.user.service.impl" /> <dubbo:application name="pinyougou-user-service"/> <dubbo:registry address="zookeeper://192.168.25.135:2181"/> |
4.2.3使用者中心WEB層
建立war工程 pinyougou-user-web 我們将注冊功能放入此工程
(1)添加web.xml
(2)引入依賴pinyougou-user-interface 、spring相關依賴(參照其它web工程),tomcat運作端口9106
(3)添加spring配置檔案
(4)拷貝靜态原型頁面register.html 及相關資源
4.3基本注冊功能實作
4.3.2後端服務實作層
修改pinyougou-user-service的UserServiceImpl.java
@Override public void add(TbUser user) { user.setCreated(new Date());//建立日期 user.setUpdated(new Date());//修改日期 String password = DigestUtils.md5Hex(user.getPassword());//對密碼加密 user.setPassword(password); userMapper.insert(user); } |
4.3.3前端控制層
修改userController.js
//控制層 app.controller('userController' ,function($scope,$controller ,userService){ //注冊 $scope.reg=function(){ if($scope.entity.password!=$scope.password) { alert("兩次輸入的密碼不一緻,請重新輸入"); return ; } userService.add( $scope.entity ).success( function(response){ alert(response.message); } ); } }); |
4.3.4修改頁面
修改頁面register.html ,引入js
<script type="text/javascript" src="plugins/angularjs/angular.min.js"></script> <script type="text/javascript" src="js/base.js"></script> <script type="text/javascript" src="js/service/userService.js"></script> <script type="text/javascript" src="js/controller/userController.js"></script> |
指令
<body ng-app="pinyougou" ng-controller="userController" > |
綁定表單
<form class="sui-form form-horizontal"> <div class="control-group"> <label class="control-label">使用者名:</label> <div class="controls"> <input type="text" placeholder="請輸入你的使用者名" ng-model="entity.username" class="input-xfat input-xlarge"> </div> </div> <div class="control-group"> <label for="inputPassword" class="control-label">登入密碼:</label> <div class="controls"> <input type="password" placeholder="設定登入密碼" ng-model="entity.password" class="input-xfat input-xlarge"> </div> </div> <div class="control-group"> <label for="inputPassword" class="control-label">确認密碼:</label> <div class="controls"> <input type="password" placeholder="再次确認密碼" ng-model="password" class="input-xfat input-xlarge"> </div> </div> <div class="control-group"> <label class="control-label">手機号:</label> <div class="controls"> <input type="text" placeholder="請輸入你的手機号" ng-model="entity.phone" class="input-xfat input-xlarge"> </div> </div> <div class="control-group"> <label for="inputPassword" class="control-label">短信驗證碼:</label> <div class="controls"> <input type="text" placeholder="短信驗證碼" class="input-xfat input-xlarge"> <a href="#">擷取短信驗證碼</a> </div> </div> <div class="control-group"> <label for="inputPassword" class="control-label"> </label> <div class="controls"> <input name="m1" type="checkbox" value="2" checked=""><span>同意協定并注冊《品優購使用者協定》</span> </div> </div> <div class="control-group"> <label class="control-label"></label> <div class="controls btn-reg"> <a class="sui-btn btn-block btn-xlarge btn-danger" ng-click="reg()" target="_blank">完成注冊</a> </div> </div> </form> |
4.4 注冊判斷短信驗證碼
4.4.1實作思路
點選頁面上的”擷取短信驗證碼”連接配接,向後端傳遞手機号。後端随機生成6位數字作為短信驗證碼,将其儲存在redis中(手機号作為KEY),并發送到短信網關。
使用者注冊時,後端根據手機号查詢redis中的驗證碼與使用者填寫的驗證碼是否相同,如果不同則提示使用者不能注冊。
4.4.2生成驗證碼
(1)修改pinyougou-user-interface工程UserService.java ,增加方法
public void createSmsCode(String phone); |
(2)修改pinyougou-user-service工程的UserServiceImpl.java
@Autowired private RedisTemplate<String , Object> redisTemplate; public void createSmsCode(String phone){ //生成6位随機數 String code = (long) (Math.random()*1000000)+""; System.out.println("驗證碼:"+code); //存入緩存 redisTemplate.boundHashOps("smscode").put(phone, code); //發送到activeMQ .... } |
(3)在 pinyougou-common 添加工具類PhoneFormatCheckUtils.java,用于驗證手機号
(4)修改pinyougou-user-web的UserController.java
@RequestMapping("/sendCode") public Result sendCode(String phone){ //判斷手機号格式 if(!PhoneFormatCheckUtils.isPhoneLegal(phone)){ return new Result(false, "手機号格式不正确"); } try { userService.createSmsCode(phone);//生成驗證碼 return new Result(true, "驗證碼發送成功"); } catch (Exception e) { e.printStackTrace(); return new Result(true, "驗證碼發送失敗"); } } |
- pinyougou-user-web的userService.js
//發送驗證碼 this.sendCode=function(phone){ return $http.get("../user/sendCode.do?phone="+phone); } |
- pinyougou-user-web的userController.js
//發送驗證碼 $scope.sendCode=function(){ if($scope.entity.phone==null){ alert("請輸入手機号!"); return ; } userService.sendCode($scope.entity.phone).success( function(response){ alert(response.message); } ); } |
- 修改頁面register.html
<a ng-click="sendCode()" >擷取短信驗證碼</a> |
4.4.3使用者注冊判斷驗證碼
(1)修改pinyougou-user-interface的UserService.java
public boolean checkSmsCode(String phone,String code); |
(2)修改pinyougou-user-service的 UserServiceImpl.java
public boolean checkSmsCode(String phone,String code){ //得到緩存中存儲的驗證碼 String sysCode = (String) redisTemplate.boundHashOps("smscode").get(phone); if(sysCode==null){ return false; } if(!sysCode.equals(code)){ return false; } return true; } |
(3)修改pinyougou-user-web的UserController.java
@RequestMapping("/add") public Result add(@RequestBody TbUser user,String smscode){ boolean checkSmsCode = userService.checkSmsCode(user.getPhone(), smscode); if(checkSmsCode==false){ return new Result(false, "驗證碼輸入錯誤!"); } try { userService.add(user); return new Result(true, "增加成功"); } catch (Exception e) { e.printStackTrace(); return new Result(false, "增加失敗"); } } |
- 修改pinyougou-user-web的userService.js
//增加 this.add=function(entity,smscode){ return $http.post('../user/add.do?smscode='+smscode ,entity ); } |
- 修改pinyougou-portal-web 的UserController.java
//儲存 $scope.reg=function(){ userService.add( $scope.entity, $scope.smscode ).success( function(response){ alert(response.message); } ); } |
(6)修改頁面,綁定變量
<input type="text" placeholder="短信驗證碼" ng-model="smscode" class="input-xfat input-xlarge"> <a href="#" ng-click="sendCode()">擷取短信驗證碼</a> |
4.4.4短信驗證碼發送到手機
(1)在pinyougou-user-service添加配置檔案applicationContext-activemq.xml
<!-- 真正可以産生Connection的ConnectionFactory,由對應的 JMS服務廠商提供--> <bean id="targetConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory"> <property name="brokerURL" value="tcp://192.168.25.135:61616"/> </bean> <!-- Spring用于管理真正的ConnectionFactory的ConnectionFactory --> <bean id="connectionFactory" class="org.springframework.jms.connection.SingleConnectionFactory"> <!-- 目标ConnectionFactory對應真實的可以産生JMS Connection的ConnectionFactory --> <property name="targetConnectionFactory" ref="targetConnectionFactory"/> </bean> <!-- Spring提供的JMS工具類,它可以進行消息發送、接收等 --> <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate"> <!-- 這個connectionFactory對應的是我們定義的Spring提供的那個ConnectionFactory對象 --> <property name="connectionFactory" ref="connectionFactory"/> </bean> <!--這個是點對點消息 --> <bean id="smsDestination" class="org.apache.activemq.command.ActiveMQQueue"> <constructor-arg value="sms"/> </bean> |
(2)修改pinyougou-user-service的UserServiceImpl.java
@Autowired private JmsTemplate jmsTemplate; @Autowired private Destination smsDestination; @Value("${template_code}") private String template_code; @Value("${sign_name}") private String sign_name; public void createSmsCode(final String phone){ //生成6位随機數 final String code = (long) (Math.random()*1000000)+""; System.out.println("驗證碼:"+code); //存入緩存 redisTemplate.boundHashOps("smscode").put(phone, code); //發送到activeMQ jmsTemplate.send(smsDestination, new MessageCreator() { @Override public Message createMessage(Session session) throws JMSException { MapMessage mapMessage = session.createMapMessage(); mapMessage.setString("mobile", phone);//手機号 mapMessage.setString("template_code", "SMS_85735065");//模闆編号 mapMessage.setString("sign_name", "黑馬");//簽名 Map m=new HashMap<>(); m.put("number", code); mapMessage.setString("param", JSON.toJSONString(m));//參數 return mapMessage; } }); } |
(3)在pinyougou-common的properties目錄下建立配置檔案sms.properties
template_code=SMS_85735065 sign_name=\u9ED1\u9A6C |