验证输入的设计模式?

时间:2010-09-13 23:46:00

标签: java design-patterns validation

验证输入的最佳方法是什么?为了论证,如果输入无效,用户想要一条消息来解释原因。

这是我能想到的。

  • Validator方法:将输入传递给验证器,如果输入有效,则返回true。否则,验证器返回false(或错误代码)并让调用者处理无效输入。或者验证者负责自己采取行动。或者验证器调用回调方法。 缺点:调用实际方法时,可能会重复验证所采取的步骤。

  • 将输入直接传递给方法,无需验证。让方法自己处理无效消息。它可以直接向用户发送错误消息,也可以使用回调方法。发送消息后,该方法必须返回或抛出异常以停止处理无效输入。调用类将继续到下一行输入。 缺点:此方法现在具有发送错误消息的副作用。

这里适当的策略是什么?请注意,我不认为抛出异常是合适的,因为处理无效输入是应用程序的核心功能,至少在我的情况下

6 个答案:

答案 0 :(得分:2)

看一下Spring的数据绑定和验证框架。非常好,并且可以单独使用或作为UI的一部分使用。

答案 1 :(得分:1)

一个很好的对象验证解决方案,无需创建许多实现“验证器”接口的类或使用不可重用的匿名内部类的负担,就是使用枚举的常量功能:

例如:

public enum ObjectValidation {

BAD_DATE_FORMAT(ErrorCode.BAD_DATE_FORMAT) {

    @Override
    boolean validate(String value, List<String> acceptableValues) {
        boolean isValid = false;
        // validate the date
        SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
        try {
            sdf.parse(value);
            isValid = true;
        } catch (ParseException ex) {

        }

        /*
         * We could use acceptableValues to validate the value against a
         * list of acceptable values
         */

        return isValid;
    }

};

private ErrorCode errorCode;

private ObjectValidation(ErrorCode ErrorCode) {
    this.errorCode = ErrorCode;
}

public ErrorCode getErrorCode() {
    return errorCode;
}

abstract boolean validate(String value, List<String> acceptableValues);

}

利用枚举提供的常量验证功能的服务方法可用于同一字段的多次验证:

public static List<ErrorCode> validate(String value, Set<ObjectValidation> objectValidators) throws Exception{
        List<ErrorCode> errorCodeList = new ArrayList<ErrorCode>();         
        for (ObjectValidation objectValidation : objectValidators) {
            if(!objectValidation.validate(value, Collections.emptyList())){
                errorCodeList.add(objectValidation.getErrorCode());
            }
        }               
    return errorCodeList;       
}

答案 2 :(得分:0)

也许看看Command Pattern并将验证逻辑放在调用者类中。

答案 3 :(得分:0)

你不应该直接将输入传递给方法(我想通过“方法”,你的意思是一些业务逻辑),因为它将视图和模型结合起来。你应该做的是制作一个带有验证方法的控制器或一个单独的验证类,它将接受输入并使用一些“外部”方法对其进行验证。然后,根据结果,控制器/验证器可以返回验证错误或将输入转发到您想要的任何位置。正如我之前所说,最大的好处是模型和视图的分离。模型不应该对视图有任何了解(如果你想改变视图怎么办?你必须重写你的模型!)。我不确定你为什么要在商业模式中复制验证码?验证和导航应该是控制器的功能。至少这就是MVC模式的作用方式。
同样抛出异常并不是那么糟糕,但它们应该被抛入模型并被控制器捕获。例如,您有一个系统,您希望用户具有唯一的登录,用户输入已存在于DB中的登录,控制器调用验证方法,该方法尝试(使用模型)将其插入DB。如果一切顺利,则插入并且控制器可以返回“您成功插入值”消息。但是如果模型抛出异常(如Unique Constraint Violation错误或其他),那么控制器应该只是捕获它并返回“此登录已存在于DB中”。这样,模型对视图一无所知,并且可以重复使用,并且没有代码重复。

答案 4 :(得分:0)

public interface Validator {
    /**
     * Validates a JComponent</code>.
     * @param component
     *       The component to validate.
     * @param message
     *       The message to display if the validation fails.
     * @return
     *       Returns <code>false</code> if the validation fails, and
     *       <code>true</code> otherwise.
     */
    boolean validate(JComponent component, String message);
}

您可以使用一个AbstractValidator(Extends javax.swing.InputVerifier)类来处理带有无效条目的JComponent旁边的消息显示。看看this示例

答案 5 :(得分:0)

现在我正在使用Hibernate验证器框架,非常简单且有用:

我用我需要的东西注释类,然后使用它:

我的实体类:

public class Content {

@NotNull
private Heading heading;

@NotNull
@Length(max = 8)
private String contentType;

    // Everything else

}

我的验证码组件:

@Component
public class Validator implements IValidator {
    protected static Log log = LogFactory.getLog(Validator.class);

    javax.validation.Validator validator;

    @Autowired 
    WebApplicationExceptionBuilder webApplicationExceptionBuilder;

    public void validate (Object entity) throws WebApplicationException {
        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        validator = factory.getValidator();
        Set<ConstraintViolation<Object>> violations = validator.validate(entity);
        if (!violations.isEmpty()) {
            webApplicationExceptionBuilder
                        .raise("some fields are missing or incorrect", 
                            violations);
        }
    }

}

在哪里使用它:

public class Foo{

    @Autowired
    private IValidator validator;

    @Autowired
    private IContentService contentService;

    public void bar(Content c) throws Exception{
        validator.validate(c);
        contentService.persist(content);
    }

}