关于这个问题,我很好奇,可以怎么办请求后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用于发生基于接受报头后的请求。
要能够计算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))
}
一种选择是创造一种包装为的。
它应该是这样的:
//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
)
另一种选择是使用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进行了测试