手机发送短信验证码登录完整实例

项目需求

后台生成随机6位数作为验证码,发送给手机,同时将验证码存入缓存,用户登录时验证输入的验证码是否过期或者是否正确。

一、发送短信

1.了解短信发送

通过发送短信的API,建立一个URL类的对象打开网络连接,通过连接对象得到输入流,就能实现短信发送

1 URL url= new URL(""https://XXXXXX?phoneNumbers=[手机号]&content=[短信内容]"");//使用方法,拼接参数
2 url.openConnection().getInputStream();

封装上述方法

 1 import com.alibaba.fastjson.JSONObject;
 2 import org.apache.commons.lang.StringUtils;
 3 
 4 import java.io.*;
 5 import java.net.HttpURLConnection;
 6 import java.net.URL;
 7 import java.net.URLConnection;
 8 import java.util.HashMap;
 9 import java.util.List;
10 import java.util.Map;
11 import java.util.Map.Entry;
12 
13 public class SendRequestMethod {
14 
15     /**
16      * 向指定 URL 发送POST方法的请求
17      *
18      * @param url   发送请求的 URL
19      * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
20      * @return 所代表远程资源的响应结果
21      */
22     public static String postMethod(String url, String param, Map<String, String> headParam) {
23         Long s0 = System.currentTimeMillis();
24         PrintWriter out = null;
25         BufferedReader in = null;
26         String result = "";
27         try {
28             URL realUrl = new URL(url);
29             // 打开和URL之间的连接
30             HttpURLConnection conn = (HttpURLConnection)realUrl.openConnection();
31             // 设置通用的请求属性
32             conn.setRequestProperty("accept", "*/*");
33             conn.setRequestMethod("POST");
34             conn.setRequestProperty("Accept-Charset", "UTF-8");
35             conn.setRequestProperty("Content-Type", "application/json");
36             conn.setRequestProperty("charset","UTF-8");
37             if (headParam != null) {
38                 for (Entry<String, String> entry : headParam.entrySet()) {
39                     conn.setRequestProperty(entry.getKey(), entry.getValue());
40                 }
41             }
42             // 发送POST请求必须设置如下两行
43             conn.setUseCaches(false);
44             conn.setDoOutput(true);
45             conn.setDoInput(true);
46             conn.setConnectTimeout(1000000);
47             conn.setReadTimeout(1000000);
48 
49             // 获取URLConnection对象对应的输出流
50             if(StringUtils.isNotBlank(param)){
51                 out = new PrintWriter(new OutputStreamWriter(conn.getOutputStream(),"utf-8"));
52                 out.write(param);
53                 // flush输出流的缓冲
54                 out.flush();
55             }
56 
57             // 定义BufferedReader输入流来读取URL的响应
58             in = new BufferedReader(
59                     new InputStreamReader(conn.getInputStream(), "utf-8"));
60             String line;
61             while ((line = in.readLine()) != null) {
62                 result += line;
63             }
64         } catch (Exception e) {
65             System.out.println("发送 POST 请求出现异常!" + e);
66             System.out.println(JSONObject.toJSONString(e));
67             e.printStackTrace();
68         }
69         //使用finally块来关闭输出流、输入流
70         finally {
71             try {
72                 if (out != null) {
73                     out.close();
74                 }
75                 if (in != null) {
76                     in.close();
77                 }
78             } catch (IOException ex) {
79                 ex.printStackTrace();
80             }
81         }
82         return result;
83     }

发送短信设置发送内容和手机号

 1 import com.alibaba.fastjson.JSONObject;
 2 import com.wisesoft.core.util.prop.PropertiesUtil;
 3 import org.apache.commons.lang.StringUtils;
 4 
 5 import java.util.*;
 6 
 7 public class SendMessage {
 8 
 9     /**
10      * 短信API服务器地址(根据自己的url设置)
11      */
12     private static String pathUrl= "http://xxxxx";
13 
14 
15     public static JSONObject send(String content,String... phoneNumbers){
16 
17         JSONObject param = new JSONObject(2);
18         param.put("content",content);
19         param.put("phoneNumbers", StringUtils.join(phoneNumbers,","));
20 
21         Map<String,String> headParam = new HashMap<>();
22         headParam.put("Content-Type","application/json;charset=UTF-8");
23 
24         String requestResult = SendRequestMethod .postMethod(pathUrl,param.toJSONString(),headParam);
25         JSONObject result = JSONObject.parseObject(requestResult );
26         return result;
27     }
28 }

二、手机号登录

1.发送短信接口

写接口之前,先写个缓存(这里用的是Redis)的工具类(只写了要用的两个方法)

=
  1 package com.wisesoft.scenic.service.joggle.utils.redis;
  2 
  3 import com.wisesoft.core.util.StringUtil;
  4 import com.wisesoft.core.util.prop.FrameworkProps;
  5 import com.wisesoft.scenic.interfaceserver.vo.InterfaceServerVO;
  6 import redis.clients.jedis.Jedis;
  7 import redis.clients.jedis.JedisPool;
  8 import redis.clients.jedis.JedisPoolConfig;
  9 import redis.clients.jedis.JedisSentinelPool;
 10 
 11 import java.util.HashSet;
 12 import java.util.List;
 13 import java.util.Map;
 14 import java.util.Set;
 15 
 16 public class RedisUtil {
 17 
 18     private static JedisSentinelPool sentinelPool;
 19     private static JedisPool jedisPool;
 20 
 21     static {
 22 
 23         String str_host = getProperty("redis.host", "");
 24         String str_port = getProperty("redis.port", "");
 25         String password = getProperty("redis.password", "");
 26         int database = getProperty("redis.database", 0);
 27         int timeout = getProperty("redis.timeout", 5000);
 28         String runmodel = getProperty("redis.runmodel", "");
 29 
 30         //连接池配置
 31         JedisPoolConfig config = new JedisPoolConfig();
 32         config .setMaxTotal(10);
 33         config .setMaxIdle(5);
 34         config .setMinIdle(5);
 35         .....
 36         
 37         if (StringUtil.isNotBlank(runmodel) && "cluster".equalsIgnoreCase(runmodel)) {
 38             // mastername是我们配置给哨兵的服务名称
 39             String mastername = getProperty("redis.mastername", "");
 40             int port = 6379;
 41             // 哨兵信息(举例,根据实际情况不同配置)
 42             Set<String> sentinels = new HashSet<String>(Arrays.asList(
 43                 "10.201.7.171:26379",
 44                 "10.201.7.175:26379",
 45                 "10.201.7.176:26379"
 46             ));
 47             sentinelPool = new JedisSentinelPool(mastername, sentinels, config, timeout, password, database);
 48 
 49         } else {
 50             int port = Integer.valueOf(str_port);
 51             jedisPool = new JedisPool(config, str_host, port, timeout, password);
 52         }
 53     }
 54 
 55     private RedisClient() {
 56     }
 57     
 58      public static String getProperty(String name, String defaultValue) {
 59         return FrameworkProps.getProperty(name, defaultValue);
 60     }
 61     
 62    /**
 63      * 设置缓存(没有过期时间)
 64      * 
 65      */
 66     public static String set(String key, String value) {
 67         Jedis jedis = getJedis();
 68         try {
 69             String val = jedis.set(key, value);
 70             return val;
 71         } finally {
 72             jedis.close();
 73         }
 74     }
 75 
 76     public static String get(String key) {
 77         Jedis jedis = getJedis();
 78         try {
 79             String val = jedis.get(key);
 80             return val;
 81         } finally {
 82             jedis.close();
 83         }
 84     }
 85 
 86    /**
 87      * 设置缓存(有过期时间)
 88      * 
 89      */
 90     public static String set(String key, String value, int second) {
 91         Jedis jedis = getJedis();
 92         try {
 93             String val = jedis.set(key, value);
 94             jedis.expire(key, second);
 95             return val;
 96         } finally {
 97             jedis.close();
 98         }
 99     }
100 
101     public static Long del(String key) {
102         Jedis jedis = getJedis();
103         try {
104             Long obj = jedis.del(key);
105             return obj;
106         } finally {
107             jedis.close();
108         }
109     }
110 
111    /**
112      * 获取客户端连接
113      * 
114      */
115     public static Jedis getJedis() {
116         if (sentinelPool != null) {
117             return sentinelPool.getResource();
118         }
119         return jedisPool.getResource();
120     }
121 
122 }

 

发送短信接口代码如下:

 1 @RequestMapping(value = "/sendMessage", method = RequestMethod.POST, produces = "application/json;charset=utf-8")
 2     @ResponseBody
 3     public String sendMessage(@RequestBody String jsonStr) {
 4         JSONObject object = JSON.parseObject(jsonStr);
 5         String phone = object.getString("phone");
 6         JSONObject object = new JSONObject();
 7         // 随机生成验证码
 8         String verifyCode = (int)(Math.random()* 900000 + 100000)+"";
 9    
10            // redis配置,实际应该封装一个工具类,这里简单写一下
11          RedisUtil.set(phone + "_verifyCode", verifyCode, 600);
12         String content = "【CSDN】验证码:"+verifyCode+",您正在使用短信验证码登录,有效期10分钟。";
13         JSONObject send = SendMessage.send(content, phone);
14         if(send != null && 200 == send.getIntValue("code")){
15             object.put("code",0);
16             object.put("msg","发送成功"); 
17             return object.toString();
18         } else {
19             object.put("code",1);
20             object.put("msg","发送失败"); 
21             return object.toString();
22         }
23 
24     }

2.登录接口

代码如下:

 1 @RequestMapping(value = "/login", method = RequestMethod.POST, produces = "application/json;charset=utf-8")
 2     @ResponseBody
 3     public String login(@RequestBody String jsonStr) {
 4         JSONObject object = JSON.parseObject(jsonStr);
 5         String phone = object.getString("phone");
 6         String verifyCode = object.getString("verifyCode");
 7         JSONObject object = new JSONObject();
 8         
 9         if (StringUtils.isEmpty(phone) || StringUtils.isEmpty(verifyCode)) {
10             object.put("code",1);
11             object.put("msg","手机号或验证码不能为空"); 
12             return object.toString();
13         } else if (!loginService.checkPhone(phone)) {
14             object.put("code",1);
15             object.put("msg","输入的手机号非法,请输入正确的手机号"); 
16             return object.toString();
17         }
18         return loginService.loginByPhone(phone, verifyCode);
19     }

登录业务逻辑

 1 @Override
 2     public String loginByPhone(String phone, String verifyCode) {
 3         JSONObject object = new JSONObject();
 4         // 获取短信验证码
 5         String codeStr = RedisUtil.get(phone + "_verifyCode");
 6         if (StringUtil.isEmpty(codeStr)) {
 7             object.put("code",1);
 8             object.put("msg","验证码已失效,请重新发送"); 
 9             return object.toString();
10         }
11         // 判断验证码是否正确
12         if (verifyCode.equals(codeStr)) {
13             // 查询用户信息
14              User user = userService.getByPhone(phone);
15              Date date = new Date();
16              // 用户登录信息
17              UserAccount account = new UserAccount();
18             // 判断账号是否存在
19             if (user == null) {
20                 // 用户不存在,则注册账号
21                 User userInfo= new User();
22                 userInfo.setId(UuidUtil.generateUUID());
23                 userInfo.setPhoneNum(phone);
24                 userInfo.setCreateTime(date);
25                 userInfo.setUpdateTime(date);
26                 userInfo.setRegTime(date);
27                 userInfo.setLastLoginTime(date);
28                 userService.insert(userInfo);
29                 BeanUtils.copyProperties(userInfo,account);
30             } else {
31                 // 用户存在
32                 if (user.getLastLoginTime() != null) {
33                     date = user.getLastLoginTime();
34                 }
35                 BeanUtils.copyProperties(user,account);
36                 // 更新登录信息
37                 user.setLastLoginTime(new Date());
38                 userService.update(user);
39             }
40             // 设置缓存(没有过期时间)
41             String userJson = JSONObject.toJSONString(account);
42             RedisUtil.set("user" + account.getUserId(), userJson);
43             object.put("code",0);
44             object.put("msg","登录成功"); 
45             object.put("result",account); 
46             return object.toString();
47         } else {
48             object.put("code",1);
49             object.put("msg","输入验证码不正确"); 
50             return object.toString();
51         }
52     }
53 
54     @Override
55     public boolean checkPhone(String phone) {
56         // 手机号格式(不验证号码段)
57         Pattern p = Pattern.compile("^^1[0-9]{10}$");
58         Matcher m = p.matcher(phone);
59         return m.matches();
60     }

总结

以上就是今天要讲的内容,本文仅仅简单介绍了手机验证码登录的流程,很多细节并没有深入,若有问题,还请大家多多指教。

posted on 2021-04-21 16:19  猫的树kireCat  阅读(712)  评论(0编辑  收藏  举报