Java案例怎么实现数据校验?

wen java案例 72

本文目录导读:

Java案例怎么实现数据校验?

  1. 手动校验(最基本方式)
  2. 使用Jakarta Bean Validation(JSR 380)
  3. Spring Boot中的集成校验
  4. 分组校验
  5. 自定义校验注解
  6. 实用最佳实践
  7. 总结与建议

在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());
        }
    }
}

总结与建议

  1. 小型项目:手动校验够用,但难以维护
  2. 中型项目:推荐使用Bean Validation注解,清晰明确
  3. 大型项目:结合分组校验、自定义注解,配合全局异常处理
  4. Spring项目:利用@Valid + 全局异常处理,开发效率最高

选择哪种方式取决于你的项目规模和团队习惯,对于新项目,建议直接使用Spring Boot + Bean Validation这套组合,既规范又高效。

抱歉,评论功能暂时关闭!