4

この質問に関して、リクエスト後のREST処理をどのように行うことができるか興味があります(粗い):

def postProcessor[T](content: T) = {
  request match {
    case Accepts.Json() => asJson(content)
    case Accepts.Xml()  => asXml(content)
    case _ => content
  }
}

グローバル構成でonRouteRequestをオーバーライドしても、応答の本文へのアクセスは提供されないようです。そのため、応答をインターセプトして後処理タスクを実行するには、アクション構成が適しているように思われます。

質問: これは良い考えですか、それとも、キャストするタイプがわかっているコントローラー (または他のクラス) メソッド内でコンテンツ タイプのキャストを直接行う方がよいですか?

現在、私はこの種のことをどこでもやっています:

toJson( i18n("account not found") )
toJson( Map('orderNum-> orderNum) )

要求後の受け入れヘッダーに基づいて toJson/toXml 変換を行いたいのですが。

4

3 に答える 3

4

リクエストのヘッダー値に従ってResult、あるタイプのオブジェクトの表現を含むを計算できるようにしたいと考えています。この機能は、次の型特性でエンコードできます。AAccept

trait Repr[-A] {
  def render(a: A, request: RequestHeader): Result
}

次に、次のヘルパー トレイトを使用して、コントローラーから任意のリソースをレンダリングできます。

trait ReprSupport {
  def repr[A](a: A)(implicit request: RequestHeader, repr: Repr[A]) =
    repr.render(a, request)
}

object MyApp extends Controller with ReprSupport {
  def index = Action { implicit request =>
    repr(Foo("bar"))
  }
}

WhereFooは、次のように定義された単純なケース クラスです。

case class Foo(bar: String)

上記のコードをコンパイルできるようにするにはRepr[Foo]、暗黙的なスコープに type の値が必要です。最初の実装は次のように記述できます。

object Foo extends AcceptExtractors {
  implicit val fooRepr = new Repr[Foo] {
    def render(foo: Foo, request: RequestHeader): Result = request match {
      case Accepts.Html() => Ok(views.html.foo(foo)) // Assumes there is a foo.scala.html template taking just one parameter of type Foo
      case Accepts.Json() => Ok(Json.obj("bar" -> foo.bar))
      case _ => NotAcceptable
    }
  }
}

Reprただし、インスタンスを作成するデータ型ごとに、renderメソッドは同じパターンに従います。

implicit val somethingRepr = new Repr[Something] {
  def render(value: Something, request: RequestHeader): Result = request match {
    // <Some interesting code> (e.g. case Accepts.Html() => Ok(views.html.something(value)))
    case _ => NotAcceptable
  }
}

このパターンを抽象化することで、ボイラープレートを削減し、ユーザーが最後の「ケース」ステートメントを忘れないようにする必要があります。たとえば、次のヘルパー メソッドを記述して を構築できますRepr[Something]

object Repr {
  def apply[A](f: PartialFunction[RequestHeader, A => Result]): Repr[A] = new Repr[A] {
    def render(a: A, request: RequestHeader): Result =
      if (f.isDefinedAt(request)) f(request)(a)
      else NotAcceptable
  }
}

したがって、次のように記述して を取得するだけですRepr[Foo]

implicit val fooRepr = Repr[Foo] {
  case Accepts.Html() => foo => Ok(views.html.foo(foo))
  case Accepts.Json() => foo => Ok(Json.obj("bar" -> foo.bar))
}
于 2012-06-17T21:28:15.187 に答える
1

1 つのオプションは、そのための一種のラッパーを作成することです。

次のようになります。

  //THE WRAPPER that takes the action computation and the formatter
  def acceptEnabledAction[A]: (RequestHeader => A, (RequestHeader, A) => Result) => Action[AnyContent] =
     (a, f) => 
        Action { request => 
            f(request, a(request))
        }

  //a sample formatter
  val encoder = (r, r) => r.accept /*or smthg*/ match {
        case x if x == "text/json" || x == "application/json" => Ok(toJson(r)) /*dummy to json*/
        case x if x == "text/xml" || x == "application/xml"   => Ok(toXml(r)) /*dummy to xml*/
        case _ => BadRequest("not accepted")
      }


  //an action using it    
  def index = acceptEnabledAction[Map[String, Boolean]](
      rh => /*the real action content is here*/Map("a" -> true), 
      encoder
    )
于 2012-06-16T21:11:21.103 に答える
0

別のオプションはmimerenderモジュールを使用することです (開示: 私が書きました)。マッピングを一度定義します。

val m = mapping(
  "text/html" -> { s: String => views.html.index(s) },
  "application/xml" -> { s: String => <message>{s}</message> },
  "application/json" -> { s: String => toJson(Map("message" -> toJson(s))) },
  "text/plain" -> identity[String]_
)

すべてのコントローラーで再利用するだけです。

object Application extends Controller {
  def index = Action { implicit request =>
    m.status(200)("Hello, world!")
  }
}

注: これは非常に初期のリリースであり、Play 2.0.4 でのみテストされています。

于 2012-12-12T22:20:01.110 に答える