05.springBoot验证器的使用
1 验证器在程序中的作用
当前计算机的处理流程就是: 输入 --> 程序 --> 输出,也就是学术上的图灵机模式。假设"程序处理"这一环节是确定的 那么能决定输出结果就取决于输入这个环节的变量了,为了获取期望的输出,那么输入也必须是合法的,也就是验证器的作用。
2 安装依赖
2.1 gradle 方式
dependencies {
implementation 'org.hibernate:hibernate-validator'
}
2 表单对象验证器示例
package com.zhuche.server.api.v1;
import com.zhuche.server.dto.PersonDTO;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/banner")
public class BannerController {
@RequestMapping(value = "/test", method = {
RequestMethod.POST,
})
public PersonDTO test(
@RequestBody @Validated PersonDTO personDTO // 要验证的对象
) {
return PersonDTO.builder().
name("hello").
age(1).
build();
}
}
package com.zhuche.server.dto;
import lombok.*;
import org.hibernate.validator.constraints.Length;
@Builder
@Getter
public class PersonDTO {
@Length(min = 2, max = 10, message = "hello, it's error") // 验证规则
private String name;
private Integer age;
}
3 自定义验证器
自定义验证器是由2部分组成的:注解类和实现类。注解类定义后,对哪个参数需要验证就打上该注解。而实现类则是声明该验证的逻辑。
3.1 对单个属性进行验证
现在声明一个自定义验证器,用于对数据的ID
进行校验是否存在该ID
数据。
3.1.1 声明注解类
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD}) // <-- 指定该注解用于类的属性
@Constraint(validatedBy = HasTodoIDWiring.class) // <-- 声明该注解的实现逻辑
public @interface HasTodoID {
String message() default "The ID ${validatedValue} not found."; // <-- 默认错误消息
Class<?>[] groups() default {}; // <-- 这是SpringBoot 验证的规范不能少
Class<? extends Payload>[] payload() default {}; //<-- 这是SpringBoot 验证的规范不能少
}
3.1.2 验证的逻辑
import com.wuchuheng.notes.server.repository.TodoRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
@Slf4j
@RequiredArgsConstructor
public class HasTodoIDWiring implements ConstraintValidator<HasTodoID, Long> {
@Override
public boolean isValid(Long id, ConstraintValidatorContext context) {
// todo ... <-- 这里业务的实现,验证通过返回true反之false
return false;
}
}
3.1.3 使用方式
使用方式跟hibernate
一样,直接把注解打在要验证的属性上就可以了
public class UpdateTodoInput { // <-- 假设这个是要验证的表单类
@HasTodoID
private Long id; // <-- 而这个是要验证的字段,直接打上去就可以了
}
3.2 自定义联合验证
当验证需要用到不止一个字段的参数时,就需要在验证的逻辑中获取到那些值才行。假如有一个登录场景,那么就需要在验证账号时就需要取值账号和密码这2个参数, 才能在验证的业务中进行验证处理,所以它需要获取至少2个字段的值才行。所以这个验证器不能作用于类的属性上而是直接打在类之上,才能获取到类下面的多个属性
3.2.1 声明联合验证的注解
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;
@Documented
@Constraint( validatedBy = AuthorizeValidatorWiring.class ) // <-- 验证业务的实现类
@Target({ElementType.TYPE}) // <-- 声明该注解作用在类上
@Retention(RetentionPolicy.RUNTIME)
public @interface AuthorizeValidator {
String message() default "Invalid authorization.";
String username(); // <-- 获取类的属性名
String password(); // <-- 获取类的属性名
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
3.2.2 联合验证的逻辑
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.Objects;
@Component
@RequiredArgsConstructor
public class AuthorizeValidatorWiring implements ConstraintValidator<AuthorizeValidator, Object> {
private String username;
private String password;
public void initialize(AuthorizeValidator constraintAnnotation) {
this.username = constraintAnnotation.username(); // 把要验证的类的名为`username`的字段名获取下来
this.password = constraintAnnotation.password();
}
@Override
public boolean isValid(Object value, ConstraintValidatorContext context) {
final var username = new BeanWrapperImpl(value).getPropertyValue(this.username).toString(); // 获取目标类下方的username 的值
var password = new BeanWrapperImpl(value).getPropertyValue(this.password).toString(); // 获取目标类下方的password的值
// todo ... 这里实现验证逻辑
return true;
}
3.2.3 验证示例
import com.zhuche.server.validators.authorizeValidator.AuthorizeValidator;
import lombok.Data;
import javax.validation.constraints.NotBlank;
@Data
@AuthorizeValidator( username = "username", password = "password" )
public class AuthorizationInput {
@NotBlank
String username;
@NotBlank
String password;
}