品優(yōu)購(gòu)電商系統(tǒng)開(kāi)發(fā) 第14章 SpringBoot框架與短信解決方案(品優(yōu)購(gòu)前端項(xiàng)目)
課程目標(biāo)
目標(biāo)1:掌握Spring boot框架的搭建方法
目標(biāo)2:能夠使用阿里大于發(fā)送短信
目標(biāo)3:運(yùn)用SpringBoot、阿里大于和ActiveMQ 開(kāi)發(fā)短信微服務(wù)
目標(biāo)4:完成品優(yōu)購(gòu)用戶注冊(cè)功能(短信驗(yàn)證碼認(rèn)證)
1.Spring Boot入門(mén)
1.1什么是Spring Boot
Spring 誕生時(shí)是 java 企業(yè)版(Java Enterprise Edition,JEE,也稱 J2EE)的輕量級(jí)代替品。無(wú)需開(kāi)發(fā)重量級(jí)的 Enterprise JavaBean(EJB),Spring 為企業(yè)級(jí)Java 開(kāi)發(fā)提供了一種相對(duì)簡(jiǎn)單的方法,通過(guò)依賴注入和面向切面編程,用簡(jiǎn)單的Java 對(duì)象(Plain Old Java Object,POJO)實(shí)現(xiàn)了 EJB 的功能。
雖然 Spring 的組件代碼是輕量級(jí)的,但它的配置卻是重量級(jí)的。一開(kāi)始,Spring 用 XML 配置,而且是很多 XML 配置。Spring 2.5 引入了基于注解的組件掃描,這消除了大量針對(duì)應(yīng)用程序自身組件的顯式 XML 配置。Spring 3.0 引入了基于 Java 的配置,這是一種類型安全的可重構(gòu)配置方式,可以代替 XML。所有這些配置都代表了開(kāi)發(fā)時(shí)的損耗。因?yàn)樵谒伎?Spring 特性配置和解決業(yè)務(wù)問(wèn)題之間需要進(jìn)行思維切換,所以寫(xiě)配置擠占了寫(xiě)應(yīng)用程序邏輯的時(shí)間。和所有框架一樣,Spring 實(shí)用,但與此同時(shí)它要求的回報(bào)也不少。
除此之外,項(xiàng)目的依賴管理也是件吃力不討好的事情。決定項(xiàng)目里要用哪些庫(kù)就已經(jīng)夠讓人頭痛的了,你還要知道這些庫(kù)的哪個(gè)版本和其他庫(kù)不會(huì)有沖突,這難題實(shí)在太棘手。并且,依賴管理也是一種損耗,添加依賴不是寫(xiě)應(yīng)用程序代碼。一旦選錯(cuò)了依賴的版本,隨之而來(lái)的不兼容問(wèn)題毫無(wú)疑問(wèn)會(huì)是生產(chǎn)力殺手。
Spring Boot 讓這一切成為了過(guò)去。
Spring Boot 是 Spring 社區(qū)較新的一個(gè)項(xiàng)目。該項(xiàng)目的目的是幫助開(kāi)發(fā)者更容易的創(chuàng)建基于 Spring 的應(yīng)用程序和服務(wù),讓更多人的人更快的對(duì) Spring 進(jìn)行入門(mén)體驗(yàn),為 Spring 生態(tài)系統(tǒng)提供了一種固定的、約定優(yōu)于配置風(fēng)格的框架。
Spring Boot 具有如下特性:
(1)為基于 Spring 的開(kāi)發(fā)提供更快的入門(mén)體驗(yàn)
(2)開(kāi)箱即用,沒(méi)有代碼生成,也無(wú)需 XML 配置。同時(shí)也可以修改默認(rèn)值來(lái)滿足特定的需求。
(3)提供了一些大型項(xiàng)目中常見(jiàn)的非功能性特性,如嵌入式服務(wù)器、安全、指標(biāo),健康檢測(cè)、外部配置等。
(4)Spring Boot 并不是不對(duì) Spring 功能上的增強(qiáng),而是提供了一種快速使用 Spring 的方式。
1.2 Spring Boot入門(mén)小Demo
1.2.1起步依賴
創(chuàng)建Maven工程 springboot_demo(打包方式j(luò)ar)
在pom.xml中添加如下依賴
<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> </dependencies>
我們會(huì)驚奇地發(fā)現(xiàn),我們的工程自動(dòng)添加了好多好多jar包
…
而這些jar包正式我們做開(kāi)發(fā)時(shí)需要導(dǎo)入的jar包。因?yàn)檫@些jar包被我們剛才引入的spring-boot-starter-web所引用了,所以我們引用spring-boot-starter-web后會(huì)自動(dòng)把依賴傳遞過(guò)來(lái)。
1.2.2變更JDK版本
我們發(fā)現(xiàn)默認(rèn)情況下工程的JDK版本是1.6 ,而我們通常用使用1.7的版本,所以我們需要在pom.xml中添加以下配置
<properties> <java.version>1.7</java.version> </properties>
添加后更新工程,會(huì)發(fā)現(xiàn)版本已經(jīng)變更為1.7
1.2.3引導(dǎo)類
只需要?jiǎng)?chuàng)建一個(gè)引導(dǎo)類 .
package cn.itcast.demo;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplicationpublic class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); }}
簡(jiǎn)單解釋一下,@SpringBootApplication其實(shí)就是以下三個(gè)注解的總和
@Configuration: 用于定義一個(gè)配置類
@EnableAutoConfiguration :Spring Boot會(huì)自動(dòng)根據(jù)你jar包的依賴來(lái)自動(dòng)配置項(xiàng)目。
@ComponentScan: 告訴Spring 哪個(gè)packages 的用注解標(biāo)識(shí)的類 會(huì)被spring自動(dòng)掃描并且裝入bean容器。
我們直接執(zhí)行這個(gè)引導(dǎo)類,會(huì)發(fā)現(xiàn)控制臺(tái)出現(xiàn)的這個(gè)標(biāo)識(shí)
你能不能看出來(lái)上邊這個(gè)圖是什么東西?
1.2.4 Spring MVC實(shí)現(xiàn)Hello World輸出
我們現(xiàn)在開(kāi)始使用spring MVC框架,實(shí)現(xiàn)json數(shù)據(jù)的輸出。如果按照我們?cè)瓉?lái)的做法,需要在web.xml中添加一個(gè)DispatcherServlet的配置,再添加一個(gè)spring的配置文件,配置文件中需要添加如下配置
<!– 使用組件掃描,不用將controller在spring中配置 –> <context:component-scan base-package=”cn.itcast.demo.controller” /> <!– 使用注解驅(qū)動(dòng)不用在下邊定義映射器和適配置器 –> <mvc:annotation-driven> <mvc:message-converters register-defaults=”true”> <bean class=”com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter”> <property name=”supportedMediaTypes” value=”application/json”/> <property name=”features”> <array> <value>WriteMapNullValue</value> <value>WriteDateUseDateFormat</value> </array> </property> </bean> </mvc:Message-converters> </mvc:annotation-driven>
但是我們用SpringBoot,這一切都省了。我們直接寫(xiě)Controller類
package cn.itcast.demo.controller;import org.springframework.web.bind.annotation.requestMapping;import org.springframework.web.bind.annotation.RestController;@RestControllerpublic class HelloWorldController { @RequestMapping(“/info”) public String info(){ return “HelloWorld”; } }
我們運(yùn)行啟動(dòng)類來(lái)運(yùn)行程序
在瀏覽器地址欄輸入 http://localhost:8080/info 即可看到運(yùn)行結(jié)果
1.2.5修改tomcat啟動(dòng)端口
在src/main/resources下創(chuàng)建application.properties
server.port=8088
重新運(yùn)行引導(dǎo)類。地址欄輸入
http://localhost:8088/info
1.2.6讀取配置文件信息
在src/main/resources下的application.properties 增加配置
url=http://www.itcast.cn
我要在類中讀取這個(gè)配置信息,修改HelloWorldController
@Autowired private Environment env; @RequestMapping(“/info”) public String info(){ return “HelloWorld~~” env.getProperty(“url”); }
1.2.7熱部署
我們?cè)陂_(kāi)發(fā)中反復(fù)修改類、頁(yè)面等資源,每次修改后都是需要重新啟動(dòng)才生效,這樣每次啟動(dòng)都很麻煩,浪費(fèi)了大量的時(shí)間,能不能在我修改代碼后不重啟就能生效呢?可以,在pom.xml中添加如下配置就可以實(shí)現(xiàn)這樣的功能,我們稱之為熱部署。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency>
趕快試試看吧,是不是很爽。
1.3 Spring Boot與ActiveMQ整合
1.3.1使用內(nèi)嵌服務(wù)
(1)在pom.xml中引入ActiveMQ起步依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-activemq</artifactId></dependency>
(2)創(chuàng)建消息生產(chǎn)者
/** * 消息生產(chǎn)者 * @author Administrator */@RestControllerpublic class QueueController { @Autowired private JmsMessagingTemplate jmsMessagingTemplate; @RequestMapping(“/send”) public void send(String text){ jmsMessagingTemplate.convertAndSend(“itcast”, text); }}
(3)創(chuàng)建消息消費(fèi)者
@Componentpublic class Consumer { @JmsListener(destination=”itcast”) public void readMessage(String text){ System.out.println(“接收到消息:” text); } }
測(cè)試:?jiǎn)?dòng)服務(wù)后,在瀏覽器執(zhí)行
http://localhost:8088/send.do?text=aaaaa
即可看到控制臺(tái)輸出消息提示。Spring Boot內(nèi)置了ActiveMQ的服務(wù),所以我們不用單獨(dú)啟動(dòng)也可以執(zhí)行應(yīng)用程序。
1.3.2使用外部服務(wù)
在src/main/resources下的application.properties增加配置, 指定ActiveMQ的地址
spring.activemq.broker-url=tcp://192.168.25.135:61616
運(yùn)行后,會(huì)在activeMQ中看到發(fā)送的queue
1.3.3發(fā)送Map信息
(1)修改QueueController.java
@RequestMapping(“/sendmap”) public void sendMap(){ Map map=new HashMap<>(); map.put(“mobile”, “13900001111”); map.put(“content”, “恭喜獲得10元代金券”); jmsMessagingTemplate.convertAndSend(“itcast_map”,map); }
(2)修改Consumer.java
@JmsListener(destination=”itcast_map”) public void readMap(Map map){ System.out.println(map); }
2.短信發(fā)送平臺(tái)-阿里大于
2.1阿里大于簡(jiǎn)介
阿里大于是阿里云旗下產(chǎn)品,融合了三大運(yùn)營(yíng)商的通信能力,通過(guò)將傳統(tǒng)通信業(yè)務(wù)和能力與互聯(lián)網(wǎng)相結(jié)合,創(chuàng)新融合阿里巴巴生態(tài)內(nèi)容,全力為中小企業(yè)和開(kāi)發(fā)者提供優(yōu)質(zhì)服務(wù)阿里大于提供包括短信、語(yǔ)音、流量直充、私密專線、店鋪手機(jī)號(hào)等個(gè)性化服務(wù)。通過(guò)阿里大于打通三大運(yùn)營(yíng)商通信能力,全面融合阿里巴巴生態(tài),以開(kāi)放API及SDK的方式向開(kāi)發(fā)者提供通信和數(shù)據(jù)服務(wù),更好地支撐企業(yè)業(yè)務(wù)發(fā)展和創(chuàng)新服務(wù)。
2.2準(zhǔn)備工作
2.2.1注冊(cè)賬戶
首先我們先進(jìn)入“阿里大于” www.alidayu.com (https://dayu.aliyun.com/)
注冊(cè)賬號(hào)后,再在手機(jī)下載“阿里云”應(yīng)用,登陸,然后進(jìn)行在線實(shí)名認(rèn)證。
2.2.2登陸系統(tǒng)
使用剛才注冊(cè)的賬號(hào)進(jìn)行登陸。
點(diǎn)擊進(jìn)入控制臺(tái)
點(diǎn)擊使用短信服務(wù)
3.2.3申請(qǐng)簽名
3.2.4申請(qǐng)模板
3.2.5創(chuàng)建accessKey
3.3 SDK安裝
從阿里云通信官網(wǎng)上下載Demo工程
解壓后導(dǎo)入Eclipce
紅線框起來(lái)的兩個(gè)工程就是阿里云通信的依賴jar源碼,我們將其安裝到本地倉(cāng)庫(kù)
(刪除aliyun-java-sdk-core的單元測(cè)試類)
本地jar包安裝后 alicom-dysms-api工程引入依賴
<dependencies> <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>
紅叉消失了
3.4發(fā)送短信測(cè)試
(1)打開(kāi)SmsDemo
替換下列幾處代碼
這個(gè)accessKeyId和accessSecret到剛才申請(qǐng)過(guò)的
手機(jī)號(hào),短信簽名和模板號(hào)
模板參數(shù)
number是我們申請(qǐng)模板時(shí)寫(xiě)的參數(shù)
執(zhí)行main方法我們就可以在手機(jī)收到短信啦
3.短信微服務(wù)
3.1需求分析
構(gòu)建一個(gè)通用的短信發(fā)送服務(wù)(獨(dú)立于品優(yōu)購(gòu)的單獨(dú)工程),接收activeMQ的消息(MAP類型) 消息包括手機(jī)號(hào)(mobile)、短信模板號(hào)(template_code)、簽名(sign_name)、參數(shù)字符串(param )
3.2代碼實(shí)現(xiàn)
3.2.1工程搭建
(1)創(chuàng)建工程itcast_sms (JAR工程),POM文件引入依賴
<properties> <java.version>1.7</java.version> </properties> <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-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>
(2)創(chuàng)建引導(dǎo)類
package cn.itcast.sms;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplicationpublic class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); }}
(3)創(chuàng)建配置文件application.properties
server.port=9003spring.activemq.broker-url=tcp://192.168.25.135:61616accessKeyId=不告訴你accessKeySecret=不告訴你
3.2.2短信工具類
參照之前的短信demo創(chuàng)建短信工具類
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;/** * 短信工具類 * @author Administrator * */@Componentpublic class SmsUtil { //產(chǎn)品名稱:云通信短信API產(chǎn)品,開(kāi)發(fā)者無(wú)需替換 static final String product = “Dysmsapi”; //產(chǎn)品域名,開(kāi)發(fā)者無(wú)需替換 static final String domain = “dysmsapi.aliyuncs.com”; @Autowired private Environment env; // TODO 此處需要替換成開(kāi)發(fā)者自己的AK(在阿里云訪問(wèn)控制臺(tái)尋找) /** * 發(fā)送短信 * @param mobile 手機(jī)號(hào) * @param template_code 模板號(hào) * @param sign_name 簽名 * @param param 參數(shù) * @return * @throws ClientException */ 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”); //可自助調(diào)整超時(shí)時(shí)間 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); //組裝請(qǐng)求對(duì)象-具體描述見(jiàn)控制臺(tái)-文檔部分內(nèi)容 SendSmsRequest request = new SendSmsRequest(); //必填:待發(fā)送手機(jī)號(hào) request.setPhoneNumbers(mobile); //必填:短信簽名-可在短信控制臺(tái)中找到 request.setSignName(sign_name); //必填:短信模板-可在短信控制臺(tái)中找到 request.setTemplateCode(template_code); //可選:模板中的變量替換JSON串,如模板內(nèi)容為”親愛(ài)的${name},您的驗(yàn)證碼為${code}”時(shí),此處的值為 request.setTemplateParam(param); //選填-上行短信擴(kuò)展碼(無(wú)特殊需求用戶請(qǐng)忽略此字段) //request.setSmsUpExtendCode(“90997”); //可選:outId為提供給業(yè)務(wù)方擴(kuò)展字段,最終在短信回執(zhí)消息中將此值帶回給調(diào)用者 request.setOutId(“yourOutId”); //hint 此處可能會(huì)拋出異常,注意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”); //可自助調(diào)整超時(shí)時(shí)間 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); //組裝請(qǐng)求對(duì)象 QuerySendDetailsRequest request = new QuerySendDetailsRequest(); //必填-號(hào)碼 request.setPhoneNumber(mobile); //可選-流水號(hào) request.setBizId(bizId); //必填-發(fā)送日期 支持30天內(nèi)記錄查詢,格式y(tǒng)yyyMMdd SimpleDateFormat ft = new SimpleDateFormat(“yyyyMMdd”); request.setSendDate(ft.format(new Date())); //必填-頁(yè)大小 request.setPageSize(10L); //必填-當(dāng)前頁(yè)碼從1開(kāi)始計(jì)數(shù) request.setCurrentPage(1L); //hint 此處可能會(huì)拋出異常,注意catch QuerySendDetailsResponse querySendDetailsResponse = acsClient.getAcsResponse(request); return querySendDetailsResponse; }}
3.2.3消息監(jiān)聽(tīng)類
創(chuàng)建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;/** * 消息監(jiān)聽(tīng)類 * @author Administrator */@Componentpublic 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代碼測(cè)試
修改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); }
啟動(dòng)itcast_sms
啟動(dòng)springboot-demo
地址欄輸入:http://localhost:8088/sendsms.do
觀察控制臺(tái)輸出
隨后短信也成功發(fā)送到你的手機(jī)上
4.用戶注冊(cè)
4.1需求分析
完成用戶注冊(cè)功能
4.2工程搭建
4.2.1用戶服務(wù)接口層
(1)創(chuàng)建pinyougou-user-interface(jar)
(2)引入pojo依賴
4.2.2用戶服務(wù)實(shí)現(xiàn)層
(1)創(chuàng)建pinyougou-user-service(war)
(2)引入spring dubbox activeMQ相關(guān)依賴,引入依賴( pinyougou-user-interface pinyougou-dao pinyougou-common),運(yùn)行端口為9006
(3)添加web.xml
(4)創(chuàng)建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層
創(chuàng)建war工程 pinyougou-user-web 我們將注冊(cè)功能放入此工程
(1)添加web.xml
(2)引入依賴pinyougou-user-interface 、spring相關(guān)依賴(參照其它web工程),tomcat運(yùn)行端口9106
(3)添加spring配置文件
(4)拷貝靜態(tài)原型頁(yè)面register.html 及相關(guān)資源
4.3基本注冊(cè)功能實(shí)現(xiàn)
4.3.1生成和拷貝代碼
4.3.2后端服務(wù)實(shí)現(xiàn)層
修改pinyougou-user-service的UserServiceImpl.java
/** * 增加 */ @Override public void add(TbUser user) { user.setCreated(new Date());//創(chuàng)建日期 user.setUpdated(new Date());//修改日期 String password = DigestUtils.md5Hex(user.getPassword());//對(duì)密碼加密 user.setPassword(password); userMapper.insert(user); }
4.3.3前端控制層
修改userController.js
//控制層 app.controller(‘userController’ ,function($scope,$controller ,userService){ //注冊(cè) $scope.reg=function(){ if($scope.entity.password!=$scope.password) { alert(“兩次輸入的密碼不一致,請(qǐng)重新輸入”); return ; } userService.add( $scope.entity ).success( function(response){ alert(response.message); } ); } });
4.3.4修改頁(yè)面
修改頁(yè)面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=”請(qǐng)輸入你的用戶名” 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=”設(shè)置登錄密碼” ng-model=”entity.password” class=”input-xfat input-xlarge”> </div> </div> <div class=”control-group”> <label for=”inputPassword” class=”control-label”>確認(rèn)密碼:</label> <div class=”controls”> <input type=”password” placeholder=”再次確認(rèn)密碼” ng-model=”password” class=”input-xfat input-xlarge”> </div> </div> <div class=”control-group”> <label class=”control-label”>手機(jī)號(hào):</label> <div class=”controls”> <input type=”text” placeholder=”請(qǐng)輸入你的手機(jī)號(hào)” ng-model=”entity.phone” class=”input-xfat input-xlarge”> </div> </div> <div class=”control-group”> <label for=”inputPassword” class=”control-label”>短信驗(yàn)證碼:</label> <div class=”controls”> <input type=”text” placeholder=”短信驗(yàn)證碼” class=”input-xfat input-xlarge”> <a href=”#”>獲取短信驗(yàn)證碼</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>同意協(xié)議并注冊(cè)《品優(yōu)購(gòu)用戶協(xié)議》</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”>完成注冊(cè)</a> </div> </div></form>
4.4 注冊(cè)判斷短信驗(yàn)證碼
4.4.1實(shí)現(xiàn)思路
點(diǎn)擊頁(yè)面上的”獲取短信驗(yàn)證碼”連接,向后端傳遞手機(jī)號(hào)。后端隨機(jī)生成6位數(shù)字作為短信驗(yàn)證碼,將其保存在redis中(手機(jī)號(hào)作為KEY),并發(fā)送到短信網(wǎng)關(guān)。
用戶注冊(cè)時(shí),后端根據(jù)手機(jī)號(hào)查詢r(jià)edis中的驗(yàn)證碼與用戶填寫(xiě)的驗(yàn)證碼是否相同,如果不同則提示用戶不能注冊(cè)。
4.4.2生成驗(yàn)證碼
(1)修改pinyougou-user-interface工程UserService.java ,增加方法
/** * 生成短信驗(yàn)證碼 * @return */ public void createSmsCode(String phone);
(2)修改pinyougou-user-service工程的UserServiceImpl.java
@Autowired private RedisTemplate<String , Object> redisTemplate; /** * 生成短信驗(yàn)證碼 */ public void createSmsCode(String phone){ //生成6位隨機(jī)數(shù) String code = (long) (Math.random()*1000000) “”; System.out.println(“驗(yàn)證碼:” code); //存入緩存 redisTemplate.boundHashOps(“smscode”).put(phone, code); //發(fā)送到activeMQ …. }
(3)在 pinyougou-common 添加工具類PhoneFormatCheckUtils.java,用于驗(yàn)證手機(jī)號(hào)
(4)修改pinyougou-user-web的UserController.java
/** * 發(fā)送短信驗(yàn)證碼 * @param phone * @return */ @RequestMapping(“/sendCode”) public Result sendCode(String phone){ //判斷手機(jī)號(hào)格式 if(!PhoneFormatCheckUtils.isPhoneLegal(phone)){ return new Result(false, “手機(jī)號(hào)格式不正確”); } try { userService.createSmsCode(phone);//生成驗(yàn)證碼 return new Result(true, “驗(yàn)證碼發(fā)送成功”); } catch (Exception e) { e.printStackTrace(); return new Result(true, “驗(yàn)證碼發(fā)送失敗”); } }
(5)pinyougou-user-web的userService.js
//發(fā)送驗(yàn)證碼 this.sendCode=function(phone){ return $http.get(“../user/sendCode.do?phone=” phone); }
(6)pinyougou-user-web的userController.js
//發(fā)送驗(yàn)證碼 $scope.sendCode=function(){ if($scope.entity.phone==null){ alert(“請(qǐng)輸入手機(jī)號(hào)!”); return ; } userService.sendCode($scope.entity.phone).success( function(response){ alert(response.message); } ); }
(7)修改頁(yè)面register.html
<a ng-click=”sendCode()” >獲取短信驗(yàn)證碼</a>
4.4.3用戶注冊(cè)判斷驗(yàn)證碼
(1)修改pinyougou-user-interface的UserService.java
/** * 判斷短信驗(yàn)證碼是否存在 * @param phone * @return */ public boolean checkSmsCode(String phone,String code);
(2)修改pinyougou-user-service的 UserServiceImpl.java
/** * 判斷驗(yàn)證碼是否正確 */ public boolean checkSmsCode(String phone,String code){ //得到緩存中存儲(chǔ)的驗(yàn)證碼 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
/** * 增加 * @param user * @return */ @RequestMapping(“/add”) public Result add(@RequestBody TbUser user,String smscode){ boolean checkSmsCode = userService.checkSmsCode(user.getPhone(), smscode); if(checkSmsCode==false){ return new Result(false, “驗(yàn)證碼輸入錯(cuò)誤!”); } try { userService.add(user); return new Result(true, “增加成功”); } catch (Exception e) { e.printStackTrace(); return new Result(false, “增加失敗”); } }
(4)修改pinyougou-user-web的userService.js
//增加 this.add=function(entity,smscode){ return $http.post(‘../user/add.do?smscode=’ smscode ,entity ); }
(5)修改pinyougou-portal-web 的UserController.java
//保存 $scope.reg=function(){ userService.add( $scope.entity, $scope.smscode ).success( function(response){ alert(response.message); } ); }
(6)修改頁(yè)面,綁定變量
<input type=”text” placeholder=”短信驗(yàn)證碼” ng-model=”smscode” class=”input-xfat input-xlarge”> <a href=”#” ng-click=”sendCode()”>獲取短信驗(yàn)證碼</a>
4.4.4短信驗(yàn)證碼發(fā)送到手機(jī)
(1)在pinyougou-user-service添加配置文件applicationContext-activemq.xml
<!– 真正可以產(chǎn)生Connection的ConnectionFactory,由對(duì)應(yīng)的 JMS服務(wù)廠商提供–> <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”> <!– 目標(biāo)ConnectionFactory對(duì)應(yīng)真實(shí)的可以產(chǎn)生JMS Connection的ConnectionFactory –> <property name=”targetConnectionFactory” ref=”targetConnectionFactory”/> </bean> <!– Spring提供的JMS工具類,它可以進(jìn)行消息發(fā)送、接收等 –> <bean id=”jmsTemplate” class=”org.springframework.jms.core.JmsTemplate”> <!– 這個(gè)connectionFactory對(duì)應(yīng)的是我們定義的Spring提供的那個(gè)ConnectionFactory對(duì)象 –> <property name=”connectionFactory” ref=”connectionFactory”/> </bean> <!–這個(gè)是點(diǎn)對(duì)點(diǎn)消息 –> <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; /** * 生成短信驗(yàn)證碼 */ public void createSmsCode(final String phone){ //生成6位隨機(jī)數(shù) final String code = (long) (Math.random()*1000000) “”; System.out.println(“驗(yàn)證碼:” code); //存入緩存 redisTemplate.boundHashOps(“smscode”).put(phone, code); //發(fā)送到activeMQ jmsTemplate.send(smsDestination, new MessageCreator() { @Override public Message createMessage(Session session) throws JMSException { MapMessage mapMessage = session.createMapMessage(); mapMessage.setString(“mobile”, phone);//手機(jī)號(hào) mapMessage.setString(“template_code”, “SMS_85735065”);//模板編號(hào) mapMessage.setString(“sign_name”, “黑馬”);//簽名 Map m=new HashMap<>(); m.put(“number”, code); mapMessage.setString(“param”, JSON.toJSONString(m));//參數(shù) return mapMessage; } }); }
(3)在pinyougou-common的properties目錄下創(chuàng)建配置文件sms.properties
template_code=SMS_85735065sign_name=u9ED1u9A6C