BootstrapValidator实现注册校验和登录错误提示效果


Posted in Javascript onMarch 10, 2017

使用BootstrapValidator进行注册校验和登录错误提示,具体内容如下

1、介绍

在AdminEAP框架中,使用了BootstrapValidator校验框架,本文以注册校验的用户名、登录名、密码、确认密码的校验(后面还有时间区间、服务器校验)为例,讲述BootstrapValidator的使用。同时以登录错误提示为例,说明如何在动态改变组件的错误提示信息。

先看下面的注册与登录的校验效果图:

注册校验:

BootstrapValidator实现注册校验和登录错误提示效果

登录错误提示:根据不同的错误类型,动态改变组件的样式和错误提示内容

BootstrapValidator实现注册校验和登录错误提示效果

BootstrapValidator实现注册校验和登录错误提示效果

2、注册校验

1、头部引入bootstrap-validator.css

<link rel="stylesheet"  href="${basePath}/resources/adminlte/plugins/bootstrap-validator/dist/css/bootstrap-validator.css" rel="external nofollow" />

${basePath}为系统的路径变量

2、form组件

 

<form action="${basePath}/oauth/register" method="post" id="register-form">
      <input type="hidden" name="oAuthId" value="${oAuthInfo.oAuthId?default('-1')}">
      <input type="hidden" name="oAuthType" value="${oAuthInfo.oAuthType?default('-1')}">
      <div class="form-group has-feedback">
        <input type="text" class="form-control" name="userName" id="userName" placeholder="请输入用户名" required>
        <span class="glyphicon glyphicon-user form-control-feedback"></span>
      </div>
      <div class="form-group has-feedback">
        <input type="text" class="form-control" name="loginName" id="loginName" placeholder="请输入登录邮箱/登录名">
        <span class="glyphicon glyphicon-envelope form-control-feedback"></span>
      </div>
      <div class="form-group has-feedback">
        <input type="password" class="form-control" name="password" id="password" placeholder="请输入密码">
        <span class="glyphicon glyphicon-lock form-control-feedback"></span>
      </div>
      <div class="form-group has-feedback">
        <input type="password" class="form-control" name="repassword" id="repassword" placeholder="再次确认密码">
        <span class="glyphicon glyphicon-log-in form-control-feedback"></span>
      </div>
      <div class="row">
        <div class="col-xs-12">
          <div class="checkbox icheck">
            <label>
              <input type="checkbox" name="rememberMe" required> 同意遵循<a href="#" rel="external nofollow" >AdminEAP协议</a>
            </label>
          </div>
        </div>
        <!-- /.col -->
      </div>
      <div class="row">
        <div class="col-xs-12">
          <button type="submit" class="btn btn-danger btn-block btn-flat">注 册</button>
        </div>
      </div>
    </form>

3、引入bootstrap-validator.js

<script src="${basePath}/resources/adminlte/bootstrap/js/bootstrap.min.js"></script>

4、校验的核心js代码

<script>
  $(function () {
    //将checkbox渲染为icheck样式
    $('input').iCheck({
      checkboxClass: 'icheckbox_square-red',
      radioClass: 'iradio_square-red',
      increaseArea: '20%' // optional
    });

    //此处为校验的核心代码
    $("#register-form").bootstrapValidator({
      submitHandler: function (valiadtor, loginForm, submitButton) {

        valiadtor.defaultSubmit();
      },
      fields: {
        userName: {
          validators: {
            notEmpty: {
              message: '用户名不能为空'
            },
            stringLength: {
              /*长度提示*/
              min: 4,
              max: 30,
              message: '用户名长度必须在4到30之间'
            }
          }
        },
        loginName: {
          validators: {
            notEmpty: {
              message: '登录邮箱名或用户名不能为空'
            },
            stringLength: {
              /*长度提示*/
              min: 4,
              max: 30,
              message: '用户名长度必须在4到30之间'
            },
            threshold: 4,//只有4个字符以上才发送ajax请求
            remote: {
              url: "${basePath}/oauth/checkUnique",
              data: function (validator) {
                return {
                  loginName: $("#loginName").val(),
                  userId: null
                };
              },
              message: '该登录名已被使用,请使用其他登录名',
              delay:2000
            }
          }
        },
        password: {
          validators: {
            notEmpty: {
              message: '密码不能为空'
            },
            stringLength: {
              /*长度提示*/
              min: 6,
              max: 30,
              message: '密码长度必须在6到30之间'
            },
            different: {//不能和用户名相同
              field: 'loginName',//需要进行比较的input name值
              message: '不能和用户名相同'
            },
            regexp: {
              regexp: /^[a-zA-Z0-9_\.]+$/,
              message: '密码由数字字母下划线和.组成'
            }
          }
        },
        repassword: {
          message: '密码无效',
          validators: {
            notEmpty: {
              message: '密码不能为空'
            },
            stringLength: {
              min: 6,
              max: 30,
              message: '用户名长度必须在6到30之间'
            },
            identical: {//相同
              field: 'password',
              message: '两次密码不一致'
            },
            different: {//不能和用户名相同
              field: 'loginName',
              message: '不能和用户名相同'
            },
            regexp: {//匹配规则
              regexp: /^[a-zA-Z0-9_\.]+$/,
              message: '密码由数字字母下划线和.组成'
            }
          }
        }

      }
    });

  });

