Play 2.5:模板中的Depedency注入

时间:2016-10-06 11:45:05

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

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

我有一个模板系统,其中我有最小HTML基础的布局模板,几乎所有其他HTML模板都包含了一个模板,这些模板构建了HTML主体的其余部分。

在模板中,我还包括顶级菜单" Logout"按钮,还有一个当前登录用户的名称。

我有一个名为LocalAuthenticator的单例对象,它提供包含用户名的User对象。到目前为止,我正在使用依赖注入使用辅助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并将其传递给模板,但是这个对象应该出现在所有模板中,将它注入每个控制器都非常烦人。

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

我试图在helper对象中获取注入器以获得单例,但只有当我有Play Application对象时才能这样做。而这只能使用DI检索。所以我在圈子里跑: - )

2 个答案:

答案 0 :(得分: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中激活模块

答案 1 :(得分:0)

我认为您可以尝试在视图上使用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上定义一个使用UserAction的requestHandler,它暗示了它的请求对象。

// 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