【问题标题】:When using a generic controller, how to return a view inherent to a specific controller?使用通用控制器时,如何返回特定控制器固有的视图?
【发布时间】:2012-05-24 13:11:49
【问题描述】:

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

【问题讨论】:

    标签: java playframework-2.0


    【解决方案1】:

    当您在控制器操作中渲染视图时,您只需调用模板引擎生成的普通函数:

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

    这里,render 是对象 index 的方法,其类型为 Template1<Integer, Html>

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

    我看到了两种解决方案:inversion of controlreflection

    让我们看看如何在一个简单的用例中实现这两者。假设您有以下通用Shower<T> 类能够计算包含T 类型的任何值的HTML 表示的HTTP 响应:

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

    控制反转

    要使用控制反转来实现Shower&lt;T&gt;,我们只需注入用于执行渲染的Template1&lt;T, Html&gt; 值:

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

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

    反射

    你可能会发现它太样板了,必须显式地注入模板以用于Shower&lt;T&gt; 的每个实例,所以你可能会想通过反射来检索它,基于命名约定,例如要显示Foo 类型的值,只需在包views.html.Foo 中查找名为show 的对象:

    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);
    }
    

    优点和缺点

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

    【讨论】:

    • ref()!哦,这些知识将非常有用!非常感谢您解释这一点!
    • 我喜欢您的控制反转解决方案!但是,如果您的 Shower 中有多个方法,您还必须传递多个视图。对这个问题也使用Builder pattern 有用吗? (另请参阅:Bloch, J. Effective Java -> 第 2 条)
    • 啊,据我了解,这种模式允许您在调用站点上编写更具可读性的代码,但仍然需要您传递所有视图。
    • 确实,您仍然需要通过所有视图。但是您不必一次将它们全部传递给构造函数。
    猜你喜欢
    • 2014-12-09
    • 2023-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-08
    • 2016-03-23
    • 1970-01-01
    • 2016-12-11
    相关资源
    最近更新 更多