2

我想验证一个名为Person. 我可以写这样的东西:

class Person {
  ...
  public boolean isValid() {
    return (name != null && age > 0);
  }
}

但是,在我的表示层中,我想向用户展示验证失败的具体原因。

我提出的解决方案是:

  1. 抛出isValid()特定于错误的异常
  2. 使isValid()返回PersonValidationError枚举而不是布尔值
  3. 在表示层复制验证逻辑

我想知道处理这种情况的最佳方法是什么。另外,Java 标准库是如何处理这种情况的呢?

4

4 回答 4

2

不知道你用的是什么。我习惯了 Spring MVC 项目。在这些情况下,您可以使用 JSR-303 验证器,它将用对象上的所有错误填充 ObjectErros 对象。

如果您使用的是 spring,请尝试寻找 SmartValidator。注入后,您可以执行以下操作:

BeanPropertyErrors br = new BeanPropertyErros();
validator.validate(object,br);

如果您不使用 Spring,请尝试查找 JSR-303 实现。

有了它,您可以在要验证的类的字段上使用@NotEmpty、@NotNull、@Min、@Length。

于 2013-10-10T01:02:42.163 回答
2

在提出我的解决方案之前有几点:

  1. 异常应该用于或多或少的异常情况。根据您的说法,用户提交错误数据的情况并不少见。

  2. 当您的Person班级增长时,您将添加越来越多必须满足的条件才能使其有效。

  3. 除了例外情况,您一次只能显示一个错误,如果提交的数据有多个错误怎么办?

  4. 将验证方法放入您的Person班级似乎不正确。例如,如果您想在应用程序的不同位置使用不同的验证策略怎么办?

所以,我会让你的 Person 类没有验证逻辑:

class Person {

    final String name;
    final int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

然后实现一些需要一个人并对其进行验证的类。这个想法是有不同的验证器,每个验证器都有自己的验证规则和自己的验证消息。enum很高兴实现这一目标:

enum Validator {

    NOT_NULL_NAME("Name must not be null") {
        @Override
        public boolean validate(Person person) {
            return person.name != null;
        }
    },
    AGE_GREATER_THAN_ZERO("Age must be greater than zero") {
        @Override
        public boolean validate(Person person) {
            return person.age > 0;
        }
    };

    final String errorMessage;

    private Validator(String errorMessage) {
        this.errorMessage = errorMessage;
    }

    public abstract boolean validate(Person person);
}

看看用不同的消息添加一些新条件有多容易?只是另一个枚举实例。

现在创建一个用于验证人员的类。它只是遍历所有验证器并收集错误消息。

class PersonValidator {

    private final List<String> errors = new ArrayList<String>();

    public PersonValidator(Person person) {
        for (Validator validator : Validator.values()) {
            if (!validator.validate(person)) {
                errors.add(validator.errorMessage);
            }
        }
    }

    public boolean isValid() {
        return errors.isEmpty();
    }

    public Collection<String> getErrors() {
        return errors;
    }
}

如何使用它的示例:

public static void main(String... args) {
    Person[] people = { new Person(null, 0), 
                         new Person(null, 42), 
                         new Person("Joe", 0), 
                         new Person("Joe", 42) };
    for (int i = 0; i < people.length; i++) {
        PersonValidator validator = new PersonValidator(people[i]);
        System.out.println(String.format("Person no %s is %s valid. %s", 
              i, 
              validator.isValid() ? "" : "not", 
              Joiner.on(", ").join(validator.getErrors())));

    }
}

以上打印:

Person no 0 is not valid. Name must not be null, Age must be greater than zero
Person no 1 is not valid. Name must not be null
Person no 2 is not valid. Age must be greater than zero
Person no 3 is  valid. 

很整洁吧?

于 2013-10-17T12:58:41.770 回答
1
  1. 从 bool 函数抛出异常不是一个好方法
  2. 如果 name 为 null 并且 age 为 <0,它会返回什么?
  3. 有时可能是一个解决方案,但在这种情况下不是

我提出类似的建议:

class Person {
...
private boolean isValidated = false;
private ArrayList<String> validationErrors = new ArrayList<String>();
private void validate()
{
    validationErrors.clear();
    if (name == null)
        validationErrors.add("Incorrect name");
    if (age < 0)
        validationErrors.add("Incorrect age");
    isValidated = true;
}
public boolean isValid()
{
    if (!isValidated)
        validate();
    return (validationErrors.size()==0);
}
public ArrayList<String> getValidationErors()
{
    if (!isValidated)
        validate();
    return validationErrors;
}
于 2013-10-09T23:09:22.727 回答
0

我现在已经确定了以下解决方案:

class Person {
  ...
  public void validate() throws ValidationException {
    if(name == null) {
      throw ValidationException("Name cannot be null");
    }

    if(age < 0) {
      throw ValidationException("Age cannot be less than 0");
    }
  }
}

然后在我的表示层中,我可以执行以下操作:

try {
  myPerson.validate();
} catch(ValidationException e) {
  errorMessage = "Invalid person: " + e.getMessage();
}
于 2013-10-10T22:43:15.807 回答