3.9、参数校验
分类: 搭建单体商城服务
参数校验
参数校验是保证数据有效性的重要手段。Spring Boot 提供了 Bean Validation 支持,可以方便地实现参数校验。本节将学习如何实现参数校验。
本节将学习:@Valid 注解、@NotNull、@NotBlank、@Size、自定义校验器,以及校验错误处理。
@Valid 注解
@Valid 使用
@Valid 注解用于触发参数校验,通常与 @RequestBody 一起使用。
依赖添加
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency>
基本使用
@PostMapping("/users") public Result<User> createUser(@RequestBody @Valid User user) { User created = userService.register(user); return Result.success(created); }
常用校验注解
@NotNull、@NotBlank、@NotEmpty
package com.example.ecommerce.entity; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import lombok.Data; @Data public class User { @NotNull(message = "ID cannot be null") private Long id; @NotBlank(message = "Username cannot be blank") private String username; @NotBlank(message = "Email cannot be blank") private String email; @NotBlank(message = "Password cannot be blank") private String password; }
@Size
@NotBlank(message = "Username cannot be blank") @Size(min = 3, max = 20, message = "Username must be between 3 and 20 characters") private String username; @NotBlank(message = "Password cannot be blank") @Size(min = 8, max = 20, message = "Password must be between 8 and 20 characters") private String password;
@NotBlank(message = "Email cannot be blank") @Email(message = "Email format is invalid") private String email;
@Pattern
@NotBlank(message = "Phone cannot be blank") @Pattern(regexp = "^1[3-9]\\d{9}$", message = "Phone format is invalid") private String phone;
校验注解列表
自定义校验器
自定义注解
package com.example.ecommerce.validation; import jakarta.validation.Constraint; import jakarta.validation.Payload; import java.lang.annotation.*; @Target({ElementType.FIELD, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @Constraint(validatedBy = PhoneValidator.class) @Documented public @interface Phone { String message() default "Phone format is invalid"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }
校验器实现
package com.example.ecommerce.validation; import jakarta.validation.ConstraintValidator; import jakarta.validation.ConstraintValidatorContext; public class PhoneValidator implements ConstraintValidator<Phone, String> { private static final String PHONE_PATTERN = "^1[3-9]\\d{9}$"; @Override public void initialize(Phone constraintAnnotation) { // 初始化 } @Override public boolean isValid(String phone, ConstraintValidatorContext context) { if (phone == null || phone.isEmpty()) { return true; // 由 @NotBlank 处理空值 } return phone.matches(PHONE_PATTERN); } }
使用自定义校验器
@Data public class User { @NotBlank(message = "Phone cannot be blank") @Phone(message = "Phone format is invalid") private String phone; }
校验错误处理
校验流程
异常处理
@RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(MethodArgumentNotValidException.class) @ResponseStatus(HttpStatus.BAD_REQUEST) public Result<?> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) { String message = e.getBindingResult().getFieldErrors().stream() .map(FieldError::getDefaultMessage) .collect(Collectors.joining(", ")); return Result.error(ResultCode.BAD_REQUEST, message); } @ExceptionHandler(BindException.class) @ResponseStatus(HttpStatus.BAD_REQUEST) public Result<?> handleBindException(BindException e) { String message = e.getBindingResult().getFieldErrors().stream() .map(FieldError::getDefaultMessage) .collect(Collectors.joining(", ")); return Result.error(ResultCode.BAD_REQUEST, message); } }
完整校验示例
实体类校验
package com.example.ecommerce.entity; import com.example.ecommerce.validation.Phone; import jakarta.validation.constraints.Email; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Size; import lombok.Data; @Data public class User { @NotNull(message = "ID cannot be null") private Long id; @NotBlank(message = "Username cannot be blank") @Size(min = 3, max = 20, message = "Username must be between 3 and 20 characters") private String username; @NotBlank(message = "Email cannot be blank") @Email(message = "Email format is invalid") private String email; @NotBlank(message = "Phone cannot be blank") @Phone(message = "Phone format is invalid") private String phone; @NotBlank(message = "Password cannot be blank") @Size(min = 8, max = 20, message = "Password must be between 8 and 20 characters") private String password; }
Controller 使用
@RestController @RequestMapping("/api/users") public class UserController { @PostMapping public Result<User> createUser(@RequestBody @Valid User user) { User created = userService.register(user); return Result.success(created); } @PutMapping("/{id}") public Result<User> updateUser(@PathVariable Long id, @RequestBody @Valid User user) { user.setId(id); userService.updateById(user); return Result.success(user); } }
分组校验
校验分组
package com.example.ecommerce.validation; public interface CreateGroup {} public interface UpdateGroup {}
使用分组
@Data public class User { @NotNull(message = "ID cannot be null", groups = UpdateGroup.class) private Long id; @NotBlank(message = "Username cannot be blank", groups = {CreateGroup.class, UpdateGroup.class}) private String username; @NotBlank(message = "Password cannot be blank", groups = CreateGroup.class) private String password; }
Controller 使用分组
@PostMapping public Result<User> createUser(@RequestBody @Validated(CreateGroup.class) User user) { User created = userService.register(user); return Result.success(created); } @PutMapping("/{id}") public Result<User> updateUser(@PathVariable Long id, @RequestBody @Validated(UpdateGroup.class) User user) { user.setId(id); userService.updateById(user); return Result.success(user); }
官方资源
- Bean Validation 规范:https://beanvalidation.org/
- Jakarta Validation:https://jakarta.ee/specifications/bean-validation/
- Spring Validation:https://docs.spring.io/spring-framework/reference/core/validation.html
本节小结
在本节中,我们学习了:
第一个是 @Valid 注解。 使用 @Valid 触发参数校验。
第二个是常用校验注解。 @NotNull、@NotBlank、@Size、@Email、@Pattern 等。
第三个是自定义校验器。 创建自定义注解和校验器类。
第四个是校验错误处理。 使用全局异常处理器处理校验错误。
这就是参数校验。通过参数校验,我们可以确保请求参数的有效性,提高系统的健壮性。
在下一节,我们将学习如何实现用户模块,包括用户注册、登录等功能。