玩2.0的RESTful请求的后处理(Play 2.0 RESTful request post-p

2019-07-29 23:36发布

关于这个问题,我很好奇,可以怎么办请求后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用于发生基于接受报头后的请求。

Answer 1:

要能够计算Result包含一个类型的对象的表示A根据所述请求的Accept标头值。 您可以编码这种能力与以下类型特点

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"))
  }
}

其中Foo是定义如下一个简单的例子类:

case class Foo(bar: String)

为了能够编译上面的代码,你需要有类型的值Repr[Foo]在您的默许范围。 第一种实现可以写成如下:

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))
}


Answer 2:

一种选择是创造一种包装为的。

它应该是这样的:

  //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
    )


Answer 3:

另一种选择是使用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!")
  }
}

注:这是一个非常早期版本,并只播放2.0.4进行了测试



文章来源: Play 2.0 RESTful request post-processing