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扩展方法判断一个数组中是否包含某个元素
Nov 08 Javascript
jQuery控制的不同方向的滑动(向左、向右滑动等)
Jul 18 Javascript
使用Meteor配合Node.js编写实时聊天应用的范例
Jun 23 Javascript
DOM事件阶段以及事件捕获与事件冒泡先后执行顺序(图文详解)
Aug 18 Javascript
jQuery事件绑定用法详解(附bind和live的区别)
Jan 19 Javascript
JavaScipt中栈的实现方法
Feb 17 Javascript
使用伪命名空间封装保护独自创建的对象方法
Aug 04 Javascript
微信小程序使用Socket的实例
Sep 19 Javascript
微信小程序使用video组件播放视频功能示例【附源码下载】
Dec 08 Javascript
jQuery阻止事件冒泡实例分析
Jul 03 jQuery
深入理解vue中的slot与slot-scope
Apr 22 Javascript
Vue3.0数据响应式原理详解
Oct 09 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中的array数组类型分析说明
2010/07/27 PHP
Laravel路由研究之domain解决多域名问题的方法示例
2019/04/04 PHP
php 下 html5 XHR2 + FormData + File API 上传文件操作实例分析
2020/02/28 PHP
Jquery ajax传递复杂参数给WebService的实现代码
2011/08/08 Javascript
jQuery对html元素取值与赋值的方法
2013/11/20 Javascript
让input框实现类似百度的搜索提示(基于jquery事件监听)
2014/01/31 Javascript
学习JavaScript设计模式(继承)
2015/11/26 Javascript
详解JavaScript逻辑And运算符
2015/12/04 Javascript
很棒的js Tab选项卡切换效果
2016/08/30 Javascript
jQuery事件与动画基础详解
2017/02/23 Javascript
小程序ios音频播放没声音问题的解决
2018/07/11 Javascript
原生JS实现简单的无缝自动轮播效果
2018/09/26 Javascript
移动端图片上传旋转、压缩问题的方法
2018/10/16 Javascript
NodeJs实现简易WEB上传下载服务器
2019/08/10 NodeJs
详解微信小程序开发之formId使用(模板消息)
2019/08/27 Javascript
AntV F2和vue-cli构建移动端可视化视图过程详解
2019/10/08 Javascript
微信小程序添加插屏广告并设置显示频率(一天一次)
2019/12/06 Javascript
JavaScript简单编程实例学习
2020/02/14 Javascript
[05:04]DOTA2上海特级锦标赛主赛事第二日TOP10
2016/03/04 DOTA
python转换摩斯密码示例
2014/02/16 Python
Python对文件操作知识汇总
2016/05/15 Python
win10系统中安装scrapy-1.1
2016/07/03 Python
Python学习笔记之Break和Continue用法分析
2019/08/14 Python
使用Python制作一个打字训练小工具
2019/10/01 Python
opencv python 对指针仪表读数识别的两种方式
2021/01/14 Python
Opodo意大利:欧洲市场上领先的在线旅行社
2019/10/24 全球购物
UNIX文件名称有什么规定
2013/03/25 面试题
校园创业策划书
2014/01/14 职场文书
建议书怎么写
2014/03/12 职场文书
供用电专业求职信
2014/07/07 职场文书
四风问题民主生活会对照检查材料思想汇报
2014/09/27 职场文书
村干部任职承诺书
2015/01/21 职场文书
教育读书笔记
2015/07/02 职场文书
JS实现简单控制视频播放倍速的实例代码
2021/04/18 Javascript
Java数据结构之链表相关知识总结
2021/06/18 Java/Android
MySQL Innodb索引机制详细介绍
2021/11/23 MySQL