Spring Validation
参考博客:SpringBoot 如何进行参数校验,老鸟们都这么玩的!-阿里云开发者社区 (aliyun.com)
*使用单参数校验时需要在Controller上加上@Validated注解,否则不生效。
依赖引入
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
BindingResult
可以跟在需要校验的参数后面,如果参数校验失败,异常信息会被绑定到该接口上,不过异常不会被抛出,无法被全局异常所捕获到
@GetMapping("/test")
public R<Object> test(@NotBlank(message = "name不能为空") String name, BindingResult bindingResult) {
List<String> list = null;
if (bindingResult.hasErrors()) {
list = bindingResult.getAllErrors().stream().map(ObjectError::toString).toList();
}
return R.success(list);
}
全局异常处理
@ExceptionHandler(value = {MethodArgumentNotValidException.class, ValidationException.class, BindException.class})
public R<String> validationException(Exception exception) {
log.info("参数校验失败!");
if (exception instanceof MethodArgumentNotValidException methodArgumentNotValidException) {
return R.error(methodArgumentNotValidException.getBindingResult().getAllErrors().stream().map(ObjectError::getDefaultMessage).collect(Collectors.joining("; ")), "数据校验失败");
} else if (exception instanceof ConstraintViolationException constraintViolationException) {
return R.error(constraintViolationException.getConstraintViolations().stream().map(ConstraintViolation::getMessage).collect(Collectors.joining("; ")), "数据效验失败");
} else if (exception instanceof BindException bindException) {
return R.error(bindException.getMessage(), "数据效验失败");
}
return R.error(exception.getMessage(), "数据效验失败");
}
自定义校验注解
自定义注解
不同的效验规则,可添加不同校验规则类实现:
@Constraint(validatedBy = {})
package com.example.portablefortheelderlybackground.config.validation;
import com.example.portablefortheelderlybackground.config.validation.Validated.isPhoneValidation;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;
/**
* @author 86187
* @description: 自定义手机效验注解
* @date: 2023/7/5 12:49
*/
@Target(value = {ElementType.FIELD, ElementType.PARAMETER})
@Retention(value = RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = {isPhoneValidation.class})//效验的逻辑类
public @interface isPhone {
String message() default "手机号不规范";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
String value() default "手机号验证";
}
自定义注解逻辑的实现类
在校验类中实现
ConstraintValidator<A,T>接口,A是具体的注解,T是注解添加的字段或者实体类型并实现初始化和校验方法
其中初始化方法能够获取到注解的所有属性,如
value(),groubs(),校验方法中第一个参数会传进添加上字段的属性值,根据属性值进行判断
package com.example.portablefortheelderlybackground.config.validation.Validated;
import com.example.portablefortheelderlybackground.config.validation.isPhone;
import org.springframework.util.StringUtils;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
public class isPhoneValidation implements ConstraintValidator<isPhone, String> {
//初始化,默认
@Override
public void initialize(isPhone constraintAnnotation) {
String value=constraintAnnotation.value()
ConstraintValidator.super.initialize(constraintAnnotation);
}
@Override
public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {
//参数s就是具体的值
if (!StringUtils.hasLength(s))
return false;
return s.matches("^(?:(?:\\+|00)86)?1[3-9]\\d{9}$");
}
}
自定义异常分组
需要用到spring提供的
@Validated注解
注解源码
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Validated {
/**
* Specify one or more validation groups to apply to the validation step
* kicked off by this annotation.
* <p>JSR-303 defines validation groups as custom annotations which an application declares
* for the sole purpose of using them as type-safe group arguments, as implemented in
* {@link org.springframework.validation.beanvalidation.SpringValidatorAdapter}.
* <p>Other {@link org.springframework.validation.SmartValidator} implementations may
* support class arguments in other ways as well.
*/
Class<?>[] value() default {};
}
实现接口
分组的类通过接口实现
package com.example.mailthirdpart.common.validation;
public interface AddGroup {
}
添加分组
在需要校验的规则上,通过groups添加分组即可,
package com.example.mailthirdpart.pojo;
import com.example.mailthirdpart.common.validation.AddGroup;
import lombok.Data;
import javax.validation.constraints.NotBlank;
@Data
public class user {
private String name;
@NotBlank(message = "not blank", groups = {AddGroup.class})//添加效验分组
private String id;
private String sex;
private String phone;
private String password;
}
分组校验
这样,只对相应的分组所属字段进行校验
@GetMapping("/test")
public R<Object> test(@Validated(value = {AddGroup.class}) @RequestBody user user, BindingResult bindingResult) {
List<String> list = null;
if (bindingResult.hasErrors()) {
list = bindingResult.getAllErrors().stream().map(ObjectError::toString).toList();
}
return R.success(list);
}