您希望能够根据请求的标头值计算Result
包含类型对象的表示的 a 。您可以使用以下类型 trait对该功能进行编码: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"))
}
}
whereFoo
是一个简单的case类定义如下:
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
}
}
您可能希望通过抽象此模式来减少样板文件并避免用户忘记最后一个“case”语句。例如,您可以编写以下辅助方法来构建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))
}