发送短信测试
创建aldy_demo的jar工程
导入依赖信息
<dependencies>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>3.7.1</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-dysmsapi</artifactId>
<version>1.1.0</version>
</dependency>
</dependencies>
参考阿里云短信服务的api短信服务api
创建demo类测试发送短信
public class SmsDemo {
//产品名称:云通信短信API产品,开发者无需替换
static final String product = "Dysmsapi";
//产品域名,开发者无需替换
static final String domain = "dysmsapi.aliyuncs.com";
//此处需要替换成开发者自己的AK(在阿里云访问控制台寻找)
static final String accessKeyId = "";
static final String accessKeySecret = "";
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("");
//必填:短信签名-可在短信控制台中找到
request.setSignName("");
//必填:短信模板-可在短信控制台中找到
request.setTemplateCode("");
//可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为
request.setTemplateParam("{\"code\":\"666888\"}");
//hint 此处可能会抛出异常,注意catch
SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);
return sendSmsResponse;
}
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());
}
}
运行测试类向自己手机上发送一条验证码
微服务搭建
构建一个通用的短信发送服务(spring boot),接收activeMQ的消息(MAP类型)消息包括手机号(mobile)、短信模板号(template_code)、签名(sign_name)、参数字符串(param)
AcitiveMQ的消息类型是点对点的队列消息
创建一个jar工程youlexuan_sms
pom依赖信息
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.4.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-core</artifactId>
<version>3.7.1</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-dysmsapi</artifactId>
<version>1.1.0</version>
</dependency>
</dependencies>
创建引导类,放在包的根目录下
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
创建配置文件application.properties
server.port = 8888
spring.activemq.broker-url=tcp://192.168.2.123:61616
accessKeyId = *********
accessKeySecret = ********
抽取短信工具类(原来短信测试类的静态方法改成非静态的,因为是工具类,所以会通过工具类调用方法,所以没必要是静态方法;抽取出来的param字段要求是json格式的)
@Component
public class SmsUtil {
@Value("${accessKeyId}")
private String accessKeyId;
@Value("${accessKeySecret}")
private String accessKeySecret;
//产品名称:云通信短信API产品,开发者无需替换
static final String product = "Dysmsapi";
//产品域名,开发者无需替换
static final String domain = "dysmsapi.aliyuncs.com";
public SendSmsResponse sendSms(String phone, String sign, String templateId, String param) 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(phone);
//必填:短信签名-可在短信控制台中找到
request.setSignName(sign);
//必填:短信模板-可在短信控制台中找到
request.setTemplateCode(templateId);
//可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为
request.setTemplateParam(param);
//hint 此处可能会抛出异常,注意catch
SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);
return sendSmsResponse;
}
}
创建SmsListener类:
@Component
public class SmsListener {
@Autowired
private SmsUtil smsUtil;
@JmsListener(destination = "smsDestination")
public void sendSms(Map<String, String> map) {
try {
String phone = map.get("phone");
String sign = map.get("sign");
String templateId = map.get("templateId");
String param = map.get("param");
System.out.println(">>>>>receive msg: phone" + phone + ", sign: " + sign + ", templateId: " + templateId + ",param: " + param);
SendSmsResponse sendSmsResponse = smsUtil.sendSms(phone, sign, templateId, param);
System.out.println(">>>>>sms_service send sms result: " + sendSmsResponse.getCode());
} catch (ClientException e) {
e.printStackTrace();
}
}
}
这样发送短信的微服务我们就搭建好了,下面只需要在用户controller层以及service层进行生成验证码以及发送AcitiveMQ的消息
配置user_service工程下的spring-jms-producer.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
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">
<context:component-scan base-package="com.weilinyang" />
<!-- 产生Connection的ConnectionFactory,由对应的 JMS服务厂商提供 -->
<bean id="targetConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://192.168.2.123:61616" />
</bean>
<!-- Spring用于管理ConnectionFactory的ConnectionFactory -->
<bean id="connectionFactory"
class="org.springframework.jms.connection.SingleConnectionFactory">
<property name="targetConnectionFactory" ref="targetConnectionFactory" />
</bean>
<!-- Spring提供的JMS工具类,它可以进行消息发送、接收等 -->
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="connectionFactory" />
</bean>
<!-- 队列目的地,点对点信息 -->
<bean id="smsDestination" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg value="sms_queue" />
</bean>
</beans>
@Reference
private UserService userService;
@RequestMapping("/sendCode")
public Result sendCode(String phone){
if (!PhoneFormatCheckUtils.isChinaPhoneLegal(phone)){
return new Result(false,"手机号非法!");
}
try {
userService.createSmsCode(phone);
return new Result(false,"短信发送成功!");
} catch (Exception e) {
e.printStackTrace();
return new Result(false,"短信发送异常!");
}
}
@Value("${sign}")
private String sign;
@Value("${templateId}")
private String templateId;
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private JmsTemplate jmsTemplate;
@Override
public void createSmsCode(String phone) {
//Math.random() 范围[0,1)
//1、生成6位验证码 100000-999999
int num = (int)(Math.random() * 900000 + 100000);
System.out.println("生成的验证码为"+num);
Map<String,String> map = new HashMap<>();
map.put("param","{\"code\":\"" + num + "\"}");
map.put("phone",phone);
map.put("sign",sign);
map.put("templateId",templateId);
// 2. 将验证码在 redis 中保存起来,以便注册时候校验
redisTemplate.boundHashOps("register_code").put("code",num);
System.out.println("存入redis");
// 3. 发送验证码:通过向消息中间件发送消息,来驱动 sms_service 短信服务帮你发验证码
jmsTemplate.convertAndSend("smsDestination",map);
System.out.println("已发送actMQ");
}
验证码的校验
验证码的保存
验证码保存在redis数据库中,当用户点击注册时,我们再去redis库中查询与前端提交的进行比对
@RequestMapping("/add")
public Result addUser(@RequestBody TbUser user, String code){
//校验验证码
Integer redisCode = (Integer) redisTemplate.boundHashOps("register_code").get("code");
try {
if (Integer.parseInt(code)!=redisCode){
return new Result(false,"验证码错误!");
}
// 设置注册时的一些默认信息
user.setCreated(new Date());
user.setUpdated(new Date());
// 密码加密 md5
user.setPassword(DigestUtils.md5Hex(user.getPassword()));
userService.addUser(user);
return new Result(true,"注册成功!");
} catch (Exception e) {
e.printStackTrace();
return new Result(false,"注册失败!");
}
}