其他的文章
公共模块:
http://www.haijin.xyz/article/930
之前的参数校验:
http://www.haijin.xyz/list/article/181
1、引入maven依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
2、相关配置:
/**
* 通用异常处理参数校验相关异常
*
* @author system
*/
@Slf4j
@RestControllerAdvice(assignableTypes = TestController.class) // 针对当前的接口进行校验拦截
@Order(1)
public class ValidationExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ResultData<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException e) {
String errorMessage = Objects.requireNonNull(e.getBindingResult().getFieldError()).getDefaultMessage();
return ResultData.builder()
.code(ReturnCodeEnum.RC999.getCode())
.message(errorMessage)
.build();
}
@ExceptionHandler(ConstraintViolationException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ResultData<Object> handleConstraintViolation(ConstraintViolationException e) {
String errorMessage = e.getMessage();
return ResultData.builder()
.code(ReturnCodeEnum.RC999.getCode())
.message(errorMessage)
.build();
}
@ExceptionHandler(MissingServletRequestParameterException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ResultData<Object> handleMissingServletRequestParameter(MissingServletRequestParameterException e) {
String errorMessage = "参数不能为空:" + e.getParameterName();
return ResultData.builder()
.code(ReturnCodeEnum.RC999.getCode())
.message(errorMessage)
.build();
}
}
3、TestController:
@GetMapping("/test/list")
@ResponseBody
public ResultData<Object> queryVideoList(
@RequestParam("type") @NotNull(message = "参数不能为空:type") Integer type) {
4、常用注解
| 注解 | 作用场景 | 示例 |
|---|---|---|
@NotBlank |
字符串非空(非 null + 非空白) | @NotBlank(message = "姓名不能为空") |
@NotNull |
任意类型非 null | @NotNull(message = "年龄不能为空") |
@NotEmpty |
集合 / 数组非空(长度 > 0) | @NotEmpty(message = "爱好不能为空") |
@Email |
邮箱格式校验 | @Email(message = "邮箱格式错误") |
@Min(value) |
数字最小值 | @Min(value = 18, message = "年龄最小18") |
@Max(value) |
数字最大值 | @Max(value = 60, message = "年龄最大60") |
@Pattern(regexp) |
正则表达式校验 | @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号错误") |
@Size(min, max) |
字符串 / 集合长度范围 | @Size(min = 6, max = 20, message = "密码长度6-20") |
5、相关注解的校验
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
/**
* 手机号格式校验器
*
* @author system
*/
public class PhoneFormatValidator implements ConstraintValidator<PhoneFormat, String> {
private static final String PHONE_PATTERN = "^1[3-9]\\d{9}$";
@Override
public void initialize(PhoneFormat constraintAnnotation) {
}
@Override
public boolean isValid(String phone, ConstraintValidatorContext context) {
if (phone == null || phone.trim().isEmpty()) {
return false;
}
if (phone.length() != 11) {
return false;
}
return phone.matches(PHONE_PATTERN);
}
}
注解
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 手机号格式校验注解
* 11位号码
*
* @author system
*/
@Documented
@Constraint(validatedBy = PhoneFormatValidator.class)
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface PhoneFormat {
String message() default "手机号格式错误,应为11位号码";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
时间戳格式校验器
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
/**
* 时间戳格式校验器
*
* @author system
*/
public class TimestampFormatValidator implements ConstraintValidator<TimestampFormat, String> {
private static final String TIMESTAMP_PATTERN = "yyyyMMddHHmmss";
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern(TIMESTAMP_PATTERN);
private static final int VALIDITY_MINUTES = 5;
@Override
public void initialize(TimestampFormat constraintAnnotation) {
}
@Override
public boolean isValid(String timestamp, ConstraintValidatorContext context) {
if (timestamp == null || timestamp.trim().isEmpty()) {
return false;
}
if (timestamp.length() != 14) {
return false;
}
if (!timestamp.matches("\\d{14}")) {
return false;
}
try {
LocalDateTime requestTime = LocalDateTime.parse(timestamp, FORMATTER);
LocalDateTime now = LocalDateTime.now();
if (requestTime.isAfter(now)) {
return false;
}
LocalDateTime expireTime = requestTime.plusMinutes(VALIDITY_MINUTES);
if (now.isAfter(expireTime)) {
return false;
}
return true;
} catch (DateTimeParseException e) {
return false;
}
}
}
时间戳格式校验注解
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 时间戳格式校验注解
* 格式:yyyyMMddHHmmss(14位数字)
* 有效期:5分钟
*
* @author system
*/
@Documented
@Constraint(validatedBy = TimestampFormatValidator.class)
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface TimestampFormat {
String message() default "时间戳格式错误或已过期,格式应为yyyyMMddHHmmss,有效期为5分钟";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
使用:
/**
* 请求时间,格式:yyyyMMddHHmmss
*/
@NotBlank(message = "timestamp不能为空")
@TimestampFormat
private String timestamp;
/**
* 手机号,11位号码
*/
@NotBlank(message = "phone不能为空")
@PhoneFormat
private String phone;