在Spring Boot中,我们可以通过多种方式实现自定义接口参数校验,其中最常用的是使用Java Bean Validation规范,如JSR 303/JSR 380等,然后再结合Hibernate Validator作为默认的实现方式,下面我们就来看看如何实现自定义的接口参数校验。
引入依赖
首先,需要在项目中引入spring-boot-starter-validation依赖,如下所示。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
定义自定义校验注解
定义一个自定义的校验注解,例如,需要验证某个字符串字段是否是一个有效的邮箱地址。
package com.example.validation;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ ElementType.FIELD, ElementType.PARAMETER }) // 可以用在字段或者方法参数上
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = EmailValidator.class) // 指定校验逻辑类
public @interface ValidEmail {
String message() default "Invalid email format"; // 默认的错误消息
Class<?>[] groups() default {}; // 分组校验相关
Class<? extends Payload>[] payload() default {}; // 可以传递元数据
}
实现校验逻辑
接下来,需要创建一个EmailValidator类实现ConstraintValidator接口,并覆写isValid方法,实现校验逻辑,如下所示。
package com.example.validation;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.regex.Pattern;
public class EmailValidator implements ConstraintValidator<ValidEmail, String> {
private static final String EMAIL_PATTERN = "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+#34;;
@Override
public void initialize(ValidEmail constraintAnnotation) {
// 这里可以进行初始化设置,如果注解支持其他属性的话
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
// 如果字符串为空,不进行验证,由其他注解如@NotNull处理
if (value == null) {
return true;
}
// 使用正则表达式验证邮箱格式
return Pattern.matches(EMAIL_PATTERN, value);
}
}
使用自定义注解进行参数校验
在控制器方法或实体类中使用自定义注解进行参数校验。如下所示在DTO类中使用。
package com.example.dto;
import com.example.validation.ValidEmail;
public class UserDTO {
@ValidEmail // 使用自定义的校验注解
private String email;
// 其他字段和getter、setter
}
或者我们可以直接在控制器参数上使用。
package com.example.controller;
import com.example.validation.ValidEmail;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
@RestController
public class UserController {
@PostMapping("/users")
public String createUser(@Valid @RequestBody UserDTO userDTO) {
// 如果参数校验失败,Spring会自动返回400错误
return "User created successfully!";
}
@PostMapping("/email-check")
public String checkEmail(@ValidEmail @RequestBody String email) {
return "Email is valid!";
}
}
全局异常处理
在参数校验失败时,Spring Boot默认会返回400状态码以及详细的错误信息。如果需要定制错误返回信息,可以通过全局异常处理机制实现,如下所示。
package com.example.exception;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import javax.validation.ConstraintViolationException;
import java.util.HashMap;
import java.util.Map;
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ResponseEntity<Map<String, String>> handleValidationExceptions(MethodArgumentNotValidException ex) {
Map<String, String> errors = new HashMap<>();
ex.getBindingResult().getFieldErrors().forEach(error ->
errors.put(error.getField(), error.getDefaultMessage())
);
return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(ConstraintViolationException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ResponseEntity<String> handleConstraintViolationException(ConstraintViolationException ex) {
return new ResponseEntity<>(ex.getMessage(), HttpStatus.BAD_REQUEST);
}
}
总结
通过上述步骤,我们就可以在Spring Boot中轻松实现自定义的接口参数校验。