练手项目1笔记 day14

目标

  • 掌握spring boot框架的搭建方法
  • 你能够使用阿里大于发送短信
  • 运用springboot、阿里大于和activemq开发短信微服务
  • 完成品优购用户注册功能(短信验证码认证)

用户中心–> 用户服务–>activeMQ–> 短信微服务–> 阿里大于

1. Spring Boot入门

1. 什么是Spring Boot

spring的配置是重量级的,另外项目依赖管理麻烦。

spring boot目的是帮助开发者更容易的创建基于spring的应用程序和服务,更快入门体验。

特性:

  1. 为基于spring的开发提供更快的入门体验
  2. 开箱即用
  3. 提供一些大型项目常见的非功能性特性,如嵌入式服务器、安全、指标,健康监测、外部配置等。
  4. springboot只是提供快速使用spring的方式。

2. 入门demo

1. 起步依赖

创建maven工程springboot_demo(打包方式为jar包)

在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>
2. 变更jdk版本

默认版本为1.6,如果想用1.8,pom.xml中添加配置

<properties>
  <java.version>1.8</java.version>
</properties>
3. 引导类

只需要创建一个引导类

package cn.itcast.demo;

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

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

简单解释:@SpringBootApplication其实就是以下三个注解的总和

  • @Configuration:用于定义一个java配置类application-solr.xml
  • @EnableAutoConfiguration:SpringBoot会自动根据jar包的依赖自动配置项目
  • @ComponentScan:告诉spring哪个package是用注解标识的类,会被spring自动扫描并且装入bean容器
4. Spring MVC实现Hello world的输出

现在开始使用spring MVC框架,实现json数据的输出。直接写Controller类

@RestController
public class HelloWorldController {

    @RequestMapping("/info")
    public String info(){
        return "HelloWorld!!";
    }
}

测试结果

5. 修改tomcat启动端口

在src/main/resources下创建application.properties

server.port=8088
6. 读取配置文件信息

在src/main/resources下的application.properties增加配置

url=http://www.baidu.com

要在类中读取这个配置信息

import org.springframework.core.env.Environment;
...
@RestController
public class HelloWorldController {

    @Autowired
    private Environment env;

    @RequestMapping("/info")
    public String info(){
        return "HelloWorld!! "+env.getProperty("url");
    }
}
7. 热部署

能否在修改代码后不重启就能生效?在pom.xml中添加如下配置即可,称为热部署

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-devtools</artifactId>
</dependency>

3. Spring Boot和ActiveMQ整合

1. 使用内嵌服务
  1. 在pom.xml中引入ActiveMQ起步依赖
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
  1. 创建消息生产者
@RestController
public class QueueController {

    @Autowired
    private JmsMessagingTemplate jmsMessagingTemplate;

    @RequestMapping("/send")
    public void send(String text){
        jmsMessagingTemplate.convertAndSend("itcast",text);
    }
}
  1. 创建消息消费者
@Component
public class Consumer {

    @JmsListener(destination = "itcast")
    public void readMessage(String text){
        System.out.println("接收到的消息:"+text);
    }
}

测试:启动服务后,浏览器执行

http://localhost:8088/send?text=abc

可以在控制台输出消息提示,内置了ActiveMQ的服务,不用单独启动也可以执行

2. 使用外部服务

在src/main/resources下的application.properties增加配置,指定ActiveMQ的地址

spring.activemq.broker-url=tcp://192.168.25.135:61616

运行后,会在activeMQ看到发送的queue

3. 发送Map消息

  1. 修改QueueController.java
@RequestMapping("/sendMap")
public void sendMap(){
  Map map = new HashMap();
  map.put("mobile","13510733521");
  map.put("content","恭喜您被彩蛋砸中了");
  jmsMessagingTemplate.convertAndSend("itcast_map",map);
}
  1. 修改Consumer.java
@JmsListener(destination = "itcast_map")
public void readMap(Map map){
  System.out.println(map);
}

2. 短信发送平台-阿里大于

