SpringBoot【短信微服务】

本贴最后更新于 1486 天前,其中的信息可能已经水流花落

SpringBoot 搭建短信微服务

SpringBoot 快速搭建 Spring 工程,所以非常适合进行搭建微服务,本片中主要介绍的是使用阿里大于进行短信为服务的搭建。

SpringBoot 和 activeMQ 的整合

MQ 是消息中间件,是一种在分布式系统中应用程序借以传递消息的媒介,常用的有 ActiveMQ,RabbitMQ,kafka。ActiveMQ 是 Apache 下的开源项目,完全支持 JMS1.1 和 J2EE1.4 规范的 JMS Provider 实现。
特点:

  1. 支持多种语言编写客户端
  2. 对 spring 的支持,可以和 Spring 进行整合
  3. 支持多种传输协议:TCP,SSL,NIO,UDP 等
  4. 支持 AJAX
    消息形式:
  5. 点对点(queue)
  6. 一对多(topic)
  1. 使用工具构建 Springboot 工程,可参考链接:https://blog.csdn.net/hax1435501085/article/details/105146038
  2. 配置文件 pom.xml
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-activemq</artifactId> </dependency> <!-- 消息队列连接池--> <dependency> <groupId>org.messaginghub</groupId> <artifactId>pooled-jms</artifactId> </dependency>

这里注意说明,如果 SpringBoot 是 2.1.X 版本以上使用以上的配置,如果是使用以下配置会出现找不到 jmsMessagingTemplate;

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-activemq</artifactId> </dependency> <!--消息队列连接池--> <dependency> <groupId>org.apache.activemq</groupId> <artifactId>activemq-pool</artifactId> </dependency>
  1. application.yml 文件配置
server: port: 8080 spring: activemq: # 看自己activeMQ安装地方配置 我在这里使用的window安装 broker-url: tcp://localhost:61616 #broker-url: tcp://192.168.1.103:61616 user: admin password: admin pool: enabled: true max-connections: 10 jms: pub-sub-domain: false #false为queues true 为topics #服务名称 application: name: boot-activemq queueName: test-queue topicName: test-topic
  1. ActiveMQConfig.java 文件