5、登录名唯一性校验的后台代码

/**
   * 校验当前登录名/邮箱的唯一性
   * @param loginName 登录名
   * @param userId 用户ID(用户已经存在,即又改回原来的名字还是唯一的)
   * @return
   */
  @RequestMapping(value = "/oauth/checkUnique", method = RequestMethod.POST)
  @ResponseBody
  public Map checkExist(String loginName, String userId) {
    Map<String, Boolean> map = new HashMap<String, Boolean>();
    User user = userService.getUserByLoginName(loginName);
    //用户不存在,校验有效
    if (user == null) {
      map.put("valid", true);
    } else {
      //用户存在(存在的用户是当前用户,登录名一致,校验通过,否则校验不通过)
      if(!StrUtil.isEmpty(userId)&&userId.equals(user.getLoginName())){
        map.put("valid",true);
      }else {
        map.put("valid", false);
      }
    }
    return map;
  }

以上的配置完成了注册文本框的各种校验,更多的校验内容,可以查看相关的bootstrap-validator的API文档。

3、登录错误动态提示

1、在后台登录时,会抛出各种登录不成功的提示,需要动态改变前端组件的错误提示信息。不同类型的错误信息编码,要控制不同的组件样式和提示内容。以下是后台抛出的错误类型和错误信息(使用shiro认证)。

try {
      subject.login(token);
      //通过认证
      if (subject.isAuthenticated()) {
        Set<String> roles = roleService.getRoleCodeSet(userName);
        if (!roles.isEmpty()) {
          subject.getSession().setAttribute("isAuthorized", true);
          return MAIN_PAGE;
        } else {//没有授权
          msg = "您没有得到相应的授权!";
          model.addAttribute("message", new ResultCode("1", msg));
          subject.getSession().setAttribute("isAuthorized", false);
          LOGGER.error(msg);
          return LOGIN_PAGE;
        }

      } else {
        return LOGIN_PAGE;
      }
      //0 未授权 1 账号问题 2 密码错误 3 账号密码错误
    } catch (IncorrectCredentialsException e) {
      msg = "登录密码错误. Password for account " + token.getPrincipal() + " was incorrect";
      model.addAttribute("message", new ResultCode("2", msg));
      LOGGER.error(msg);
    } catch (ExcessiveAttemptsException e) {
      msg = "登录失败次数过多";
      model.addAttribute("message", new ResultCode("3", msg));
      LOGGER.error(msg);
    } catch (LockedAccountException e) {
      msg = "帐号已被锁定. The account for username " + token.getPrincipal() + " was locked.";
      model.addAttribute("message", new ResultCode("1", msg));
      LOGGER.error(msg);
    } catch (DisabledAccountException e) {
      msg = "帐号已被禁用. The account for username " + token.getPrincipal() + " was disabled.";
      model.addAttribute("message", new ResultCode("1", msg));
      LOGGER.error(msg);
    } catch (ExpiredCredentialsException e) {
      msg = "帐号已过期. the account for username " + token.getPrincipal() + " was expired.";
      model.addAttribute("message", new ResultCode("1", msg));
      LOGGER.error(msg);
    } catch (UnknownAccountException e) {
      msg = "帐号不存在. There is no user with username of " + token.getPrincipal();
      model.addAttribute("message", new ResultCode("1", msg));
      LOGGER.error(msg);
    } catch (UnauthorizedException e) {
      msg = "您没有得到相应的授权!" + e.getMessage();
      model.addAttribute("message", new ResultCode("1", msg));
      LOGGER.error(msg);
    }

2、前端核心JS代码

