美文网首页spring boot
手机发送短信验证码登录完整实例

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

作者: 猫的树 | 来源:发表于2021-06-16 09:19 被阅读0次

    项目需求

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

    一、发送短信

    1.了解短信发送

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

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

    封装上述方法

    import com.alibaba.fastjson.JSONObject;
    import org.apache.commons.lang.StringUtils;
    
    import java.io.*;
    import java.net.HttpURLConnection;
    import java.net.URL;
    import java.net.URLConnection;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import java.util.Map.Entry;
    
    public class SendRequestMethod {
    
        /**
         * 向指定 URL 发送POST方法的请求
         *
         * @param url   发送请求的 URL
         * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
         * @return 所代表远程资源的响应结果
         */
        public static String postMethod(String url, String param, Map<String, String> headParam) {
            Long s0 = System.currentTimeMillis();
            PrintWriter out = null;
            BufferedReader in = null;
            String result = "";
            try {
                URL realUrl = new URL(url);
                // 打开和URL之间的连接
                HttpURLConnection conn = (HttpURLConnection)realUrl.openConnection();
                // 设置通用的请求属性
                conn.setRequestProperty("accept", "*/*");
                conn.setRequestMethod("POST");
                conn.setRequestProperty("Accept-Charset", "UTF-8");
                conn.setRequestProperty("Content-Type", "application/json");
                conn.setRequestProperty("charset","UTF-8");
                if (headParam != null) {
                    for (Entry<String, String> entry : headParam.entrySet()) {
                        conn.setRequestProperty(entry.getKey(), entry.getValue());
                    }
                }
                // 发送POST请求必须设置如下两行
                conn.setUseCaches(false);
                conn.setDoOutput(true);
                conn.setDoInput(true);
                conn.setConnectTimeout(1000000);
                conn.setReadTimeout(1000000);
    
                // 获取URLConnection对象对应的输出流
                if(StringUtils.isNotBlank(param)){
                    out = new PrintWriter(new OutputStreamWriter(conn.getOutputStream(),"utf-8"));
                    out.write(param);
                    // flush输出流的缓冲
                    out.flush();
                }
    
                // 定义BufferedReader输入流来读取URL的响应
                in = new BufferedReader(
                        new InputStreamReader(conn.getInputStream(), "utf-8"));
                String line;
                while ((line = in.readLine()) != null) {
                    result += line;
                }
            } catch (Exception e) {
                System.out.println("发送 POST 请求出现异常!" + e);
                System.out.println(JSONObject.toJSONString(e));
                e.printStackTrace();
            }
            //使用finally块来关闭输出流、输入流
            finally {
                try {
                    if (out != null) {
                        out.close();
                    }
                    if (in != null) {
                        in.close();
                    }
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
            return result;
        }
    

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

    import com.alibaba.fastjson.JSONObject;
    import com.wisesoft.core.util.prop.PropertiesUtil;
    import org.apache.commons.lang.StringUtils;
    
    import java.util.*;
    
    public class SendMessage {
    
        /**
         * 短信API服务器地址(根据自己的url设置)
         */
        private static String pathUrl= "http://xxxxx";
    
    
        public static JSONObject send(String content,String... phoneNumbers){
    
            JSONObject param = new JSONObject(2);
            param.put("content",content);
            param.put("phoneNumbers", StringUtils.join(phoneNumbers,","));
    
            Map<String,String> headParam = new HashMap<>();
            headParam.put("Content-Type","application/json;charset=UTF-8");
    
            String requestResult = SendRequestMethod .postMethod(pathUrl,param.toJSONString(),headParam);
            JSONObject result = JSONObject.parseObject(requestResult );
            return result;
        }
    }
    

    二、手机号登录

    1.发送短信接口

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

    package com.wisesoft.scenic.service.joggle.utils.redis;
    
    import com.wisesoft.core.util.StringUtil;
    import com.wisesoft.core.util.prop.FrameworkProps;
    import com.wisesoft.scenic.interfaceserver.vo.InterfaceServerVO;
    import redis.clients.jedis.Jedis;
    import redis.clients.jedis.JedisPool;
    import redis.clients.jedis.JedisPoolConfig;
    import redis.clients.jedis.JedisSentinelPool;
    
    import java.util.HashSet;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    
    public class RedisUtil {
    
        private static JedisSentinelPool sentinelPool;
        private static JedisPool jedisPool;
    
        static {
    
            String str_host = getProperty("redis.host", "");
            String str_port = getProperty("redis.port", "");
            String password = getProperty("redis.password", "");
            int database = getProperty("redis.database", 0);
            int timeout = getProperty("redis.timeout", 5000);
            String runmodel = getProperty("redis.runmodel", "");
    
            //连接池配置
            JedisPoolConfig config = new JedisPoolConfig();
            config .setMaxTotal(10);
            config .setMaxIdle(5);
            config .setMinIdle(5);
            .....
            
            if (StringUtil.isNotBlank(runmodel) && "cluster".equalsIgnoreCase(runmodel)) {
                // mastername是我们配置给哨兵的服务名称
                String mastername = getProperty("redis.mastername", "");
                int port = 6379;
                // 哨兵信息(举例,根据实际情况不同配置)
                Set<String> sentinels = new HashSet<String>(Arrays.asList(
                    "10.201.7.171:26379",
                    "10.201.7.175:26379",
                    "10.201.7.176:26379"
                ));
                sentinelPool = new JedisSentinelPool(mastername, sentinels, config, timeout, password, database);
    
            } else {
                int port = Integer.valueOf(str_port);
                jedisPool = new JedisPool(config, str_host, port, timeout, password);
            }
        }
    
        private RedisClient() {
        }
        
        public static String getProperty(String name, String defaultValue) {
            return FrameworkProps.getProperty(name, defaultValue);
        }
        
       /**
        * 设置缓存(没有过期时间)
        * 
        */
        public static String set(String key, String value) {
            Jedis jedis = getJedis();
            try {
                String val = jedis.set(key, value);
                return val;
            } finally {
                jedis.close();
            }
        }
    
        public static String get(String key) {
            Jedis jedis = getJedis();
            try {
                String val = jedis.get(key);
                return val;
            } finally {
                jedis.close();
            }
        }
    
       /**
        * 设置缓存(有过期时间)
        * 
        */
        public static String set(String key, String value, int second) {
            Jedis jedis = getJedis();
            try {
                String val = jedis.set(key, value);
                jedis.expire(key, second);
                return val;
            } finally {
                jedis.close();
            }
        }
    
        public static Long del(String key) {
            Jedis jedis = getJedis();
            try {
                Long obj = jedis.del(key);
                return obj;
            } finally {
                jedis.close();
            }
        }
    
       /**
        * 获取客户端连接
        * 
        */
        public static Jedis getJedis() {
            if (sentinelPool != null) {
                return sentinelPool.getResource();
            }
            return jedisPool.getResource();
        }
    
    }
    
    

    发送短信接口代码如下:

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

    2.登录接口

    代码如下:

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

    登录业务逻辑

        @Override
        public String loginByPhone(String phone, String verifyCode) {
            JSONObject object = new JSONObject();
            // 获取短信验证码
            String codeStr = RedisUtil.get(phone + "_verifyCode");
            if (StringUtil.isEmpty(codeStr)) {
                object.put("code",1);
                object.put("msg","验证码已失效,请重新发送"); 
                return object.toString();
            }
            // 判断验证码是否正确
            if (verifyCode.equals(codeStr)) {
                // 查询用户信息
                User user = userService.getByPhone(phone);
                Date date = new Date();
                // 用户登录信息
                UserAccount account = new UserAccount();
                // 判断账号是否存在
                if (user == null) {
                    // 用户不存在,则注册账号
                    User userInfo= new User();
                    userInfo.setId(UuidUtil.generateUUID());
                    userInfo.setPhoneNum(phone);
                    userInfo.setCreateTime(date);
                    userInfo.setUpdateTime(date);
                    userInfo.setRegTime(date);
                    userInfo.setLastLoginTime(date);
                    userService.insert(userInfo);
                    BeanUtils.copyProperties(userInfo,account);
                } else {
                    // 用户存在
                    if (user.getLastLoginTime() != null) {
                        date = user.getLastLoginTime();
                    }
                    BeanUtils.copyProperties(user,account);
                    // 更新登录信息
                    user.setLastLoginTime(new Date());
                    userService.update(user);
                }
                // 设置缓存(没有过期时间)
                String userJson = JSONObject.toJSONString(account);
                RedisUtil.set("user" + account.getUserId(), userJson);
                object.put("code",0);
                object.put("msg","登录成功"); 
                object.put("result",account); 
                return object.toString();
            } else {
                object.put("code",1);
                object.put("msg","输入验证码不正确"); 
                return object.toString();
            }
        }
    
        @Override
        public boolean checkPhone(String phone) {
            // 手机号格式(不验证号码段)
            Pattern p = Pattern.compile("^^1[0-9]{10}$");
            Matcher m = p.matcher(phone);
            return m.matches();
        }
    

    总结

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

    相关文章

      网友评论

        本文标题:手机发送短信验证码登录完整实例

        本文链接:https://www.haomeiwen.com/subject/eyxdsltx.html