使用通用控制器时,如何返回特定控制器固有的视图? [英] When using a generic controller, how to return a view inherent to a specific controller?

查看:141
本文介绍了使用通用控制器时,如何返回特定控制器固有的视图?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

作为这个答案的结果: https://stackoverflow.com/a/10708026/694597 ,我是想知道在使用通用控制器时如何返回特定控制器固有的视图。

As a result of this answer: https://stackoverflow.com/a/10708026/694597, I am wondering how to return a view inherent to a specific controller when using a generic controller.

推荐答案

在控制器中渲染视图时动作,你只需要调用一个由模板引擎生成的普通函数:

When you render a view in a controller action, you just invoke a plain function which has been generated by the template engine:

public Application extends Controller {
  public static Result index() {
    return ok(views.html.index.render(42));
  }
}

此处,渲染是对象 index 的方法,其类型为 Template1< Integer,Html>

Here, render is a method of the object index which has type Template1<Integer, Html>.

现在的问题是:如何编写能够调用特定于另一个控制器的视图的通用控制器?或者简单地说:如何抽象视图

Now the question is: how to write a generic controller able to invoke a view specific to another controller? Or simply: how to abstract over views?

我看到两个解决方案: 控制权转换 反思

I see two solutions: inversion of control and reflection.

让我们看看如何实施两者都是一个简单的用例。假设您有以下通用 Shower< T> 类,它能够计算包含任何类型值 T

Let’s see how to implement both on a simple use case. Say you have the following generic Shower<T> class able to compute an HTTP response containing an HTML representation of any value of type T:

public class Shower<T> {
  public Result show(T value) {
    // TODO return an HTML representation of `value`
  }
}



控制权反转



实施淋浴< T> 使用控制反转我们只需要注入用于执行渲染的 Template1< T,Html> 值:

Inversion of control

To implement Shower<T> using inversion of control we just need to inject the Template1<T, Html> value used to perform the rendering:

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> 的静态实例并将其注入要使用的模板:

To use it in a controller, create a static instance of Shower<T> and inject it the template to use:

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

Reflection

You may find it too boilerplate to have to inject explicitly the template to use for each instance of Shower<T>, so you may be tempted to retrieve it by reflection, based on a naming convention, e.g. to show a value of type Foo, just look for an object named show in the package 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对象的方式)

(that’s the way to access Scala objects using reflection)

您可以在控制器中使用如下:

You can use it as follows in a controller:

public class Application extends Controller {
  public static Shower<Foo> foo = new Shower<Foo>(Foo.class);
}



利弊



基于反射的解决方案在呼叫站点上需要较少的样板,但它依赖于命名约定这一事实使其更脆弱。此外,此解决方案只有在失败时在运行时失败,而第一个解决方案将在编译时向您显示您缺少的模板 。最后但同样重要的是,基于反射的解决方案可能会因反射而增加一些性能开销

Pros and cons

The reflection-based solution requires less boilerplate on the call site, but the fact it relies on a naming convention makes it more fragile. Furthermore, this solution will only fail at runtime when it’ll fail, while the first solution will show you your missing templates at compile time. Last but not least, the reflection based solution may add some performance overhead due to the reflection.

这篇关于使用通用控制器时,如何返回特定控制器固有的视图?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