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

项目需求

后台生成随机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 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 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 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 sentinels = new HashSet(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();
    }

总结

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

你可能感兴趣的:(手机发送短信验证码登录完整实例)