How to inject Application in Play Framework 2.5 template

时间:2016-08-31 17:44:19

标签: java templates playframework playframework-2.0 playframework-2.5

With the new Version 2.4/2.5 of the Play Framework they moved further towards injecting everything and removing the servers state. play.Play.application() is now deprecated. However, I need the application in my template (e.g. to get all supported languages displayed on all pages with play.i18n.Lang.availables(play.Play.application())).

I'm aware I could:

  • Pass play.Application explicitly to all of my templates.
  • Add an implicit parameter to my template like @()(implicit app: play.Application). However, in my Java-Project it's not really implicit, I have to pass it every time I render the template.
  • Create a Scala object providing the application implicitly. However, this also needs the deprecated play.api.Play.current.

How can I inject play.Application in my templates?

---- Update: ----

What I've tried so far, I created the following setup:

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>

Controller function:

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

4 个答案:

答案 0 :(得分:2)

您可以使用Play.current()获取应用程序,或者在控制器中注入应用程序,如此question中所述。模板应该得到类型为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());
    }
}

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

模板:

@(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"));
    }
}

答案 1 :(得分:1)

我只需要研究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将使用注入Configuration对象的构造函数在模板后面生成一个类。

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

答案 2 :(得分:0)

通常不鼓励注入应用程序本身,因为这会使您的代码非常麻烦。相反,想想你实际需要什么并直接注入它。

如果你在几乎每个模板中都需要很多东西,我的建议是创建一些你可以在你的控制器中注入的上下文类,然后将它传递给模板。

答案 3 :(得分:0)

首先,虽然您在询问如何注入应用,但您真正需要的是配置

你可以在游戏2.5中做这样的事情。我将展示构造函数注入,您可以使用现场注入作为您的要求。

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

public class MyClass{
    private Configuration conf;

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

}

现在你有了配置类。然后专门针对您在评论中发布的要求,您可以这样做。

 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中找到您的语言列表。