当前位置: 首页 > 知识库问答 >
问题:

基于请求参数的Scala Play运行时注入

孙星鹏
2023-03-14

我正在使用Scala Play 2.6,并尝试使用依赖注入来实例化基于请求参数的服务类。如下面的示例代码所示,控制器类从查询字符串中获取支付方法

package controllers

import com.google.inject.Inject
import play.api.mvc._
import scala.concurrent.ExecutionContext

class PaymentController @Inject()()
                                 (implicit ec: ExecutionContext)
  extends InjectedController  {

  def doPayment() = Action.async { implicit request =>
    request.getQueryString("payment-method").getOrElse("") match {
      case "paypal" => // Inject a PaypalPaymentService
        val paymentService = Play.current.injector.instanceOf[PaypalPaymentService]
        paymentService.processPayment()

      case "creditcard" => // Inject a CreditCardPaymentService
        val paymentService = Play.current.injector.instanceOf[CreditCardPaymentService]
        paymentService.processPayment()

      case _ => // Return error
    }
  }
}

以及处理PayPal或信用卡付款的服务类

package services

import scala.concurrent.Future

trait PaymentService {    
  def processPayment(): Future[Boolean]    
}

package services

import com.google.inject.Inject
import scala.concurrent.{ExecutionContext, Future}
import play.api.libs.ws.WSClient

class PaypalPaymentService @Inject()(ws: WSClient)
                                     (implicit ec: ExecutionContext)
  extends PaymentService {

  def processPayment(): Future[Boolean] = {
    //Process paypal payment
  }
}

class CreditCardPaymentService @Inject()(ws: WSClient)
                                    (implicit ec: ExecutionContext)
  extends PaymentService {

  def processPayment(): Future[Boolean] = {
    //Process credit card payment

  }
}

对于Play 2.5以后的版本,<code>Play。当前和播放。应用程序已被弃用。

我有两个问题:

  1. 上面的示例代码是基于请求参数注入类的正确方法吗?还是有其他更好的方法?
  2. 对于Play 2.5/2.6,获得应用注射器的方式是什么?

共有1个答案

万俟靖
2023-03-14

您已经正确地说明了Play.currentPlay.application已经被弃用,从2.5开始,使用它们的方式确实是通过注入它们。

我将更改您的控制器定义,以便您使用DI来包括所需的组件。类似于:

class PaymentController @Inject()(configuration: Configuration)
                                 (implicit ec: ExecutionContext) extends Controller  {


  // your code goes here
}

现在是棘手的部分。您可能会认为可以只注入应用程序:播放。应用程序,但这并不完全正确,因为您将遇到循环依赖项。这是正常的,因为您希望在实际进入应用程序时注入整个应用程序。有一个黑客,它是通过注入提供者[应用程序]。我称之为黑客,因为通常您不需要/不想注入整个应用程序。在 99% 的情况下,您只对特定部分感兴趣 - 例如配置环境等。

解决方案来了。您只需注射注射

class PaymentController @Inject()(injector: Injector)
                                 (implicit ec: ExecutionContext) extends Controller  {

  // your code goes here
}

从这里看,这场比赛很容易。只需使用Injector即可获得所需的服务。这样地:

case "paypal" => // Inject a PaypalPaymentService
      val paymentService = injector.instanceOf(classOf[PaypalPaymentService])
      paymentService.processPayment()

最后一句话是关于“正确的使用方法”。我实际上觉得你的方法还可以,不一定会改变。这个方向上的一个想法是,您创建一个模块,如下所示:

import com.google.inject.AbstractModule
import com.google.inject.name.Names

class PaymentModule extends AbstractModule {
  def configure() = {

    bind(classOf[PaymentService])
      .annotatedWith(Names.named("paypal"))
      .to(classOf[PaypalPaymentService])

    bind(classOf[PaymentService])
      .annotatedWith(Names.named("creditcard"))
      .to(classOf[CreditCardPaymentService])
  }
}

在这种情况下,拥有一个共同的特性(正如你所做的那样)会有所帮助,你可以有多个实现,甚至可以为你的测试模拟实现。如果模块位于根包中,则将自动注册该模块。否则,你应该告诉Play它的位置:

play.modules.enabled="模块.支付模块"

 类似资料:
  • 我正在开发的应用程序已经具有Spring Security来处理基于表单的身份验证。现在,如果在某个请求参数中发现了令牌,则需要通过外部服务以编程方式登录用户。 换句话说,如果存在一个特定的请求参数,比如“token”,它需要用该令牌调用一个外部服务来验证它是否是一个有效的令牌。如果是,则用户将登录。 我不知道如何以及在哪里“触发”或“挂钩”Spring Security来检查这个参数并进行验证,

  • 可以在模板中直接使用$Request对象,直接输入它的属性或调用它的大部分方法,但只支持方法的第一个参数; // 调用Request对象的get方法 传入参数为id {$Request.get.id} // 调用Request对象的param方法 传入参数为name {$Request.param.name} // 调用Request对象的param方法 传入参数为post.post_title

  • 可以在模板中直接使用$Request对象,直接输入它的属性或调用它的大部分方法,但只支持方法的第一个参数; // 调用Request对象的get方法 传入参数为id {$Request.get.id} // 调用Request对象的param方法 传入参数为name {$Request.param.name} // 调用Request对象的param方法 传入参数为post.post_title

  • 我已经浪费了10个小时试图弄明白一件简单的事情。 我有一个反应前端和一个Spring Boot后端在端口8080上运行。 我在前端有自己的登录表单。 在一个理想的世界里,我所希望的是让Spring Boot像往常一样进行表单验证,而没有那个丑陋的引导表单。 我设置了一个基本的内存身份验证只是为了练习,但它根本不起作用 我有两个选择: > 在Restendpoint中处理身份验证,然后将安全上下文设

  • 问题内容: 而且我正在尝试更改方法注释,但是java.lang.reflect.Method不包含任何地图字段(例如“ annotations”)或方法(例如“ getDeclaredAnnotationMap”) 只有但是我可以用这个字节数组做什么? 那么,如何修改方法的注释呢? 编辑: 我创建了:http : //pastebin.com/T2rewcwU 但是,仅编辑此方法实例,如果取消注释

  • 我试图写一个Spring MVC GET控制器,它需要Java8即时作为请求参数: 与: 我正在从一些React/Javascript代码触发一个GET请求,如下所示: Spring似乎不喜欢它,并抛出一个错误。以下是错误消息: 知道我为什么会收到这个吗? 谢谢你