目录
Spring validate 是什么?
Spring Validate 是 Spring 框架提供的一个用于数据校验的模块。它提供了一种方便的方式来验证应用程序中的数据,例如用户输入、请求参数等。通过使用 Spring Validate,您可以定义验证规则,并在数据不符合这些规则时抛出异常,从而确保数据的完整性和准确性。
Spring Validate 提供了以下功能:
- 注解验证:使用注解来定义验证规则,例如 @NotNull、@Size 等。这些注解可以应用于类、字段或方法上,以便在运行时进行验证。
- 自定义验证器:您可以使用自定义验证器来定义自己的验证规则。自定义验证器可以扩展 Spring 的 Validator 接口,并实现 validate() 方法来执行自定义的验证逻辑。
- 校验分组:您可以根据不同的需求将校验规则分组,并在运行时选择要应用的组。这对于在不同场景下使用不同的校验规则非常有用。
- 错误处理:如果数据不符合验证规则,Spring Validate 将抛出 ConstraintViolationException 异常。您可以使用 @ControllerAdvice 注解和 @ExceptionHandler 方法来处理这些异常,并返回适当的错误消息给用户。
总的来说,Spring Validate 是一个强大的工具,可以帮助您在 Spring 应用程序中确保数据的完整性和准确性。通过使用注解和自定义验证器,您可以轻松地定义验证规则,并在运行时执行这些规则来确保数据的正确性。
Spring validate能干什么?
Spring Validate主要功能包括但不限于:
- 参数校验:Spring Validate可以用于对Controller层中接收的参数进行校验,包括请求参数、用户输入等。通过注解的方式,可以方便地定义验证规则,例如非空验证、长度验证等。
- 数据完整性验证:在数据传输和存储过程中,可能会遇到数据被篡改或损坏的情况。通过Spring Validate对数据进行校验,可以确保数据的完整性和准确性。
- 自定义校验规则:如果默认的验证规则不能满足需求,Spring Validate允许自定义校验规则。用户可以扩展验证器接口,实现自定义的验证逻辑。
- 错误处理:当数据不符合验证规则时,Spring Validate会抛出异常。通过捕获并处理这些异常,可以在前端页面上展示错误信息,或者在日志中记录错误信息。
- 校验分组:可以将校验规则分组,并在运行时选择要应用的组。这可以帮助在不同的场景下使用不同的校验规则。
Spring validate在项目中怎么使用
首先导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.3.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
</dependency>
义: boot-2.3.x
开始,spring-boot-starter-web
不再引入 spring-boot-starter-validation
,因此我们额外引入validation
依赖,而 2.3
之前的版本只需要引入 web 依赖。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>2.3.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.18.Final</version>
<scope>compile</scope>
^ 以上两个依赖都是可以实现功能的
对象参数的使用(实体类)
package org.example.entity.po;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.example.expleImport.ExcelExport;
import org.example.expleImport.ExcelImport;
import java.util.Date;
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("xinbo_celebrity")
public class XinboCelebrity {
@ExcelExport("编号")
@TableId(type = IdType.AUTO)
private Integer cid;
@ExcelExport("姓名")
private String name;
@ExcelExport("省")
private String province;
@ExcelExport("市")
private String city;
@ExcelExport("区")
private String district;
@ExcelExport("地址")
private String fullAddress;
@ExcelExport("类型")
private Integer type;
@ExcelExport("租金")
private Integer deposit;
@ExcelExport("押金")
private Integer rent;
@ExcelExport("备注")
private String remk;
@ExcelExport("第一张图片")
private String firstImage;
@ExcelExport("第二章图片")
private String secondImage;
@ExcelExport("第三张图片")
private String hirdImage;
@ExcelExport("创建人")
private String createdby;
@ExcelExport("修改人")
private String modifiedby;
@ExcelExport("创建时间")
private Date creationtime;
@ExcelExport("修改时间")
private Date modifytime;
// 业务字段 (图片的数组)
@TableField(exist = false)
private String[] images;
// 日志的类型
@TableField(exist = false)
private Integer logstatus;
// 日志的操作时间
@TableField(exist = false)
private Date logdate;
}
我们有以上的一个实体类
可以在某一个变量上加 @NotBlank(message = "name为必传参数") 传参不能为空
@NotBlank(message = "name为必传参数")
private String name;
加了注解就会执行对应的操作
在需要校验的对象前面加 @RequestBody
注解以及@Validated
或者@Valid
注解,如果校验失败,会抛出MethodArgumentNotValidException
异常
@RestController
public class XinboCelredayController{
@PostMapping("queryCelready")
public void queryCelready(@RequestBody @Validated Celready cel){}
}
不使用@RequestBody的情况
@Validated
注解或者@Valid
注解,如果校验失败,会抛出BindException
异常
@RestController
public class XinboCelredayController{
@PostMapping("queryCelready")
public void queryCelready(@Validated Celready cel){}
}
基本类型使用
其实也就是路径传参,在参数前面加上相对应的校验注解,还必须在
Controller
类上加@Validated
注解。如果校验失败,会抛出ConstraintViolationException
异常
在传单个参数的形式添加
@RestController
public class XinboCelredayController{
@PostMapping("queryCelready")
public void queryCelready(@NotBlank(message="name")String name,@NotBlank(message="age")String age){}
}
全局异常处理
如果参数校验失败,三种使用场景会抛出三种异常或者警告,分别是
MethodArgumentNotValidException
、ConstraintViolationException
、BindException
异常,每种异常的响应格式不一致。所以在实际项目开发中,通常会使用统一异常处理来返回一个统一格式的信息来友好的提示。
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* @RequestBody 上校验失败后抛出的异常是 MethodArgumentNotValidException 异常。
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public String handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
BindingResult bindingResult = e.getBindingResult();
String messages = bindingResult.getAllErrors()
.stream()
.map(ObjectError::getDefaultMessage)
.collect(Collectors.joining(";"));
return messages;
}
/**
* 不加 @RequestBody注解,校验失败抛出的则是 BindException
*/
@ExceptionHandler(value = BindException.class)
public String exceptionHandler(BindException e){
String messages = e.getBindingResult().getAllErrors()
.stream()
.map(ObjectError::getDefaultMessage)
.collect(Collectors.joining(";"));
return messages;
}
/**
* @RequestParam 上校验失败后抛出的异常是 ConstraintViolationException
*/
@ExceptionHandler({ConstraintViolationException.class})
public String methodArgumentNotValid(ConstraintViolationException exception) {
String message = exception.getConstraintViolations().stream().map(ConstraintViolation::getMessage).collect(Collectors.joining(";"));
return message;
}
}
它是将校验完才抛出的异常,能不能只要检测到一个不通过就抛出异常?
@Configuration
public class ParamValidatorConfig {
@Bean
public Validator validator() {
ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class)
.configure()
//failFast:只要出现校验失败的情况,就立即结束校验,不再进行后续的校验。
.failFast(true)
.buildValidatorFactory();
return validatorFactory.getValidator();
}
@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
MethodValidationPostProcessor methodValidationPostProcessor = new MethodValidationPostProcessor();
methodValidationPostProcessor.setValidator(validator());
return methodValidationPostProcessor;
}
}
MethodValidationPostProcessor
是Spring
提供的来实现基于方法Method
的JSR
校验的核心处理器,最终会由MethodValidationInterceptor
进行校验拦截。
校验注解合集o:
注解 | 备注 | 适用类型 | 示例 |
---|---|---|---|
@AssertFalse | 被注释的元素必须为 false ,null 值是有效的。 | boolean 和 Boolean | @AssertFalse(message = "该参数必须为 false") |
@AssertTrue | 被注释的元素必须为 true ,null 值是有效的。 | boolean 和 Boolean | @AssertTrue(message = "该参数必须为 true") |
@DecimalMax | 被注释的元素必须是一个数字,其值必须小于或等于指定的最大值,null 值是有效的。 | BigDecimal、BigInteger、CharSequence、byte、short、int、long以及包装类型 | @DecimalMax(value = "100",message = "该参数不能大于 100") |
@DecimalMin | 被注释的元素必须是一个数字,其值必须大于或等于指定的最小值,null 值是有效的。 | BigDecimal、BigInteger、CharSequence、byte、short、int、long以及包装类型 | @DecimalMin(value = "0",message = "该参数不能小于 0") |
@Digits | 被注释的元素必须是可接受范围内的数字,null 值是有效的。 | BigDecimal、BigInteger、CharSequence、byte、short、int、long以及包装类型 | @Digits(integer = 3,fraction = 2,message = "该参数整数位数不能超出3位,小数位数不能超过2位") |
@Max | 被注释的元素必须是一个数字,其值必须小于或等于指定的最大值,null 值是有效 | BigDecimal、BigInteger、byte、short、int、long以及包装类型 | @Max(value = 200,message = "最大金额不能超过 200") |
@Min | 被注释的元素必须是一个数字,其值必须大于或等于指定的最小值,null 值是有效的。 | BigDecimal、BigInteger、byte、short、int、long以及包装类型 | @Min(value = 0,message = "最小金额不能小于 0") |
@Negative | 被注释的元素必须是负数,null 值是有效 | BigDecimal、BigInteger、byte、short、int、long、float、double 以及包装类型 | @Negative(message = "必须是负数") |
@NegativeOrZero | 被注释的元素必须是负数或 0,null 值是有效的。 | BigDecimal、BigInteger、byte、short、int、long、float、double 以及包装类型 | @NegativeOrZero(message = "必须是负数或者为0") |
@Positive | 被注释的元素必须是正数,null 值是有效的。 | BigDecimal、BigInteger、byte、short、int、long、float、double 以及包装类型 | @Positive(message = "必须是正数") |
@PositiveOrZero | 被注释的元素必须是正数或0,null 值是有效的。 | BigDecimal、BigInteger、byte、short、int、long、float、double 以及包装类型 | @PositiveOrZero(message = "必须是正数或者为0") |
@Future | 被注释的元素必须是未来的日期(年月日),null 值是有效的。 | 基本所有的时间类型都支持。常用的:Date、LocalDate、LocalDateTime、LocalTime、Instant | @Future(message = "预约日期要大于当前日期") |
@FutureOrPresent | 被注释的元素必须是现在或者未来的日期(年月日),null 值是有效的。 | 基本所有的时间类型都支持。常用的:Date、LocalDate、LocalDateTime、LocalTime、Instant | @FutureOrPresent(message = "预约日要大于当前日期") |
@Past | 被注释的元素必须是过去的日期,null 值是有效的。 | 基本所有的时间类型都支持。常用的:Date、LocalDate、LocalDateTime、LocalTime、Instant | @Past(message = "出生日期要小于当前日期") |
@PastOrPresent | 被注释的元素必须是过去或者现在的日期,null 值是有效的 | 基本所有的时间类型都支持。常用的:Date、LocalDate、LocalDateTime、LocalTime、Instant | @PastOrPresent(message = "出生时间要小于当前时间") |
@NotBlank | 被注释的元素不能为空,并且必须至少包含一个非空白字符 | CharSequence | @NotBlank(message = "name为必传参数") |
@NotEmpty | 被注释的元素不能为 null 也不能为空 | CharSequence、Collection、Map、Array | @NotEmpty(message = "不能为null或者为空") |
@NotNull | 被注释的元素不能为null | 任意类型 | @NotNull(message = "不能为null") |
@Null | 被注释的元素必须为null | 任意类型 | @Null(message = "必须为null") |
被注释的元素必须是格式正确的电子邮件地址,null 值是有效的 | CharSequence | @Email(message = "email格式错误,请重新填写") | |
@Pattern | 被注释的元素必须匹配指定的正则表达式,null 值是有效的 | CharSequence | @Pattern(regexp = "^1[3456789]\d{9}$",message = "手机号格式不正确") |
@Size | 被注释的元素大小必须在指定范围内,null 值是有效的 | CharSequence、Collection、Map、Array | @Size(min = 5,max = 20,message = "字符长度在 5 -20 之间") |
以上注解有几个需要注意一下,因为经常用到,也经常使用错误
-
@NotNull:适用于任何类型,不能为null,但可以是 (",")
-
@NotBlank:只能用于 String,不能为null,而且调用 trim() 后,长度必须大于0,必须要有实际字符。
-
@NotEmpty:用于 String、Collection、Map、Array,不能为null,长度必须大于0。