1. 简介

阿里云旗下产品,融合三大运营商的通信能力,提供通信和数据相关服务

2. 准备工作

  1. 注册账户
  2. 登录
  3. 使用短信服务
  4. 申请签名(一般两个小时审核时间)
  5. 创建accessKey

3. SDK安装

从阿里云官网下载demo工程

两个依赖jar包的maven安装

mvn install:install-file -DgroupId=com.aliyun -DartifactId=aliyun-java-sdk-dysmsa pi -Dversion=1.0.0-SANPSHOT -Dpackaging=jar -Dfile=e:\aliyun-java-sdk-dysmsapi-1.0.0-SANPSHOT.jar

mvn install:install-file -DgroupId=com.aliyun -DartifactId=aliyun-java-sdk-core - Dversion=3.2.3 -Dpackaging=jar -Dfile=e:\aliyun-java-sdk-core-3.2.3.jar

本地jar包安装后,alicom-dysms-api工程引入依赖

<dependency>
  <groupId>com.aliyun</groupId>
  <artifactId>aliyun-java-sdk-dysmsapi</artifactId>
  <version>1.0.0</version>
</dependency>
<dependency>
  <groupId>com.aliyun</groupId>
  <artifactId>aliyun-java-sdk-core</artifactId>
  <version>3.2.5</version>
</dependency>

4. 发送短信测试

  1. 打开SmsDemo

替换下列几处代码

// TODO 此处需要替换成开发者自己的AK(在阿里云访问控制台寻找)
static final String accessKeyId = "xxxx";
static final String accessKeySecret = "xxxx";

手机号、短信签名和模板好

//必填:待发送手机号
request.setPhoneNumbers("xxxxx");
//必填:短信签名-可在短信控制台中找到
request.setSignName("xxxx");
//必填:短信模板-可在短信控制台中找到
request.setTemplateCode("xxxx");
//可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为
request.setTemplateParam("{ \"code\":\"xxx\"}");

执行main方法,接收短信

3. 短信微服务

1. 需求分析

构建一个通用的短信发送服务(独立于品优购),接收activeMQ的消息(Map类型),消息包括手机号(mobile)、短信模板号(template_code)、签名(sign_name)、参数字符串(param)。

2. 代码实现

1. 工程搭建
  1. 创建工程itcast_sms(jar工程),POM文件引入依赖
<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</version>
  </dependency>
  <dependency>
    <groupId>com.aliyun</groupId>
    <artifactId>aliyun-java-sdk-core</artifactId>
    <version>3.2.5</version>
  </dependency>
</dependencies>
  1. 创建引导类
@SpringBootApplication
public class Application {
  public static void main(String[] args) {
    SpringApplication.run(Application.class,args);
  }
}
  1. 创建配置文件application.properties
server.port=9003
spring.activemq.broker-url=tcp://192.168.25.128:61616
accessKeyId=xxxx
accessKeySecret=xxxx
2. 短信工具类

参照之前的短信demo创建短信工具类

@Component
public class SmsUtil {

    //产品名称:云通信短信API产品,开发者无需替换
    static final String product = "Dysmsapi";
    //产品域名,开发者无需替换
    static final String domain = "dysmsapi.aliyuncs.com";

    @Autowired
    private Environment environment;

    // TODO 此处需要替换成开发者自己的AK(在阿里云访问控制台寻找)
//    static final String accessKeyId = "LTAIAVy4oL7adI4W";
//    static final String accessKeySecret = "pF0zNhQQQxYAtxbEYuRbACdvLCz47j";

    public  SendSmsResponse sendSms(String mobile,String template_code,String sign_name,String param) throws ClientException {

        String accessKeyId = environment.getProperty("accessKeyId");
        String accessKeySecret = environment.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 = environment.getProperty("accessKeyId");
        String accessKeySecret = environment.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. 消息监听类

创建SmsListener.java

@Component
public class SmsListener {
  @Autowired
  private SmsUtil smsUtil;

  @JmsListener(destination = "sms")
  public void sendMsg(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());
    } catch (ClientException e) {
      e.printStackTrace();
    }
  }
}

