Validator自定义注解
原视频:
项目结构建议
src/
├── main/
│ ├── java/
│ │ └── com.example.demo/
│ │ ├── DemoApplication.java // Spring Boot 主类
│ │ ├── annotation/
│ │ │ └── Phone.java // 自定义注解
│ │ ├── validator/
│ │ │ └── PhoneValidator.java // 校验器
│ │ ├── controller/
│ │ │ └── UserController.java // 接口控制器
│ │ └── handler/
│ │ └── GlobalExceptionHandler.java // 异常处理器
│ └── resources/
│ └── application.yml // 配置(可选)
pom.xml // Maven 配置文件
1. pom.xml (Maven 依赖)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for custom validation</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.0</version> <!-- 根据需要调整版本 -->
<relativePath/>
</parent>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
- 下载方式:复制到本地文件名为
pom.xml
,然后运行mvn clean install
构建项目。
2. Phone.java
(自定义注解,路径:src/main/java/com/example/demo/annotation/Phone.java)
package com.example.demo.annotation;
import com.example.demo.validator.PhoneValidator;
import jakarta.validation.Constraint;
import jakarta.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 = PhoneValidator.class)
public @interface Phone {
String message() default "无效的手机号码格式";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
- 注意:使用
jakarta.validation
(Spring Boot 3+ 默认),如果使用旧版可替换为javax.validation
。
3. PhoneValidator.java
(校验逻辑,路径:src/main/java/com/example/demo/validator/PhoneValidator.java)
package com.example.demo.validator;
import com.example.demo.annotation.Phone;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import java.util.regex.Pattern;
public class PhoneValidator implements ConstraintValidator<Phone, String> {
private static final Pattern PHONE_PATTERN = Pattern.compile("^1[3-9]\\d{9}$");
@Override
public boolean isValid(String phone, ConstraintValidatorContext context) {
if (phone == null) {
return false;
}
return PHONE_PATTERN.matcher(phone).matches();
}
}
4. UserController.java
(接口使用,路径:src/main/java/com/example/demo/controller/UserController.java)
package com.example.demo.controller;
import com.example.demo.annotation.Phone;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
@Validated
public class UserController {
@PostMapping("/user")
public String createUser(@Phone @RequestBody String phone) {
return "手机号码合法: " + phone;
}
}
- 注意:对于@RequestBody参数,校验需在DTO对象上使用注解。这里简化示例;实际中建议用DTO类包裹参数。
5. GlobalExceptionHandler.java
(错误处理,路径:src/main/java/com/example/demo/handler/GlobalExceptionHandler.java)
package com.example.demo.handler;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<String> handleValidationException(MethodArgumentNotValidException ex) {
String errorMessage = ex.getBindingResult().getFieldError().getDefaultMessage();
return new ResponseEntity<>(errorMessage, HttpStatus.BAD_REQUEST);
}
// 对于ConstraintViolationException(方法参数校验)的处理
@ExceptionHandler(jakarta.validation.ConstraintViolationException.class)
public ResponseEntity<String> handleConstraintViolation(jakarta.validation.ConstraintViolationException ex) {
String errorMessage = ex.getConstraintViolations().iterator().next().getMessage();
return new ResponseEntity<>(errorMessage, HttpStatus.BAD_REQUEST);
}
}
- 扩展:添加了对
ConstraintViolationException
的处理,以支持方法级校验。
6. DemoApplication.java
(Spring Boot 主类,路径:src/main/java/com/example/demo/DemoApplication.java)
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
7. application.yml
(可选配置,路径:src/main/resources/application.yml)
server:
port: 8080
spring:
application:
name: validation-demo
使用说明
-
创建项目:使用Spring Initializr(https://start.spring.io/)生成基础项目,或手动创建文件夹并粘贴代码。
-
运行测试:
- 启动应用:运行
DemoApplication.main()
。 - 测试接口:使用Postman发送POST请求到
http://localhost:8080/user
,body为raw text如"13812345678"(合法)或无效号码。 - 预期:合法返回成功消息,非法返回400错误和提示。
- 启动应用:运行
-
扩展建议:在实际项目中,将注解应用于DTO字段而非直接参数,以支持复杂对象校验。