如何为游戏框架编写自定义检查/验证

2022-09-02 14:13:21

我尝试为游戏框架编写检查,并看到两种不同的可能性。我描述了两者,并想知道我的理解是否正确(所以它更像是一个教程而不是一个问题,特别是因为我没有得到任何回应,我错过了一些东西)。那么存在什么可能性。

  1. 简单的方法:扩展类:
    优点:更易于编写,更易于阅读
    缺点:您无法参数化检查,只能定义消息。Check
  2. 高级方法:基于 OVal 编写检查。
    优点:您可以对检查进行参数化,并有一个更简单的注释
    缺点:稍微复杂一点。AbstractAnnotationCheck

在我们看一下实现之前,我想解释一下这些消息。您始终可以直接设置消息,也可以使用键在消息属性中引用消息。最后一个是更干净和推荐的方式。每次验证都会获得至少 1 个参数:无效的属性的名称。因此,验证或检查特定参数始终与i>1的位置一起引用。消息字符串的格式应遵循格式化程序的规则,但我不确定是否支持所有功能。据我所知,只有 %s、%d 和 %f 支持定位。因此,转换只能是s,d或f。%i$s%[argument_index$][flags]conversion

让我们看一下两个例子:我在模块中使用的简单方法进行乐观锁定:

/**
 * Check with proof if the version of the current edited object is lesser
 * than the version in db.
 * Messagecode: optimisticLocking.modelHasChanged
 * Parameter: 1 the request URL.
 * Example-Message: The object was changed. <a href="%2$s">Reload</a> and do your changes again.
 *
 */
static class OptimisticLockingCheck extends Check {

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean isSatisfied(Object model, Object optimisiticLockingViolatedValue) {
        //The comparision of version was made in the setter. Here
        //we only have to check the flag.
        if (((VersionedModel) model).optimisiticLockingViolated) {
            final Request request = Request.current();
            //The following doesn't work in 1.0 but in 1.1 see https://bugs.launchpad.net/play/+bug/634719
            //http://play.lighthouseapp.com/projects/57987-play-framework/tickets/116
            //setMessage(checkWithCheck.getMessage(), request != null ? request.url : "");
            setMessage("optimisticLocking.modelHasChanged", request != null ? request.url : ""); 

        }
        return !((VersionedModel) model).optimisiticLockingViolated;
    }
}

您可以使用此检查与注释@CheckWith(value=OptimisticLockingCheck.class, message="optimisticLocking.modelHasChanged")

因此,让我们仔细看看它是如何工作的。我们唯一要做的就是扩展类 play.data.validation.Check 并覆盖 isSatisfied 方法。在那里,您可以获得模型和属性的值。您所要做的就是在一切正常的情况下返回 true,否则返回 false。在我们的例子中,我们希望将当前url设置为参数。这可以通过调用 setMessage() 轻松完成。我们给出消息或消息键,该消息键在消息属性和参数中定义。请记住,我们只给出 1 个参数,但以 %2$s 表示,因为第一个参数始终是属性的名称。

现在基于范围检查的复杂方式:首先我们需要定义一个注释

/**
 * This field must be lower than and greater than.
 * Message key: validation.range
 * $1: field name
 * $2: min reference value
 * $3: max reference value
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Constraint(checkWith = RangeCheck.class)
public @interface Range {

    String message() default RangeCheck.mes;
    double min() default Double.MIN_VALUE;
    double max() default Double.MAX_VALUE;
}

,然后检查

@SuppressWarnings("serial")
public class RangeCheck extends AbstractAnnotationCheck<Range> {

    final static String mes = "validation.range";

    double min;
    double max;

    @Override
    public void configure(Range range) {
        this.min = range.min();
        this.max = range.max();
        setMessage(range.message());
    }

    public boolean isSatisfied(Object validatedObject, Object value, OValContext context, Validator validator) {
        requireMessageVariablesRecreation();
        if (value == null) {
            return true;
        }
        if (value instanceof String) {
            try {
                double v = Double.parseDouble(value.toString());
                return v >= min && v <= max;
            } catch (Exception e) {
                return false;
            }
        }
        if (value instanceof Number) {
            try {
                return ((Number) value).doubleValue() >= min && ((Number) value).doubleValue() <= max;
            } catch (Exception e) {
                return false;
            }
        }
        return false;
    }

    @Override
    public Map<String, String> createMessageVariables() {
        Map<String, String> messageVariables = new TreeMap<String, String>();
        messageVariables.put("2-min", Double.toString(min));
        messageVariables.put("3-max", Double.toString(max));
        return messageVariables;
    }

}

好吧,我认为注释不必解释。让我们看看检查。在本例中,它是扩展 。我们必须编写一个配置方法,在其中获取注释并可以复制参数。然后,我们必须定义检查。这类似于另一个检查的实现。因此,我们只编写我们的条件并返回 true 或 false,除了一个特殊行!如果我们使用参数化消息,则必须调用我们的方法。至少我们必须覆盖该方法 。在这里,我们必须得到一点游戏知识(所有其他的东西都在这里描述)。您将消息放入具有键和值的映射中,但 play 仅采用这些值(请参阅框架代码)。因此,它将按位置引用。这就是我更改了 using 而不是 .此外,我让密钥以它们可以引用的索引开始。net.sf.oval.configuration.annotation.AbstractAnnotationCheckrequireMessageVariablesRecreation();createMessageVariablesValidCheck.javaRangeCheckTreeMapHashMap

所以我希望这能更清楚地说明如何为游戏编写自定义验证/检查。我希望描述是正确的。因此,问题我的理解是否正确?


答案 1

至少你的第一个示例似乎在正确的路径上。您可以将其与下面提供的文档进行比较,但是从示例的复杂性来看,我已经引用了它。

http://www.playframework.org/documentation/1.1/validation#custom

我对游戏框架的了解还不够多,无法评论第二个例子。


答案 2

推荐