短信发送是电信运营商提供的服务,需要访问对应的接口,不同运营商提供的接口地址肯定不一样,如果直接访问这些接口就需要判断收信息的手机号属于哪个运营商,关键在于这些接口不对个人开放,还要考虑调用短信服务的费用问题
因此目前调用短信业务都是使用第三方企业的短信服务,他们与运营商合作,封装了短信接口,调用方法,而且费用相对便宜
第一步:云市场搜索短信服务
点击购买,有5条免费使用,测试也会消耗使用次数,用完了在付费购买即可
找到自己购买的云服务
可以看到已购买的服务
这里有几项重要信息:AppKey AppSecret AppCode 调用购买的这个短信服务接口时候需要用到,用于确认使用者身份
接口 : 调用该服务时访问的接口
参考API,编写发送短信工具类
import cn.hutool.http.Header; import cn.hutool.http.HttpRequest; import java.util.HashMap; import java.util.Map; /** * 测试短信 */ public class SmsUtilTest { public static void main(String[] args) { //手机号码 String mobile = ""; //验证码 String code = ""; //签名ID。(联系客服申请。测试请用:2e65b1bb3d054466b82f0c9d125465e2) String smsSignId=""; //模板ID。(联系客服申请。测试ID请用:908e94ccf08b4476ba6c876d13f084ad,短信内容为 { 验证码:**code**,**minute**分钟内有效,请勿泄漏于他人!}) String templateId=""; //应用code https://market.console.aliyun.com/imageconsole/index.htm?#/bizlist?_k=r5f9m0 查找 String appCode=""; //请求连接 String host = "https://gyytz.market.alicloudapi.com/sms/smsSend"; //拼装请求体 Map<String, Object> querys = new HashMap<String, Object>(); querys.put("mobile", mobile); querys.put("param", "**code**:"+code+",**minute**:5"); querys.put("smsSignId", smsSignId); querys.put("templateId", templateId); try { String result = HttpRequest.post(host) .header(Header.AUTHORIZATION, "APPCODE " + appCode)//头信息,多个头信息多次调用此方法即可 .form(querys)//表单内容 .timeout(20000)//超时,毫秒 .execute().body(); System.out.println(result); } catch (Exception e) { e.printStackTrace(); } } }
前端Vue
<template> <div style="text-align:left"> 用户名:<input type="text" class="txt" v-model="user.username" name="username" />3-20位字符,可由中文、字母、数字和下划线组成<br> 密码 :<input type="password" class="txt" name="password" v-model="user.password"/>6-20位字符,可使用字母、数字和符号的组合,不建议使用纯数字、纯字母、纯符号<br> 确认密码:<input type="password" class="txt" name="password" v-model="user.repassword"/><br> 手机号码:<input type="text" class="txt" name="mobile" v-model="user.mobile" /> <button @click.prevent="sendSMS" :disabled="smsBtnDisabled">点击发送短信验证码<span v-if="smsBtnDisabled">{{second}}秒</span></button> <br> 验证码:<input type="text" name="user.code" v-model="user.code"/><br> <input type="submit" value="注册" @click="regist()"/> </div> </template> <script> export default { data() { return { user:{}, smsBtnDisabled:false,// true 禁用按钮 false不禁用 second:5,//倒计时秒数 timer:null//倒计时对象 } }, methods: { async sendSMS(){ let res = await this.$http.get("http://localhost:10010/user/sendSms?phone="+this.user.mobile) // let res = await this.$http.get("/user/sendSms",{params:user.mobile}) if(res.data.code==0){ //发送成功 alert("发送成功") //按钮禁用 this.smsBtnDisabled = true //倒计时:每个1s执行某个函数 this.timer = setInterval(this.daojishi,1000) } }, daojishi(){ //如果second大于0,那second-- //否则停止倒计时,按钮生效 if(this.second>0){ this.second-- }else{ //停止倒计时 clearInterval(this.timer) //恢复秒数。给下次使用 this.second=5 //按钮恢复 this.smsBtnDisabled = false } }, async regist(){ try { let res = await this.$http.post("http://localhost:10010/user/reg",this.user) if(res.data.code==0){ alert("注册成功") console.log(res) this.$router.push("登录页") }else{ alert("注册失败") } }catch (error) { alert("res.msg") } } }, } </script>
后端
启动类
UserController
@RestController @RequestMapping("/user") public class UserController { // @Autowired // private HttpServletRequest request; @Autowired private RabbitTemplate rabbitTemplate; // RabbitTemplate rabbitTemplate; @Autowired private StringRedisTemplate redisTemplate; @PostMapping public BaseResult addUser(@RequestBody User user, @RequestHeader("Authorization") String authorization){ // String token = request.getHeader("authorization"); Claims claims = JWTUtil.parseToken(authorization, "user"); Object userId = claims.get("userId"); System.out.println("新增的用户信息:"+user); return BaseResult.success(null); } /** * 1 产生随机码6位 * 2 保存到rabbitMQ中 * 3 保存到redis中 * 4 返回发送成功 * @param phone * @return */ // @GetMapping("/sendSms") public BaseResult sendSMS(String phone){ // 1 产生随机码6位 String code = RandomUtil.code(); //拼接消息内容 String msg = phone + "%%%%%%" + code; // 2 保存到rabbitMQ中 rabbitTemplate.convertAndSend("sms.queue",msg); // 3 保存到redis中 redisTemplate.opsForValue().set(phone,code,1, TimeUnit.MINUTES); // 4 返回发送成功 return BaseResult.success("成功"); } @PostMapping("/reg") public BaseResult reg(@RequestBody User user){ String s2 = user.getMobile(); String s = redisTemplate.opsForValue().get(s2); System.out.println(s); if (s==null){ return BaseResult.fail(); } if (user.getCode().equals(s)){ System.out.println("注册成功,"+user); redisTemplate.delete(user.getMobile()); return BaseResult.success("成功"+user); } return BaseResult.fail(); } }
配置文件bootstrap.yaml
spring: datasource: url: jdbc:mysql://localhost/数据库表名?useSSL=false username: 账户名 password: 密码 driver-class-name: com.mysql.jdbc.Driver application: //服务名 name: userservice profiles: active: dev cloud: nacos: server-addr: localhost:8848 config: file-extension: yaml # rabbitmq: # host:# 主机名 # port: 5672 # 端口 # virtual-host: / # 虚拟主机 # username: # 用户名 # password: # 密码 redis: host: localhost port: 6379 database: 0 jedis: pool: max-idle: 8 min-idle: 0 max-active: 8 server: port: 8000
SmsListener同步redis中的值
@Component public class SmsListener { @RabbitListener(queues = "sms.queue") public void listenerWorkQueue1(String msg) throws Exception{ String[] vals = msg.split("%%%%%%"); //这里调用短信接口 AliyunSendSmsUtil.send(vals[0],vals[1]); System.out.println("sms接收到的消息:【"+msg+"】发送成功"); } }
短信接口类
public class AliyunSendSmsUtil { /** * * @param to 手机号码 * @param code 验证码 */ public static void send(String to, String code) { String accessKeyId=""; String accessSecret = ""; DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessSecret); IAcsClient client = new DefaultAcsClient(profile); CommonRequest request = new CommonRequest(); request.setSysMethod(MethodType.POST); request.setSysDomain("dysmsapi.aliyuncs.com"); request.setSysVersion("2017-05-25"); request.setSysAction("SendSms"); request.putQueryParameter("RegionId", "cn-hangzhou"); request.putQueryParameter("PhoneNumbers", to); request.putQueryParameter("SignName", ""); request.putQueryParameter("TemplateCode", "SMS_85550034"); request.putQueryParameter("TemplateParam", "{\"code\":\""+code+"\"}"); try { CommonResponse response = client.getCommonResponse(request); System.out.println(response.getData()); } catch (ServerException e) { e.printStackTrace(); } catch (ClientException e) { e.printStackTrace(); } } }
启动类
@SpringBootApplication public class SmsConsumerApplication { @Bean public Queue createSmsQueue(){ return new Queue("sms.queue"); } public static void main(String[] args) { SpringApplication.run(SmsConsumerApplication.class, args); } }
配置文件application.yml
server:
port: 20000
spring:
rabbitmq:
host: # 主机名
port: 5672 # 端口
virtual-host: / # 虚拟主机
username: # 用户名
password: # 密码
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.example</groupId> <artifactId>jwt-common03</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <!--nacos配置管理依赖--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> <!--AMQP依赖,包含RabbitMQ--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> </dependencies>