播放框架:将结果转换为 Json

Play Framework: Transform Result to Json

如何在可重复使用的操作中将结果转换为 Json?

示例:

object JsonAction {

  def apply(block: Request[JsValue] => ???): Action[JsValue] = {
    Action(BodyParsers.parse.json) { request =>
      val result = block(request)

      val finalResult = result.copy(body = Json.toJson(result.body))

      finalResult
    }
  }
}

在我的控制器中:

def index = JsonAction { req =>
  Ok(new SomeModel(...))
}

我们的想法是能够将结果模型和表示分离为 json(或 xml,例如)。

我找不到很好的解决方案...

是这样的吗?

import play.api.libs.json._
import play.api.mvc._


object JsonAction extends Results {
  def apply[A, B](block: A => B)(implicit reads: Reads[A], writes: Writes[B]): Action[JsValue] =
    Action(BodyParsers.parse.json) { request =>
      val result = for {
        a <- Json.fromJson(request.body).asOpt
        b = block(a)
      } yield Ok(Json.toJson(b))
      result getOrElse InternalServerError(???)
    }
}

或者您想在块中手动定义结果状态

object JsonAction extends Results {
  def apply[A, B](block: A => (Option[(Status, B)]), 
                  noneStatus: Result = BadRequest("could not parse json"))
                 (implicit reads: Reads[A], writes: Writes[B]): Action[JsValue] =
    Action(BodyParsers.parse.json) { request =>
      val result = for {
        a <- Json.fromJson(request.body).asOpt
        (status, b) <- block(a)
      } yield status(Json.toJson(b))
      result getOrElse noneStatus
    }
}

object MathController {
  import JsonAction._
  def squareEquasion = JsonAction[Map[String, Double], Set[Double]] { map =>
    for {a <- map get "a"
         b <- map get "b"
         c <- map get "c"
         d = b * b - 4 * a * c} yield d match {
      case d if d < 0 => (InternalServerError, Set.empty[Double])
      case d if d == 0 => (Ok, Set(-b / 2 * a))
      case d if d > 0 => (Ok, Set(1, -1) map (q => (-b + q * math.sqrt(d)) / 2 * a))
    }
  }
}

和最后的尝试 - 这里我们使用 json.Writes 实例隐式提供 http.Writeable 的实例,并在该实例中将值转换为 JSON,因此我们可以使用 Result 临时工。如果类型有自己的 Writeable 实例(例如 String),这实际上可能会导致一些歧义:

import play.api.http.Writeable
import play.api.libs.json._
import play.api.mvc._

import scala.language.implicitConversions

object JsonAction {
  private object Res extends Results

  implicit def jsonWriteable[T](implicit writes: Writes[T]): Writeable[T] = {
    val jsonWriteable = implicitly[Writeable[JsValue]]
    def transform(obj: T) = jsonWriteable.transform(Json.toJson(obj))
    new Writeable[T](transform, jsonWriteable.contentType)
  }

  def apply[A, B](block: A => Option[Result],   noneStatus: Result = Res.BadRequest("could not parse json"))
                 (implicit reads: Reads[A], writes: Writes[B]): Action[JsValue] =
    Action(BodyParsers.parse.json) { request =>
      val result = for {
        a <- Json.fromJson(request.body).asOpt
        result <- block(a)
      } yield result
      result getOrElse noneStatus
    }
}

object MathController extends Results{
  import JsonAction._
  def squareEquasion = JsonAction[Map[String, Double], Set[Double]] { map =>
    for {a <- map get "a"
         b <- map get "b"
         c <- map get "c"
         d = b * b - 4 * a * c} yield d match {
      case d if d < 0 => InternalServerError("No answer")
      case d if d == 0 => Ok(Set(-b / 2 * a))
      case d if d > 0 => Ok(Set(1, -1) map (q => (-b + q * math.sqrt(d)) / 2 * a))
    }
  }
}