gpt4 book ai didi

scala - 从 Controller 中重构业务逻辑的好习惯方法

转载 作者:行者123 更新时间:2023-12-04 02:05:31 25 4
gpt4 key购买 nike

我是 Scala 和 Play 的新手;我编写了一个包含业务和表示逻辑的“全部” Controller 。我想从 Controller 中重构业务逻辑。

这是我的 Scala/Play 的样子。用干净的界面重构出这个 Controller 的业务逻辑的好/惯用的方法是什么?

object NodeRender extends Controller {
...
def deleteNode(nodeId: Long) = Action { request =>
//business logic
val commitDocument = Json.toJson(
Map(
"delete" -> Seq( Map( "id" -> toJson( nodeId)))
))
val commitSend = Json.stringify( commitDocument)
val commitParams = Map( "commit" -> "true", "wt" -> "json")
val headers = Map( "Content-type" -> "application/json")

val sol = host( "127.0.0.1", 8080)
val updateReq = sol / "solr-store" / "collection1" / "update" / "json" <<?
commitParams <:< headers << commitSend

val commitResponse = Http( updateReq)()

//presentation logic
Redirect( routes.NodeRender.listNodes)
}

在 Python/Django 中,我编写了两个类 XApiHandlerXBackend并在它们之间使用干净的界面。
xb = XBackend( user).do_stuff()
if not xb:
return a_404_error
else:
return the_right_stuff( xb.content) #please dont assume its a view!

最佳答案

几个假设:

1)你的倒数第二行 block 上的 HTTP 调用

2)您没有说重定向是否需要等待来自 Http 调用的响应,但我认为确实如此。

阻塞调用应该移到另一个线程,这样你就不会阻塞处理请求的线程。 Play 文档对此非常具体。 Akka.future功能结合 Async有帮助。

Controller 代码:

1 def deleteNode(nodeId: Long) = Action { request =>
2 Async{
3 val response = Akka.future( BusinessService.businessLogic(nodeId) )
4
5 response.map { result =>
6 result map {
7 Redirect( routes.NodeRender.listNodes)
8 } recover {
9 InternalServerError("Failed due to ...")
10 } get
11 }
12 }
13}

这比你的 PHP 多一点,但它是多线程的。

传递给 Akka.future 的代码第 3 行将在 future 某个时间使用不同的线程调用。但是调用 Akka.future立即返回 Future[Try] (业务方法的返回类型见下文)。这意味着变量 response类型为 Future[Try] .调用 map第 5 行的方法不会调用 map block 内的代码,而是将该代码(第 6-10 行)注册为回调。线程不会在第 5 行阻塞并返回 FutureAsync堵塞。 Async block 返回 AsyncResult到 Play 并告诉 Play 在 future 完成时为回调注册自己。

同时,其他一些线程将调用 BusinessService从第 3 行开始,一旦您对后端系统进行的 HTTP 调用返回, response第 3 行的变量是“已完成”,这意味着第 6-10 行的回调被调用。 result类型为 Try它是抽象的,只有两个子类: SuccessFailure .如果 result是成功的,那么 map方法调用第 7 行并将其包装在新的 Success 中.如果 result是失败,则 map 方法返回失败。 recover第 8 行的方法正好相反。如果 map 方法的结果是成功,则返回成功,否则调用第 9 行并将其包装在 Success 中。 (不是 Failure !)。调用 get第 10 行的方法从 Success 中取出重定向或错误。并且该值用于完成 AsyncResult Play 坚持的。 Play 然后会收到一个回调,表明响应已准备好并且可以呈现和发送。

使用此解决方案,服务传入请求的线程不会被阻塞。这很重要,因为例如在 4 核机器上,Play 只有 8 个线程能够处理传入请求。它不会产生任何新的,至少在使用默认配置时不会。

这是来自业务服务对象的代码(几乎复制了您的代码):
def businessLogic(nodeId: Long): Future[Try] {

val commitDocument = Json.toJson(
Map(
"delete" -> Seq( Map( "id" -> toJson( nodeId)))
))
val commitSend = Json.stringify( commitDocument)
val commitParams = Map( "commit" -> "true", "wt" -> "json")
val headers = Map( "Content-type" -> "application/json")

val sol = host( "127.0.0.1", 8080)
val updateReq = sol / "solr-store" / "collection1" / "update" / "json" <<?
commitParams <:< headers << commitSend

val commitResponse = Http( updateReq)()

Success(commitResponse) //return the response or null, doesnt really matter so long as its wrapped in a successful Try
}

表示逻辑和业务逻辑现在完全解耦了。

https://speakerdeck.com/heathermiller/futures-and-promises-in-scala-2-dot-10http://docs.scala-lang.org/overviews/core/futures.html了解更多信息。

关于scala - 从 Controller 中重构业务逻辑的好习惯方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15230896/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com