常用的原生校验注解有:
@NotNull 所有对象判空
@NotBlank 字符串判空
@NotEmpty 集合判空
自定义校验注解实现方式:
如果spring-boot版本小于2.3.x,spring-boot-starter-web会自动传入hibernate-validator依赖。如果spring-boot版本大于2.3.x,则需要手动引入依赖:
org.hibernate
hibernate-validator
6.0.1.Final
自定义一个校验注解,针对字符串参数校验,校验逻辑是字符串必须是"xzh"。
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE_USE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.validation.Constraint;
import javax.validation.Payload;
/**
* @author 向振华
* @date 2022/11/23 16:52
*/
@Documented
@Constraint(validatedBy = {EqualsXzhValidator.class})
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
public @interface EqualsXzh {
String message() default "必须是xzh";
Class>[] groups() default { };
Class extends Payload>[] payload() default { };
}
校验逻辑是字符串必须是"xzh"。
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
/**
* @author 向振华
* @date 2022/11/23 16:56
*/
public class EqualsXzhValidator implements ConstraintValidator {
public EqualsXzhValidator() {
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
// 自定义校验规则,字段的value必须是"xzh",否则抛异常
return "xzh".equals(value);
}
}
参数校验会默认抛出MethodArgumentNotValidException异常,通常使用全局异常捕获拦截,然后返回提示信息出去 。
import com.xzh.exception.BusinessException;
import com.xzh.web.ApiResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.servlet.http.HttpServletRequest;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.StringJoiner;
/**
* 全局异常捕获处理
*
* @author 向振华
* @date 2022/11/23 16:52
*/
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* 异常处理程序
*
* @param request
* @param exception
* @return
*/
@ExceptionHandler(value = Exception.class)
public Object handler(HttpServletRequest request, Exception exception) {
String errorLog = this.errorLog(request, exception);
log.error("全局异常捕获日志 ---> {}", errorLog);
String message;
if (exception instanceof MethodArgumentNotValidException) {
MethodArgumentNotValidException e = (MethodArgumentNotValidException) exception;
BindingResult bindingResult = e.getBindingResult();
StringJoiner sj = new StringJoiner(",");
for (FieldError fieldError : bindingResult.getFieldErrors()) {
String longField = fieldError.getField();
String shortField = longField.substring(longField.lastIndexOf(".") + 1);
String defaultMessage = fieldError.getDefaultMessage();
sj.add(shortField + defaultMessage);
}
message = sj.toString();
} else if (exception instanceof BusinessException) {
BusinessException e = (BusinessException) exception;
message = e.getMessage();
} else {
message = "系统异常,请稍后重试";
}
return ApiResponse.fail(message);
}
private String errorLog(HttpServletRequest request, Exception exception) {
StringWriter sw = new StringWriter();
sw.append(String.format("[接口] %s\n", request.getRequestURL()));
exception.printStackTrace(new PrintWriter(sw));
return sw.toString();
}
}
参数校验也可以使用工具类进行校验,校验不通过抛出业务异常(也会被全局异常捕获拦截)
import com.xzh.exception.BusinessException;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import java.util.Set;
import java.util.StringJoiner;
/**
* 参数校验工具
*
* @author 向振华
* @date 2022/11/23 16:52
*/
public class ValidatedUtils {
private static final Validator VALIDATOR;
static {
VALIDATOR = Validation.buildDefaultValidatorFactory().getValidator();
}
private ValidatedUtils() {
}
public static void verify(Object object, Class>... groups) {
Set> constraintViolations = VALIDATOR.validate(object, groups);
if (!constraintViolations.isEmpty()) {
StringJoiner sj = new StringJoiner(",");
for (ConstraintViolation
在参数上面加上@EqualsXzh注解即可
@EqualsXzh
private String name;
如果是嵌套校验还需要加上@Valid
@Data
public class OrderDTO {
@EqualsXzh
private String name;
@Valid
private AccountDTO account;
@Valid
private List orderItemList;
}
在对象前加@Validated注解
@PostMapping("/test")
public ApiResponse test(@RequestBody @Validated OrderDTO dto) {
// TODO
return ApiResponse.success();
}
校验不通过会出现提示:name必须是xzh
其中BusinessException是自定义的业务异常,ApiResponse是自定义的通用返回格式。
以前的校验注解文章
Spring Boot 全局异常处理 与 Hibernate Validator校验框架整合_抓手的博客-CSDN博客
Spring校验框架的使用 @Validated_抓手的博客-CSDN博客