我正在尝试处理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检索。所以我在圈子里跑: - )
答案 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