項目需求
后臺生成隨機(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é)并沒有深入酷勺,若有問題本橙,還請大家多多指教。