SpringMVC Validator验证示例

SpringMVC服务器验证一种是有两种方式,一种是基于Validator接口,一种是使用Annotaion JSR-303标准的验证,下面主要是学习这两种,工作中推荐后者,方便很多

一.基于Validator接口的验证.

首先创建User实例,并加入几个属性

public class User {
  private String username;
  private String password;
  private String nickname;

  public String getUsername() {
    return username;
  }

  public void setUsername(String username) {
    this.username = username;
  }

  public String getPassword() {
    return password;
  }

  public void setPassword(String password) {
    this.password = password;
  }

  public String getNickname() {
    return nickname;
  }

  public void setNickname(String nickname) {
    this.nickname = nickname;
  }

  @Override
  public String toString() {
    return "username--"+username+"password--"+password+"nickname--"+nickname;
  }
}

接着创建用于校检的类UserValidator,让其实现Validator,覆盖其中的两个方法

import main.java.model.User;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;

public class UserValidator implements Validator {

  @Override
  public boolean supports(Class<?> aClass) {
    //判断是否是要校验的类,这里是User
    return User.class.equals(aClass);
  }

  @Override
  public void validate(Object o, Errors errors) {
    User u = (User) o;
    if (null == u.getPassword() || "".equals(u.getPassword())){
      //此方法可以加四个参数,第一个表单域field,
      //区分是哪个表单出错,第二个errorCode错误码,
      //第三个制定了资源文件中占位符,第四个具体错误返回信息
      //简写版可以把2,3参数去掉
      errors.rejectValue("password",null,null,"password is null");
    }
  }
}

上面的类只实现了对密码判断是否为空,为空则注册这一错误信息,也就是”password is null”,接下来要实现控制器,控制器要做的事情,第一是注册这个校验器,第二是实现校验.

import main.java.model.User;
......

/**
 * 加上@Controller决定这个类是一个控制器
 */
@Controller
@RequestMapping("/user")
public class HelloController {

  //我们知道在Controller类中通过@InitBinder标记的方法只有在请求当前Controller的时候才会被执行
  //所以在这里注册校验器
  @InitBinder
  public void initBainder(DataBinder binder){
    binder.replaceValidators(new UserValidator());

  }
  //这个方法主要是跳转到登录页面
  @RequestMapping(value = "/login",method = RequestMethod.GET)
  public String login(Model model){
    model.addAttribute(new User());
    return "user/login";
  }
  //处理登录表单
  @RequestMapping(value = "/login",method = RequestMethod.POST)
  public String login(@Validated User user, BindingResult br){

    if (br.hasErrors()){
      return "user/login";
    }
    return "--";
  }
  }

上面代码可以看到@Validated User user, BindingResult br这两个参数,@Validated表明参数user是要校验的类,BindingResult是存储错误信息的类,两者必须一一对应,并且位置挨着,不能中间有其他参数,

最后随便写一个jsp页面实现校检

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="sf" uri="http://www.springframework.org/tags/form" %>
<%
  request.setCharacterEncoding("utf-8");
%>
<html>
<head>
  <meta charset="utf-8">
  <title>用户登录</title>
</head>
<body>
  <sf:form modelAttribute="user" method="post">
    用户名:<sf:input path="username"/><sf:errors path="username"/>
    <br>
    密码:<sf:input path="password"/><sf:errors path="password"/>
    <br>
    昵称:<sf:input path="nickname"/><sf:errors path="nickname"/>
    <br>
    <input type="submit" value="提交">
  </sf:form>
</body>
</html>

前面实现的是局部校验,只对当前控制器有效,如果要实现全局校验的话需要配置springMVC.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
  xmlns:mvc="http://www.springframework.org/schema/mvc"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
   http://www.springframework.org/schema/context
   http://www.springframework.org/schema/context/spring-context-3.0.xsd
   http://www.springframework.org/schema/mvc
   http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

  <mvc:annotation-driven validator="userValidator"/>

  <bean id="userValidator" class="com.xxx.xxx.UserValidator"/>

  ...
</beans>

二.使用Annotaion JSR-303标准的验证

使用这个需要导入支持JSR-303标准的包,建议使用hibernate Validator这个包,先看这个标准的原生标注

