【问题标题】:Play 2.5: Depedency injection in templates玩法 2.5:模板中的依赖注入
【发布时间】:2016-10-06 11:45:05
【问题描述】:

我正在尝试处理 Scala 模板中的依赖注入对象(我使用的是基于 Java 的 Play 2.5)。

我有一个模板系统,其中我的布局模板具有最少的 HTML 基础,并且几乎所有其他构建 HTML 正文的其他 HTML 模板都包含该模板。

在模板中,我还包括带有“注销”按钮的顶部菜单,并且还有一个当前登录用户的名称。

我有一个名为 LocalAuthenticator 的单例对象,它传递包含用户名的用户对象。到目前为止,我一直在使用像这样的辅助 Scala 对象进行依赖注入

object LocalAuthenticator {   
  private val cache = Application.instanceCache[core.security.LocalAuthenticator]

  object Implicits {
    implicit def localAuth(implicit application: Application): core.security.LocalAuthenticator = cache(application)   } 
  }

然后我可以使用这个构造从模板访问 LocalAuthenticator

@import play.api.Play.current
@import scala.LocalAuthenticator.Implicits._

Logged in user is: @localAuth.getCurrentUser().name

这在 2.4 中有效,但是 2.5 抱怨 play.api.Play.current 因使用静态上下文而被弃用。

我知道正确的方法是将 LocalAuthenticator 注入 Controller 并将其传递给模板,但是该对象应该存在于所有模板中,并且将其注入每个控制器非常烦人。

有没有办法直接将单例类注入到模板中?

我试图在辅助对象中获取注入器以获取单例,但这只有在我有 Play Application 对象时才能完成。这只能使用 DI 来检索。所以我在兜圈子:-)

【问题讨论】:

标签: java scala playframework dependency-injection playframework-2.5


【解决方案1】:

好的,找到了解决方案(或者可能是解决方法)。

使用此页面https://github.com/google/guice/wiki/Injections#static-injections 我创建了一个在应用程序启动时加载的帮助模块。

public class DIStaticModule extends AbstractModule {
    protected void configure() {
        requestStaticInjection(DIStaticFactory.class);
    }
}

...然后是工厂类...

public class DIStaticFactory {
    @Inject
    static LocalAuthenticator localAuthenticator;
    @Inject
    static LocalMessagingService localMessagingService;
    @Inject
    static OperationsMessagingService operationsMessagingService;

    public static LocalAuthenticator getLocalAuthenticator() {
        return localAuthenticator;
    }

    public static LocalMessagingService getLocalMessagingService() {
        return localMessagingService;
    }

    public static OperationsMessagingService getOperationsMessagingService() {
        return operationsMessagingService;
    }
}

为了简单的使用,我还创建了 Scala 对象,以便直接在模板中包含隐式变量。

package core.di.scala

object DIStaticFactory {
  implicit val operationsMessaging: OperationsMessagingService = core.di.DIStaticFactory.getOperationsMessagingService
  implicit val localAuth: LocalAuthenticator = core.di.DIStaticFactory.getLocalAuthenticator
  implicit val localMessaging: LocalMessagingService = core.di.DIStaticFactory.getLocalMessagingService
}

如 Guice 文档中所述,在 Guice 注入器启动时注入静态变量。一切都按预期进行。

在 Scala 模板中的使用很简单 ...

@import core.di.scala.DIStaticFactory._

@if(localAuth.getCurrentUser().hasPermission("debug.tweaker")) { .. do something ... }

不要忘记在 application.conf 中激活模块

【讨论】:

    【解决方案2】:

    我认为您可以尝试在视图上使用 ActionBuilder + 隐式参数来实现您的要求。 (我的回答基于我评论中的链接)。

    首先,您需要定义一个 ActionBuild,它根据请求从数据库或会话对象字段中提取当前用户,并将其添加到 WrappedRequest 的子类型中。

    //The subtype of WrapperRequest which now contains the username. 
    class UserRequest[A](val username: Option[String], request: Request[A]) extends WrappedRequest[A](request)
    
    object UserAction extends
      ActionBuilder[UserRequest] with ActionTransformer[Request, UserRequest] {
      def transform[A](request: Request[A]) = Future.successful {
        //request.session.get("username") in this example is the code to get the current user
        //you can do db access here or other means. 
        new UserRequest(request.session.get("username"), request)
      }
    }
    

    在您查看时,您将定义一个 UserRequest 类型的隐式参数:

    (message: String)(implicit h: UserRequest[AnyContent])
    
    @main("Welcome to Play") {
       //DISPLAY h.username
       @h.username
    }
    

    最后,在你的 Controller 上定义一个 requestHandler,它使用 UserAction 来暗示它的请求对象。

    // implicit user: UserRequest does the magic
    def index = UserAction { implicit user: UserRequest[AnyContent] =>
        Ok(views.html.index("Not Yet Implemented."))
    }
    

    希望对您有所帮助。

    更多关于 ActionBuilder:https://www.playframework.com/documentation/2.5.x/ScalaActionsComposition

    【讨论】:

    • 看起来很有希望。我正在使用 Java Play,但 ActionBuilder 也可用,所以我会试一试。谢谢。
    • 我在模板、控制器和服务上的几乎所有注入都是由implicits 或google guice 完成的:) 我认为这将满足您的要求。如果您认为这是您问题的答案,请标记。谢谢。
    • 好吧,我无法完成这个。我有一个基于 JAVA 的 Play,所以我不能在 Controller 中使用 Scala ActionBuild 和隐式变量。 Java API 中似乎没有这样的东西。 Java API 中有一个动作组合 (playframework.com/documentation/2.5.x/JavaActionsComposition) 还包括“将对象传递给控制器​​”,但是如何将对象传递给视图?
    • @LeoBufiBarrameda 你为什么要给一个java问题的scala答案?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-10
    • 1970-01-01
    • 2017-06-04
    • 2017-03-27
    • 2016-10-27
    相关资源
    最近更新 更多