2

我正在使用 Playframework 2.5 并尝试创建一个所有 Json 请求/响应控制器方法调用的方法,以避免implicit val foo = Json.writes[Bar] or reads[Bar]在每个控制器方法内部写入以及处理基本验证并返回错误代码。

BaseController 将被每个控制器继承

class BaseController @Inject()(implicit exec: ExecutionContext) extends Controller {
  def handleJson[T <: RequestModel,U <: ResponseModel](request: Request[JsValue])(cb: (T) => Future[U]):Future[Result] = {
    implicit val convertReq = Json.reads[T]
    implicit val convertRes = Json.writes[U]
    val reqOpt = request.body.asOpt[T]
    reqOpt match {
      case Some(data) =>
        cb(data).map{x => Ok(Json.toJson(x))}
      case None =>
        Future.successful(Ok(Json.obj("foo" -> "bar")))
    }
  }
}

控制器

  def send = Action.async(parse.json) { req =>
    handleJson[RequestCaseClass,ResponseCaseClass](req)( (x)  =>
      injectedClass.foo(x.bar).map{ case (success: Boolean,mes: String) =>
        if(success) SendRes(SomethingForSuccess)
        else SendRes(SomethingForError)
      }
    )
  }

上面的代码无法编译,因为handleJson'simplicit val convertReq = Json.reads[T]implicit val convertRes = Json.writes[U]

找不到类型 T 的 Json 反序列化器。尝试为此类型实现隐式读取或格式。

我已经尝试过制作案例类的伴生对象并将隐含的对象放入其中,尽管这并不能解决任何问题。

我的问题是,如何使用参数化类型的隐式值?

提前致谢。

4

2 回答 2

3

您可以在调用之前初始化implicit变量handleJson并将其设置convertReqconvertRes隐式方法参数handleJson

def send = Action.async(parse.json) { req =>
    implicit val convertReq = Json.reads[RequestCaseClass]
    implicit val convertRes = Json.writes[ResponseCaseClass]
    handleJson[RequestCaseClass,ResponseCaseClass](req)( (x)  =>
      injectedClass.foo(x.bar).map{ case (success: Boolean,mes: String) =>
        if(success) SendRes(SomethingForSuccess)
        else SendRes(SomethingForError)
      }
    )
}

def handleJson[T <: RequestModel,U <: ResponseModel](request: Request[JsValue])(cb: (T) => Future[U])(implicit convertReq: Reads, convertRes: Writes):Future[Result] = {
    val reqOpt = request.body.asOpt[T]
    reqOpt match {
      case Some(data) =>
        cb(data).map{x => Ok(Json.toJson(x))}
      case None =>
        Future(Ok(Json.obj("foo" -> "bar")))
    }
  }
于 2016-04-01T08:44:39.230 回答
3

我建议这样做

class Application @Inject()(implicit exec: ExecutionContext) extends Controller {
  def handleJson[A : Reads, B : Writes](request: Request[JsValue])(cb: A => Future[B]): Future[Result] = {
    val reqOpt = request.body.asOpt[A]
    reqOpt match {
      case Some(data) =>
        cb(data).map { x => Ok(Json.toJson(x)) }
      case None =>
        Future.successful(Ok(Json.obj("foo" -> "bar")))
    }
  }

  def index = Action.async(parse.json) { req =>
    handleJson[MyReq, MyResp](req)(x => Future.successful(MyResp((x.i to x.i + 4).toList)))
  }
}

你不必用任何特征来约束你的模型,只要隐含ReadsWrites存在就足够了。

为确保这一点,最好在类的伴生对象中定义你的Reads和。Writes当您导入模型类时,您会将它们带入隐式范围。

object MyReq {
  implicit val myReqReads: Reads[MyReq] = Json.reads[MyReq]
}
case class MyReq(i: Int)

object MyResp {
  implicit val myRespWrites: Writes[MyResp] = Json.writes[MyResp]
}
case class MyResp(l: List[Int])
于 2016-04-01T10:36:29.257 回答