【问题标题】:How to inject Application in Play Framework 2.5 template如何在 Play Framework 2.5 模板中注入应用程序
【发布时间】:2016-08-31 17:44:18
【问题描述】:

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

我知道我可以:

  • play.Application 明确传递给我的所有模板。
  • 向我的模板添加一个隐式参数,例如@()(implicit app: play.Application)。但是,在我的 Java 项目中,它并不是真正隐式的,每次渲染模板时我都必须传递它。
  • Create a Scala object providing the application implicitly。但是,这也需要弃用的play.api.Play.current

如何在我的模板中注入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.Application 到底需要做什么?
  • 我想列出所有可用的语言,如new play.api.i18n.DefaultLangs(play.Play.application().configuration()).availables() 以显示语言切换器。
  • 我已将答案作为您的要求。如果您对此有任何疑问,请告诉我。 :)
  • 不幸的是,没有。我仍在寻找一种方法来inject 我的模板。到目前为止,所有答案都需要我将其传递给我的所有模板。 play.Application 只是一个例子,我也不知道怎么注入 play.Configuration 之类的东西。
  • 所以基本上你正在努力注入任何东西吧??

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


【解决方案1】:

您可以使用 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());
    }
}

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

模板:

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

【讨论】:

【解决方案2】:

我只需要针对 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 将在模板后面生成一个类,其中包含一个注入配置对象的构造函数。

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

【讨论】:

    【解决方案3】:

    通常不鼓励注入应用程序本身,因为这会使您的代码测试起来非常麻烦。相反,请考虑您实际需要什么并直接注入。

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

    【讨论】:

    • 感谢您的回答,您能否进一步解释一下如何“直接注入”?我还没有弄清楚如何在模板中注入任何东西,而不必每次在我的 Java 代码中渲染模板时都传递它。
    • 不是我的意思——每次使用模板时,您仍然需要将该上下文对象显式传递到模板中。
    【解决方案4】:

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

    你可以在 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;
        }
    
    }
    

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-30
      • 1970-01-01
      • 2017-03-28
      • 2016-07-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多