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 相关文章推荐
Aptana调试javascript图解教程
Nov 30 Javascript
JS不能跨域借助jquery获取IP地址的方法
Aug 20 Javascript
JS实现弹性菜单效果代码
Sep 07 Javascript
高效利用Angular中内置服务$http、$location等
Mar 22 Javascript
详解基于webpack和vue.js搭建开发环境
Apr 05 Javascript
详解Vue双向数据绑定原理解析
Sep 11 Javascript
详解vantUI框架在vue项目中的应用踩坑
Dec 06 Javascript
express框架下使用session的方法
Jul 31 Javascript
Jquery使用each函数实现遍历及数组处理
Jul 14 jQuery
JS新手入门数组处理的实用方法汇总
Apr 07 Javascript
浅谈Web Storage API的使用
Jun 23 Javascript
vue3语法糖内的defineProps及defineEmits
Apr 14 Vue.js
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
超外差式晶体管收音机的组装与统调
2021/03/01 无线电
PHP HTML代码串 截取实现代码
2009/06/29 PHP
献给php初学者(入门学习经验谈)
2010/10/12 PHP
php下安装配置fckeditor编辑器的方法
2011/03/02 PHP
php实现删除空目录的方法
2015/03/16 PHP
Codeigniter实现发送带附件的邮件
2015/03/19 PHP
基于thinkPHP实现的微信自定义分享功能示例
2016/09/23 PHP
PHP CURL采集百度搜寻结果图片不显示问题的解决方法
2017/02/03 PHP
Ajax+PHP实现的模拟进度条功能示例
2019/02/11 PHP
学习YUI.Ext基础第一天
2007/03/10 Javascript
javascript实现文字图片上下滚动的具体实例
2013/06/28 Javascript
jQuery中map()方法用法实例
2015/01/06 Javascript
JS实现三级折叠菜单特效,其它级可自动收缩
2015/08/06 Javascript
jQuery validate插件submitHandler提交导致死循环解决方法
2016/01/21 Javascript
js实现商品抛物线加入购物车特效
2020/11/18 Javascript
JS判断iframe是否加载完成的方法
2016/08/03 Javascript
详解Sea.js中Module.exports和exports的区别
2017/02/12 Javascript
Angular2下使用pdf插件的方法详解
2017/04/29 Javascript
浅谈 Vue v-model指令的实现原理
2017/06/08 Javascript
JS中将多个逗号替换为一个逗号的实现代码
2017/06/23 Javascript
ajax跨域访问遇到的问题及解决方案
2019/05/23 Javascript
layui监听下拉选框选中值变化的方法(包含监听普通下拉选框)
2019/09/24 Javascript
Vue + element 实现多选框组并保存已选id集合的示例代码
2020/06/03 Javascript
python爬虫正则表达式之处理换行符
2018/06/08 Python
python3实现二叉树的遍历与递归算法解析(小结)
2019/07/03 Python
python实现美团订单推送到测试环境,提供便利操作示例
2019/08/09 Python
HTML5 标准将把互联网视频扔回到黑暗时代
2010/02/10 HTML / CSS
一个不错的HTML5 Canvas多层点击事件监听实例
2014/04/29 HTML / CSS
美国领先的在线邮轮旅游公司:CruiseDirect
2018/06/07 全球购物
教师的实习鉴定
2013/12/15 职场文书
保安的辞职报告怎么写
2014/01/20 职场文书
2014领导班子四风剖析对照检查材料思想汇报
2014/09/20 职场文书
2014年财务科工作总结
2014/11/11 职场文书
补充协议书
2015/01/28 职场文书
python urllib库的使用详解
2021/04/13 Python
厉害!这是Redis可视化工具最全的横向评测
2021/07/15 Redis