如何在 Play Framework 2.5 模板中注入应用程序

How to inject Application in Play Framework 2.5 template

随着 Play Framework 的新版本 2.4/2.5,他们进一步朝着注入所有内容和删除服务器状态的方向发展。 play.Play.application() 现已弃用。 但是,我需要在我的模板中应用该应用程序(例如,让所有支持的语言显示在所有带有 play.i18n.Lang.availables(play.Play.application()) 的页面上)。

我知道我可以:

如何在我的模板中注入 play.Application

----更新:----

到目前为止我已经尝试过,我创建了以下设置:

index.scala.html:

@(title: String)
@template(title) { //here is the play.Application obviously missing, however I don't want to pass it in every template - even worse in every Controller <-- this is the core of my question
    Welcome to my page!
}

template.scala.html:

@(title: String)(content: Html)(implicit app: play.Application)
<html>
    <head>
        <title>@title</title>
    </head>
    <body>
        <p>Is live? @app.isProd</p>
        @content
    </body>
</html>

控制器功能:

public Result index() {
    return ok(views.html.index.render("home"));
}

您可以使用 Play.current() 获取应用程序或在控制器中注入应用程序,如 中所述。模板应获得类型为 play.Application.

的参数

应该是这样的

模板,假设是 injectappexample.scala.html:

@(app: play.Application)
.... use the app object 

控制器:

public class SomeController extends Controller {
    Provider<Application> applicationProvider;

    @Inject 
    public SomeController(Provider<Application> applicationProvider) {
        this.applicationProvider = applicationProvider;
    }

    public Result injectAppExample() {
        return ok(injectappexample.render(applicationProvider.get());
    }
}

值得重新考虑将应用程序对象发送到模板。如果你应该发送一个特定的配置 属性 值,在控制器中注入配置,从配置对象中获取值并将其发送到模板。在这种情况下,根本不需要注入应用程序。

模板:

@(value: String)
.... use the value 

控制器:

public class SomeController extends Controller {
    Configuration configuration;

    @Inject 
    public SomeController(Configuration configuration) {
        this.configuration = configuration;
    }

    public Result injectAppExample() {
        return ok(injectappexample.render(configuration.getString("SOME_PROPERTY"));
    }
}

通常不鼓励注入应用程序本身,因为这会使您的代码测试起来非常麻烦。相反,想想你真正需要什么,然后直接注入。

如果几乎每个模板都需要很多东西,我的建议是创建某种上下文 class,您可以将其注入控制器,然后将其传递给模板。

首先,虽然你问的是如何注入 application 但你真正需要的是 configuration.

你可以在 play 2.5 中做这样的事情。我将展示构造函数注入,您可以根据需要使用字段注入。

import com.google.inject.Inject;
import play.Configuration;

public class MyClass{
    private Configuration conf;

    @Inject
    public MyClass(Configuration conf){
        this.conf = conf;
    }

}

现在您的配置已经完成 class。然后专门针对你的需求贴在你的评论里,你可以这样做。

 List<Object> langList = conf.getList("play.i18n.langs");  
 //conf.getList("") returns an object array. 
 //You can cast to Strings (assuming you are using Java8).

 List<String> languages = new ArrayList<>(langList.size());
 for (Object object : langList) {
    languages.add(Objects.toString(object, null));
 }

现在您可以在 languages 中列出您的语言。

我只需要研究 Play 框架 2 的这个问题。6.x。可以根据文档将对象注入模板:https://www.playframework.com/documentation/2.6.x/ScalaTemplatesDependencyInjection.

我实现了一个简单的示例(有点做作)并且我使用了 Scala:

test.scala.html:

@this(configuration: play.api.Configuration)
@(key: String)
config = @configuration.get[Seq[String]](key).mkString(", ")

HomeController.scala

package controllers

import javax.inject._

import play.api._
import play.api.i18n._
import play.api.mvc._

/**
 * This controller creates an `Action` to handle HTTP requests to the
 * application's home page.
 */
@Singleton
class HomeController @Inject()(cc: ControllerComponents, testView: views.html.test) (implicit configuration: Configuration) extends AbstractController(cc) with I18nSupport{

  def test() = Action  { implicit request =>
    Ok(testView("play.i18n.langs"))
  }
}

路线:

GET        /test                controllers.HomeController.test()

配置对象被注入到 views.html.test 模板中,视图本身被注入到控制器中。请注意模板中的 @this(configuration: play.api.Configuration) 语句。 Play 将在模板后面生成一个 class,其中包含一个注入 Configuration 对象的构造函数。

请注意,注入到控制器中的配置在此特定代码中没有任何作用。在我找到这个解决方案之前,我尝试了其他排列......假设你有一个内部模板被从控制器调用的外部模板使用,并且内部模板需要配置对象,你需要从控制器顶部提供配置向下,并在层次结构路径中的所有模板中向需要它的模板添加一个 implicit configuration: play.api.Configuration 参数,如下所示:@(message: String)(implicit messagesProvider: MessagesProvider, configuration: play.api.Configuration) 。然后控制器注入的配置被馈送到顶层模板,一直到需要它的模板。