项目需求
后台生成随机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();
}
总结
以上就是今天要讲的内容,本文仅仅简单介绍了手机验证码登录的流程,很多细节并没有深入,若有问题,还请大家多多指教。