3. 代码测试

修改springboot-demo的QueueController.java

@RequestMapping("/sendsms")
public void sendsms(){
  Map map = new HashMap();
  map.put("mobile","17816872186");
  map.put("template_code","SMS_141616649");
  map.put("sign_name","八零大蔬");
  map.put("param","{ \"code\":\"123\"}");
  jmsMessagingTemplate.convertAndSend("sms",map);
}

启动itcast_sms

启动springboot-demo

地址栏输入localhost:8088/sendsms.do

观察控制台输出,短信也成功发送到手机上。

4. 用户注册

1. 需求分析

完成用户注册功能

2. 工程搭建

1. 用户服务接口层
  1. 创建user-interface(jar)
  2. 引入pojo依赖
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和applicationContext-tx.xml
<dubbo:protocol name="dubbo" port="20886"></dubbo:protocol>
<dubbo:application name="pinyougou-user-service"/>
<dubbo:registry address="zookeeper://192.168.25.128:2181"/>
<dubbo:annotation package="com.pinyougou.user.service.impl" />
3. 用户中心web层

创建war工程 pinyougou_user_web 我们将注册功能放入此工程

  1. 添加web.xml
  2. 引入依赖user-interface、spring相关依赖,tomcat运行端口为9106
  3. 添加spring配置文件
  4. 拷贝静态原型页面register.html以及相关资源

3. 基本注册功能实现

1. 生成和拷贝代码
2. 后端服务实现层
@Override
public void add(TbUser user) {
  user.setCreated(new Date());
  user.setUpdated(new Date());
  user.setPassword(DigestUtils.md5DigestAsHex(user.getPassword().getBytes()));
  userMapper.insert(user);		
}
3. 前端控制层

修改userController.js

app.controller('userController' ,function($scope,$controller   ,userService){	

  // 注册用户
  $scope.reg = function () {
    // 比较两次输入的密码是否一致
    if($scope.password!=$scope.entity.password){
      alert("两次输入密码不一致,请重新输入");
      $scope.entity.password = "";
      $scope.password = "";
      return;
    }

    // 新增
    userService.add($scope.entity).success(
      function (response) {
        alert(response.message);
      }
    )
  }
});	
4. 修改页面

修改页面register.html,引入js

<script 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" ng-model="entity.username" placeholder="请输入你的用户名" class="input-xfat input-xlarge">
    </div>
  </div>
  <div class="control-group">
    <label for="inputPassword" class="control-label">登录密码:</label>
    <div class="controls">
      <input type="password" ng-model="entity.password" placeholder="设置登录密码" class="input-xfat input-xlarge">
    </div>
  </div>
  <div class="control-group">
    <label for="inputPassword" class="control-label">确认密码:</label>
    <div class="controls">
      <input type="password" ng-model="password" placeholder="再次确认密码" class="input-xfat input-xlarge">
    </div>
  </div>

  <div class="control-group">
    <label class="control-label">手机号:</label>
    <div class="controls">
      <input type="text" ng-model="entity.phone" placeholder="请输入你的手机号" 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">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</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. 注册判断短信验证码

1. 实现思路
  1. 点击发送验证码的逻辑:

    • 生成一个6位随机数字
    • 将生成的验证码存入redis,以手机号为key,以验证码为值
    • 将短信内容发送到activeMQ
  2. 校验验证码是否正确

    用户注册前要进行校验

    获取用户填写的验证码,与redis中的验证码进行比较

2. 生成验证码
  1. 修改user-interface工程UserService.java,增加方法
  2. 修改user-service的UserServiceImpl.java
