本文目录导读:

在Java中实现数据校验有多种方式,下面我从简单到复杂,整理几个最实用的实现方案。
手动校验(最基本方式)
最直接的方式,适合简单场景或学习理解。
public class User {
private String name;
private int age;
private String email;
// 手动校验方法
public String validate() {
if (name == null || name.trim().isEmpty()) {
return "用户名不能为空";
}
if (name.length() > 50) {
return "用户名长度不能超过50";
}
if (age < 0 || age > 150) {
return "年龄必须在0-150之间";
}
if (email != null && !email.contains("@")) {
return "邮箱格式不正确";
}
return null; // null表示校验通过
}
}
使用Jakarta Bean Validation(JSR 380)
这是Java官方标准的校验框架,最推荐的方式。
添加依赖(Maven)
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>8.0.1.Final</version>
</dependency>
定义校验规则
import jakarta.validation.constraints.*;
import jakarta.validation.constraints.Email;
public class User {
@NotBlank(message = "用户名不能为空")
@Size(min = 2, max = 50, message = "用户名长度在2-50之间")
private String name;
@NotNull(message = "年龄不能为空")
@Min(value = 0, message = "年龄不能小于0")
@Max(value = 150, message = "年龄不能大于150")
private Integer age;
@NotBlank(message = "邮箱不能为空")
@Email(message = "邮箱格式不正确")
private String email;
@Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确")
private String phone;
}
执行校验
import jakarta.validation.Validation;
import jakarta.validation.Validator;
import jakarta.validation.ValidatorFactory;
import java.util.Set;
import jakarta.validation.ConstraintViolation;
public class ValidationDemo {
public static void main(String[] args) {
// 创建校验器
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
// 创建测试对象
User user = new User();
user.setName("张"); // 太短了
user.setAge(200); // 太大了
user.setEmail("abc"); // 不是邮箱
// 执行校验
Set<ConstraintViolation<User>> violations = validator.validate(user);
// 输出错误信息
for (ConstraintViolation<User> violation : violations) {
System.out.println(violation.getMessage());
}
}
}
Spring Boot中的集成校验
如果在Spring Boot项目中使用,可以更加方便。
在Controller中使用
import jakarta.validation.Valid;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/users")
public class UserController {
@PostMapping
public Result addUser(@Valid @RequestBody User user) {
// 如果校验失败,会自动抛出MethodArgumentNotValidException
// 不会执行到这里
return Result.success("添加成功");
}
}
全局异常处理
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 Result handleValidationException(MethodArgumentNotValidException ex) {
// 获取第一个错误信息
String message = ex.getBindingResult()
.getAllErrors()
.get(0)
.getDefaultMessage();
return Result.error(message);
}
}
分组校验
有时同一个对象在不同的场景下需要不同的校验规则。
// 定义分组接口
public interface CreateGroup {}
public interface UpdateGroup {}
public class User {
@NotBlank(message = "ID不能为空", groups = UpdateGroup.class)
private String id;
@NotBlank(message = "用户名不能为空", groups = {CreateGroup.class, UpdateGroup.class})
private String name;
@NotNull(message = "年龄不能为空", groups = CreateGroup.class)
private Integer age;
}
// 使用分组校验
@PostMapping
public Result createUser(@Validated(CreateGroup.class) @RequestBody User user) {
// ...
}
@PutMapping
public Result updateUser(@Validated(UpdateGroup.class) @RequestBody User user) {
// ...
}
自定义校验注解
当内置注解不能满足需求时,可以创建自己的校验注解。
定义注解
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
import java.lang.annotation.*;
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = PhoneValidator.class)
public @interface Phone {
String message() default "手机号格式不正确";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
实现校验器
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
public class PhoneValidator implements ConstraintValidator<Phone, String> {
@Override
public boolean isValid(String phone, ConstraintValidatorContext context) {
if (phone == null) {
return true; // 允许为空,由@NotNull控制
}
return phone.matches("^1[3-9]\\d{9}$");
}
}
使用自定义注解
public class User {
@Phone(message = "请输入正确的手机号")
private String phone;
}
实用最佳实践
结合Service层校验
@Service
public class UserService {
@Autowired
private Validator validator;
public User createUser(User user) {
// 手动触发校验
Set<ConstraintViolation<User>> violations = validator.validate(user);
if (!violations.isEmpty()) {
String message = violations.iterator().next().getMessage();
throw new ValidationException(message);
}
// 业务处理...
return userRepository.save(user);
}
}
链式校验工具类
public class ValidationUtils {
private static Validator validator;
static {
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
validator = factory.getValidator();
}
public static <T> void validate(T obj) {
Set<ConstraintViolation<T>> violations = validator.validate(obj);
if (!violations.isEmpty()) {
StringBuilder sb = new StringBuilder();
for (ConstraintViolation<T> violation : violations) {
sb.append(violation.getMessage()).append("; ");
}
throw new IllegalArgumentException(sb.toString());
}
}
}
总结与建议
- 小型项目:手动校验够用,但难以维护
- 中型项目:推荐使用Bean Validation注解,清晰明确
- 大型项目:结合分组校验、自定义注解,配合全局异常处理
- Spring项目:利用@Valid + 全局异常处理,开发效率最高
选择哪种方式取决于你的项目规模和团队习惯,对于新项目,建议直接使用Spring Boot + Bean Validation这套组合,既规范又高效。