<script>
    $(function () {
      $('input').iCheck({
        checkboxClass: 'icheckbox_square-red',
        radioClass: 'iradio_square-red',
        increaseArea: '20%' // optional
      });

      fillbackLoginForm();
      $("#login-form").bootstrapValidator({
        message:'请输入用户名/密码',
        submitHandler:function (valiadtor,loginForm,submitButton) {
          rememberMe($("input[name='rememberMe']").is(":checked"));
          valiadtor.defaultSubmit();
        },
        fields:{
          userName:{
            validators:{
              notEmpty:{
                message:'登录邮箱名或用户名不能为空'
              }
            }
          },
          password:{
            validators:{
              notEmpty:{
                message:'密码不能为空'
              }
            }
          }
        }
      });
      <!--freemark语法,查看是否从后台传送过来错误信息,并初始化错误提示组件LoginValidator-->
      <#if message??>
        new LoginValidator({
          code:"${message.code?default('-1')}",
          message:"${message.message?default('')}",
          userName:'userName',
          password:'password'
        });
      </#if>
    });

    //使用本地缓存记住用户名密码
    function rememberMe(rm_flag){
      //remember me
      if(rm_flag){
         localStorage.userName=$("input[name='userName']").val();
         localStorage.password=$("input[name='password']").val();
        localStorage.rememberMe=1;
      }
      //delete remember msg
      else{
        localStorage.userName=null;
        localStorage.password=null;
        localStorage.rememberMe=0;
      }
    }

    //记住回填
    function fillbackLoginForm(){
      if(localStorage.rememberMe&&localStorage.rememberMe=="1"){
        $("input[name='userName']").val(localStorage.userName);
        $("input[name='password']").val(localStorage.password);
        $("input[name='rememberMe']").iCheck('check');
        $("input[name='rememberMe']").iCheck('update');
      }
    }
  </script>

3、LoginValidator组件的代码 login.js

/**
 * Created by billJiang on 2017/1/12.
 * 登录异常信息显示
 */

function LoginValidator(config) {
  this.code = config.code;
  this.message = config.message;
  this.userName = config.userName;
  this.password = config.password;
  this.initValidator();
}

//0 未授权 1 账号问题 2 密码错误 3 账号密码错误
LoginValidator.prototype.initValidator = function () {
  if (!this.code)
    return;
  if(this.code==0){
    this.addPasswordErrorMsg();
  }else if(this.code==1){
    this.addUserNameErrorStyle();
    this.addUserNameErrorMsg();
  }else if(this.code==2){
    this.addPasswordErrorStyle();
    this.addPasswordErrorMsg();
  }else if(this.code==3){
    this.addUserNameErrorStyle();
    this.addPasswordErrorStyle();
    this.addPasswordErrorMsg();
  }
  return;
}

LoginValidator.prototype.addUserNameErrorStyle = function () {
  this.addErrorStyle(this.userName);
}

LoginValidator.prototype.addPasswordErrorStyle = function () {
  this.addErrorStyle(this.password);
}

LoginValidator.prototype.addUserNameErrorMsg = function () {
  this.addErrorMsg(this.userName);
}

LoginValidator.prototype.addPasswordErrorMsg = function () {
  this.addErrorMsg(this.password);
}


LoginValidator.prototype.addErrorMsg=function(field){
  $("input[name='"+field+"']").parent().append('<small data-bv-validator="notEmpty" data-bv-validator-for="'+field+'" class="help-block">' + this.message + '</small>');
}

LoginValidator.prototype.addErrorStyle=function(field){
  $("input[name='" + field + "']").parent().addClass("has-error");
}

以上把错误提示封装成了一个LoginValidator组件,方便前端调用,增强代码的可维护性,因为没有找到Bootstrap-validator改变错误提示的接口,所以查看了源码之后做了封装。

4、补充

1、时间区间校验

"startTime":{
          validators:{
            date:{
              format:'YYYY-MM-DD HH:mm',
              message:'日期格式不正确'
            },
            callback:{
              callback:function(value,validator){
                var startTime=value;
                var endTime=$("#endTime").val();
                if(startTime&&endTime){
                  return DateDiff(endTime,startTime)>0;
                }else{
                  return true;
                }

              },
              message:'结束时间不能小于开始时间'
            }
          }
        },
        "endTime":{
          validators:{
            date:{
              format:'YYYY-MM-DD HH:mm',
              message:'日期格式不正确'
            },
            callback:{
              callback:function(value,validator){
                var startTime=$("#startTime").val();
                var endTime=value;
                if(startTime&&endTime){
                  return DateDiff(endTime,startTime)>0;
                }else{
                  return true;
                }

              },
              message:'结束时间不能小于开始时间'
            }

          }
        },

2、服务器校验

"jobClass": {
    validators: {
        notEmpty: {message: '执行类名不能为空'},
        remote:{
          url:basePath+"/job/checkJobClass",
          data: function(validator) {
            return {
              jobClass:$('#jobClass').val(),
            };
          },
          message:'该执行类不存在'
        }
      }
    }

后台代码