限制 说明
@Null 限制只能为null
@NotNull 限制必须不为null
@AssertFalse 限制必须为false
@AssertTrue 限制必须为true
@DecimalMax(value) 限制必须为一个不大于指定值的数字
@DecimalMin(value) 限制必须为一个不小于指定值的数字
@Digits(integer,fraction) 限制必须为一个小数,且整数部分的位数不能超过integer,小数部分的位数不能超过fraction
@Future 限制必须是一个将来的日期
@Max(value) 限制必须为一个不大于指定值的数字
@Min(value) 限制必须为一个不小于指定值的数字
@Past 限制必须是一个过去的日期
@Pattern(value) 限制必须符合指定的正则表达式
@Size(max,min) 限制字符长度必须在min到max之间
@Past 验证注解的元素值(日期类型)比当前时间早
@NotEmpty 验证注解的元素值不为null且不为空(字符串长度不为0、集合大小不为0)
@NotBlank 验证注解的元素值不为空(不为null、去除首位空格后长度为0),不同于@NotEmpty,@NotBlank只应用于字符串且在比较时会去除字符串的空格
@Email 验证注解的元素值是Email,也可以通过正则表达式和flag指定自定义的email格式

要使用很简单,在需要验证的变量前面加上该Annotation即可,看下面使用后的User

public class User {
  @NotEmpty(message = "用户名不能为空")
  private String username;
  @Size(min=6 ,max= 20 ,message = "密码长度不符合标准")
  private String password;
  private String nickname;

  ......
}

然后再控制器里面加入验证就可以了

@Controller
@RequestMapping("/user")
public class HelloController {

  @RequestMapping(value = "/login",method = RequestMethod.GET)
  public String login(Model model){
    model.addAttribute(new User());
    return "user/login";
  }

  @RequestMapping(value = "/login",method = RequestMethod.POST)
  public String login(@Validated User user, BindingResult br){

    if (br.hasErrors()){
      return "user/login";
    }
    return "user/login";
  }
  }

然后jsp页面还是之前的页面,验证效果如下,这种方法明显简单多了

3.定义自己的Annotation Validator

这部分直接从[大牛][1]那拷贝过来的.

除了JSR-303原生支持的限制类型之外我们还可以定义自己的限制类型。定义自己的限制类型首先我们得定义一个该种限制类型的注解,而且该注解需要使用@Constraint标注。现在假设我们需要定义一个表示金额的限制类型,那么我们可以这样定义:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import javax.validation.Constraint;
import javax.validation.Payload;

import com.xxx.xxx.constraint.impl.MoneyValidator;

@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy=MoneyValidator.class)
public @interface Money {

  String message() default"不是金额形式";

  Class<?>[] groups() default {};

  Class<? extends Payload>[] payload() default {};

}

我们可以看到在上面代码中我们定义了一个Money注解,而且该注解上标注了@Constraint注解,使用@Constraint注解标注表明我们定义了一个用于限制的注解。@Constraint注解的validatedBy属性用于指定我们定义的当前限制类型需要被哪个ConstraintValidator进行校验。在上面代码中我们指定了Money限制类型的校验类是MoneyValidator。另外需要注意的是我们在定义自己的限制类型的注解时有三个属性是必须定义的,如上面代码所示的message、groups和payload属性。

在定义了限制类型Money之后,接下来就是定义我们的限制类型校验类MoneyValidator了。限制类型校验类必须实现接口javax.validation.ConstraintValidator,并实现它的initialize和isValid方法。我们先来看一下MoneyValidator的代码示例:

import java.util.regex.Pattern;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

import com.xxx.xxx.constraint.Money;

public class MoneyValidator implements ConstraintValidator<Money, Double> {

  private String moneyReg = "^\\d+(\\.\\d{1,2})?$";//表示金额的正则表达式
  private Pattern moneyPattern = Pattern.compile(moneyReg);

  public void initialize(Money money) {
    // TODO Auto-generated method stub

  }

  public boolean isValid(Double value, ConstraintValidatorContext arg1) {
    // TODO Auto-generated method stub
    if (value == null)
      return true;
    return moneyPattern.matcher(value.toString()).matches();
  }

}

从上面代码中我们可以看到ConstraintValidator是使用了泛型的。它一共需要指定两种类型,第一个类型是对应的initialize方法的参数类型,第二个类型是对应的isValid方法的第一个参数类型。从上面的两个方法我们可以看出isValid方法是用于进行校验的,有时候我们在校验的过程中是需要取当前的限制类型的属性来进行校验的,比如我们在对@Min限制类型进行校验的时候我们是需要通过其value属性获取到当前校验类型定义的最小值的,我们可以看到isValid方法无法获取到当前的限制类型Money。这个时候initialize方法的作用就出来了。

