恢复未来时,在Play控制器操作中键入不匹配

时间:2017-03-28 22:11:01

标签: scala playframework controller future partialfunction

我在scala play控制器方法中返回正确的类型有问题,有人可以在这里给我一个提示吗?我正在使用comprehantion来处理两个返回Future的服务方法,我想优雅地处理结果和错误。

这样做的最佳做法是什么?

test2.reset_index(inplace=True)
test2['index'] = test2['index'].dt.tz_localize('UTC').dt.tz_convert('US/Eastern').dt.tz_localize(None)

                index groups  value
0 2016-08-31 18:08:12      A      1
1 2016-08-31 18:08:12    NaN      1
2                 NaT      A      3

错误:

 def registerUser = Action { implicit request =>
    Logger.info("Start play actoin")

    RegisterForm.form.bindFromRequest.fold(
      formWithErrors => {
        BadRequest(views.html.register(formWithErrors))
      },
      formData => {

        val registerResult = for {
          reCaptchaOk <- registerUserService.checkRecaptcha(formData.gRecaptchaResponse)
          userId <- registerUserService.registerUser(formData) if reCaptchaOk
        } yield userId

        registerResult.map(
          result => Redirect(routes.DashboardController.dashboard).withSession("USER_ID" -> result.toString))
        .recover{
          e => handleRegisterError(e)
        }

      })

  }

  def handleRegisterError(cause: Throwable)(implicit request: Request[_]) : Result = {
    val form = RegisterForm.form.bindFromRequest
    cause match {
      case dae: DataAccessException =>
        val globalError = dae.getCause.asInstanceOf[PSQLException].getSQLState match {
          case "23505" => GlobalMessages(Seq(GlobalMessage(Messages("errors.db.userAlreadyExists") ,ERROR)))
          case _ => GlobalMessages(Seq(GlobalMessage(Messages("errors.system.error"),ERROR)))
        }
        BadRequest(views.html.register(form,globalError))
      case _ =>
        BadRequest(views.html.register(form))
    }

1 个答案:

答案 0 :(得分:1)

简短回答

您需要部分功能来恢复未来的故障:

    def handleRegisterError(implicit request: Request[_]): PartialFunction[Throwable, Result] = {
      case dae: DataAccessException =>
        val form = RegisterForm.form.bindFromRequest
        val globalError = dae.getCause.asInstanceOf[PSQLException].getSQLState match {
          case "23505" => GlobalMessages(Seq(GlobalMessage(Messages("errors.db.userAlreadyExists"), ERROR)))
          case _ => GlobalMessages(Seq(GlobalMessage(Messages("errors.system.error"), ERROR)))
        }
        BadRequest(views.html.register(form, globalError))
      case _ =>
        val form = RegisterForm.form.bindFromRequest
        BadRequest(views.html.register(form))
    }

然后将控制器代码更改为

  registerResult
    .map { result => 
      Redirect(routes.DashboardController.dashboard).withSession("USER_ID" -> result.toString)
    }
    .recover { 
      handleRegisterError
    }

另请注意,您需要异步操作,即

def registerUser = Action.async { implicit request =>
  ...
}

因为您没有返回Result而是Future[Result]。您可以在Play docs中找到有关操作的更多信息。

详细

如果您查看recover的{​​{1}}方法的文档(请参阅here),您会发现它需要Future

部分函数就像普通函数一样,但它们可能会拒绝某些值(例如,这里,recover方法不接受所有异常,只接受正文中指定的异常)。 定义部分函数需要特殊的语法。它非常像模式匹配,但没有匹配表达式。

pf: PartialFunction[Throwable, U]

这里我们使用内联的部分恢复函数,因此将自动推断类型,但如果要将recover定义为单独的函数,则需要显式声明其类型。

高级

在大多数情况下,部分函数语法(没有Future(someAsyncWork).recover { case my: MyException => .... case _ => .... } 关键字的模式匹配)非常简洁和方便,但有时您需要更多。

例如,请注意使用此语法,我们必须在recover函数中复制部分代码(match)。

虽然在您的情况下可能有更好的解决方案,但您始终可以将普通功能转换为部分功能。首先,您需要定义类型val form = RegisterForm.form.bindFromRequest的函数,然后您可以使用Function#unlift将其转换为所需的部分函数。 您也可以直接从PartialFunction继承并实施其两种方法(applyisDefinedAt)。