主要参考博文: http://elim.iteye.com/blog/1812584
官方网址: https://docs.spring.io/spring/docs/current/spring-framework-reference/html/validation.html
Validation QuickStart on Spring Boot : https://spring.io/guides/gs/validating-form-input/
Hibernate-validation: http://hibernate.org/validator/documentation/getting-started/
Introduction
spring Validation 是一种参数检验工具,集成在spring-context包中, 常用于spring mvc中Controller的参数处理,主要针对整个实体类的多个可选域进行判定.对于不合格的数据信息springMVC会把它保存在错误对象中,这些错误信息我们也可以通过SpringMVC提供的标签在前端JSP页面上进行展示。
判定方式可以通过两种方式实现
- 实现Validator,利用DataBinder获取Errors信息
- 采用@Valid 以及 JSR-303中的参数判定注解
基于注解的Validation
springMVC项目中快速使用:
1.pom配置文件添加依赖:
<!--JSR-303的hibernate实现-->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.0.1.Final</version>
</dependency>
2.在实体类字段上标注检验注解
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.NotEmpty;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import javax.validation.constraints.*;
/**
* Created by shuangxingzhang on 17-8-20.
*/
@Component
@Scope("prototype")
public class User4Test {
@NotEmpty(message = "不得为空")
@Pattern(regexp = "张.*", message = "这是一张张家家谱!")
private String name;
@NotNull(message = "不能为空")
@Min(value = 15, message = "年龄不在规定范围内,15以上")
@Max(value = 18, message = "不能比18更老了")
private int age;
@NotEmpty(message = "请输入邮箱")
@Email(message = "邮箱格式不正确!")
private String email;
@NotEmpty(message = "请输入昵称")
@Length(min = 3,max = 10, message = "昵称长度应在3-10之间")
private String nickname;
// Getter And Setter ...
3.注解实体类参数,并且必须紧跟着添加错误信息收集类BingResult
import com.qunar.fresh2017.spring.model.User4Test;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import javax.validation.Valid;
import java.util.List;
/**
* Created by shuangxingzhang on 17-8-20.
*/
@Controller
public class ValidationTestController {
@RequestMapping(value = "valid", method = RequestMethod.POST)
public ModelAndView testValidation(@Valid User4Test user, BindingResult bindingResult){
if(bindingResult.hasErrors()){
//TODO
}
// generic return;
}
}
4.在ViewResolve中使用BingResult??!!. GettingStart提供示例html
<html><body>
<form action="#" th:action="@{/}" th:object="${personForm}" method="post">
<table>
<tr><td>Name:</td>
<td><input type="text" th:field="*{name}" /></td>
<td th:if="${#fields.hasErrors('name')}" th:errors="*{name}">Name Error</td></tr>
<tr><td>Age:</td>
<td><input type="text" th:field="*{age}" /></td>
<td th:if="${#fields.hasErrors('age')}" th:errors="*{age}">Age Error</td></tr>
<tr><td><button type="submit">Submit</button></td></tr>
</table>
</form>
</body></html>
5.结果示意图
相关内容
JSR-303 规范:
JSR(Java Specification Requests),是一种关于请求参数的规范,最新为JSR-349,主要提供了一些参数检验注解,如下:
常用实现的补充Hibernate-validator
提供另外几个常用的注解:
实现Validator接口方法:
- 实现Validator接口的两个函数:
supports(Class<?>)方法检测类型
validate(Object,Errors) 方法将错误信息记录到另一个类中
BindingResult继承了spring的Errors接口
public class UserValidator implements Validator {
public boolean supports(Class<?> clazz) {
// TODO Auto-generated method stub
return User.class.equals(clazz);
}
public void validate(Object obj, Errors errors) {
// TODO Auto-generated method stub
ValidationUtils.rejectIfEmpty(errors, "username", null, "Username is empty.");
User user = (User) obj;
if (null == user.getPassword() || "".equals(user.getPassword()))
errors.rejectValue("password", null, "Password is empty.");
}
}
对单个域特定判空:
rejectIfEmpty( Errors, FieldName, Message)
rejectIfEmptyOrWhitespace(......)
获取整体错误信息的方式:
ValidatorUtils.invokeValidator(Validator,Entity,Errors)
获取错误信息
由BindingResult接口获取.
- 获取多个错误信息列表: getFieldErrors();
- 获取错误信息字段名称: getObjectName();
- 获取错误的描述信息: getDefaultMessage();
List<FieldError> errors = bindingResult.getFieldErrors();
for (FieldError error : errors ) {
System.out.println (error.getObjectName() + " - " + error.getDefaultMessage());
}
扩展
自定义检验注解 @DIY
首先要定义@interface DIY
@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 {};
}
两种形式自定义
1.组合现有的注解 直接在该接口上添加现有注解:
@DecimalMin(10000)
@DecimalMax(8000)
@Constraint(validatedBy = {})
@Documented
@Target( { ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface Money {
String message() default "错误的价格";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
2.实现特定接口
实现ConstraintValidator 实现两个方法.
第二个泛型类型为isValid的第一个参数类型....
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();
}
}
具体参考上面博文.
NOTE:
- Hibernate-validator 版本不能太高,6.0.1只能基于Java8
- 表单提交时,不填该表的内容,正常
submit
,默认为空字符串 "" - @NotEmpty只能用来修饰String,不能用于数值性,int double等
Error: No validator could be found for type: java.lang.Integer - 数值性参数: 当输入为空时,字符串"",解析失败之后不能再进行其他判断,会出现NPE
- @Size尽量别用,报错
Error: No validator could be found for type: java.lang.Integer - spring对应参数时,名字不能写错,要一致,默认为null