手機(jī)發(fā)送短信驗證碼登錄完整實(shí)例

項目需求

后臺生成隨機(jī)6位數(shù)作為驗證碼,發(fā)送給手機(jī),同時將驗證碼存入緩存,用戶登錄時驗證輸入的驗證碼是否過期或者是否正確抵乓。

一、發(fā)送短信

1.了解短信發(fā)送

通過發(fā)送短信的API靶衍,建立一個URL類的對象打開網(wǎng)絡(luò)連接灾炭,通過連接對象得到輸入流,就能實(shí)現(xiàn)短信發(fā)送

URL url= new URL(""https://XXXXXX?phoneNumbers=[手機(jī)號]&content=[短信內(nèi)容]"");//使用方法颅眶,拼接參數(shù)
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 發(fā)送POST方法的請求
     *
     * @param url   發(fā)送請求的 URL
     * @param param 請求參數(shù)蜈出,請求參數(shù)應(yīng)該是 name1=value1&name2=value2 的形式瑟啃。
     * @return 所代表遠(yuǎn)程資源的響應(yīng)結(jié)果
     */
    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();
            // 設(shè)置通用的請求屬性
            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());
                }
            }
            // 發(fā)送POST請求必須設(shè)置如下兩行
            conn.setUseCaches(false);
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setConnectTimeout(1000000);
            conn.setReadTimeout(1000000);

            // 獲取URLConnection對象對應(yīng)的輸出流
            if(StringUtils.isNotBlank(param)){
                out = new PrintWriter(new OutputStreamWriter(conn.getOutputStream(),"utf-8"));
                out.write(param);
                // flush輸出流的緩沖
                out.flush();
            }

            // 定義BufferedReader輸入流來讀取URL的響應(yīng)
            in = new BufferedReader(
                    new InputStreamReader(conn.getInputStream(), "utf-8"));
            String line;
            while ((line = in.readLine()) != null) {
                result += line;
            }
        } catch (Exception e) {
            System.out.println("發(fā)送 POST 請求出現(xiàn)異常矩肩!" + e);
            System.out.println(JSONObject.toJSONString(e));
            e.printStackTrace();
        }
        //使用finally塊來關(guān)閉輸出流、輸入流
        finally {
            try {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        return result;
    }

發(fā)送短信設(shè)置發(fā)送內(nèi)容和手機(jī)號

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服務(wù)器地址(根據(jù)自己的url設(shè)置)
     */
    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;
    }
}

二由捎、手機(jī)號登錄

1.發(fā)送短信接口

寫接口之前商叹,先寫個緩存(這里用的是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是我們配置給哨兵的服務(wù)名稱
            String mastername = getProperty("redis.mastername", "");
            int port = 6379;
            // 哨兵信息(舉例燕刻,根據(jù)實(shí)際情況不同配置)
            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);
    }
    
   /**
    * 設(shè)置緩存(沒有過期時間)
    * 
    */
    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();
        }
    }

   /**
    * 設(shè)置緩存(有過期時間)
    * 
    */
    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();
    }

}

發(fā)送短信接口代碼如下:

    @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();
        // 隨機(jī)生成驗證碼
        String verifyCode = (int)(Math.random()* 900000 + 100000)+"";
   
        // redis配置,實(shí)際應(yīng)該封裝一個工具類,這里簡單寫一下
        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","發(fā)送成功"); 
            return object.toString();
        } else {
            object.put("code",1);
            object.put("msg","發(fā)送失敗"); 
            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","手機(jī)號或驗證碼不能為空"); 
            return object.toString();
        } else if (!loginService.checkPhone(phone)) {
            object.put("code",1);
            object.put("msg","輸入的手機(jī)號非法弥咪,請輸入正確的手機(jī)號"); 
            return object.toString();
        }
        return loginService.loginByPhone(phone, verifyCode);
    }

登錄業(yè)務(wù)邏輯

    @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","驗證碼已失效过蹂,請重新發(fā)送"); 
            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);
            }
            // 設(shè)置緩存(沒有過期時間)
            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) {
        // 手機(jī)號格式(不驗證號碼段)
        Pattern p = Pattern.compile("^^1[0-9]{10}$");
        Matcher m = p.matcher(phone);
        return m.matches();
    }

總結(jié)

以上就是今天要講的內(nèi)容十绑,本文僅僅簡單介紹了手機(jī)驗證碼登錄的流程,很多細(xì)節(jié)并沒有深入酷勺,若有問題本橙,還請大家多多指教。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末脆诉,一起剝皮案震驚了整個濱河市甚亭,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌库说,老刑警劉巖狂鞋,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件片择,死亡現(xiàn)場離奇詭異潜的,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)字管,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進(jìn)店門啰挪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人嘲叔,你說我怎么就攤上這事亡呵。” “怎么了硫戈?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵锰什,是天一觀的道長。 經(jīng)常有香客問我丁逝,道長汁胆,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任霜幼,我火速辦了婚禮嫩码,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘罪既。我一直安慰自己铸题,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布琢感。 她就那樣靜靜地躺著丢间,像睡著了一般。 火紅的嫁衣襯著肌膚如雪驹针。 梳的紋絲不亂的頭發(fā)上烘挫,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天,我揣著相機(jī)與錄音牌捷,去河邊找鬼墙牌。 笑死涡驮,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的喜滨。 我是一名探鬼主播捉捅,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼虽风!你這毒婦竟也來了棒口?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤辜膝,失蹤者是張志新(化名)和其女友劉穎无牵,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體厂抖,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡茎毁,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了忱辅。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片七蜘。...
    茶點(diǎn)故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖墙懂,靈堂內(nèi)的尸體忽然破棺而出橡卤,到底是詐尸還是另有隱情,我是刑警寧澤损搬,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布碧库,位于F島的核電站,受9級特大地震影響巧勤,放射性物質(zhì)發(fā)生泄漏嵌灰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一踢关、第九天 我趴在偏房一處隱蔽的房頂上張望伞鲫。 院中可真熱鬧,春花似錦签舞、人聲如沸秕脓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽吠架。三九已至,卻和暖如春搂鲫,著一層夾襖步出監(jiān)牢的瞬間傍药,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留拐辽,地道東北人拣挪。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像俱诸,于是被迫代替她去往敵國和親菠劝。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評論 2 353

推薦閱讀更多精彩內(nèi)容