我们知道initialize方法是可以获取到当前的限制类型的,所以当我们在校验某种限制类型时需要获取当前限制类型的某种属性的时候,我们可以给当前的ConstraintValidator定义对应的属性,然后在initialize方法中给该属性赋值,接下来我们就可以在isValid方法中使用其对应的属性了。针对于这种情况我们来看一个代码示例,现在假设我要定义自己的@Min限制类型和对应的MinValidator校验器,那么我可以如下定义:

@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy=MinValidator.class)
public @interface Min {

  int value() default 0;

  String message();

  Class<?>[] groups() default {};

  Class<? extends Payload>[] payload() default {};
}
MinValidator校验器
public class MinValidator implements ConstraintValidator<Min, Integer> {

  private int minValue;

  public void initialize(Min min) {
    // TODO Auto-generated method stub
    //把Min限制类型的属性value赋值给当前ConstraintValidator的成员变量minValue
    minValue = min.value();
  }

  public boolean isValid(Integer value, ConstraintValidatorContext arg1) {
    // TODO Auto-generated method stub
    //在这里我们就可以通过当前ConstraintValidator的成员变量minValue访问到当前限制类型Min的value属性了
    return value >= minValue;
  }

}

继续来说一下ConstraintValidator泛型的第二个类型,我们已经知道它的第二个类型是对应的isValid的方法的第一个参数,从我给的参数名称value来看也可以知道isValid方法的第一个参数正是对应的当前需要校验的数据的值,而它的类型也正是对应的我们需要校验的数据的数据类型。这两者的数据类型必须保持一致,否则spring会提示找不到对应数据类型的ConstraintValidator。建立了自己的限制类型及其对应的ConstraintValidator后,其用法跟标准的JSR-303限制类型是一样的。以下就是使用了上述自己定义的JSR-303限制类型——Money限制和Min限制的一个实体类:

public class User {

  private int age;

  private Double salary;

  @Min(value=8, message="年龄不能小于8岁")
  public int getAge() {
    return age;
  }

  public void setAge(int age) {
    this.age = age;
  }

  @Money(message="标准的金额形式为xxx.xx")
  public Double getSalary() {
    return salary;
  }

  public void setSalary(Double salary) {
    this.salary = salary;
  }

}

4.配合ajax验证

最近写的项目,感觉直接使用validator不太好用,主要是返回时会刷新整个页面才会出来错误信息,体验相当不好,验证还是用ajax体验比较好,所以配合ajax

思路:验证还是使用springMVC来验证,只是这次发现错误的话,把错误取出,存放到一个map中,然后ajax返回,页面根据ajax返回值来判断,从而显示不同的信息

主要代码:

 if (br.hasErrors()){//判断是否有错误
       //对错误集合进行遍历,有的话,直接放入map集合中
      br.getFieldErrors().forEach(p->{
        maps.put(p.getField(),p.getDefaultMessage());
      });
      return maps;
    }

这样的话 maps里面存放的就是 错误变量名,错误信息,例如 username -‘用户名不能为空'

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

时间: 2017-01-11

BootStrap与validator 使用笔记(JAVA SpringMVC实现)

BootStrap 是一个强大的前面框架,它用优雅的方式解决了网页问题.最近正在使用其开发网站的表单验证,一点体会记录如下: 注:本文中借鉴了博客Franson 的文章使用bootstrap validator的remote验证代码经验分享(推荐) 一.准备工作 1.你的网站环境中要有 BootStrap,中文网地址:http://www.bootcss.com/ 2.下载BootStrap Validator相关材料,地址:http://bv.doc.javake.cn/ 当然,如果你不想一个

JSP中springmvc配置validator的注意事项

SpringMVC介绍之Validation 对于任何一个应用而言在客户端做的数据有效性验证都不是安全有效的,这时候就要求我们在开发的时候在服务端也对数据的有效性进行验证.SpringMVC自身对数据在服务端的校验有一个比较好的支持,它能将我们提交到服务端的数据按照我们事先的约定进行数据有效性验证,对于不合格的数据信息SpringMVC会把它保存在错误对象中,这些错误信息我们也可以通过SpringMVC提供的标签在前端JSP页面上进行展示. 关于springmvc配置validator的注意事项

springmvc的validator数据校验的实现示例代码

一.什么是数据校验? 这个比较好理解,就是用来验证客户输入的数据是否合法,比如客户登录时,用户名不能为空,或者不能超出指定长度等要求,这就叫做数据校验. 数据校验分为客户端校验和服务端校验 客户端校验:js校验 服务端校验:springmvc使用validation校验,struts2使用validation校验.都有自己的一套校验规则. 二.springmvc的validation校验 Springmvc本身没有校验功能,它使用hibernate的校验框架,hibernate的校验框架和orm

使用react实现手机号的数据同步显示功能的示例代码

