spring validation实现对Restful请求的数据进行校验
转发:https://blog.csdn.net/steven2xupt/article/details/874526641、前言
数据的校验是交互式网站一个不可或缺的功能,前端的js校验可以涵盖大部分的校验职责,如用户名唯一性,生日格式,邮箱格式校验等等常用的校验。但是为了避免用户绕过浏览器,使用http工具直接向后端请求一些违法数据,服务端的数据校验也是必要的,可以防止脏数据落到数据库中,如果数据库中出现一个非法的邮箱格式,也会让运维人员头疼不已。可以使用本文将要介绍的validation来对数据进行校验。
2、常用校验
-
JSR303/JSR-349: JSR303是一项标准,只提供规范不提供实现,规定一些校验规范即校验注解,如@Null,@NotNull,@Pattern,位于javax.validation.constraints包下。JSR-349是其的升级版本,添加了一些新特性。
<ul><li>@Null 被注释的元素必须为null</li> <li>@NotNull 被注释的元素必须不为null</li> <li>@AssertTrue 被注释的元素必须为true</li> <li>@AssertFalse 被注释的元素必须为false</li> <li>@Min(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值</li> <li>@Max(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值</li> <li>@DecimalMin(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值</li> <li>@DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值</li> <li>@Size(max, min) 被注释的元素的大小必须在指定的范围内</li> <li>@Digits (integer, fraction) 被注释的元素必须是一个数字,其值必须在可接受的范围内</li> <li>@Past 被注释的元素必须是一个过去的日期</li> <li>@Future 被注释的元素必须是一个将来的日期</li> <li>@Pattern(value) 被注释的元素必须符合指定的正则表达式</li> </ul></li> <li> <p>hibernate validation:hibernate validation是对这个规范的实现,并增加了一些其他校验注解,如@Email,@Length,@Range等等</p> <ul><li>@Email 被注释的元素必须是电子邮箱地址</li> <li>@Length 被注释的字符串的大小必须在指定的范围内</li> <li>@NotEmpty 被注释的字符串的必须非空</li> <li>@Range 被注释的元素必须在合适的范围内</li> </ul></li> <li>spring validation:spring validation对hibernate validation进行了二次封装,在springmvc模块中添加了自动校验,并将校验信息封装进了特定的类中</li>
3、spring boot的数据自动校验功能
3.1 引入依赖
spring-web模块使用了hibernate-validation,并且databind模块也提供了相应的数据绑定功能。
-
<dependencies>
-
<dependency>
-
<groupId>org.springframework.boot
</groupId>
-
<artifactId>spring-boot-starter-web
</artifactId>
-
</dependency>
-
</dependencies>
我们只需要引入spring-boot-starter-web依赖即可,如果查看其子依赖,可以发现如下的依赖:
-
<dependency>
-
<groupId>org.hibernate
</groupId>
-
<artifactId>hibernate-validator
</artifactId>
-
</dependency>
-
<dependency>
-
<groupId>com.fasterxml.jackson.core
</groupId>
-
<artifactId>jackson-databind
</artifactId>
-
</dependency>
3.2 构建启动类
-
@SpringBootApplication
-
public
class App {
-
public
static
void main(
String[] args) {
-
SpringApplication.run(App.
class, args);
-
System.out.println(
"Start app success.");
-
}
-
}
3.3 创建需要被校验的实体类
-
public
class Person {
-
@NotEmpty(message = "name不能为空")
-
private String name;
-
@Range(min = 0, max = 100, message = "age不能大于100小于0")
-
private
int age;
-
-
public String getName() {
-
return name;
-
}
-
-
public void setName(String name) {
-
this.name = name;
-
}
-
-
public int getAge() {
-
return age;
-
}
-
-
public void setAge(int age) {
-
this.age = age;
-
}
3.4 在Controller中校验数据
springmvc为我们提供了自动封装表单参数的功能,一个添加了参数校验的典型controller如下所示。
-
@RequestMapping("/test")
-
public String valid(
@Validated Person person, BindingResult bindingResult) {
-
if (bindingResult.hasErrors()) {
-
for (FieldError fieldError : bindingResult.getFieldErrors()) {
-
System.
out.println(fieldError);
-
}
-
return
"fail";
-
}
-
return
"success";
-
}
值得注意的地方:
- 参数Persion前需要加上@Validated注解,表明需要spring对其进行校验,而校验的信息会存放到其后的BindingResult中。注意,必须相邻,如果有多个参数需要校验,形式可以如下。valid(@Validated Person person, BindingResult fooBindingResult ,@Validated Bar bar, BindingResult barBindingResult);即一个校验类对应一个校验结果。
- 校验结果会被自动填充,在controller中可以根据业务逻辑来决定具体的操作,如跳转到错误页面。 一个最基本的校验就完成了.
启动容器测试结果如下:
Field error in object 'person' on field 'age': rejected value [105]; codes [Range.person.age,Range.age,Range.int,Range]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [person.age,age]; arguments []; default message [age],100,0]; default message [age不能大于100小于0]
3.5 统一异常处理
前面那种方式处理校验错误,略显复杂,而且一般网站都会对请求错误做统一的404页面封装,如果数据校验不通过,则Spring boot会抛出BindException异常,我们可以捕获这个异常并使用Result封装返回结果。通过@RestControllerAdvice定义异常捕获类。
Controller类:
-
@RequestMapping(value = "valid", method = RequestMethod.GET)
-
public String valid(
@Validated Person person) {
-
System.
out.println(person);
-
return
"success";
-
}
统一异常处理类:
-
@RestControllerAdvice
-
public
class BindExceptionHanlder {
-
@ExceptionHandler(BindException.
class)
-
public
String handleBindException(HttpServletRequest request, BindException
exception) {
-
List<FieldError> allErrors =
exception.getFieldErrors();
-
StringBuilder sb =
new StringBuilder();
-
for (FieldError errorMessage : allErrors) {
-
sb.append(errorMessage.getField()).append(
": ").append(errorMessage.getDefaultMessage()).append(
", ");
-
}
-
System.out.println(sb.toString());
-
return sb.toString();
-
}
-
}
测试: http://localhost:8080/valid?age=105&name=steven
输出:age: age不能大于100小于0,
4、自定义校验注解
4.1 @NameValidation
-
@Documented
-
@Constraint(validatedBy = NameValidationValidator.class)
-
@Target({ElementType.METHOD, ElementType.FIELD})
-
@Retention(RUNTIME)
-
public
@interface NameValidation {
-
String message()
default
"不是合法的名字";
-
-
Class<?>[] groups()
default {};
-
-
Class<? extends Payload>[] payload()
default {};
-
-
@Target({PARAMETER, ANNOTATION_TYPE})
-
@Retention(RUNTIME)
-
@Documented
-
@interface List {
-
NameValidation[] value();
-
}
-
}
4.2 校验类NameValidationValidator
-
public
class NameValidationValidator implements ConstraintValidator<NameValidation, String> {
-
@Override
-
public
boolean isValid(
String value, ConstraintValidatorContext context) {
-
if (
"steven".equalsIgnoreCase(value)) {
-
return
true;
-
}
-
String defaultConstraintMessageTemplate = context.getDefaultConstraintMessageTemplate();
-
System.out.println(
"default message :" + defaultConstraintMessageTemplate);
-
//禁用默认提示信息
-
//context.disableDefaultConstraintViolation();
-
//设置提示语
-
//context.buildConstraintViolationWithTemplate("can not contains blank").addConstraintViolation();
-
return
false;
-
}
-
}
4.3 在Person类增加新注解
-
@NotEmpty(message =
"name不能为空")
-
@NameValidation
-
private String name;
测试: http://localhost:8080/valid?age=105&name=lxy
输出:age: age不能大于100小于0, name: 不是合法的名字,
spring validation实现对Restful请求的数据进行校验
1、前言
数据的校验是交互式网站一个不可或缺的功能,前端的js校验可以涵盖大部分的校验职责,如用户名唯一性,生日格式,邮箱格式校验等等常用的校验。但是为了避免用户绕过浏览器,使用http工具直接向后端请求一些违法数据,服务端的数据校验也是必要的,可以防止脏数据落到数据库中,如果数据库中出现一个非法的邮箱格式,也会让运维人员头疼不已。可以使用本文将要介绍的validation来对数据进行校验。
2、常用校验
-
JSR303/JSR-349: JSR303是一项标准,只提供规范不提供实现,规定一些校验规范即校验注解,如@Null,@NotNull,@Pattern,位于javax.validation.constraints包下。JSR-349是其的升级版本,添加了一些新特性。
<ul><li>@Null 被注释的元素必须为null</li> <li>@NotNull 被注释的元素必须不为null</li> <li>@AssertTrue 被注释的元素必须为true</li> <li>@AssertFalse 被注释的元素必须为false</li> <li>@Min(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值</li> <li>@Max(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值</li> <li>@DecimalMin(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值</li> <li>@DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值</li> <li>@Size(max, min) 被注释的元素的大小必须在指定的范围内</li> <li>@Digits (integer, fraction) 被注释的元素必须是一个数字,其值必须在可接受的范围内</li> <li>@Past 被注释的元素必须是一个过去的日期</li> <li>@Future 被注释的元素必须是一个将来的日期</li> <li>@Pattern(value) 被注释的元素必须符合指定的正则表达式</li> </ul></li> <li> <p>hibernate validation:hibernate validation是对这个规范的实现,并增加了一些其他校验注解,如@Email,@Length,@Range等等</p> <ul><li>@Email 被注释的元素必须是电子邮箱地址</li> <li>@Length 被注释的字符串的大小必须在指定的范围内</li> <li>@NotEmpty 被注释的字符串的必须非空</li> <li>@Range 被注释的元素必须在合适的范围内</li> </ul></li> <li>spring validation:spring validation对hibernate validation进行了二次封装,在springmvc模块中添加了自动校验,并将校验信息封装进了特定的类中</li>
3、spring boot的数据自动校验功能
3.1 引入依赖
spring-web模块使用了hibernate-validation,并且databind模块也提供了相应的数据绑定功能。
-
<dependencies>
-
<dependency>
-
<groupId>org.springframework.boot
</groupId>
-
<artifactId>spring-boot-starter-web
</artifactId>
-
</dependency>
-
</dependencies>
我们只需要引入spring-boot-starter-web依赖即可,如果查看其子依赖,可以发现如下的依赖:
-
<dependency>
-
<groupId>org.hibernate
</groupId>
-
<artifactId>hibernate-validator
</artifactId>
-
</dependency>
-
<dependency>
-
<groupId>com.fasterxml.jackson.core
</groupId>
-
<artifactId>jackson-databind
</artifactId>
-
</dependency>
3.2 构建启动类
-
@SpringBootApplication
-
public
class App {
-
public
static
void main(
String[] args) {
-
SpringApplication.run(App.
class, args);
-
System.out.println(
"Start app success.");
-
}
-
}
3.3 创建需要被校验的实体类
-
public
class Person {
-
@NotEmpty(message = "name不能为空")
-
private String name;
-
@Range(min = 0, max = 100, message = "age不能大于100小于0")
-
private
int age;
-
-
public String getName() {
-
return name;
-
}
-
-
public void setName(String name) {
-
this.name = name;
-
}
-
-
public int getAge() {
-
return age;
-
}
-
-
public void setAge(int age) {
-
this.age = age;
-
}
3.4 在Controller中校验数据
springmvc为我们提供了自动封装表单参数的功能,一个添加了参数校验的典型controller如下所示。
-
@RequestMapping("/test")
-
public String valid(
@Validated Person person, BindingResult bindingResult) {
-
if (bindingResult.hasErrors()) {
-
for (FieldError fieldError : bindingResult.getFieldErrors()) {
-
System.
out.println(fieldError);
-
}
-
return
"fail";
-
}
-
return
"success";
-
}
值得注意的地方:
- 参数Persion前需要加上@Validated注解,表明需要spring对其进行校验,而校验的信息会存放到其后的BindingResult中。注意,必须相邻,如果有多个参数需要校验,形式可以如下。valid(@Validated Person person, BindingResult fooBindingResult ,@Validated Bar bar, BindingResult barBindingResult);即一个校验类对应一个校验结果。
- 校验结果会被自动填充,在controller中可以根据业务逻辑来决定具体的操作,如跳转到错误页面。 一个最基本的校验就完成了.
启动容器测试结果如下:
Field error in object 'person' on field 'age': rejected value [105]; codes [Range.person.age,Range.age,Range.int,Range]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [person.age,age]; arguments []; default message [age],100,0]; default message [age不能大于100小于0]
3.5 统一异常处理
前面那种方式处理校验错误,略显复杂,而且一般网站都会对请求错误做统一的404页面封装,如果数据校验不通过,则Spring boot会抛出BindException异常,我们可以捕获这个异常并使用Result封装返回结果。通过@RestControllerAdvice定义异常捕获类。
Controller类:
-
@RequestMapping(value = "valid", method = RequestMethod.GET)
-
public String valid(
@Validated Person person) {
-
System.
out.println(person);
-
return
"success";
-
}
统一异常处理类:
-
@RestControllerAdvice
-
public
class BindExceptionHanlder {
-
@ExceptionHandler(BindException.
class)
-
public
String handleBindException(HttpServletRequest request, BindException
exception) {
-
List<FieldError> allErrors =
exception.getFieldErrors();
-
StringBuilder sb =
new StringBuilder();
-
for (FieldError errorMessage : allErrors) {
-
sb.append(errorMessage.getField()).append(
": ").append(errorMessage.getDefaultMessage()).append(
", ");
-
}
-
System.out.println(sb.toString());
-
return sb.toString();
-
}
-
}
测试: http://localhost:8080/valid?age=105&name=steven
输出:age: age不能大于100小于0,
4、自定义校验注解
4.1 @NameValidation
-
@Documented
-
@Constraint(validatedBy = NameValidationValidator.class)
-
@Target({ElementType.METHOD, ElementType.FIELD})
-
@Retention(RUNTIME)
-
public
@interface NameValidation {
-
String message()
default
"不是合法的名字";
-
-
Class<?>[] groups()
default {};
-
-
Class<? extends Payload>[] payload()
default {};
-
-
@Target({PARAMETER, ANNOTATION_TYPE})
-
@Retention(RUNTIME)
-
@Documented
-
@interface List {
-
NameValidation[] value();
-
}
-
}
4.2 校验类NameValidationValidator
-
public
class NameValidationValidator implements ConstraintValidator<NameValidation, String> {
-
@Override
-
public
boolean isValid(
String value, ConstraintValidatorContext context) {
-
if (
"steven".equalsIgnoreCase(value)) {
-
return
true;
-
}
-
String defaultConstraintMessageTemplate = context.getDefaultConstraintMessageTemplate();
-
System.out.println(
"default message :" + defaultConstraintMessageTemplate);
-
//禁用默认提示信息
-
//context.disableDefaultConstraintViolation();
-
//设置提示语
-
//context.buildConstraintViolationWithTemplate("can not contains blank").addConstraintViolation();
-
return
false;
-
}
-
}
4.3 在Person类增加新注解
-
@NotEmpty(message =
"name不能为空")
-
@NameValidation
-
private String name;
测试: http://localhost:8080/valid?age=105&name=lxy
输出:age: age不能大于100小于0, name: 不是合法的名字,