SpringMVC学习记录--Validator验证分析

一.基于Validator接口的验证.

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<code class="hljs cs">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;
    }
}</code>

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<code class="hljs java">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");
        }
    }
}</code>

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<code class="hljs java">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 "--";
    }
    }</code>

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<code class="hljs xml"><%@ contenttype="text/html;charset=UTF-8" language="java" page="">
<%@taglib prefix="sf" uri="http://www.springframework.org/tags/form">
<%>
    <sf:form method="post" modelattribute="user">
        用户名:<sf:input path="username"></sf:input><sf:errors path="username"></sf:errors>
         
        密码:<sf:input path="password"></sf:input><sf:errors path="password"></sf:errors>
         
        昵称:<sf:input path="nickname"></sf:input><sf:errors path="nickname"></sf:errors>
         
        <input type="submit" value="提交">
    </sf:form></code>
<%@ contenttype="text/html;charset=UTF-8" language="java" page=""><%@taglib prefix="sf" uri="http://www.springframework.org/tags/form"><%>

这里写图片描述

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<code class="hljs xml">
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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"></mvc:annotation-driven>
    <bean class="com.xxx.xxx.UserValidator" id="userValidator"></bean>
    ...
</beans></code>

二.使用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

?
1
2
3
4
5
6
7
8
9
<code class="hljs java">public class User {
    @NotEmpty(message = "用户名不能为空")
    private String username;
    @Size(min=6 ,max= 20 ,message = "密码长度不符合标准")
    private String password;
    private String nickname;
   ......
}</code>

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<code class="hljs java">@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";
    }
    }</code>

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


3.定义自己的Annotation Validator

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<code class="hljs avrasm">
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[] payload() default {};
}</code>

我们可以看到在上面代码中我们定义了一个Money注解,而且该注解上标注了@Constraint注解,使用@Constraint注解标注表明我们定义了一个用于限制的注解。@Constraint注解的validatedBy属性用于指定我们定义的当前限制类型需要被哪个ConstraintValidator进行校验。在上面代码中我们指定了Money限制类型的校验类是MoneyValidator。另外需要注意的是我们在定义自己的限制类型的注解时有三个属性是必须定义的,如上面代码所示的message、groups和payload属性。
在定义了限制类型Money之后,接下来就是定义我们的限制类型校验类MoneyValidator了。限制类型校验类必须实现接口javax.validation.ConstraintValidator,并实现它的initialize和isValid方法。我们先来看一下MoneyValidator的代码示例:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<code class="hljs axapta">
import java.util.regex.Pattern;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import com.xxx.xxx.constraint.Money;
public class MoneyValidator implements ConstraintValidator {
    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();
    }
}</code>

从上面代码中我们可以看到ConstraintValidator是使用了泛型的。它一共需要指定两种类型,第一个类型是对应的initialize方法的参数类型,第二个类型是对应的isValid方法的第一个参数类型。从上面的两个方法我们可以看出isValid方法是用于进行校验的,有时候我们在校验的过程中是需要取当前的限制类型的属性来进行校验的,比如我们在对@Min限制类型进行校验的时候我们是需要通过其value属性获取到当前校验类型定义的最小值的,我们可以看到isValid方法无法获取到当前的限制类型Money。这个时候initialize方法的作用就出来了。我们知道initialize方法是可以获取到当前的限制类型的,所以当我们在校验某种限制类型时需要获取当前限制类型的某种属性的时候,我们可以给当前的ConstraintValidator定义对应的属性,然后在initialize方法中给该属性赋值,接下来我们就可以在isValid方法中使用其对应的属性了。针对于这种情况我们来看一个代码示例,现在假设我要定义自己的@Min限制类型和对应的MinValidator校验器,那么我可以如下定义:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
<code class="hljs handlebars">@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[] payload() default {};
}</code>

MinValidator校验器

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<code class="hljs axapta">public class MinValidator implements ConstraintValidator {
    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;
    }
}</code>

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<code class="hljs cs">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;
    }
}</code>

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/387415.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

NTP时间服务器实现Linux时间同步

在linux下&#xff0c;可以通过自带的NTP(Network Time Protocol)协议通过网络使自己的系统保持精确的时间。 什么是NTP&#xff1f; NTP是用来使系统和一个时间源保持时间同步的协议。 在自己管理的网络中建立至少一台时间服务器来同步本地时间&#xff0c;这样可以使得在不同…

阿里云天池 Python训练营Task1:从变量到异常处理

本学习笔记为阿里云天池龙珠计划Python训练营的学习内容&#xff0c;学习链接为&#xff1a;https://tianchi.aliyun.com/specials/promotion/aicamppython?spm5176.22758685.J_6770933040.1.6f103da1tESyzu 目录 一、学习知识点概要 二、学习内容 I.变量、运算符与数据类…

python回收机制

目录 Python的垃圾回收机制引子:一、什么是垃圾回收机制&#xff1f;二、为什么要用垃圾回收机制&#xff1f;三、垃圾回收机制原理分析1、什么是引用计数&#xff1f;2、引用计数扩展阅读&#xff1f;&#xff08;折叠&#xff09;Python的垃圾回收机制 引子: 我们定义变量会申…

安装openssl-devel命令

centos&#xff1a; yum install openssl-devel ubuntu&#xff1a; sudo apt-get install openssl sudo apt-get install libssl-dev

阿里云天池 Python训练营Task2: Python基础练习:数据结构大汇总 学习笔记