本文介绍了使用react实现手机号的数据同步显示功能的示例代码,分享给大家,具体如下: 要求如下 输入框输入内容数据长度大于0,展示出预览信息 光标离开关闭预览信息 预览信息每隔4位插入一个特殊字符_,输入内容不变 限制长度为13位 只允许输入数字(0-9) // Zinput.js import React, { Component } from 'react'; import './Zinput.css' // NOTE: 获取焦点事件 原生onFocus 即可 // NOTE: 离开焦点事

SqlServer2000+ 身份证合法校验函数的示例代码

下面看下sqlserver2000身份证校验的代码,具体代码如下所示: /* 身份校验行数 */ if exists(select * from sysobjects where name='fun_utils_idnumberoprater' and type='FN') drop function fun_utils_idnumberoprater go create function fun_utils_idnumberoprater ( @idnumber varchar(50)=''

Spring AOP实现功能权限校验功能的示例代码

实现功能权限校验的功能有多种方法,其一使用拦截器拦截请求,其二是使用AOP抛异常. 首先用拦截器实现未登录时跳转到登录界面的功能.注意这里没有使用AOP切入,而是用拦截器拦截,因为AOP一般切入的是service层方法,而拦截器是拦截控制器层的请求,它本身也是一个处理器,可以直接中断请求的传递并返回视图,而AOP则不可以. 1.使用拦截器实现未登录时跳转到登录界面的功能 1.1 拦截器SecurityInterceptor package com.jykj.demo.filter; import

Ext GridPanel加载完数据后进行操作示例代码

比如load数据之后选定某些行数据. this相当于当前的GridPanel, idxs相当于你要选中的行号 复制代码 代码如下: this.store.on("load",function(store) { this.getSelectionModel().selectRows(idxs); //this.selectedRows = []; },this);

AngularJs导出数据到Excel的示例代码

公司一个新的需求导出Exce表格,研究了一下,最后终于实现,分享给大家. 1 使用FileSaver 第一次采用FileSaver.js 由于刚开始导致导出一片空白,还只能抓取网页里面的表格地址:https://github.com/eligrey/FileSaver.js HTML <div id="exportable"> <table width="100%"> <thead> <tr> <th>Na

Vue中组件之间数据的传递的示例代码

Vue中组件的作用域是隔离的,父组件中的数值子组件看不到!也就是说,用angular作比喻,组件的scope天生是scope:()的! 如果父组件需要往子组件中传数据,此时应该使用标签属性: <div id="app"> <my-compo c="886"></my-compo> </div> 子组件中,用props声明这个值即可.并且在template里面可以直接使用{{c}}来获得这个属性,而不需要写为{{this

Ajax叠加(Ajax返回数据用Ajax发出)示例代码

最近在做人事管理系统的一个签到功能,首先是把部门当做参数,把参数用Ajax发送到数据库进行查询,然后以表格形式动态生成员工信息到返回页面的Div里,表格最后的一列是签到按钮,这时我想用JQuery继续获取被点击的"签到"按钮,然后用Ajax将数据发送到数据库签到表,更新签到表,于是我就把每个签到按钮的id属性设置成第一次Ajax返回的每个员工信息的工号,再次用JQuery获取,怎么获取呢?想到了标签加事件选择器,于是写了下面代码: 复制代码 代码如下: $(function(){ $(

JQuery以JSON方式提交数据到服务端示例代码

JQuery将Ajax数据请求进行了封装,从而使得该操作实现起来容易许多.以往我们要写很多的代码来实现该功能,现在只需要调用$.ajax()方法,并指明请求的方式.地址.数据类型,以及回调方法等.下面的代码演示了如何将客户端表单数据封装成JSON格式,然后通过JQuery的Ajax请求将数据发送到服务端,并最终将数据存储到数据库中.服务端定义为一个.ashx文件,事实上你可以将服务端定义为任何能接收并处理客户端数据的类型,如Web Service,ASP.NET Page,Handler等. 首

Android使用KeyStore对数据进行加密的示例代码

谈到 Android 安全性话题,Android Developers 官方网站给出了许多很好的建议和讲解,涵盖了存储数据.权限.网络.处理凭据.输入验证.处理用户数据.加密等方方面面 密钥的保护以及网络传输安全 应该是移动应用安全最关键的内容.Android 提供大量用来保护数据的加密算法,例如 Cipher 类中提供了 AES 和 RSA 算法,再例如安全随机数生成器 SecureRandom 给 KeyGenerator 提供了更加可靠的初始化参数,避免离线攻击等等. 而如果需要存储密钥以