package com.example.demo.config; import javax.jms.Queue; import javax.jms.Topic; import org.apache.activemq.ActiveMQConnectionFactory; import org.apache.activemq.command.ActiveMQQueue; import org.apache.activemq.command.ActiveMQTopic; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.jms.config.DefaultJmsListenerContainerFactory; import org.springframework.jms.config.JmsListenerContainerFactory; /** * @author Administrator_hax */ @Configuration public class ActiveMQConfig { @Value("${queueName}") private String queueName; @Value("${topicName}") private String topicName; @Value("${spring.activemq.user}") private String usrName; @Value("${spring.activemq.password}") private String password; @Value("${spring.activemq.broker-url}") private String brokerUrl; @Bean public Queue queue(){ return new ActiveMQQueue(queueName); } @Bean public Topic topic(){ return new ActiveMQTopic(topicName); } @Bean public ActiveMQConnectionFactory connectionFactory() { return new ActiveMQConnectionFactory(usrName, password, brokerUrl); } @Bean public JmsListenerContainerFactory<?> jmsListenerContainerQueue(ActiveMQConnectionFactory connectionFactory){ DefaultJmsListenerContainerFactory bean = new DefaultJmsListenerContainerFactory(); bean.setConnectionFactory(connectionFactory); return bean; } @Bean public JmsListenerContainerFactory<?> jmsListenerContainerTopic(ActiveMQConnectionFactory connectionFactory){ DefaultJmsListenerContainerFactory bean = new DefaultJmsListenerContainerFactory(); //设置为发布订阅方式, 默认情况下使用的生产消费者方式 bean.setPubSubDomain(true); bean.setConnectionFactory(connectionFactory); return bean; } }
  1. 生产者 ProviderController.java 文件
package com.example.demo.Controller; import java.util.UUID; import javax.jms.Queue; import javax.jms.Topic; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jms.annotation.JmsListener; import org.springframework.jms.core.JmsMessagingTemplate; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/provider") public class ProviderController { @Autowired private JmsMessagingTemplate jms; @Autowired private Queue queue; @Autowired private Topic topic; //点对点的消息发送 @RequestMapping("/queue") public String queue(){ for (int i = 0; i < 10 ; i++){ jms.convertAndSend(queue, " queue"+i); } return "queue 发送成功"; } //接受消息 @JmsListener(destination = "out.queue") public void consumerMsg(String msg){ System.out.println(msg); } //订阅消息发送 @RequestMapping("/topic") public String topic(){ for (int i = 0; i < 10 ; i++){ jms.convertAndSend(topic, "topic"+i); } return "topic 发送成功"; } // 定时推送queues消息 @Scheduled(fixedDelay = 3000) public void timeSendQueueMsg() { String str = UUID.randomUUID().toString().replace("-", "").substring(0, 10); System.out.println("定时推送Queue消息:" + str); jms.convertAndSend(queue, str); } //定时推送topics消息 @Scheduled(fixedDelay = 8000) public void timeSendTopicMsg() { String str = UUID.randomUUID().toString().replace("-", "").substring(0, 10); System.out.println("定时推送Topic消息:" + str); jms.convertAndSend(topic, str); } }
  1. 消费者 ActiveMQListener.java
package com.example.demo.Listener; import javax.jms.JMSException; import javax.jms.TextMessage; import org.springframework.jms.annotation.JmsListener; import org.springframework.messaging.handler.annotation.SendTo; import org.springframework.stereotype.Component; @Component public class ActiveMQListener { //queues消息监听 @JmsListener(destination = "test-queue",containerFactory = "jmsListenerContainerQueue") //将检测到的消息写入到 queue : out.queue 中去. @SendTo("out.queue") public String receiveQueue(TextMessage textMessage) throws JMSException { System.out.println("消费者接收到queues消息:"+textMessage.getText()); return textMessage.getText(); } //topic消息监听 @JmsListener(destination = "test-topic",containerFactory = "jmsListenerContainerTopic") public void receiveTopic(TextMessage textMessage) throws JMSException { System.out.println("消费者接收到topics消息:"+textMessage.getText()); } }
  1. DemoApplication.java 文件
package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.ComponentScan; //yml包扫描 //@EnableScheduling //开启定时任务 @ComponentScan @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }

注意:如果在运行出现了 无法加载文件 application.yml,文件的话,可以在 pom.xml 配置文件中加入

<!--yml文件解析 --> <dependency> <groupId>org.yaml</groupId> <artifactId>snakeyaml</artifactId> </dependency>
  1. 目录结构

20200405224559114.png
9. 启动测试
开启 activeMQ 服务
在这里插入图片描述
访问链接:localhost:8080/provider/queue
在这里插入图片描述
在这里插入图片描述
访问链接:localhost:8080/provider/topic
在进行 topic 访问的时候需要修改 application.yml 配置文件

jms: pub-sub-domain: true #false为queues true 为topics

在这里插入图片描述
在这里插入图片描述
测试成功

整合好了 SpringBoot 和 ActiveMQ 下面开始了解关于阿里大于的相关信息,搭建短信微服务

2 种方式进行阿里大于短信服务的开发

  1. 在阿里大于里面下载 demo 测试文件 www.alidayu.com 在这里插入图片描述
    打开文件里面有
    在这里插入图片描述
    将里面四个 maven 工程导入到开发工具中
    在这里插入图片描述
    将红色的线框进行 maven 安装本地
  2. alicom-dysms-api 进行测试
    在这里插入图片描述
    SmsDemo.java
package com.alicom.dysms.api; 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; /** * Created on 17/6/7. * 短信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 */ public class SmsDemo { //产品名称:云通信短信API产品,开发者无需替换 static final String product = "Dysmsapi"; //产品域名,开发者无需替换 static final String domain = "dysmsapi.aliyuncs.com"; // TODO 此处需要替换成开发者自己的AK(在阿里云访问控制台寻找) static final String accessKeyId = "youraccessKeyId"; static final String accessKeySecret = "youraccessKeySecret"; public static SendSmsResponse sendSms() throws ClientException { //可自助调整超时时间 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("15671381019"); //必填:短信签名-可在短信控制台中找到 request.setSignName("CRM客户管理系统"); //必填:短信模板-可在短信控制台中找到 request.setTemplateCode("SMS_186968097"); //可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为 request.setTemplateParam("{\"code\":\"520111\"}"); //选填-上行短信扩展码(无特殊需求用户请忽略此字段) //request.setSmsUpExtendCode("90997"); //可选:outId为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者 request.setOutId("yourOutId"); //hint 此处可能会抛出异常,注意catch SendSmsResponse sendSmsResponse=null; try { sendSmsResponse = acsClient.getAcsResponse(request); } catch (Exception e) { // TODO: handle exception } return sendSmsResponse; } public static QuerySendDetailsResponse querySendDetails(String bizId) throws ClientException { //可自助调整超时时间 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("15671381019"); //可选-流水号 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; } public static void main(String[] args) throws ClientException, InterruptedException { //发短信 SendSmsResponse response = sendSms(); System.out.println("短信接口返回的数据----------------"); System.out.println("Code=" + response.getCode()); System.out.println("Message=" + response.getMessage()); System.out.println("RequestId=" + response.getRequestId()); System.out.println("BizId=" + response.getBizId()); Thread.sleep(3000L); //查明细 if(response.getCode() != null && response.getCode().equals("OK")) { QuerySendDetailsResponse querySendDetailsResponse = querySendDetails(response.getBizId()); System.out.println("短信明细查询接口返回数据----------------"); System.out.println("Code=" + querySendDetailsResponse.getCode()); System.out.println("Message=" + querySendDetailsResponse.getMessage()); int i = 0; for(QuerySendDetailsResponse.SmsSendDetailDTO smsSendDetailDTO : querySendDetailsResponse.getSmsSendDetailDTOs()) { System.out.println("SmsSendDetailDTO["+i+"]:"); System.out.println("Content=" + smsSendDetailDTO.getContent()); System.out.println("ErrCode=" + smsSendDetailDTO.getErrCode()); System.out.println("OutId=" + smsSendDetailDTO.getOutId()); System.out.println("PhoneNum=" + smsSendDetailDTO.getPhoneNum()); System.out.println("ReceiveDate=" + smsSendDetailDTO.getReceiveDate()); System.out.println("SendDate=" + smsSendDetailDTO.getSendDate()); System.out.println("SendStatus=" + smsSendDetailDTO.getSendStatus()); System.out.println("Template=" + smsSendDetailDTO.getTemplateCode()); } System.out.println("TotalCount=" + querySendDetailsResponse.getTotalCount()); System.out.println("RequestId=" + querySendDetailsResponse.getRequestId()); } } }
  1. 然后将安装好依赖添加到 pom.xml 工程中即可
<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>4.1.0</version> </dependency>
  • 第二种是直接添加依赖,镜像链接下载
<dependency> <groupId>com.aliyun</groupId> <artifactId>aliyun-java-sdk-core</artifactId> <version>4.1.0</version> </dependency> <dependency> <groupId>com.aliyun</groupId> <artifactId>aliyun-java-sdk-dysmsapi</artifactId> <version>1.0.0</version> </dependency>
  1. 封装 SmsUtil.java 工具类
package com.example.demo.Utils; import java.text.SimpleDateFormat; import java.util.Date; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.PropertySource; import org.springframework.core.env.Environment; import org.springframework.stereotype.Component; 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; /** * * @author Administrator_hax * 短信发送工具类 */ @PropertySource("classpath:application.properties")//在加载钥密 @Component public class SmsUtil { //产品名称:云通信短信API产品,开发者无需替换 static final String product = "Dysmsapi"; //产品域名,开发者无需替换 static final String domain = "dysmsapi.aliyuncs.com"; @Autowired private Environment env; /** * 发送短信 * @param mobile 手机号 * @param template_code 模板号 * @param sign_name 签名 * @param param 参数 * @return * @throws ClientException */ public SendSmsResponse sendSms(String mobile,String template_code,String sign_name,String param) throws ClientException { // TODO 此处需要替换成开发者自己的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(sign_name); //必填:短信模板-可在短信控制台中找到 request.setTemplateCode(template_code); //可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为 request.setTemplateParam(param); //选填-上行短信扩展码(无特殊需求用户请忽略此字段) //request.setSmsUpExtendCode("90997"); //可选:outId为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者 request.setOutId("yourOutId"); //hint 此处可能会抛出异常,注意catch SendSmsResponse sendSmsResponse=null; try { sendSmsResponse = acsClient.getAcsResponse(request); } catch (Exception e) { e.printStackTrace(); } return sendSmsResponse; } /** * 消息查询响应 * @param mobile 电话号码 * @param bizId * @return * @throws ClientException */ 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; } }

监听 SmsListener.java

package com.example.demo.Listener; 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; import com.example.demo.Utils.SmsUtil; @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(); } } }
  • 拦截 SendController.java
package com.example.demo.Controller; import java.util.HashMap; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jms.core.JmsMessagingTemplate; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @Controller public class SendController { @Autowired private JmsMessagingTemplate jmsMessagingTemplate; @RequestMapping("/sendsms") public void sendSms(){ Map<String,String > map=new HashMap<String,String>(); map.put("mobile", "15671381019"); map.put("template_code", "SMS_186968097"); map.put("sign_name", "CRM客户管理系统"); map.put("param", "{\"code\":\"520520\"}"); jmsMessagingTemplate.convertAndSend("sms",map); } }
  • application.properties 文件
accessKeyId:不告诉你 accessKeySecret:不告诉你
  • 目录结构
    ![在这里插入图片描述](20200405224559114.png
  • 测试链接:localhost:8080/sendsms
    在这里插入图片描述

分析思路:

  • 在实际的开发项目中,只需要依赖该 maven 工程即可了,然后在进行登陆注册的操作的时候,发送一个请求地址,地址拦截进行短信发送,短信验证码使用随机数产生,然后在将用户手机号码可以以 key 的形式 value 为验证码存储到 redis 中 ,可以设置过期时间达到几分钟验证的效果,将用户输入的验证码和 redis 中的验证码进行比较,已达到注册登录的效果.

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...