2017-05-28 105 views
1

兩個未來的異步操作我討厭問 - 我真的,但這個已經讓我的那一刻..組合與輸出在屏幕上

我想創作一些動作(在播放框架 & scala)與我的主要指南是this vid。然而,它是在幾年前取得的,因此一些功能已經被棄用,因此我必須隨時找到解決方法。目前我正在嘗試在某些HTML標記中輸出兩個異步操作。

我成功地輸出一個動作與此控制器:

package controllers 

import akka.actor.ActorSystem 
import javax.inject._ 
import play.api.mvc._ 
import services.ServiceClient 
import scala.concurrent.ExecutionContext 

@Singleton 
class AsyncController @Inject() (sc: ServiceClient)(actorSystem: ActorSystem)(implicit exec: ExecutionContext) extends Controller { 

    def index = Action.async { request => 

    val asy1 = sc.makeServiceCall("async1") 

    for { 
     async1Message <- asy1 
    } yield { 
     Ok(views.html.async1.async1(async1Message)) 
    } 
    } 

} 

在你想知道的sc.makeServiceCall情況下指的是這個文件:

class ServiceClient @Inject() (ws: WSClient) { 

    def makeServiceCall(serviceName: String): Future[String] = { 
    ws.url(s"http://localhost:9000/mock/$serviceName").get().map(_.body) 
    } 

} 

所以我也跟着在其指導視頻撰寫兩個與一些HTML的異步操作。這是它變得難以/有趣/鐓:

package controllers 

import javax.inject.Inject 
import akka.actor.ActorSystem 
import play.api.mvc._ 
import scala.concurrent.{ExecutionContext} 
import Ui.Pagelet 

class AsyncHomeController @Inject() (as1: AsyncController)(as2: Async2Controller)(actorSystem: ActorSystem)(implicit exec: ExecutionContext) extends Controller { 

    def index = Action.async { request => 

    val asy1 = as1.index(request) 
    val asy2 = as2.index(request) 

    for { 
     async1Result <- asy1 
     async2Result <- asy2 

     async1Body <- Pagelet.readBody(async1Result) 
     async2Body <- Pagelet.readBody(async2Result) 

    } yield { 
     Ok(views.html.home2(async1Body, async2Body)) 
    } 
    } 

} 

所以Async2Controller非常相似AsyncControllerPagelet.readBody指的是這樣的:

package Ui 

import play.api.libs.iteratee.Iteratee 
import play.api.mvc.{Codec, Result} 
import play.twirl.api.Html 
import scala.concurrent._ 

object Pagelet { 

    def readBody(result: Result)(implicit codec: Codec): Future[Html] = { 
    result.body.run(Iteratee.consume()).map(bytes => Html(new String(bytes, codec.charset))) 
    } 

} 

,這是其中的錯誤所在 - 那就是:

值運行是不play.api.http.HttpEntity

的成員

我無法找到它是否需要注入文檔或任何跡象,因爲它已被棄用。 如果有人得到了這個或解決方法的答案,請泄露。非常感謝

+0

這可能是一個問題與不同的版本。視頻相當古老。 – Zernike

+0

是@Zemike - 這不是一個兼容性問題,但是現在視頻已經有幾年了。這就是我尋找現代替代解決方案的原因。 –

回答

0

Iteratee lib已棄用,由akka-stream替代。您需要更改的readBody實現:

def readBody(result: Result)(implicit mat: Materializer, ec: ExecutionContext, codec: Codec): Future[Html] = { 
    result.body.consumeData.map(byteString => Html(codec.decode(byteString)) 
} 

您還需要改變控制器的依賴性獲得Materializer

class AsyncHomeController @Inject() (as1: AsyncController, as2: Async2Controller)(actorSystem: ActorSystem)(implicit exec: ExecutionContext, mat: Materializer) 

編輯:代碼更新

+0

謝謝 - 這似乎很接近,但我得到這個錯誤***方法consumeData ***沒有足夠的參數,所以我做了這個'def readBody(result:Result)(隱含mat:Materializer,編解碼器:編解碼器):Future [Html] = { result.body.consumeData(mat).map(byteString => Html(codec.decode(byteString))) }然後引發這個錯誤 - ***找不到隱含的ExecutionContext ***。當然,如果我把它作爲一個隱含的含義,那麼它會導致另一個隱含的問題,所以我很難得到正確的組合。感覺就像我們越來越接近了。 –

+0

感謝您的更新 - 幾乎錯過了它。像這樣實現它會導致***無法找到參數mat的隱式值:akka.stream.Materializer ***,儘管導入它的錯誤。所以使用這種技術時,我必須在每次調用看起來不正確的函數時將「Materializer」作爲參數傳遞。然而,我通過創建'implicit val system = ActorSystem();在* Object *中隱式地使用val mat = ActorMaterializer()'並像以前一樣在方法內傳遞它,即'consumeData(mat)',但這看起來也很冗長 –

+0

通過這樣做,您創建了一個'ActorSystem'和一個'Materializer '但玩已經有一個。在你的控制器中,你需要告訴play注入一個:'AsyncHomeController @Inject()(as1:AsyncController,as2:Async2Controller)(actorSystem:ActorSystem)(隱式exec:ExecutionContext,mat:Materializer)' – vdebergue