玩法 2.5:模板中的依赖注入

Posted

技术标签:

【中文标题】玩法 2.5:模板中的依赖注入【英文标题】:Play 2.5: Depedency injection in templates 【发布时间】: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 来检索。所以我在兜圈子:-)

【问题讨论】:

也许这会有所帮助:***.com/questions/9629250/… 【参考方案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答案?

以上是关于玩法 2.5:模板中的依赖注入的主要内容,如果未能解决你的问题,请参考以下文章

ASP.NET Core依赖注入高级玩法——如何注入多个服务实现类

ASP.NET Core依赖注入高级玩法——如何注入多个服务实现类

再说php依赖注入

ASP.NET Core中的依赖注入:依赖注入(DI)

如何使用 Angular 中的依赖注入将属性指令实例传递给嵌套组件

为什么喜欢模板方法而非依赖注入?