@RequestMapping(value="/checkJobClass",method = RequestMethod.POST)
  @ResponseBody
  public Map checkJobClass(String jobClass){
    Map map=new HashMap<>();
    try {
      Class<?> objClass = Class.forName(jobClass);
      if(objClass!=null)
      map.put("valid", true);
      return map;
    } catch (Exception ex) {
      logger.error(ex.getMessage().toString());
      map.put("valid", false);
      return map;
    }
  }

Github: https://github.com/bill1012
AdminEAP:http://www.admineap.com

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
你所要知道JS(DHTML)中的一些技巧
Jan 09 Javascript
JavaScript省市联动实现代码
Feb 15 Javascript
jquery实现的导航固定效果
Apr 28 Javascript
JavaScript字符串对象substring方法入门实例(用于截取字符串)
Oct 17 Javascript
jQuery使用slideUp方法实现控制元素缓慢收起
Mar 27 Javascript
JavaScript ParseFloat()方法
Dec 18 Javascript
BootStrap 下拉菜单点击之后不会出现下拉菜单(下拉菜单不弹出)的解决方案
Dec 14 Javascript
js 获取图像缩放后的实际宽高,位置等信息
Mar 07 Javascript
Bootstrap多级菜单的实现代码
May 23 Javascript
JavaScript中关于base64的一些事
May 06 Javascript
Layui 导航默认展开和菜单栏选中高亮设置的方法
Sep 04 Javascript
vue.js实现三级菜单效果
Oct 19 Javascript
Bootstrap fileinput组件封装及使用详解
Mar 10 #Javascript
Bootstrap栅格系统使用方法及页面调整变形的解决方法
Mar 10 #Javascript
Node.js中.pfx后缀文件的处理方法
Mar 10 #Javascript
Vue.js结合bootstrap实现分页控件
Mar 10 #Javascript
js获取ip和地区
Mar 10 #Javascript
Vue.js bootstrap前端实现分页和排序
Mar 10 #Javascript
JavaScript组件开发之输入框加候选框
Mar 10 #Javascript
You might like
PHP PDOStatement::setAttribute讲解
2019/02/01 PHP
动手学习无线电
2021/03/10 无线电
Javascript打印网页部分内容的脚本
2008/11/17 Javascript
替代window.event.srcElement效果的可兼容性的函数
2009/12/18 Javascript
解析DHTML,JavaScript,DOM,BOM以及WEB标准的描述
2013/06/19 Javascript
jQuery中:header选择器用法实例
2014/12/29 Javascript
简单理解vue中track-by属性
2016/10/26 Javascript
JS FormData上传文件的设置方法
2017/07/05 Javascript
基于BootStrap multiselect.js实现的下拉框联动效果
2017/07/28 Javascript
打字效果动画的4种实现方法(超简单)
2017/10/18 Javascript
在vue中获取微信支付code及code被占用问题的解决方法
2019/04/16 Javascript
js笔试题-接收get请求参数
2019/06/15 Javascript
JavaScript This指向问题详解
2019/11/25 Javascript
[37:50]VP vs TNC Supermajor小组赛B组 BO3 第一场 6.2
2018/06/03 DOTA
[41:17]VG vs Optic 2018国际邀请赛小组赛BO2 第二场 8.19
2018/08/21 DOTA
python 装饰器功能以及函数参数使用介绍
2012/01/27 Python
python实现求最长回文子串长度
2018/01/22 Python
python 对象和json互相转换方法
2018/03/22 Python
python装饰器常见使用方法分析
2019/06/26 Python
Python基于OpenCV实现人脸检测并保存
2019/07/23 Python
python读写csv文件的方法
2019/08/13 Python
python爬虫 urllib模块反爬虫机制UA详解
2019/08/20 Python
Django中的cookie和session
2019/08/27 Python
python print 格式化输出,动态指定长度的实现
2020/04/12 Python
python实现图片转换成素描和漫画格式
2020/08/19 Python
最新PyCharm 2020.2.3永久激活码(亲测有效)
2020/11/26 Python
canvas绘制表情包的示例代码
2018/07/09 HTML / CSS
HTML5之WebGL 3D概述(上)—WebGL原生开发开启网页3D渲染新时代
2013/01/31 HTML / CSS
瑞典手机壳品牌:Richmond & Finch
2018/04/28 全球购物
建龙钢铁面试总结
2014/04/15 面试题
优秀党员转正的自我评价
2013/10/06 职场文书
高中数学教学反思
2014/01/30 职场文书
董事长秘书职责
2014/01/31 职场文书
小学教师年度个人总结
2015/02/05 职场文书
《小小的船》教学反思
2016/02/18 职场文书
分布式架构Redis中有哪些数据结构及底层实现原理
2022/03/13 Redis