SpringBoot参数校验详解
前言
在web开发时,对于请求参数,一般上都需要进行参数合法性校验的,原先的写法时一个个字段一个个去判断,这种方式太不通用了,Hibernate Validator 是 Bean Validation 规范的参考实现,用于在 Java 应用中进行对象的校验。以下是如何在 Spring Boot 项目中安装和使用 Hibernate Validator 的详细步骤。
一、Hibernate Validator参数校验依赖的安装
SpringBoot 2.3以前版本
<!-- Spring Boot Starter Web 包含了 Spring MVC 和 Bean Validation 等常用依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>
Springboot从2.3以后,spring-boot-starter-web中不再引入hibernate-validator,需要手动引入。
<!-- Spring Boot Starter Web 包含了 Spring MVC 和 Bean Validation 等常用依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Hibernate Validator 是 Bean Validation 的默认实现 --><dependency><groupId>org.hibernate.validator</groupId><artifactId>hibernate-validator</artifactId></dependency>
二、SpringBoot参数校验异常返回结果类封装
在使用 Spring Boot 进行参数校验时,如果参数不符合要求,会抛出校验异常。为了更好地处理这些异常并返回统一的错误格式,可以通过以下方式进行封装:
1. 使用 @ControllerAdvice
全局异常处理
创建一个全局异常处理类,捕获 MethodArgumentNotValidException
和 ConstraintViolationException
,并将其转换为统一的响应格式。
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.FieldError;
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.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;@ControllerAdvice
public class GlobalExceptionHandler {// 处理 @Valid 校验异常@ExceptionHandler(MethodArgumentNotValidException.class)@ResponseStatus(HttpStatus.BAD_REQUEST)@ResponseBodypublic Map<String, Object> handleValidationException(MethodArgumentNotValidException ex) {Map<String, Object> errors = new HashMap<>();errors.put("status", HttpStatus.BAD_REQUEST.value());errors.put("message", "Validation failed");Map<String, String> fieldErrors = new HashMap<>();for (FieldError error : ex.getBindingResult().getFieldErrors()) {fieldErrors.put(error.getField(), error.getDefaultMessage());}errors.put("errors", fieldErrors);return errors;}// 处理 @Validated 校验异常@ExceptionHandler(ConstraintViolationException.class)@ResponseStatus(HttpStatus.BAD_REQUEST)@ResponseBodypublic Map<String, Object> handleConstraintViolationException(ConstraintViolationException ex) {Map<String, Object> errors = new HashMap<>();errors.put("status", HttpStatus.BAD_REQUEST.value());errors.put("message", "Validation failed");Map<String, String> fieldErrors = new HashMap<>();Set<ConstraintViolation<?>> violations = ex.getConstraintViolations();for (ConstraintViolation<?> violation : violations) {fieldErrors.put(violation.getPropertyPath().toString(), violation.getMessage());}errors.put("errors", fieldErrors);return errors;}
}
2. 自定义返回结果格式
在返回结果中包含自定义的状态码、错误信息和字段错误列表。
例如:
{"status": 400,"message": "Validation failed","errors": {"fieldName1": "Error message 1","fieldName2": "Error message 2"}
}
3. 参数校验示例
控制器中可以使用 @Valid
或 @Validated
注解进行参数校验:
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 ResponseEntity<String> createUser(@Valid @RequestBody UserRequest userRequest) {// 业务逻辑return ResponseEntity.ok("User created successfully");}
}
4. 校验注解
在请求对象中使用 JSR-303/JSR-380 提供的校验注解,例如 @NotNull
, @Size
, @Email
等。
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;public class UserRequest {@NotBlank(message = "Username is mandatory")@Size(min = 3, max = 20, message = "Username must be between 3 and 20 characters")private String username;@NotBlank(message = "Email is mandatory")@Email(message = "Email should be valid")private String email;// getters and setters
}
通过以上方法,可以将参数校验异常统一封装成一个标准格式的响应结果,便于前端处理。
三、@Valid 和 @Validated之间的区别
@Valid
和 @Validated
是 Spring 框架中用于进行参数验证的两个注解,尽管它们的作用相似,但在使用场景和功能上有一些区别:
1. @Valid
- 作用:
@Valid
是 JSR-303/JSR-380 标准中的注解,用于在 Bean Validation 中对对象进行校验。它可以用在方法参数、返回值、或者类字段上。 - 适用范围:
- 对单个对象进行校验。
- 当用在集合类(如
List
、Set
)或者数组时,它会对集合中的每个元素进行校验。
- 典型用法:
@PostMapping("/user") public ResponseEntity<String> createUser(@Valid @RequestBody User user) {// 如果 user 对象不符合校验规则,会抛出 MethodArgumentNotValidExceptionreturn ResponseEntity.ok("User created"); }
2. @Validated
- 作用:
@Validated
是 Spring 提供的一个注解,扩展了@Valid
的功能。除了能够进行标准的 Bean Validation 校验外,它还支持分组校验(Group Validation)。 - 适用范围:
- 可以用来对不同的校验场景使用不同的校验规则(通过分组)。
- 主要在 Spring 的
@Service
、@Controller
等类中用于方法级别的校验。
- 典型用法:
@PostMapping("/user") public ResponseEntity<String> createUser(@Validated(OnCreate.class) @RequestBody User user) {// 如果 user 对象不符合 OnCreate 分组的校验规则,会抛出 MethodArgumentNotValidExceptionreturn ResponseEntity.ok("User created"); }
主要区别:
-
标准 vs. 扩展:
@Valid
是标准的 Java Bean Validation 注解。@Validated
是 Spring 提供的扩展注解,支持更多功能。
-
分组校验:
@Valid
不支持分组校验,只能进行默认的校验。@Validated
支持分组校验,允许根据不同的操作或场景应用不同的校验逻辑。
-
使用场景:
- 如果只需要基本的校验,使用
@Valid
即可。 - 如果需要在不同的场景下应用不同的校验逻辑,使用
@Validated
并结合分组校验。
- 如果只需要基本的校验,使用
希望这些信息能帮你更好地理解这两个注解的区别。
四、常用的校验参数详解
结合 Hibernate Validator 实现。通过在实体类字段或方法参数上使用各种注解,可以轻松进行参数校验。
以下是 Spring Boot 中常用的参数校验注解及其用法详解:
1. 基本校验注解
-
@NotNull:字段不能为
null
,但可以为空字符串。@NotNull(message = "Name cannot be null") private String name;
-
@NotEmpty:字段不能为
null
,也不能为空字符串或空集合。@NotEmpty(message = "List cannot be empty") private List<String> items;
-
@NotBlank:字段不能为
null
,且去掉首尾空格后,必须至少有一个字符。常用于校验字符串。@NotBlank(message = "Email cannot be blank") private String email;
-
@Size:校验字符串、集合、数组的大小或长度。
@Size(min = 2, max = 30, message = "Name must be between 2 and 30 characters") private String name;
-
@Min 和 @Max:校验数值型字段的最小值和最大值。
@Min(value = 18, message = "Age must be at least 18") @Max(value = 60, message = "Age must be less than 60") private int age;
-
@Email:校验是否为合法的电子邮件格式。
@Email(message = "Email should be valid") private String email;
-
@Pattern:使用正则表达式校验字符串的格式。
@Pattern(regexp = "^\\d{10}$", message = "Phone number must be 10 digits") private String phoneNumber;
-
@Past 和 @Future:校验日期字段是否在过去或未来。
@Past(message = "Birthday must be in the past") private LocalDate birthday;@Future(message = "Appointment date must be in the future") private LocalDate appointmentDate;
-
@AssertTrue 和 @AssertFalse:校验布尔类型字段是否为
true
或false
。@AssertTrue(message = "Must agree to terms") private boolean agreedToTerms;
2. 组合注解
可以组合多个注解来实现复杂的校验规则。例如,校验一个字段既不为空,又必须符合特定格式:
@NotBlank(message = "Username cannot be blank")
@Pattern(regexp = "^[a-zA-Z0-9]{3,}$", message = "Username must be alphanumeric and at least 3 characters long")
private String username;
3. 分组校验(@Validated)
分组校验可以根据不同场景应用不同的校验规则。需要结合 @Validated
注解来实现。
-
定义分组接口:
public interface CreateGroup {} public interface UpdateGroup {}
-
在实体类中应用分组:
@NotNull(groups = UpdateGroup.class, message = "Id cannot be null when updating") private Long id;@NotBlank(groups = CreateGroup.class, message = "Name cannot be blank when creating") private String name;
-
在 Controller 方法中指定分组:
@PostMapping("/create") public ResponseEntity<String> createUser(@Validated(CreateGroup.class) @RequestBody User user) {// 校验仅针对 CreateGroup 分组return ResponseEntity.ok("User created"); }@PutMapping("/update") public ResponseEntity<String> updateUser(@Validated(UpdateGroup.class) @RequestBody User user) {// 校验仅针对 UpdateGroup 分组return ResponseEntity.ok("User updated"); }
4. 自定义校验注解
如果内置的校验注解不能满足需求,可以创建自定义校验注解。
-
创建注解:
@Target({ElementType.FIELD, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Constraint(validatedBy = MyCustomValidator.class) public @interface MyCustomValidation {String message() default "Invalid value";Class<?>[] groups() default {};Class<? extends Payload>[] payload() default {}; }
-
实现校验逻辑:
public class MyCustomValidator implements ConstraintValidator<MyCustomValidation, String> {@Overridepublic boolean isValid(String value, ConstraintValidatorContext context) {// 校验逻辑,例如:字符串必须包含 "valid"return value != null && value.contains("valid");} }
-
使用自定义注解:
@MyCustomValidation(message = "The value must contain 'valid'") private String customField;
通过这些校验注解和机制,可以在 Spring Boot 中高效地处理参数校验逻辑,确保应用的输入数据符合预期。
通过以上就可以正常使用注解在SpringBoot中完成参数校验功能了!感谢大家的收看 如果感觉有帮助请留下小星星