19

私はplay-frameworkのチェックを書いて、 2つの異なる可能性を見ようとしています。私は両方を説明し、私の理解が正しいかどうかを知りたいと思います(したがって、質問というよりはチュートリアルです。特に、何かを見逃したという応答が得られなかったためです)。したがって、どのような可能性が存在します。

  1. 簡単な方法:クラスを拡張するCheck
    長所:書きやすく、読みやすい
    短所:チェックをパラメーター化することはできず、メッセージを定義することしかできません。
  2. 高度な方法:OValに基づいてチェックを作成しますAbstractAnnotationCheck
    長所:チェックをパラメーター化して、注釈をより簡単に使用できる
    短所:もう少し複雑です。

実装を見る前に、メッセージについて説明したいと思います。メッセージはいつでも直接設定することも、キーを使用してメッセージプロパティでメッセージを参照することもできます。最後の方法は、よりクリーンで推奨される方法です。すべての検証は、少なくとも1つのパラメーターを取得します。無効なプロパティの名前。したがって、検証または特定のパラメータのチェックは、常に%i$si>1の場合に参照されます。メッセージ文字列の形式はFormatterの規則に従う必要がありますが、すべての機能がサポートされているかどうかはわかりません。私の知る限り、%s、%d、%fのみがポジショニングでサポートされています。したがって%[argument_index$][flags]conversion、変換はs、d、またはfのみである可能性があります。

2つの例を見てみましょう。楽観的ロックのためにモジュールで使用した簡単な方法:

/**
 * 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メソッドを上書きすることです。ここで、モデルとプロパティの値を取得します。あなたがしなければならないのは、すべてがOKの場合は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;
    }

}

OK注釈は説明する必要はないと思います。チェックを見てみましょう。この場合、それはextendsnet.sf.oval.configuration.annotation.AbstractAnnotationCheckです。アノテーションを取得してパラメーターをコピーできるconfigure-methodを作成する必要があります。次に、チェックを定義する必要があります。これは、他のチェックの実装に類似しています。したがって、条件を記述してtrueまたはfalseを返すだけですが、特別な1行を除きます。パラメータ化されたメッセージを使用した場合はrequireMessageVariablesRecreation();、メソッドを呼び出す必要があります。少なくとも、メソッドをオーバーライドする必要がありますcreateMessageVariables。ここでは、ちょっとした遊びの知識を得る必要があります(他のすべてのものはここで説明されています)。キーと値を使用してメッセージをマップに配置しますが、playは値のみを取得します(を参照)ValidCheck.javaフレームワークコードで)。したがって、位置によって参照されます。これが、の代わりにRangeCheckusingの実装を変更した理由です。さらに、キーを参照できるインデックスから始めます。TreeMapHashMap

だから私はこれが遊びのためのカスタム検証/チェックを書く方法をより明確にすることを願っています。説明が正しいことを願っています。そのため、私の理解は正しいのでしょうか。

4

1 に答える 1

1

少なくとも最初の例は正しい道にあるようです。以下のドキュメントと比較できますが、例の複雑さから、既に参照していると思います。

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

2 番目の例についてコメントするには、play フレームワークについて十分に知りません。

于 2010-11-04T16:13:29.757 に答える