异步等待 Playframework (2.4-M3) 和 Slick (3.0.0-RC3) 中的数据库值

Asynchronous wait for database-value in Playframework (2.4-M3) and Slick (3.0.0-RC3)

我想让我的应用程序尽可能异步。现在我有了这个存储库:

object LanguageRepository extends LanguageRepositoryTrait
{
    private val languages = TableQuery[Languages]
    private def db:Database = Database.forDataSource(DB.getDataSource())

    private def filterQuery(id: Long): Query[Languages, Language, Seq] = languages.filter(_.id === id)
    private def filterCode(code: String): Query[Languages, Language, Seq] = languages.filter(_.code === code)
    private def all() : Query[Languages, Language, Seq] = languages

    override def find(id: Long): Future[Language]  =
    {
        try db.run(filterQuery(id).result.head)
        finally db.close()
    }

    override def find(code: String): Future[Language] =
    {
        try db.run(filterCode(code).result.head)
        finally db.close()
    }

    override def get(): Future[Seq[Language]] =
    {
        try db.run(all().result)
        finally db.close()
    }
}

当我像 "domain.tld/{language}" 这样调用 url 时,我想检查给定的语言(代码)是否确实存在。比如,如果该站点没有法语版 (fr),我想抛出异常或 404。

现在,我的问题是整个异步过程非常酷,虽然我确实想理解它背后的理论,但我现在很困惑。我的意思是,我希望它是非阻塞的(并且是异步的,这就是我使用 Future 和 async 的原因 ;))

在我的控制器中,我想做类似的事情:

def checkLanguage(language:String) = Action
{
  val lang:Future[Language] = languageRepository.find(language)

 lang.onComplete
 {
   case Success(s) = Ok("Yay")
   case Failure(f) = 404("Oh no!")
 }
}

当然这行不通,但这是我想让事情正常进行的模式。我想等待或推迟网站的呈现,直到确认给定的语言代码有效或无效。

我查看了 2.3.6 的 Playframeworks 异步文档 (https://www.playframework.com/documentation/2.3.6/ScalaAsync),但我无法真正让它按预期工作。

感谢任何意见!

试试这个,

Action.async {
    val lang:Future[Option[Language]] = languageRepository.find(language)
    lang.map {l => l.map{_ => Ok("Yay") }.getOrElse(NotFound("Oh no!"))
} 

首先,我假设如果有一种语言可能不存在,那么 languageRepository.find(language) 应该 return 和 LanguageOption。将 Future[Language] 更改为 Future[Result] 并使用 Action.async 而不是 Action

现在进行一些解释,Action 取一个块,其结果应该是 Result。然而,你得到的却是Future[Option[Language]]。 Play 为需要 Future[Result]Action 提供了 async 方法,它负责完成请求。

因此,您需要将 Future[Option[Language]] 转换为 Future[Result]

 lang.map {l => l.map{_ => Ok("Yay") }.getOrElse(NotFound("Oh no!"))

我们映射 lang,如果 Option[Language] 不是 None 那么我们将其转换为 Ok("yay") 否则我们将其转换为 NotFound

甚至,如果没有得到Option[Language],思路还是一样的。将 Future[Language] 转换为 Future[Result] 并使用 Action.async 而不是 Action

在您的数据库查询中,不要使用 .head,而是使用 .headOption。这样你的 return 类型将是 Future [Option [x]]

在你的控制器中你可以做这样的事情

Lang.map { case Some (x) => Ok (x)
  case None =>  404 ( "not found ")

}