这几天做的项目接触到了用手机验证码完成一些功能,例如登录、注册、以及修改手机号码,想把流程总结出来分享给大家
基于登录发送验证码
操作 | 手机号 |
---|---|
登录 | 非空、格式正确、已注册 |
先用ajax获取框输入的手机号码提交到controller处理,部分jsp代码如下
<input type="hidden" id="u-name-reg-first" value="0" /><!--第一次输入的号码-->
<input type="text" name="key" placeholder="手机号" value=''/>
<a type="button" onclick="sendPhoneCodelogin()" titlelogin="登陆">登陆</a>
第一个框中用于双重验证号码,在点击发送信息时将第二个框中输入的号码赋值
给它,防止发送信息后改动号码
js中代码:
/**
* 发送手机验证码
*/
function sendPhoneCode() {
var mobileVal=$("#u-name-reg").val();//输入的号码
var pageFrom = "phoneLogin";//页面来源
$("#u-name-reg-first").val(mobileVal);//给第一次号码赋值
$.ajax({
url:baselocation+'/login/ajax/sendPhoneMsg',
type:'post',
dataType:'json',
data:{
"mobileVal":mobileVal,
"pageFrom":pageFrom
},
success:function(result){
if(result.success==true){
layer.msg(result.message, {icon: 1, shift: 6});
var timeTicket;
var timeNum = 60;
clearInterval(timeTicket);
/*当点击获取验证码后设置60秒计时不可点击*/
timeTicket = setInterval(function () {
if (timeNum>1){
timeNum--;
/*设置按钮不可点击*/
$(".mobile-yz-btn").addClass("mobile-yz-btn-no");
$(".mobile-yz-btn").attr("onclick","");
$(".mobile-yz-btn").text(timeNum+"秒后重新获取");
}else if (timeNum==1){
$(".mobile-yz-btn").text("点击获取验证码");
$(".mobile-yz-btn").attr("onclick","sendPhoneRegister()");
$(".mobile-yz-btn").removeClass("mobile-yz-btn-no");
timeNum = 60;
clearInterval(timeTicket);
//刷新验证码
$(".js-verify-refresh.c-green").click();
}
},1000);
}else{
layer.msg(result.message, {icon: 5, shift: 6});
}
}
})
}
消息成功发送后,提交按钮的文本框显示倒计时时间,每隔一秒触发一次事件,60秒后计时结束
在conreoller中:
//发送手机验证码
@RequestMapping("/login/ajax/sendPhoneMsg")
@ResponseBody
public Map<String,Object> sendPhoneMsg(HttpServletRequest request) throws ClientException {
Map<String,Object> json;
//获取手机号
String mobile=request.getParameter("mobileVal");
if(StringUtils.isEmpty(mobile)){
json = this.setJson(false,"号码不能为空", null);
return json;
}
if(!WebUtils.checkMobile(mobile)){
json = this.setJson(false, "号码格式错误", null);
return json;
}
//获取页面来源
String pageFrom=request.getParameter("pageFrom");
if(pageFrom!=null){
if(pageFrom.equals("register")){
String userName = request.getParameter("nameVal");
if(userService.checkUsername(userName)){
json = this.setJson(false,"该用户名已注册", null);
return json;
}
if(userService.checkMobile(mobile)){
json = this.setJson(false,"该号码已注册", null);
return json;
}
}
if(pageFrom.equals("phoneLogin")){
if(!userService.checkMobile(mobile)){
json = this.setJson(false,"该号码未注册", null);
return json;
}
}
}
json=userService.sendMobileCode(mobile,"_mobileCodeNum");
return json;
}
进行号码判空和格式处理,同时根据pageFrom参数获取页面来源,根据“登录”或“注册”页面进行号码判断。若不符合要求则无法发送信息;若通过则调用sendMobileCode方法进行信息发送
@Override
public Map<String, Object> sendMobileCode( String mobile, String cachePostfix) throws ClientException {
Map<String, Object> json = new HashMap<String, Object>();
String mobileCodeNum = "";
//获得验证码
mobileCodeNum = WebUtils.getRandomNum(4);//随机验证码4为数
//先删除之前的验证码缓存
String usedMobileCodeNum = (String) cache.get(mobile+"_mobileCodeNum");
cache.remove(usedMobileCodeNum);
//将验证码存入缓存
cache.set(mobile + cachePostfix, mobileCodeNum, 300);
SendSmsResponse sendSmsResponse = sendSms(mobile, mobileCodeNum);
if (sendSmsResponse.getCode() != null && sendSmsResponse.getCode().equals("OK")) {
//请求成功
json.put("success", Boolean.valueOf(true));
json.put("message", "短信发送成功");
json.put("entity", null);
return json;
}
json.put("success", Boolean.valueOf(false));
json.put("message", "短信发送失败,请重试");
json.put("entity", null);
return json;
}
生成随机验证码:
/**获取k位由0-9的随机数字拼成的符串*/
public static String getRandomNum(int k){
String RandomNum = "";
for (int i=0;i<k;i++){
Random rd = new Random();
RandomNum += (int)Math.floor(rd.nextInt(9));
}
return RandomNum;
}
返回的json到ajax中,用
layer.msg(result.message, {icon: 1, shift: 6});
layer.msg(result.message, {icon: 5, shift: 6});
表示发送成功或失败
输入验证码后完成登录逻辑
用户登录条件
操作 | 号码 | 验证码 |
---|---|---|
登录 | 非空、格式、与第一次输入相同 | 非空、正确 |
js中代码:
/**
* 根据手机号和验证码登陆
*/
function sendPhoneCodelogin() {
var mobileVal=$("#u-name-reg").val();//手机号
var mobileCode=$("#pp-randomcode-reg").val();//验证码
var firstMobile = $("#u-name-reg-first").val();//第一次输入的号码
$.ajax({
url:baselocation+'/user/ajax/phonelogin',
type:'post',
dataType:'json',
data:{
"mobileVal":mobileVal,
"mobilecode":mobileCode,
"firstMobile":firstMobile
},
success:function(result){
if(result.success==true){
window.location.href="${ctx}";
}else{
layer.msg(result.message, {icon: 5, shift: 6});
}
}
})
}
controller中代码:
/**
* 手机号登录
*/
@RequestMapping("/phonelogin")
@ResponseBody
public Map<String,Object> phoneLogin(HttpServletRequest request, HttpServletResponse response){
Map<String,Object> json = new HashMap<String,Object>();
Map<String,Object> map = new HashMap<String, Object>();
try{
//获取手机号
String mobile=request.getParameter("mobileVal");
//第一次输入的号码
String firstMobile = request.getParameter("firstMobile");
//验证码
String mobileCode=request.getParameter("mobilecode");
//从缓存提取手机验证码
String mobileCodeNum = (String) cache.get(mobile+"_mobileCodeNum");
if(StringUtils.isEmpty(mobile)){
json = this.setJson(false,"号码为空","mobile");
return json;
}
if(!WebUtils.checkMobile(mobile)){
json = this.setJson(false, "号码格式错误", null);
return json;
}
if(StringUtils.isEmpty(firstMobile) || !mobile.equals(firstMobile)){
json = this.setJson(false, "系统错误", null);
return json;
}
if(StringUtils.isEmpty(mobileCode)){
json = this.setJson(false, "验证码为空", null);
return json;
}
if (mobileCode.equals(mobileCodeNum)){
userService.phonelogin(mobile);
cache.remove(mobile+"_mobileCodeNum");
}else{
json = this.setJson(false,"验证码错误","mobile");
return json;
}
//进行登录操作
map.put("ipForget","true");
map.put("mobile",mobile);
map.put("request",request);
map.put("response",response);
map=userService.queryDoUserLoginByMobile(map);
json = this.setJson((boolean)map.get("success"), (String)map.get("message"), map);
WebUtils.setCookie(response, UserCacheConstans.WEB_USER_LOGIN_PREFIX, (String) map.get("uuid"), 1);
}catch (Exception e) {
this.setAjaxException(json);
logger.error("getVipInfo()---error",e);
}
return json;
}
1.若条件不符合返回相应的信息回到ajax并用
layer.msg(result.message, {icon: 5, shift: 6});
弹框显示错误信息
2.若条件符合且验证码正确,将该用户数据封装在map对象中,调用queryDoUserLoginByMobile方法,执行登录操作
/**
* 手机号登录操作
*/
public Map<String,Object> queryDoUserLoginByMobile(Map<String,Object> parameterMap) throws Exception {
Map map = new HashMap();
//--在线人数统计/限制 开始--
if(!OnlineUtil.ckeckLimit(map)) {
return map;
}
//--在线人数统计/限制 结束--
HttpServletRequest request = (HttpServletRequest)parameterMap.get("request");
HttpServletResponse response = (HttpServletResponse)parameterMap.get("response");
String ipForget = (String)parameterMap.get("ipForget");
String mobile = (String)parameterMap.get("mobile");
User user = userMapper.queryUserByEmailOrMobile(mobile);//通过号码查询用户
String account = user.getUserName();
String prefix = WebUtils.getCookie(request, UserCacheConstans.WEB_USER_LOGIN_PREFIX);
if(StringUtils.isNotEmpty(prefix)){
cache.remove(prefix);
}
if(user.getIsavalible()==2){
map.put("success",false);
map.put("message","该帐号已被禁用");
return map;
}
cache.remove(UserCacheConstans.NAME_OR_PASS_ERR_COUNT+account);
return queryDoLogin(user,ipForget,response,request);
}
User user = userMapper.queryUserByEmailOrMobile(mobile);
由于号码是唯一的,所有根据号码查询获取该用户
user.getIsavalible()
若该账号被禁用,登录失败
return queryDoLogin(user,ipForget,response,request);
若该账号不被禁用,删除之前该用户的缓存,执行登录操作
/**
* 登陆操作
*/
public Map queryDoLogin(User user, String ipForget, HttpServletResponse response, HttpServletRequest request)throws Exception{
Map map = new HashMap();
//用户密码不能让别人看到
user.setPassword("");
String uuid = RandomUtils.simpleUUID();
//当前时间戳
Long currentTimestamp=System.currentTimeMillis();
user.setLoginTimeStamp(currentTimestamp);
//当前时间
user.setLoginDatatime(new Date());
//客户端登录时间
String userLoginDatatime = URLEncoder.encode(DateUtils.format(user.getLoginDatatime(),"yyyy-MM-dd HH:mm:ss"),"UTF-8").replaceAll("\\+", "%20");
if("true".equals(ipForget)){
//缓存用户
cache.set(uuid, user,UserCacheConstans.userTime);
//缓存用户cookie key(后台获取后,可以清除登录用户的缓存)
cache.set(UserCacheConstans.WEB_USER_LOGIN_PREFIX+user.getUserId(), uuid,UserCacheConstans.userTime);
WebUtils.setCookie(response, UserCacheConstans.WEB_USER_LOGIN_PREFIX, uuid, (UserCacheConstans.userTime/60/60/24));
WebUtils.setCookie(response, UserCacheConstans.WEB_USER_LOGINDATATIME, userLoginDatatime , (UserCacheConstans.userTime/60/60/24));
}else{
//缓存用户
cache.set(uuid, user,86400);
//缓存用户cookie key(后台获取后,可以清除登录用户的缓存)
cache.set(UserCacheConstans.WEB_USER_LOGIN_PREFIX+user.getUserId(), uuid,UserCacheConstans.userTime);
WebUtils.setCookie(response, UserCacheConstans.WEB_USER_LOGIN_PREFIX, uuid, 1);
WebUtils.setCookie(response, UserCacheConstans.WEB_USER_LOGINDATATIME, userLoginDatatime , 1);
}
loginCommonOperate(request,user);
// 登录时把cookie中的购物车信息加到数据库中
shopcartService.addTempShopCart(request, response, Long.valueOf(user.getUserId()));
map.put("success",true);
map.put("message","登陆成功");
map.put("user",user);
map.put("uuid",uuid);
//--在线人数统计/限制 开始--
OnlineUtil.resetOnline(request, response, user.getUserId());
//--在线人数统计/限制 结束--
return map;
}
将各种信息写入到缓存中,返回“登录成功”的信息
if(result.success==true){
window.location.href="${ctx}";
}
登录成功后,跳转到网站首页
基于注册发送验证码
操作 | 账号 | 密码 | 确认密码 | 手机号 |
---|---|---|---|---|
注册 | 非空、格式 、未注册 | 非空、格式 | 非空、格式、与第一次输入相同 | 非空、格式、未注册 |
jsp中:
<input id="u-name-reg" type="text" name="key" placeholder="请输入账号(英文、数字、减号或下划线且6-24个字符)" value='' class="name-input" autocomplete="off"/>
<input id="u-password-reg" type="password" name="key" placeholder="请输入密码(包含字母、数字且不小于8位)" value='' class="bui-input" autocomplete="off"/>
<input id="u-password-reg-again" type="password" name="key" placeholder="请确认密码" value='' style="margin:20px 0px" class="bui-input" autocomplete="off"/>
<input id="u-phone-reg" type="text" name="key" placeholder="请输入手机号码" value='' class="name-input" autocomplete="off"/>
<input id="pp-randomcode-reg" class="name-input" placeholder="请输入验证码" name="" value="" onkeyup="$(this).next().next().next().html('');" maxlength="4" type="text">
<a class="vam ml10 disIb fl mobile-yz-btn" href="javascript:void(0)" onclick="sendPhoneCode()" title="">点击获取验证码</a>
<a class="loginBtn" type="button" onclick="Register()" title="注 册">注册</a>
1.可以同上面所说的“登录”一样将获取到的值通过ajax发送到controller中处理,再将结果返回
2.可以在js的function()中获取各个框中输入的值作判断处理,若不符合要求则无法跳到controller中处理,本例采用这种方式
//发送验证码
function sendPhoneCode() {
var pageFrom = "register";
var mobileVal=$("#u-phone-reg").val();
var nameVal = $("#u-name-reg").val();
if (nameVal == null || nameVal == "") {
layer.msg("请输入账号", {icon: 5, shift: 6});
return;
}
if (!isNaN(nameVal)) {
layer.msg("账号不能全为数字", {icon: 5, shift: 6});
return;
}
if (nameVal.length < 6 || nameVal.length > 24) {
layer.msg("账号长度为6-24个字符", {icon: 5, shift: 6});
return;
}
if (usernameRegex.test(nameVal) == false) {//账号格式
layer.msg("账号仅支持英文、数字、减号或下划线", {icon: 5, shift: 6});
return;
}
var password = $("#u-password-reg").val();
if (password == null || password == "") {
layer.msg("请输入密码", {icon: 5, shift: 6});
return;
}
password = encrypt(password);
var passwordAgain = $("#u-password-reg-again").val();
if (passwordAgain == null || passwordAgain == "") {
layer.msg("请确认密码", {icon: 5, shift: 6});
return;
}
passwordAgain = encrypt(passwordAgain);
if (password!=passwordAgain) {
layer.msg("两次密码不一致", {icon: 5, shift: 6});
return;
}
$.ajax({
url:baselocation+'/login/ajax/sendPhoneMsg',
type:'post',
dataType:'json',
data:{
"nameVal":nameVal,
"mobileVal":mobileVal,
"pageFrom":pageFrom
},
success:function(result){
if(result.success==true){
layer.msg("短信发送成功", {icon: 1, shift: 6});
var timeTicket;
var timeNum = 60;
//$("#phoneClick").css("visibility","hidden");
// $("#recoverPhoneClick").css("visibility","visible");
clearInterval(timeTicket);
/*当点击获取验证码后设置60秒计时不可点击*/
timeTicket = setInterval(function () {
if (timeNum>1){
timeNum--;
/*设置按钮不可点击*/
$(".mobile-yz-btn").addClass("mobile-yz-btn-no");
$(".mobile-yz-btn").attr("onclick","");
$(".mobile-yz-btn").text(timeNum+"秒后重新获取");
}else if (timeNum==1){
$(".mobile-yz-btn").text("点击获取验证码");
$(".mobile-yz-btn").attr("onclick","sendPhoneRegister()");
$(".mobile-yz-btn").removeClass("mobile-yz-btn-no");
timeNum = 60;
clearInterval(timeTicket);
//刷新验证码
$(".js-verify-refresh.c-green").click();
}
},1000);
}else{
layer.msg(result.message, {icon: 5, shift: 6});
}
}
})
}
其余代码跟登录相似,只是pageFrom的值不同,这样controller中才会根据不同页面对“用户名”和“手机号”作判断。若该账号或手机号已注册,则无法发送验证码,相比在点击“注册”时对之作判断,可以减少很多“无用”信息
if(pageFrom.equals("register")){
String userName = request.getParameter("nameVal");
if(userService.checkUsername(userName)){
json = this.setJson(false,"该用户名已注册", null);
return json;
}
if(userService.checkMobile(mobile)){
json = this.setJson(false,"该号码已注册", null);
return json;
}
}
输入验证码后完成注册逻辑
用户注册条件
操作 | 号码 | 验证码 |
---|---|---|
注册 | 非空、格式、未注册、与发送验证码的号码相同 | 非空、正确 |
其余逻辑均与“登录”时相似,注册成功后,登录该用户,显示主页面
Tips:本人第一篇博客,若有不足之处,欢迎大家予以斧正。