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判断屏幕分辨率的代码
Jul 16 Javascript
使用原生js写的一个简单slider
Apr 29 Javascript
PageSwitch插件实现100种不同图片切换效果
Jul 28 Javascript
基于javascript实现动态显示当前系统时间
Jan 28 Javascript
js实现交通灯效果
Jan 13 Javascript
jquery处理checkbox(复选框)是否被选中实例代码
Jun 12 jQuery
浅谈vue.js中v-for循环渲染
Jul 26 Javascript
JS中使用media实现响应式布局
Aug 04 Javascript
vue组件watch属性实例讲解
Nov 07 Javascript
webpack 如何解析代码模块路径的实现
Sep 04 Javascript
JS+CSS实现随机点名(实例代码)
Nov 04 Javascript
基于vue 动态菜单 刷新空白问题的解决
Aug 06 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
非常好用的Zend Framework分页类
2014/06/25 PHP
PHP实现的简单日历类
2014/11/29 PHP
php+mysqli实现批量替换数据库表前缀的方法
2014/12/29 PHP
php多重接口的实现方法
2015/06/20 PHP
PHP合并discuz用户脚本的方法
2015/08/04 PHP
PHP安全下载文件的方法
2016/04/07 PHP
PHP 500报错的快速解决方法
2016/12/14 PHP
谈谈从phpinfo中能获取哪些值得注意的信息
2017/03/28 PHP
Yii 框架入口脚本示例分析
2020/05/19 PHP
js操作select控件的几种方法
2010/06/02 Javascript
window.ActiveXObject使用说明
2010/11/08 Javascript
基于Jquery+div+css实现弹出登录窗口(代码超简单)
2015/10/27 Javascript
浅谈js多维数组和hash数组定义和使用
2016/07/27 Javascript
AngularJS中一般函数参数传递用法分析
2016/11/22 Javascript
详解handlebars+require基本使用方法
2016/12/21 Javascript
Webpack执行命令参数详解
2017/06/17 Javascript
laydate日历控件使用方法详解
2017/11/20 Javascript
JS中Map和ForEach的区别
2018/02/05 Javascript
解决vue-router在同一个路由下切换,取不到变化的路由参数问题
2018/09/01 Javascript
jQuery中each遍历的三种方法实例分析
2018/09/07 jQuery
[01:20]DOTA2 2017国际邀请赛冠军之路无止竞
2017/06/19 DOTA
Python实现简单的可逆加密程序实例
2015/03/05 Python
Python中多线程的创建及基本调用方法
2016/07/08 Python
PyQt5主窗口动态加载Widget实例代码
2018/02/07 Python
解决pycharm 工具栏Tool中找不到Run manager.py Task的问题
2019/07/01 Python
Python进阶之使用selenium爬取淘宝商品信息功能示例
2019/09/16 Python
如何定义TensorFlow输入节点
2020/01/23 Python
Python实现七个基本算法的实例代码
2020/10/08 Python
为2021年的第一场雪锦上添花:用matplotlib绘制雪花和雪景
2021/01/05 Python
乐高积木玩具美国官网:LEGO Shop US
2016/09/16 全球购物
酒后驾车标语
2014/06/30 职场文书
咖啡店创业计划书范文
2014/09/15 职场文书
单位计划生育责任书
2015/05/09 职场文书
业务员管理制度范本
2015/08/06 职场文书
MySQL时间盲注的五种延时方法实现
2021/05/18 MySQL
再次探讨go实现无限 buffer 的 channel方法
2021/06/13 Golang