如何在Spring Boot 项目中自定义 Validation 注解
目录
- 一、定义自定义注解
- 二、实现校验逻辑(ConstraintValidator)
- 三、应用自定义注解
- 1. 在DTO中使用
- 2. 在Controller中触发校验
- 四、处理校验异常(全局异常处理器)
- 五、扩展功能
- 1. 分组校验(如新增和更新场景)
- 2. 国际化错误消息
- 3. 复杂业务校验(如手机号唯一性)
- 六、验证效果
- 总结
在Spring Boot项目中自定义Validation注解,可按以下步骤实现,以手机号格式校验(支持多地区)为例:
一、定义自定义注解
import Javax.validation.Constraint; import javax.validation.Payload; import java.lang.annotation.*; @Target({ElementType.FIELD, ElementType.PARAMETER}) // 作用于字段和方法参数 @Retention(RetentionPolicy.RUNTIME) // 运行时生效 @Constraint(validatedBy = PhoneValidator.class) // 关联校验器 public @interface Phone { String message() default "手机号格式错误"; // 错误提示 Class<?>[] groups() default {}; // 分组校验(如新增、更新) Class<? extends Payload>[] payload() default {}; // 负载信息(可选) String region() default "CN"; // 自定义属性:地区(默认中国) }
二、实现校验逻辑(ConstraintValidator)
import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; public class PhoneValidator implements ConstraintValidator<Phone, String> { private String region; // 存储注解的region属性 @Override public void initialize(Phone constraintAnnotation) { this.region = constraintAnnotation.region(); // 初始化,获取地区配置 } @Override public boolean isValid(String value, ConstraintValidatorContext context) { if (value == null) return true; // 允许为空(若必填需额外处理,如@NotBlank配合使用) // 根据地区校验格式 switch (region) { case WRtCD"CN": // 中国手机号:11位,以1开头,第二位3-9 return value.matches("^1[3-9]\\d{9}$"); case "US": // 美国手机号:+1开头,后跟10位数字 return value.matches("^\\+1\\d{10}$"); default: return false; // 未知地区,校验失败 } } }
三、应用自定义注解
1. 在DTO中使用
public class UserDTO { @NotBlank private String username; @Phone(region = "CN") // 校验中国手机号 private String phone; // 若需校验美国手机号,可设置region="US" // @Phone(region = "US") // private String usPhone; // getters/setters }
2. 在Controller中触发校验
import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @RestController public class UserController { @PostMapping("/register") public String register(@Validated @RequestBody UserDTO dto) { // 校验通过,执行注册逻辑 return "注册成功"; } }
四、处理校验异常(全局异常处理器)
import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.validation.BindingResult; 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; @ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity<ErrorResponse> h编程客栈andleValidationError(MethodArgumentNotValidException ex) { BindingResult result = ex.getBindingResult(); StringBuilder errorMsg = new StringBuilder(); for (FieldError error : result.getFieldErrors()) { errorMsg.append(error.getField()).append(": ").appythonpend(error.getDefaultMessage()).append("; "); } return ResponseEntity .status(HttpStatus.BAD_REQUEST) javascript .body(new ErrorResponse(HttpStatus.BAD_REQUEST.value(), errorMsg.toString())); } static class ErrorResponse { private int code; private String message; public ErrorResponse(int code, String message) { this.code = code; this.message = message; } // getters } }
五、扩展功能
1. 分组校验(如新增和更新场景)
// 定义分组接口 public interface CreateGroup {} public interface UpdateGroup {} // 在DTO中指定分组 @Phone(region = "CN", groups = CreateGroup.class) // 新增时校验手机号 private String phone; // Controller中使用分组 @PostMapping("/create") public String create(@Validated(CreateGroup.class) @RequestBody UserDTO dto) { ... } @PutMapping("/update") public String update(@Validated(UpdateGroup.class) @RequestBody UserDTO dto) { ... }
2. 国际化错误消息
在src/main/resources
下创建ValidationMessages.properties
:
Phone.message=手机号格式错误(中文) Phone.message_en=Invalid phone number fphpormat(英文)
Spring Boot会根据Accept-Language
头自动匹配语言。
3. 复杂业务校验(如手机号唯一性)
// 校验器中注入Service(需将校验器标记为@Component,由Spring管理) @Component public class PhoneValidator implements ConstraintValidator<Phone, String> { @Autowired private UserService userService; // 假设UserService提供手机号唯一性查询 @Override public boolean isValid(String value, ConstraintValidatorContext context) { // 先校验格式,再校验唯一性 if (!isFormatValid(value)) return false; return !userService.existsByPhone(value); // 假设existsByPhone查询数据库 } private boolean isFormatValid(String value) { // 复用之前的格式校验逻辑 return value.matches("^1[3-9]\\d{9}$"); } }
六、验证效果
- 合法请求:
phone=13812345678
,校验通过,正常处理。 - 非法请求:
phone=123
(格式错误),返回:{ "code": 400, "message": "phone: 手机号格式错误; " }
总结
自定义Validation注解的关键步骤为:
- 定义注解:通过
@Constraint
关联校验器,设置属性(如地区、错误消息)。 - 实现校验逻辑:在
ConstraintValidator
中编写具体规则(格式、唯一性等)。 - 应用注解:在DTO/参数上标注,结合
@Validated
触发校验。 - 处理异常:通过全局异常处理器返回标准化错误,提升用户体验。
这种方式可灵活扩展Spring Boot的校验能力,满足复杂业务需求(如多地区格式、业务规则校验),确保输入数据的合法性,是微服务架构中参数校验的重要实践。
到此这篇关于聊一聊在 Spring Boot 项目中自定义 Validation 注解的文章就介绍到这了,更多相关Spring Boot 自定义 Validation 注解内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!
精彩评论