Play framework + Scala:使用动作组合注入依赖
Posted
技术标签:
【中文标题】Play framework + Scala:使用动作组合注入依赖【英文标题】:Play framework + Scala: Inject dependency using Action Composition 【发布时间】:2014-10-23 19:26:47 【问题描述】:我正在设置 Play!我们的 API 应用程序。该 API 封装了不同的服务。我想将这些服务注入到一个动作中,但只注入该特定端点所需的那些。比如:
object Application extends Controller
def index = (UsersAction andThen OrdersAction)
// boom UsersService and OrdersService is available here
for
users <- usersService.list
orders <- ordersService.list
yield "whatever"
我一直在玩这个想法并使用 ActionTransformers 我能够将传入的请求转换为具有给定服务的请求,但我不知道如何使该请求足够通用,以便我可以编写这些以任意顺序执行操作,而不为 WrapperRequests 的所有可能组合创建 ActionTransformers。
也许动作组合并不是实现这一目标的最佳方式。我全神贯注。
谢谢
更新:
为了澄清,上面的代码是伪代码,理想的场景,其中 usersService 和 ordersService 可用于该范围(隐含?我不知道)。如果那是不可能的,那么无论在该样本顶部添加较少量的噪声,都可以。谢谢
【问题讨论】:
你有显示UsersAction
和OrdersAction
示例的代码(简化版)
这只是伪代码。我一直在玩动作组合,试图按照这里的例子做一些事情:playframework.com/documentation/2.3.5/ScalaActionsComposition
我问的原因是我看不到您打算如何使usersService
和ordersService
可用。您想在哪里指定它们以及如何使它们可用于您的操作主体?
这是问题的一部分 ^^U 意思是,类似伪代码中的内容是理想的,然后我们必须根据需要添加更多代码以使其编译。对困惑感到抱歉。我会澄清的。
【参考方案1】:
我最接近您的问题的是:
def index =
new UsersAction with OrdersAction
def body =
for
users <- userService.list
orders <- orderService.list
yield Ok("whatever")
实现非常简单
trait CustomAction extends Action[AnyContent]
def body: Future[Result]
def apply(request: Request[AnyContent]): Future[Result] = body
val parser = BodyParsers.parse.anyContent
trait UsersAction extends CustomAction
val userService: UserService = ???
trait OrdersAction extends CustomAction
val orderService: OrderService = ???
这些是我用来编译它的其他部分:
trait User
trait Order
trait UserService
def list: Future[Seq[User]]
trait OrderService
def list: Future[Seq[Order]]
【讨论】:
哇,谢谢!我会将其标记为已接受。我看到这种方法的唯一问题(我认为)是我们失去了执行 Action.asycn 等的能力。这能解决吗? 是async
,正文输入为Future[Result]
【参考方案2】:
您可以通过 guice、spring 或您想要的方式进行注入。 guice 的例子。 只需将对象更改为类:
class Application @Inject(userAction:UsersAction,ordersAction:OrdersAction) extends Controller
def index = (UsersAction andThen OrdersAction)
// boom UsersService and OrdersService is available here
for
users <- usersService.list
orders <- ordersService.list
yield "whatever"
您必须在全局中覆盖:
object Global extends GlobalSettings
private lazy val injector = Guice.createInjector(new CommonModule)
override def getControllerInstance[A](clazz: Class[A]) =
injector.getInstance(clazz)
class CommonModule extends AbstractModule
protected def configure()
bind(classOf[UsersAction]).to(classOf[UsersActionImpl])
bind(classOf[OrdersAction]).to(classOf[OrdersActionImpl])
在路由文件中添加@到控制器:
GET /service @controllers.Application.index
【讨论】:
感谢您的回复。我希望在端点的基础上注入每个依赖项,而不是在控制器中全局注入。换句话说,我只希望某个端点能够访问给定的依赖项,而不使该依赖项可用于同一控制器中的端点。 那为什么不使用不同的控制器呢? 如果您想要请求特定服务 - 只需使用 [工厂方法设计模式](或带有输入参数的修改版本)或提供程序。在游戏世界中 - 您不能使用请求范围 guice 提供程序 - 但您可以实现它。以上是关于Play framework + Scala:使用动作组合注入依赖的主要内容,如果未能解决你的问题,请参考以下文章
如何将 IntelliJ 与 Play Framework 和 Scala 一起使用
Play Framework Routes 中的 Scala 反引号
在 Play Framework 2.4 中为 Scala 实现 Akka