@Override
public void createSmsCode(String phone) {
  // 1. 生成一个6位随机数(验证码)
  String smscode = (long)(Math.random()*1000000)+"";
  System.out.println("验证码:"+smscode);
  // 2. 验证码放入redis
  redisTemplate.boundHashOps("smscode").put(phone,smscode);
  // 3. 将短信内容发送给activeMQ
	// TODO
}
  1. 在pinyougou-common添加工具类PhoneFormatCheckUtils.java,用于验证手机号
  2. 修改pinyougou-user-web的UserController.java
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(false,"验证码发送失败");
  }
}
  1. pinyougou-user-web的userService.js
// 发送验证码
this.sendCode=function (phone) {
  return $http.get('../user/sendCode.do?phone='+phone);
}
  1. user-web的userController.js
// 发送验证码
$scope.sendCode = function () {
  if($scope.entity.phone==null || $scope.entity.phone===""){
    alert("请填写手机号!");
    return;
  }
  userService.sendCode($scope.entity.phone).success(
    function (response) {
      alert(response.message);
    }
  )
}
  1. 修改页面register.html
<a href="#" ng-click="sendCode()">获取短信验证码</a>
3. 用户注册判断验证码
  1. 修改user-interface的UserService.java
// 校验验证码
public boolean checkSmsCode(String phone,String code);
  1. 修改user-service的UserServiceImpl.java
@Override
public boolean checkSmsCode(String phone, String code) {
  String systomcode = (String) redisTemplate.boundHashOps("smscode").get(phone);
  if(systomcode==null){
    return false;
  }
  if(!code.equals(systomcode)){
    return false;
  }
  return true;
}
  1. 修改user-web的UserController.java
@RequestMapping("/add")
public Result add(@RequestBody TbUser user,String smscode){
  boolean checkSmsCode = userService.checkSmsCode(user.getPhone(), smscode);
  if(!checkSmsCode){
    return new Result(false, "验证码输入错误!");
  }
  try {
    userService.add(user);
    return new Result(true, "增加成功");
  } catch (Exception e) {
    e.printStackTrace();
    return new Result(false, "增加失败");
  }
}
  1. 修改userService.js
//增加 
this.add=function(entity,smscode){
  return  $http.post('../user/add.do?smscode='+smscode,entity );
}
  1. 修改UserController.js
userService.add($scope.entity,$scope.smscode).success(
  function (response) {
    alert(response.message);
  }
)
  1. 修改页面,绑定变量
<input type="text" ng-model="smscode" placeholder="短信验证码" class="input-xfat input-xlarge">  <a href="#" ng-click="sendCode()">获取短信验证码</a>
4. 短信验证码发送到手机
  1. 在user-service添加配置文件applicationContext-activemq.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:jms="http://www.springframework.org/schema/jms"
       xsi:schemaLocation="http://www.springframework.org/schema/beans   
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context   
                           http://www.springframework.org/schema/context/spring-context.xsd
                           http://www.springframework.org/schema/jms
                           http://www.springframework.org/schema/jms/spring-jms.xsd">


  <!-- 真正可以产生Connection的ConnectionFactory,由对应的 JMS服务厂商提供-->
  <bean id="targetConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">  
    <property name="brokerURL" value="tcp://192.168.25.128: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>    

</beans>
  1. 修改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;

@Override
public void createSmsCode(String phone) {
  // 1. 生成一个6位随机数(验证码)
  String smscode = (long)(Math.random()*1000000)+"";
  System.out.println("验证码:"+smscode);
  // 2. 验证码放入redis
  redisTemplate.boundHashOps("smscode").put(phone,smscode);
  // 3. 将短信内容发送给activeMQ
  jmsTemplate.send(smsDestination, new MessageCreator() {
    @Override
    public Message createMessage(Session session) throws JMSException {
      MapMessage message = session.createMapMessage();
      message.setString("mobile",phone);// 手机号
      message.setString("template_code",template_code);
      message.setString("sign_name",sign_name);
      Map map = new HashMap();
      map.put("number",smscode);
      message.setString("param", JSON.toJSONString(map));
      return message;
    }
  });
}
  1. 在pinyougou-common的properties目录创建配置文件sms.properties
template_code=SMS_141616649
sign_name=\u516b\u96f6\u5927\u852c
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值