虽然 Spring Boot 的内置验证注释很有用,但它们可能无法涵盖所有情况。如果有特殊参数验证的场景,可以使用 Spring 的 JSR 303 验证框架创建自定义验证注释。自定义注解可以让你的的验证逻辑更具可重用性和可维护性。
假设我们有一个应用程序,用户可以在其中创建帖子。每个帖子都应该有一个标题和一个正文,并且标题在所有帖子中应该是唯一的。虽然 Spring Boot 提供了用于检查字段是否为空的内置验证注释,但它没有提供用于检查唯一性的内置验证注释。在这种情况下,我们可以创建一个自定义验证注解来处理这种情况。
首先,我们创建自定义约束注解
UniqueTitle
:
@Target({ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @Constraint(validatedBy = UniqueTitleValidator.class) public @interfaceUniqueTitle{ String message()default "Title must be unique";
Class>[] groups() default {};
Class extends Payload>[] payload() default {}; }
接下来,我们创建一个
PostRepository
接口,目的是从数据库中检索帖子:
publicinterfacePostRepositoryextendsJpaRepository<Post, Long> { Post findByTitle(String title); }
@PostMapping public ResponseEntitycreateUser(@Valid @RequestBody User user, BindingResult result){ if (result.hasErrors()) { List errorMessages = result.getAllErrors().stream() .map(DefaultMessageSourceResolvable::getDefaultMessage) .collect(Collectors.toList()); return ResponseEntity.badRequest().body(errorMessages.toString()); }
// save the user to the database using UserService userService.saveUser(user);
return ResponseEntity.status(HttpStatus.CREATED).body("User created successfully"); } }
我们使用
@Valid
注释来触发
User
对象的验证,并使用
BindingResult
对象来捕获任何验证错误。
5 将 i18n 用于错误消息
如果你的应用程序支持多种语言,则必须使用国际化 (i18n) 以用户首选语言显示错误消息。
以下是在 Spring Boot 应用程序中使用 i18n 处理错误消息的示例
首先,在资源目录下创建一个包含默认错误消息的
messages.properties
文件
# messages.properties user.name.required=Name is required. user.email.invalid=Invalid email format. user.age.invalid=Age must be a number between 18 and 99.
// getters and setters omitted for brevity publicinterfaceEmailNotEmpty{} publicinterfaceDefault{} }
请注意,我们在
User
类中定义了两个接口,
EmailNotEmpty
和
Default
。这些将作为我们的验证组。
接下来,我们更新
Controller
使用这些验证组
@RestController @RequestMapping("/users") @Validated publicclassUserController{ public ResponseEntitycreateUser( @Validated({org.example.model.ex6.User.EmailNotEmpty.class}) @RequestBody User userWithEmail, @Validated({User.Default.class}) @RequestBody User userWithoutEmail) { // Create the user and return a success response
} }
我们已将
@Validated
注释添加到我们的控制器,表明我们想要使用验证组。我们还更新了
createUser
方法,将两个
User
对象作为输入,一个在
email
字段不为空时使用,另一个在它为空时使用。
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Constraint(validatedBy = EndDateAfterStartDateValidator.class) public @interfaceEndDateAfterStartDate{ String message()default "End date must be after start date"; Class>[] groups() default {}; Class extends Payload>[] payload() default {}; }