私はplay-frameworkのチェックを書いて、 2つの異なる可能性を見ようとしています。私は両方を説明し、私の理解が正しいかどうかを知りたいと思います(したがって、質問というよりはチュートリアルです。特に、何かを見逃したという応答が得られなかったためです)。したがって、どのような可能性が存在します。
- 簡単な方法:クラスを拡張する
Check
:
長所:書きやすく、読みやすい
短所:チェックをパラメーター化することはできず、メッセージを定義することしかできません。 - 高度な方法:OValに基づいてチェックを作成します
AbstractAnnotationCheck
。
長所:チェックをパラメーター化して、注釈をより簡単に使用できる
短所:もう少し複雑です。
実装を見る前に、メッセージについて説明したいと思います。メッセージはいつでも直接設定することも、キーを使用してメッセージプロパティでメッセージを参照することもできます。最後の方法は、よりクリーンで推奨される方法です。すべての検証は、少なくとも1つのパラメーターを取得します。無効なプロパティの名前。したがって、検証または特定のパラメータのチェックは、常に%i$s
i>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
フレームワークコードで)。したがって、位置によって参照されます。これが、の代わりにRangeCheck
usingの実装を変更した理由です。さらに、キーを参照できるインデックスから始めます。TreeMap
HashMap
だから私はこれが遊びのためのカスタム検証/チェックを書く方法をより明確にすることを願っています。説明が正しいことを願っています。そのため、私の理解は正しいのでしょうか。