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,也可以通过正则表达式和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>
|
SpringMVC学习记录--Validator验证分析相关推荐
- SpringMVC学习记录二——非注解和注解的处理器映射器和适配器
3 非注解的处理器映射器和适配器 3.1 非注解的处理器映射器 处理器映射器: org.springframework.web.servlet.handler.BeanNameUr ...
- springmvc学习记录
<<看透springMvc源代码分析与实践.pdf>> spring Web MVC 框架提供"模型-视图-控制器"( Model-View-Control ...
- python学习记录—— 利用再分析数据绘制天气图
1 方法数据 1.1数据 数据采用1°*1°的NCEP/NCAR的再分析数据,数据格式为grib2. 数据下载地址:FNL1*1 说明:需要用邮箱注册账号,之后按需求下载具体日期的数据,每日4个时次, ...
- 【C语言进阶深度学习记录】二十六 C语言中的字符串与字符数组的详细分析
之前有一篇文章是学习了字符和字符串的,可以与之结合学习:[C语言进阶深度学习记录]十二 C语言中的:字符和字符串 文章目录 1 字符串的概念 1.1 字符串与字符数组 1.2 字符数组与字符串代码分析 ...
- SpringMVC之使用Validator接口进行验证
对于任何一个应用而言在客户端做的数据有效性验证都不是安全有效的,这时候就要求我们在开发的时候在服务端也对数据的有效性进行验证.SpringMVC自身对数据在服务端的校验有一个比较好的支持,它能将我们提 ...
- 【C语言进阶深度学习记录】十九 #pragma使用与分析
文章目录 1 #pragma 概念简介 1.1 #pragma message 的用法 1.2 #pragma once 的用法 1.3 #pragma pack 的用法 1.31 struct占用的 ...
- 【C语言进阶深度学习记录】九 C语言中const的详细分析
文章目录 1 const的分析 2 const本质的分析实验 2.1 代码案例分析 3 const修饰函数参数和返回值时的情况 3.1 代码案例分析 4 总结 1 const的分析 不管是C语言还是C ...
- Abaqus学习记录:分析步、增量步和迭代
Abaqus学习记录:分析步.增量步和迭代 相信大家在学习Abaqus都会对分析步的设置有一定的困惑,不知道该怎么设置.以及各个参数代表的含义.我也在网上找了很多资料,今天就为大家简单的总结一下. 一 ...
- 【博学谷学习记录】超强总结,用心分享 |产品经理-从盈利模式和推广方法对酷我英语和网易云音乐进行竞品分析
[博学谷学习记录]超强总结,用心分享 |产品经理-从盈利模式和推广方法对酷我英语和网易云音乐进行竞品分析 前言 据产业信息网报道数据,2020年中国网络音乐用户规模达6.58亿,其中手机网络音乐用户占 ...
最新文章
- 【错误记录】Android 中调用 Process 命令行执行指令 ( java.lang.IllegalThreadStateException: process hasn‘t exited )
- 怎么绘制机械孔_机械制图中常用的图纸简化画法,相当适合初学者!
- Nginx Parsing HTTP Package、header/post/files/args Sourcecode Analysis
- 翁恺老师C语言学习笔记(十一)字符串
- 基于http live streaming, 使用vlc + mediastreamsegmenter + apache 实现iOS视频直播
- 网路收包流程-网桥的处理流程(br网桥)(四)
- python alphago_资源 | 如何通过 Python 打造一款简易版 AlphaGo?
- ACM PKU 题目分类(完整整理版本)
- html格式蠕虫病毒,XiaoBa自制蠕虫病毒[2018-1-10]
- wamp mysql 密码_wamp如何设置数据库的密码
- 深度跳转-scheme
- 服务器都没有显卡型号吗,云服务器都没显卡么?
- Photoshop中的标尺、参考线
- 业聚医疗在港交所上市:市值约76亿港元,钱永勋、刘桂祯夫妇控股
- lol祖安服务器维护,LOL:最坑的十个大区,艾欧尼亚排第十!如果你在第一赶快换区!...
- 利用Flash获取摄像头视频进行动态捕捉
- 08——驾校科目一考试——布局按钮
- 光电效应在计算机中应用,光电效应在现在的应用主要包括哪几个方面?
- 小牛vs小客 小牛再战 两篇小博弈
- 3.7V升5V2A兼容进口MP2359/AH6901
热门文章
- 如何在Java中同步ArrayList?
- Java IdentityHashMap isEmpty()方法与示例
- 线性插值算法实现图像_C程序实现插值搜索算法
- fmax()函数以及C ++中的示例
- 第五章 条件、循环及其他语句
- Linux内核设计与实现---虚拟文件系统
- java制作h5视频聊天_JAVA实现大华摄像头WEB方式实时显示视频,H5界面展示方式思路。...
- 【转载】ACM中矩阵乘法的应用
- uva 550——Multiplying by Rotation
- I/O复用之 epoll