gpt4 book ai didi

validation - 寻找 GWT 验证示例...你在哪里?

转载 作者:行者123 更新时间:2023-12-04 02:23:39 25 4
gpt4 key购买 nike

作为Why are there no decent examples of CompositeCell in use within a CellTable?的后续

我正在尝试添加 JSR-303 验证支持。我在这里遵循了 Koma 的配置建议:How to install gwt-validation with gwt-2.4.0 (注意:我使用的是 GWT 2.4 的内置验证,而不是 GWT-Validation)。

再次,为了得到一些重用,我制作了一对类, ValidatableInputCell AbstractValidatableColumn .我从他们那里得到灵感:

  • http://code.google.com/p/google-web-toolkit/source/browse/trunk/samples/validation/src/main/java/com/google/gwt/sample/validation/client/ValidationView.java?r=10642
  • http://gwt.google.com/samples/Showcase/Showcase.html#!CwCellValidation

  • 让我们来看看他们...
    public class ValidatableInputCell extends AbstractInputCell<String, ValidatableInputCell.ValidationData> {

    interface Template extends SafeHtmlTemplates {
    @Template("<input type=\"text\" value=\"{0}\" size=\"{1}\" style=\"{2}\" tabindex=\"-1\"></input>")
    SafeHtml input(String value, String width, SafeStyles color);
    }

    private static Template template;

    /**
    * The error message to be displayed as a pop-up near the field
    */
    private String errorMessage;

    private static final int DEFAULT_INPUT_SIZE = 15;

    /**
    * Specifies the width, in characters, of the &lt;input&gt; element contained within this cell
    */
    private int inputSize = DEFAULT_INPUT_SIZE;

    public ValidatableInputCell() {
    super("change", "keyup");
    if (template == null) {
    template = GWT.create(Template.class);
    }
    }

    public void setInputSize(int inputSize) {
    this.inputSize = inputSize;
    }

    public void setErrorMessage(String errorMessage) {
    this.errorMessage = SafeHtmlUtils.htmlEscape(errorMessage);
    }

    @Override
    public void onBrowserEvent(Context context, Element parent, String value,
    NativeEvent event, ValueUpdater<String> valueUpdater) {
    super.onBrowserEvent(context, parent, value, event, valueUpdater);

    // Ignore events that don't target the input.
    final InputElement input = (InputElement) getInputElement(parent);
    final Element target = event.getEventTarget().cast();
    if (!input.isOrHasChild(target)) {
    return;
    }

    final Object key = context.getKey();
    final String eventType = event.getType();

    if ("change".equals(eventType)) {
    finishEditing(parent, value, key, valueUpdater);
    } else if ("keyup".equals(eventType)) {
    // Mark cell as containing a pending change
    input.getStyle().setColor("blue");

    ValidationData viewData = getViewData(key);
    // Save the new value in the view data.
    if (viewData == null) {
    viewData = new ValidationData();
    setViewData(key, viewData);
    }
    final String newValue = input.getValue();
    viewData.setValue(newValue);
    finishEditing(parent, newValue, key, valueUpdater);

    // Update the value updater, which updates the field updater.
    if (valueUpdater != null) {
    valueUpdater.update(newValue);
    }
    }
    }

    @Override
    public void render(Context context, String value, SafeHtmlBuilder sb) {
    // Get the view data.
    final Object key = context.getKey();
    ValidationData viewData = getViewData(key);
    if (viewData != null && viewData.getValue().equals(value)) {
    // Clear the view data if the value is the same as the current value.
    clearViewData(key);
    viewData = null;
    }

    /*
    * If viewData is null, just paint the contents black. If it is non-null,
    * show the pending value and paint the contents red if they are known to
    * be invalid.
    */
    final String pendingValue = viewData == null ? null : viewData.getValue();
    final boolean invalid = viewData == null ? false : viewData.isInvalid();

    final String color = pendingValue != null ? invalid ? "red" : "blue" : "black";
    final SafeStyles safeColor = SafeStylesUtils.fromTrustedString("color: " + color + ";");
    sb.append(template.input(pendingValue != null ? pendingValue : value, String.valueOf(inputSize), safeColor));
    }

    @Override
    protected void onEnterKeyDown(Context context, Element parent, String value,
    NativeEvent event, ValueUpdater<String> valueUpdater) {
    final Element target = event.getEventTarget().cast();
    if (getInputElement(parent).isOrHasChild(target)) {
    finishEditing(parent, value, context.getKey(), valueUpdater);
    } else {
    super.onEnterKeyDown(context, parent, value, event, valueUpdater);
    }
    }

    @Override
    protected void finishEditing(Element parent, String value, Object key,
    ValueUpdater<String> valueUpdater) {
    final ValidationData viewData = getViewData(key);

    final String pendingValue = viewData == null ? null : viewData.getValue();
    final boolean invalid = viewData == null ? false : viewData.isInvalid();

    if (invalid) {
    final DecoratedPopupPanel errorMessagePopup = new DecoratedPopupPanel(true);
    final VerticalPanel messageContainer = new VerticalPanel();
    messageContainer.setWidth("200px");
    final Label messageTxt = new Label(errorMessage, true);
    messageTxt.setStyleName(UiResources.INSTANCE.style().error());
    messageContainer.add(messageTxt);
    errorMessagePopup.setWidget(messageContainer);

    // Reposition the popup relative to input field
    final int left = parent.getAbsoluteRight() + 25;
    final int top = parent.getAbsoluteTop();

    errorMessagePopup.setPopupPositionAndShow(new PopupPanel.PositionCallback() {
    @Override
    public void setPosition(int offsetWidth, int offsetHeight) {
    errorMessagePopup.setPopupPosition(left, top);
    }
    });
    }
    // XXX let user continue or force focus until value is valid? for now the former is implemented
    super.finishEditing(parent, pendingValue, key, valueUpdater);
    }

    /**
    * The ViewData used by {@link ValidatableInputCell}.
    */
    static class ValidationData {
    private boolean invalid;
    private String value;

    public String getValue() {
    return value;
    }

    public boolean isInvalid() {
    return invalid;
    }

    public void setInvalid(boolean invalid) {
    this.invalid = invalid;
    }

    public void setValue(String value) {
    this.value = value;
    }
    }

    }


    public abstract class AbstractValidatableColumn<T> implements HasCell<T, String> {

    private ValidatableInputCell cell = new ValidatableInputCell();
    private CellTable<T> table;

    public AbstractValidatableColumn(int inputSize, CellTable<T> table) {
    cell.setInputSize(inputSize);
    this.table = table;
    }

    @Override
    public Cell<String> getCell() {
    return cell;
    }

    @Override
    public FieldUpdater<T, String> getFieldUpdater() {
    return new FieldUpdater<T, String>() {
    @Override
    public void update(int index, T dto, String value) {
    final Set<ConstraintViolation<T>> violations = validate(dto);
    final ValidationData viewData = cell.getViewData(dto);
    if (!violations.isEmpty()) { // invalid
    final StringBuffer errorMessage = new StringBuffer();
    for (final ConstraintViolation<T> constraintViolation : violations) {
    errorMessage.append(constraintViolation.getMessage());
    }
    viewData.setInvalid(true);
    cell.setErrorMessage(errorMessage.toString());
    table.redraw();
    } else { // valid
    viewData.setInvalid(false);
    cell.setErrorMessage(null);
    doUpdate(index, dto, value);
    }
    }
    };
    }

    protected abstract void doUpdate(int index, T dto, String value);

    protected Set<ConstraintViolation<T>> validate(T dto) {
    final Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
    final Set<ConstraintViolation<T>> violations = validator.validate(dto);
    return violations;
    }

    }

    我使用 AbstractValidatableColumn 像这样...
    protected HasCell<ReserveOfferDTO, String> generatePriceColumn(DisplayMode currentDisplayMode) {
    HasCell<ReserveOfferDTO, String> priceColumn;
    if (isInEditMode(currentDisplayMode)) {
    priceColumn = new AbstractValidatableColumn<ReserveOfferDTO>(5, this) {

    @Override
    public String getValue(ReserveOfferDTO reserveOffer) {
    return obtainPriceValue(reserveOffer);
    }

    @Override
    protected void doUpdate(int index, ReserveOfferDTO reserveOffer, String value) {
    // number format exceptions should be caught and handled by event bus's handle method
    final double valueAsDouble = NumberFormat.getDecimalFormat().parse(value);
    final BigDecimal price = BigDecimal.valueOf(valueAsDouble);
    reserveOffer.setPrice(price);
    }

    };
    } else {
    priceColumn = new Column<ReserveOfferDTO, String>(new TextCell()) {

    @Override
    public String getValue(ReserveOfferDTO reserveOffer) {
    return obtainPriceValue(reserveOffer);
    }
    };
    }
    return priceColumn;
    }

    哦!这是 DTO 带有 JSR-303 注释...
    public class ReserveOfferDTO extends DateComparable implements Serializable {

    private static final long serialVersionUID = 1L;

    @NotNull @Digits(integer=6, fraction=2)
    private BigDecimal price;
    @NotNull @Digits(integer=6, fraction=2)
    private BigDecimal fixedMW;

    private String dispatchStatus;
    private String resourceName;
    private String dateTime;
    private String marketType;
    private String productType;

    ...

    }

    中删除断点onBrowserEvent 我希望在每次击键和/或单元格失去焦点后都有验证触发器。它永远不会被调用。我可以在单元格中输入任何我喜欢的内容。有关修复方法的任何线索?

    我早期的想法... a) AbstractValidatableColumn#getFieldUpdater 永远不会被调用,b) ValidatableInputCell#onBrowserEvent 或 ValidatableInputCell#render 中的逻辑需要大修。

    最终,我希望看到每个违反约束的单元格旁边都出现一个弹出窗口,并且当然会看到应用了适当的着色。

    最佳答案

    来这里透透气。 我终于想出了一个解决方案! 我选择使用 GWT 验证 图书馆,见 http://code.google.com/p/gwt-validation/wiki/GWT_Validation_2_0 (已知以下代码可用于 2.1 SNAPSHOT)。

    对单元格执行验证时的技巧是调用 验证值 而不是验证(后者触发对所有实体字段的验证)。同样,所有输入单元格值都是字符串,并在验证之前转换为相应的实体字段类型。 (甚至适用于嵌套实体字段)。

    这是 的修订版实现AbstractValidatableColumn (AVC) 和 ValidatableInputCell .

    /**
    * A {@link Column} implementation that encapsulates a {@link ValidatableInputCell}.
    * Performs JSR-303 validation on a field (or nested field) of the type.
    * @author cphillipson
    *
    * @param <T> the type
    * @param <O> the owning type of the field to be validated; in many cases T may have only primitive or wrapper types, therefore O will be the same type as T
    */
    public abstract class AbstractValidatableColumn<T, O> extends Column<T, String> {

    /**
    * Preferred constructor.
    * Allows for definition of tabIndex but uses a default for the input cell size.
    * @param tabIndex the <code>tabindex</code> attribute's value for the input cell
    * @param table the grid instance
    */
    public AbstractValidatableColumn(int tabIndex, final AbstractHasData<T> table) {
    this(App.INSTANCE.defaultValidatableInputCellSize(), tabIndex, table);
    }

    /**
    * Overloaded constructor.
    * Allows for definition of tabIndex and allows for an override to the default for the input cell size.
    * @param inputSize the <code>size</code> attribute's value for the input cell
    * @param tabIndex the <code>tabindex</code> attribute's value for the input cell
    * @param table the grid instance
    */
    public AbstractValidatableColumn(int inputSize, int tabIndex, final AbstractHasData<T> table) {
    super(new ValidatableInputCell());
    getCell().setInputSize(inputSize);
    getCell().setTabIndex(tabIndex);
    init(table);
    }

    // meat and potatoes
    private void init(final AbstractHasData<T> table) {
    setFieldUpdater(new FieldUpdater<T, String>() {
    @Override
    public void update(int index, T dto, String newValue) {
    final ConversionResult cr = attemptValueConversion(newValue);
    final ValidationData viewData = getCell().getViewData(dto);
    if (cr.wasConvertedSuccessfully()) {
    final Set<ConstraintViolation<O>> violations = validate(cr.getValue());
    if (!violations.isEmpty()) { // invalid
    final StringBuffer errorMessage = new StringBuffer();
    for (final ConstraintViolation<O> constraintViolation : violations) {
    errorMessage.append(constraintViolation.getMessage());
    }
    viewData.setInvalid(true);
    getCell().setErrorMessage(errorMessage.toString());
    } else { // valid
    viewData.setInvalid(false);
    getCell().setErrorMessage("");
    doUpdate(index, dto, newValue);
    }
    } else { // conversion exception
    viewData.setInvalid(true);
    getCell().setErrorMessage(UiMessages.INSTANCE.improper_input_format());
    }
    }
    });
    }


    /**
    * Attempts conversion of a String value into another type
    * Instances are responsible for the conversion logic as it may vary from type to type
    * @param value a String value to be converted into an owning class's property type
    * @return a ConversionResult
    */
    protected abstract ConversionResult attemptValueConversion(String value);

    @Override
    public ValidatableInputCell getCell() {
    return (ValidatableInputCell) super.getCell();
    }

    /**
    * Template method for updating a field (or nested field) value within a DTO
    * @param index the row index for the instance of the DTO within the grid
    * @param dto the object whose field we wish to update
    * @param value the new value that will be set on a field (or nested field) of the DTO
    */
    protected abstract void doUpdate(int index, T dto, String value);

    /**
    * Template method for specifying the property name of an owning class
    * @return the field name of the owning class whose value is to be updated
    */
    protected abstract String getPropertyName();

    /**
    * Template method for specifying the owning class
    * @return the owning class of the field whose value is to be updated
    */
    protected abstract Class<O> getPropertyOwner();

    /**
    * Validates a value against a set of constraints (i.e., JSR-303 annotations on a field)
    * @param newValue the value to be validated
    * @return the set of constraint violations induced by an inappropriate value
    */
    protected Set<ConstraintViolation<O>> validate(Object newValue) {
    final Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
    final Set<ConstraintViolation<O>> violations = validator.validateValue(getPropertyOwner(), getPropertyName(), newValue);
    return violations;
    }

    }

    /**
    * <p>A cell that will update its styling and provide feedback upon a validation constraint violation.</p>
    * <p>Implementation based upon GWT Showcase's <a href="http://gwt.google.com/samples/Showcase/Showcase.html#!CwCellValidation">Cell Validation</a> example.</p>
    * @author cphillipson
    *
    */
    public class ValidatableInputCell extends AbstractInputCell<String, ValidatableInputCell.ValidationData> {

    interface Template extends SafeHtmlTemplates {
    @Template("<input type=\"text\" value=\"{0}\" size=\"{1}\" style=\"{2}\" tabindex=\"{3}\"></input>")
    SafeHtml input(String value, String width, SafeStyles color, String tabIndex);
    }

    private static Template template;

    /**
    * The error message to be displayed as a pop-up near the field
    */
    private String errorMessage;

    private static final int DEFAULT_INPUT_SIZE = App.INSTANCE.defaultValidatableInputCellSize();

    /**
    * Specifies the width, in characters, of the &lt;input&gt; element contained within this cell
    */
    private int inputSize = DEFAULT_INPUT_SIZE;

    /**
    * Specifies the tab index for this cell
    */
    private int tabIndex = -1;

    public ValidatableInputCell() {
    // since onBrowserEvent method is overridden, we must register all events that handled in overridden method impl
    super("change", "keyup", "focus", "blur", "keydown");
    if (template == null) {
    template = GWT.create(Template.class);
    }
    }

    public void setInputSize(int inputSize) {
    this.inputSize = inputSize;
    }

    public void setTabIndex(int index) {
    tabIndex = index;
    }

    public void setErrorMessage(String errorMessage) {
    this.errorMessage = SafeHtmlUtils.fromSafeConstant(errorMessage).asString();
    }

    @Override
    public void onBrowserEvent(Context context, Element parent, String value,
    NativeEvent event, ValueUpdater<String> valueUpdater) {
    super.onBrowserEvent(context, parent, value, event, valueUpdater);

    final InputElement input = (InputElement) getInputElement(parent);
    final Object key = context.getKey();
    final String eventType = event.getType();

    if ("keyup".equals(eventType)) {

    ValidationData viewData = getViewData(key);
    // Save the new value in the view data.
    if (viewData == null) {
    viewData = new ValidationData();
    setViewData(key, viewData);
    }
    final String newValue = input.getValue();
    viewData.setValue(newValue);

    finishEditing(parent, newValue, key, valueUpdater);
    }
    }

    @Override
    public void render(Context context, String value, SafeHtmlBuilder sb) {
    // Get the view data.
    final Object key = context.getKey();
    ValidationData viewData = getViewData(key);
    if (viewData != null && viewData.getValue().equals(value)) {
    // Clear the view data if the value is the same as the current value.
    clearViewData(key);
    viewData = null;
    }

    /*
    * If viewData is null, just paint the contents black. If it is non-null,
    * show the pending value and paint the contents red if they are known to
    * be invalid.
    */
    final String pendingValue = viewData == null ? null : viewData.getValue();
    final boolean invalid = viewData == null ? false : viewData.isInvalid();

    final String color = pendingValue != null ? invalid ? App.INSTANCE.invalidCellInputTextColor() : App.INSTANCE.pendingCellInputTextColor() : App.INSTANCE.defaultCellInputTextColor();
    final String backgroundColor = pendingValue != null ? invalid ? App.INSTANCE.invalidCellInputTextBackgroundColor() : App.INSTANCE.pendingCellInputTextBackgroundColor() : App.INSTANCE.defaultCellInputTextBackgroundColor();
    final SafeStyles style = SafeStylesUtils.fromTrustedString("color: " + color + "; background-color: " + backgroundColor + ";");
    sb.append(template.input(pendingValue != null ? pendingValue : value, String.valueOf(inputSize), style, String.valueOf(tabIndex)));
    }

    /*
    @Override
    protected void onEnterKeyDown(Context context, Element parent, String value,
    NativeEvent event, ValueUpdater<String> valueUpdater) {
    final Element target = event.getEventTarget().cast();
    if (getInputElement(parent).isOrHasChild(target)) {
    finishEditing(parent, value, context.getKey(), valueUpdater);
    } else {
    super.onEnterKeyDown(context, parent, value, event, valueUpdater);
    }
    }
    */

    @Override
    protected void onEnterKeyDown(Context context, Element parent, String value,
    NativeEvent event, ValueUpdater<String> valueUpdater) {
    // do nothing
    }

    @Override
    protected void finishEditing(Element parent, String value, Object key,
    ValueUpdater<String> valueUpdater) {

    // Update the value updater, which updates the field updater.
    if (valueUpdater != null) {
    valueUpdater.update(value);
    }

    final InputElement input = (InputElement) getInputElement(parent);
    final ValidationData viewData = getViewData(key);

    /*
    * If viewData is null, just paint the contents black. If it is non-null,
    * show the pending value and paint the contents red if they are known to
    * be invalid.
    */
    final String pendingValue = viewData == null ? null : viewData.getValue();
    final boolean invalid = viewData == null ? false : viewData.isInvalid();

    final String color = pendingValue != null ? invalid ? App.INSTANCE.invalidCellInputTextColor() : App.INSTANCE.pendingCellInputTextColor() : App.INSTANCE.defaultCellInputTextColor();
    final String backgroundColor = pendingValue != null ? invalid ? App.INSTANCE.invalidCellInputTextBackgroundColor() : App.INSTANCE.pendingCellInputTextBackgroundColor() : App.INSTANCE.defaultCellInputTextBackgroundColor();
    input.getStyle().setColor(color);
    input.getStyle().setBackgroundColor(backgroundColor);

    if (invalid) {
    final DecoratedPopupPanel errorMessagePopup = new DecoratedPopupPanel(true);
    final FlowPanel messageContainer = new FlowPanel();
    messageContainer.setWidth(App.INSTANCE.errorMessagePopupWidth());
    final Label messageTxt = new Label(errorMessage, true);
    messageTxt.setStyleName(UiResources.INSTANCE.style().error());
    messageContainer.add(messageTxt);
    errorMessagePopup.setWidget(messageContainer);

    // Reposition the popup relative to input field
    final int left = parent.getAbsoluteRight() +5;
    final int top = parent.getAbsoluteTop() - 5;

    errorMessagePopup.setPopupPositionAndShow(new PopupPanel.PositionCallback() {
    @Override
    public void setPosition(int offsetWidth, int offsetHeight) {
    errorMessagePopup.setPopupPosition(left, top);
    }
    });
    }

    }

    /**
    * The ViewData used by {@link ValidatableInputCell}.
    */
    static class ValidationData {
    private boolean invalid;
    private String value;

    public String getValue() {
    return value;
    }

    public boolean isInvalid() {
    return invalid;
    }

    public void setInvalid(boolean invalid) {
    this.invalid = invalid;
    }

    public void setValue(String value) {
    this.value = value;
    }
    }

    }

    AVC 的变体可能看起来像……
    /**
    * A variant of {@link AbstractValidatableColumn} that works with {@link BigDecimal} field types.
    * @author cphillipson
    *
    * @param <T> the type
    * @param <O> the owning type of the field to be validated; in many cases T may have only primitive or wrapper types, therefore O will be the same type as T
    */
    public abstract class BigDecimalValidatableColumn<T, O> extends AbstractValidatableColumn<T, O> {

    public BigDecimalValidatableColumn(int tabIndex, AbstractHasData table) {
    super(tabIndex, table);
    }

    public BigDecimalValidatableColumn(int inputSize, int tabIndex, final AbstractHasData<T> table) {
    super(inputSize, tabIndex, table);
    }

    @Override
    protected ConversionResult attemptValueConversion(String value) {
    return doConversion(value);
    }

    public static ConversionResult doConversion(String value) {
    ConversionResult result = null;
    try {
    final Double dblValue = Double.valueOf(value);
    final BigDecimal convertedValue = BigDecimal.valueOf(dblValue);
    result = ConversionResult.converted(convertedValue);
    } catch (final NumberFormatException nfe) {
    result = ConversionResult.not_converted();
    }
    return result;
    }
    }

    A 转换结果 由 Column 的 fieldUpdater 咨询。这是它的样子......
    /**
    * An attempted conversion result.
    * Returns both the converted value (from <code>String</code>) and whether or not the conversion was successful.
    * E.g., if you tried to convert from a <code>String</code> to a <code>Number</code>, in the failure case this would result in a <code>NumberFormatException</code>.
    * On failure, the boolean would be false and the value would be null.
    * On success, the boolean would be true and the value would be of the type needed to continue validation against a set of constraints
    * @author cphillipson
    *
    */
    public class ConversionResult {
    private Object value;
    private boolean convertedSuccessfully;

    private ConversionResult () {}

    /**
    * Use this method when a successful conversion is made to return a result
    * @param value the convertedValue
    * @return the result of the conversion containing the converted value and a success flag
    */
    public static ConversionResult converted(Object value) {
    final ConversionResult result = new ConversionResult();
    result.setConvertedSuccessfully(true);
    result.setValue(value);
    return result;
    }

    /**
    * Use this method when an attempt to convert a String value failed
    * @return the result of a failed conversion
    */
    public static ConversionResult not_converted() {
    return new ConversionResult();
    }

    private void setValue(Object value) {
    this.value = value;
    }

    public Object getValue() {
    return value;
    }

    private void setConvertedSuccessfully(boolean flag) {
    convertedSuccessfully = flag;
    }

    public boolean wasConvertedSuccessfully() {
    return convertedSuccessfully;
    }
    }

    最后,这是您在网格中指定列的方法
    new BigDecimalValidatableColumn<EnergyOfferDTO, OfferPriceMwPairDTO>(nextTabIndex(), getGrid()) {

    @Override
    public String getValue(EnergyOfferDTO energyOffer) {
    return obtainPriceValue(colIndex, energyOffer, false);
    }

    @Override
    public void doUpdate(int index, EnergyOfferDTO energyOffer, String value) {
    if (value != null && !value.isEmpty()) {
    // number format exceptions should be caught and handled by event bus's handle method
    final double valueAsDouble = NumberFormat.getDecimalFormat().parse(value);

    final BigDecimal price = BigDecimal.valueOf(valueAsDouble);
    final List<OfferPriceMwPairDTO> offerPriceCurve = energyOffer.getCurve();
    final OfferPriceMwPairDTO offerPriceMwPairDTO = offerPriceCurve.get(colIndex);
    if (offerPriceMwPairDTO == null) { // we have a new price value
    newOfferPriceMwPair.setPrice(price);
    offerPriceCurve.add(newOfferPriceMwPair);
    } else {
    offerPriceMwPairDTO.setPrice(price);
    }

    }
    }

    @Override
    protected String getPropertyName() {
    return "price";
    }

    @Override
    protected Class<OfferPriceMwPairDTO> getPropertyOwner() {
    return OfferPriceMwPairDTO.class;
    }

    };

    请注意,上面示例中的 DTO 对其字段 JSR-303 约束进行了注释(例如,使用 @Digits、@NotNull)。

    以上做了一些工作,它可能只是目前网络上最全面的解决方案。享受!

    关于validation - 寻找 GWT 验证示例...你在哪里?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9122802/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com