在Java开发中,类的属性输入校验与自动修正是保障数据合法性的重要环节,合理的实现方式可以减少业务层的重复校验代码,降低数据异常风险。

手动校验与修正实现
最基础的方式是在属性的setter方法中嵌入校验和修正逻辑,这种方式简单直接,适合属性较少、校验规则简单的场景。
下面以用户类为例,对年龄和用户名属性做校验和修正:
public class User {
private String username;
private int age;
public String getUsername() {
return username;
}
public void setUsername(String username) {
// 校验:用户名不能为空,为空时自动修正为默认游客名
if (username == null || username.trim().isEmpty()) {
this.username = "默认游客";
} else {
// 修正:去除用户名前后空格
this.username = username.trim();
}
}
public int getAge() {
return age;
}
public void setAge(int age) {
// 校验:年龄不能小于0,大于120,超出范围时自动修正为合法值
if (age < 0) {
this.age = 0;
} else if (age > 120) {
this.age = 120;
} else {
this.age = age;
}
}
}
结合Bean Validation实现校验
当校验规则较多时,手动编写setter逻辑会显得冗余,我们可以结合Bean Validation规范,使用注解标注校验规则,再通过校验工具触发校验。
首先需要在项目中引入Bean Validation的依赖,以Maven为例:
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
<version>3.0.2</version>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>8.0.0.Final</version>
</dependency>
然后在类的属性上添加校验注解,同时保留setter中的修正逻辑:
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
public class User {
@NotBlank(message = "用户名不能为空")
private String username;
@Min(value = 0, message = "年龄不能小于0")
@Max(value = 120, message = "年龄不能大于120")
private int age;
public String getUsername() {
return username;
}
public void setUsername(String username) {
// 修正逻辑:去除前后空格
if (username != null) {
this.username = username.trim();
} else {
this.username = null;
}
}
public int getAge() {
return age;
}
public void setAge(int age) {
// 修正逻辑:超出范围自动修正
if (age < 0) {
this.age = 0;
} else if (age > 120) {
this.age = 120;
} else {
this.age = age;
}
}
}
校验时可以通过Validator实例触发:
import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validation;
import jakarta.validation.Validator;
import jakarta.validation.ValidatorFactory;
import java.util.Set;
public class Test {
public static void main(String[] args) {
User user = new User();
user.setUsername(" testUser ");
user.setAge(150);
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
Set<ConstraintViolation<User>> violations = validator.validate(user);
if (!violations.isEmpty()) {
for (ConstraintViolation<User> violation : violations) {
System.out.println(violation.getMessage());
}
}
System.out.println("修正后用户名:" + user.getUsername());
System.out.println("修正后年龄:" + user.getAge());
}
}
自定义校验器实现复杂规则
如果遇到Bean Validation内置注解无法满足的复杂校验规则,我们可以自定义校验注解和校验器,同时结合修正逻辑。
例如我们需要校验手机号格式,并且自动去除手机号中的空格和横线:
首先定义自定义注解:
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
import java.lang.annotation.*;
@Documented
@Constraint(validatedBy = PhoneValidator.class)
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidPhone {
String message() default "手机号格式不正确";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
然后实现对应的校验器:
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import java.util.regex.Pattern;
public class PhoneValidator implements ConstraintValidator<ValidPhone, String> {
private static final Pattern PHONE_PATTERN = Pattern.compile("^1[3-9]\d{9}$");
@Override
public void initialize(ValidPhone constraintAnnotation) {
}
@Override
public boolean isValid(String phone, ConstraintValidatorContext context) {
if (phone == null) {
return false;
}
// 先去除空格和横线再校验
String cleanedPhone = phone.replaceAll("[\s-]", "");
return PHONE_PATTERN.matcher(cleanedPhone).matches();
}
}
在类中使用该注解并添加修正逻辑:
import jakarta.validation.constraints.NotBlank;
public class User {
@NotBlank(message = "手机号不能为空")
@ValidPhone
private String phone;
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
// 自动修正:去除手机号中的空格和横线
if (phone != null) {
this.phone = phone.replaceAll("[\s-]", "");
} else {
this.phone = null;
}
}
}
不同实现方式对比
我们可以通过下表对比几种实现方式的特点,选择适合自己场景的方案:
| 实现方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 手动校验修正 | 无额外依赖,逻辑直观 | 重复代码多,规则复杂时维护成本高 | 属性少、规则简单的类 |
| Bean Validation注解 | 规则声明清晰,减少重复代码 | 需要引入额外依赖,复杂规则需要扩展 | 规则较多、符合标准校验场景的类 |
| 自定义校验器 | 支持复杂自定义规则,扩展性强 | 需要额外编写注解和校验器代码 | 有特殊校验需求的场景 |
注意事项
- 修正逻辑不要改变数据的原始语义,比如年龄修正为0是合理的边界处理,但不要将负数年龄修正为随机正数
- 如果类会被序列化或反序列化,要确保setter中的校验修正逻辑会被正确触发
- 校验和修正的异常信息要做好记录,方便后续排查数据问题
Java属性校验自动修正Bean_Validation修改时间:2026-07-21 17:30:40