玩法 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依赖注入高级玩法——如何注入多个服务实现类