在GWT中使用JSR-303进行内联验证,第2部分:一个很好的实现?

时间:2014-11-25 16:06:51

标签: validation gwt

这个问题来自我之前的Inline validation using JSR-303 in GWT, part 1: Validation on TextBox fails. Why?,其中我描述了首次尝试使用JSR-303进行内联验证的失败,并请求帮助理解它为什么不起作用。< / p>

我使用的主要文档是 GWT validation dev guideJSR-303 spec

我的第二次尝试将约束定义移动到界面中:

import javax.validation.constraints.Pattern;
public interface FooValidation {
    @Pattern(regexp="^[0-9]+$", message="Foo: expected digits.")
    public String getFoo();
}

MyValidatorFactory现在指定要验证FooValidation接口

@GwtValidation(FooValidation.class)
public interface GwtValidator extends Validator {
}

和我的TextBox实现了定义JSR-303约束的接口:

public class FooWidget extends TextBox implements FooValidation {
    public String getFoo() { 
        return getValue();  // from TextBox
    }
}

该字段使用UiBinder

放置在表单中
<my:FooWidget ui:field="foo"></my:FooWidget>

并以通常的方式包含在我的表单小部件中:

@UiField
FooWidget foo;

然后可以在布尔上检查约束,例如:

@UiHandler("foo")
void onBlur(BlurEvent ev) {
    // Need to cast (code smell?) to FooValidation, 
    // because that is the class set up for validations
    Set<ConstraintViolation<FooValidation>> violations =
                              validator.validate((FooValidation)foo);
    for (ConstraintViolation<FooValidation> violation : violations) {
        // TODO - report violation.getMessage() to user
    }
}

现在,这似乎有效(基于昨天非常有限的烟雾测试!)。 但这种方法感觉有点费力。 我已经介绍了两件新的&#39;文物&#39; (FooWidgetFooValidation)只是为验证机制提供服务, 这与Occam's Razor的剪辑相反! 我错过了一些更简单的东西吗? 在我继续使用这种模式实现大量验证之前,我非常有兴趣了解任何陷阱, 以及其他人使用JSR-303在GWT中进行内联验证的经验。

我希望我可以改进上面的方法,并梳理出一些通用的抽象, 但是,在继续沿着这条路走下去之前,知道我是否错过了一些东西会很好。

1 个答案:

答案 0 :(得分:0)

由于这个问题仍然没有答案,我发布的答案反映了我们的决定。

@Thomas Broyer指出here“GWT-Validation几乎没有维护”。因此,我们决定发展自己的想法,借用这样的想法:当验证器执行验证时,它会返回一组违规,但也会在触发验证器时添加控制权。

以下是使用我们自己开发的验证框架的代码示例。我们有一个表单,用户可以在其中指定出站和入境旅程的日期和时间。我们希望将出站时间限制在过去最多15分钟,并且在入站时间之前(实际上,这只是略微过度简化,但希望足以理解此示例背后的要求)。

// Check that we're not returning from our destination before we get there.
// Create a Validator that can get DateTime from two widgets 
// (both implement HasValue<DateTime>) so that it may compare 
// two DateTime values:
JourneyDateTimeValidator journeyDateTimeValidator 
    = new JourneyDateTimeValidator(outboundDateTime, inboundDateTime);

//  Add a constraint with an error message for when it is violated:
journeyDateTimeValidator.addConstraint(
        new JourneyDateTimeValidator.Constraint(
            MESSAGES.mustNotLeaveBeforeArriving()));

// Create a Validator to check that a DateTime is not in the past:
ValueValidator<DateTime> outboundValidator 
    = new ValueValidator<DateTime>(outboundDateTime);

// outboundDateTime must be no more than 15 mins in the past.
final int N = 15;

// Add a constrint to the validator, 
// to check the DateTime value is no more than N minutes in the past.
// The NotInThePastConstraint is an example of a special-purpose constraint,
// but, of course there are many general-purpose ones.  We can add many
// Constraints to the same Validator.  This is similar specification
// of a list of Constraints in JSR-303.
outboundValidator.addConstraint(new NotInThePastConstraint(N*60*1000, // ms
            MESSAGES.mustNotBeInThePast()));

// outboundValidityIndicator is a GWT Label that can display 
// a Tick, or a Cross with an error message, or nothing.
// We set up Triggers, each of which can have a list of Validators 
// to be run when the Trigger fires. 
// The ValidityIndicator refreshes its display 
// based on the list of Violations returned by the Validators.

outboundValidityIndicator.getTriggers().onValueChange(outboundDateTime)
    .addValidator(outboundValidator)
    .addValidator(journeyDateTimeValidator);

// We also want the same Validators triggered when inboundDateTime changes:
outboundValidityIndicator.getTriggers().onValueChange(inboundDateTime)
    .addValidator(outboundValidator)
    .addValidator(journeyDateTimeValidator);

// We keep a list of all ValidatityIndicators in our form, 
// so we can get them all to refresh at once
// (we may do this, for example, onMouseOver of the form's submit button):
formValidatorList.add(outboundValidityIndicator);