この回答の結果:https ://stackoverflow.com/a/10708026/694597 、汎用コントローラーを使用するときに特定のコントローラーに固有のビューを返す方法を考えています。
1 に答える
コントローラアクションでビューをレンダリングするときは、テンプレートエンジンによって生成されたプレーン関数を呼び出すだけです。
public Application extends Controller {
public static Result index() {
return ok(views.html.index.render(42));
}
}
ここで、はタイプが。render
のオブジェクトのメソッドです。index
Template1<Integer, Html>
ここで問題となるのは、別のコントローラーに固有のビューを呼び出すことができる汎用コントローラーを作成する方法です。または単に:ビューを抽象化する方法は?
制御の反転と反射という2つの解決策があります。
単純なユースケースで両方を実装する方法を見てみましょう。Shower<T>
タイプの任意の値のHTML表現を含むHTTP応答を計算できる次のジェネリッククラスがあるとしますT
。
public class Shower<T> {
public Result show(T value) {
// TODO return an HTML representation of `value`
}
}
制御の反転
Shower<T>
制御の反転を使用して実装Template1<T, Html>
するには、レンダリングの実行に使用される値を挿入する必要があります。
public class Shower<T> {
public final Template1<T, Html> template;
public Shower(Template1<T, Html> template) {
this.template = template;
}
public Result show(T value) {
return ok(template.render(value));
}
}
コントローラで使用するには、の静的インスタンスを作成し、Shower<T>
使用するテンプレートを挿入します。
public class Application extends Controller {
public static Shower<Foo> foo = new Shower<Foo>(views.html.Foo.show.ref());
}
反射
の各インスタンスに使用するテンプレートを明示的に挿入する必要があるのは定型的すぎるためShower<T>
、命名規則に基づいて、たとえばタイプの値を表示するFoo
ために、オブジェクトを探すだけで、リフレクションによってテンプレートを取得したくなる場合があります。show
パッケージで名前が付けられていますviews.html.Foo
:
public class Shower<T> {
private final Class<T> clazz;
public Shower(Class<T> clazz) {
this.clazz = clazz;
}
public Result show(T value) throws Exception {
Class<?> object = Play.application().classLoader().loadClass("views.html." + clazz.getSimpleName() + ".show$");
Template1<T, Html> template = (Template1<T, Html>)object.getField("MODULE$").get(null);
return ok(template.render(value));
}
}
(これが、リフレクションを使用してScalaオブジェクトにアクセスする方法です)
コントローラでは次のように使用できます。
public class Application extends Controller {
public static Shower<Foo> foo = new Shower<Foo>(Foo.class);
}
長所と短所
リフレクションベースのソリューションは、コールサイトで必要な定型文が少なくて済みますが、命名規則に依存しているため、脆弱性が高くなります。さらに、このソリューションは実行時に失敗する場合にのみ失敗しますが、最初のソリューションはコンパイル時に不足しているテンプレートを表示します。大事なことを言い忘れましたが、リフレクションベースのソリューションは、リフレクションのためにパフォーマンスのオーバーヘッドを追加する可能性があります。