在GWT中使用JSR-303进行内联验证,第2部分:一个好的实现? [英] Inline validation using JSR-303 in GWT, part 2: A good implementation?

查看:152
本文介绍了在GWT中使用JSR-303进行内联验证,第2部分:一个好的实现?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个问题跟我以前的一样,使用GWT中的JSR-303进行内联验证,第1部分:对TextBox的验证失败。为什么?,我在其中描述了首次尝试使用JSR-303进行内联验证的尝试,并要求帮助理解它为什么不起作用。



我使用的主要文档是
GWT验证开发指南
JSR-303规范。第二次尝试将约束定义移动到一个接口中:

p>

  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 {
}

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

  public类FooWidget扩展TextBox实现FooValidation {
public String getFoo(){
return getValue(); // from TextBox
}
}

该字段放置在表单中使用 UiBinder

 < my:FooWidget ui:field = foo的>< /我的:FooWidget> 

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

  @UiField 
FooWidget foo;

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

  @UiHandler(foo)
void onBlur(BlurEvent ev){
//需要强制转换(代码气味?)到FooValidation,
//因为这是为验证设置的类
Set< ConstraintViolation< FooValidation>>违规=
validator.validate((FooValidation)foo);
for(ConstraintViolation< FooValidation>违规:违规){
// TODO - 向用户报告violation.getMessage()到用户
}
}

现在,这似乎起作用了(基于昨天非常有限的烟雾测试!)。
但是这种方法感觉有点费力。
我引入了两个新的artefacts( FooWidget FooValidation ),以便为验证机制提供服务,
违背了奥卡姆的剃刀
我是否缺少更简单的东西?
在我继续使用这种模式执行一系列验证之前,我会非常有兴趣了解任何陷阱,
和其他人使用JSR-303在GWT中进行内联验证的经验。



我期望我可以改进上述方法,并梳理出一些通用抽象,
,但是在继续沿着这条路走之前,我很高兴知道自己是否遗漏了某些东西。

仍然没有答案,我发布了一个答案,反映了我们决定要做的事。



据指出在这里通过@Thomas Broyer说:GWT验证几乎没有维护。所以,我们决定发展我们自己,借鉴这样一个想法,即当验证器执行验证时,它会返回一组违例,但也会在验证器被触发时添加控制权。

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

  //在我们到达目的地之前,检查我们是否从我们的目的地返回。 
//创建一个可以从两个小部件获取DateTime的Validator
//(都实现HasValue< DateTime>),以便它可以比较
//两个DateTime值:
JourneyDateTimeValidator journeyDateTimeValidator
= new JourneyDateTimeValidator(outboundDateTime,inboundDateTime);

//添加一个约束,并在错误消息被违反时给出:
journeyDateTimeValidator.addConstraint(
new JourneyDateTimeValidator.Constraint(
MESSAGES.mustNotLeaveBeforeArriving()) );

//创建一个验证器来检查DateTime是否过去:
ValueValidator< DateTime> outboundValidator
= new ValueValidator< DateTime>(outboundDateTime);

// outboundDateTime过去不得超过15分钟。
final int N = 15;

//向验证程序中添加一个constrint,
//检查DateTime值不超过N分钟。
// NotInThePastConstraint是一个特殊用途约束的例子,
//但是,当然有许多通用约束。我们可以将许多
// Constraints添加到同一个Validator中。这与JSR-303中约束列表的类似规范
//相似。
outboundValidator.addConstraint(new NotInThePastConstraint(N * 60 * 1000,// ms
MESSAGES.mustNotBeInThePast()));

// outboundValidityIndi​​cator是一个GWT标签,它可以显示
//一个Tick或带有错误信息的Cross,或者什么也不显示。
//我们设置了触发器,每个触发器都有一个Validator
//在触发器触发时运行。
// ValidityIndi​​cator根据验证器返回的违规列表刷新其显示
// //。

outboundValidityIndi​​cator.getTriggers()。onValueChange(outboundDateTime)
.addValidator(outboundValidator)
.addValidator(journeyDateTimeValidator);

//我们还希望在inboundDateTime更改时触发相同的Validator:
outboundValidityIndi​​cator.getTriggers()。onValueChange(inboundDateTime)
.addValidator(outboundValidator)
.addValidator (journeyDateTimeValidator);

//我们保存我们表单中所有ValidatityIndi​​cators的列表,
//所以我们可以让它们全部立即刷新
//(我们可以这样做,例如,表单的提交按钮的onMouseOver):
formValidatorList.add(outboundValidityIndi​​cator);


This question follows on from my earlier one, Inline validation using JSR-303 in GWT, part 1: Validation on TextBox fails. Why? in which I describe a failed first attempt to use JSR-303 for inline validation, and ask for help in understanding why it didn't work.

The main documentation I'm using is the GWT validation dev guide and JSR-303 spec.

My second attempt moves the constraint definitions into an interface:

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

MyValidatorFactory now specifies that the FooValidation interface is to be validated

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

and my TextBox implements the interface in which the JSR-303 constraints are defined:

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

The field is placed in the form using UiBinder:

<my:FooWidget ui:field="foo"></my:FooWidget>

and included in my form widget in the usual way:

@UiField
FooWidget foo;

The constraints can then be checked onBlur, for example:

@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
    }
}

Now, this seems to work (based on very limited smoke testing, yesterday!). But the approach feels a bit laboured. I've introduced two new 'artefacts' (FooWidget and FooValidation) just to service the validation mechanism, which goes against the cut of Occam's Razor! Am I missing something simpler? Before I go ahead and implement a load of validations using this pattern, I'd be very interested to learn of any pitfalls, and of other people's experience using JSR-303 for inline validation in GWT.

I expect I can refine the above approach, and tease out some general purpose abstractions, but it would be good to know if I've missed something before continuing along that path.

解决方案

As this question has remained unanswered, I'm posting an answer that reflects what we decided to do.

It was pointed out here by @Thomas Broyer that "GWT-Validation is almost unmaintained". So, we have decided to grow our own, borrowing the idea that when a validator performs validation, it returns a set of Violations, but also adding control over when validators are triggered.

Here's an example of code that uses our home-grown validation framework. We have a form in which the user specifies the date and time of outbound and inbound journeys. We want to constrain the outbound time to be at most 15 minutes in the past, and to be before the inbound time (actually, that's a slight over simplification, but it's hopefully enough to understand the requirements behind this example).

// 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);

这篇关于在GWT中使用JSR-303进行内联验证,第2部分:一个好的实现?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