本学习笔记为阿里云天池龙珠计划Python训练营的学习内容&#xff0c;学习链接为&#xff1a;https://tianchi.aliyun.com/specials/promotion/aicamppython?spm5176.22758685.J_6770933040.1.6f103da1tESyzu 目录 一、学习知识点概要 二、学习内容 I.列表&#xff08;list…

windows文件与Linux文件互转

使用命令 unix2dos filename dos2unix filename

1G.小a的排列(C++)

小a的排列&#xff08;C&#xff09; 点击做题网站链接 题目描述 小a有一个长度为n的排列。定义一段区间是"萌"的&#xff0c;当且仅当把区间中各个数排序后相邻元素的差为1现在他想知道包含数x,y的长度最小的"萌"区间的左右端点 也就是说&#xff0c;我们…

阿里云天池 Python训练营Task3: Python基础进阶:从函数到高级魔法方法 学习笔记

本学习笔记为阿里云天池龙珠计划Python训练营的学习内容&#xff0c;学习链接为&#xff1a;https://tianchi.aliyun.com/specials/promotion/aicamppython?spm5176.22758685.J_6770933040.1.6f103da1tESyzu 目录 一、学习知识点概要 二、学习内容 I.函数 1.定义自己的函…

C# 获取句柄程序

这个小程序需要用到系统API&#xff0c;也就是需要用到user32中的三个函数。 第一个&#xff1a;WindowFromPoint 返回一个窗口句柄 第二个&#xff1a;GetWindowText 获取窗口标题 第三个&#xff1a;GetClassName 获取类名 当然&#xff0c;最重要的一点就是要引用命名空间…

HBase安装配置

HBase的安装配置&#xff1a; 4台主机&#xff1a;hdp0 hdp1 hdp2 hdp3 hdp0 hdp1 跑HMaster hdp2 hdp3 跑HRegionServer 将HBase解压之后 1、确保安装ZooKeeper&#xff1b; 2、修改hbase-env.sh export JAVA_HOME/.../jdk export HBASE_MANAGES_ZKfalse //使用外部的…

python cook读书笔记第2章字符串和文本

使用多个界定符分割字符串 line asdf fjdk; afed, fjek,asdf, fooimport re# line re.split(r[;,\s]\s*,line)# print(line)# [asdf, fjdk, afed, fjek, asdf, foo]"""当你使用 re.split() 函数时候&#xff0c;需要特别注意的是正则表达式中是否包含一个括号…

centos7安装oracle12c 一

本文 基本参考了下面这篇文章http://blog.csdn.net/gq5251/article/details/42004035 和http://www.linuxidc.com/Linux/2017-08/146528.htm 但是改正了一些错误操作系统:CentOS Linux release 7.2.1511 (Core) oracle: oarcle (12.1.0.2.0) - Standard Edition (SE2)几点要注…

Bigtable的些许重点

分布式数据库系统 针对于海量数据&#xff0c;可扩展&#xff0c;高吞吐量&#xff0c;低时延 不支持关系模型 通过row和column进行索引&#xff0c;row和column可以是任意字符串 所存储的数据也是字符串 Bigtable是一个map&#xff0c;value是array of bytes&#xff0c;通…

阿里云天池 Python训练营Task4: Python数据分析:从0完成一个数据分析实战 学习笔记

本学习笔记为阿里云天池龙珠计划Python训练营的学习内容&#xff0c;学习链接为&#xff1a;https://tianchi.aliyun.com/specials/promotion/aicamppython?spm5176.22758685.J_6770933040.1.6f103da1tESyzu 一、学习知识点概要 本次主要通过阿里云天池的赛题【Python入门系…

JMETER从JSON响应中提取数据

如果你在这里&#xff0c;可能是因为你需要使用JMeter从Json响应中提取变量。 好消息&#xff01;您正在掌握掌握JMeter Json Extractor的权威指南。作为Rest API测试指南的补充&#xff0c;您将学习掌握Json Path Expressions 所需的一切。 我们走吧&#xff01;并且不要惊慌&…

centos7安装oracle12c 二

环境&#xff1a;CentOS7VMware12&#xff0c;分配资源&#xff1a;CPU&#xff1a;2颗&#xff0c;内存&#xff1a;4GB&#xff0c;硬盘空间&#xff1a;30GB Oracle 12C企业版64位 下载地址&#xff1a;http://www.oracle.com/technetwork/database/enterprise-edition/down…

阿里云天池 Python训练营Task5:Python训练营测试 学习笔记

一、学习知识点概要 本次是Python训练营的测试&#xff0c;在45分钟内完成25题&#xff0c;满分100分及格80分。题目主要考察Task1到Task3里面的Python基础知识。在我随到的25道题里&#xff0c;知识点有&#xff1a; 变量&#xff08;包括数据类型和容器类型&#xff09;运算…

centos7安装oracle12c 三

场景描述&#xff1a;我在自己电脑的虚拟机上linux环境下安装oracle11g数据库。 Linux版本为&#xff1a;CentOS release 6.8 (Final)&#xff0c;Oracle版本为&#xff1a;linux.x64_11gR2 问题描述&#xff1a;在oracle安装到Prerequisite Checks这一步的时候&#xff0c;出现…

mysql删除一条记录

mysql如何删除一条记录delete from 表名 where 条件实例&#xff1a;use db1delete from tb1 where id 1; 转载于:https://www.cnblogs.com/effortsing/p/10393229.html

HBase体系结构

HBase HBase是Apache Hadoop的数据库&#xff0c;基于HDFS文件系统 random,realtime read/write access to Big Data 开源、分布式、可扩展、面向列 larger tables--billions of rows X millions of columns 不支持表链接操作 不支持事务处理 HBase存储的数据从逻辑上来…