Scala - 玩吧! 2 - 通用 Crud
Scala - Play! 2 - Generic Crud
我正在尝试创建一个通用的 crud 控制器,但我遇到了 json 问题。
我对我的每个域对象都有一个隐式读写,因为我的 crud 控制器是 "generic",我正在为它传递 T,这导致找不到类型 T 的隐式转换器。
这是我的 TestController
object AddressController extends Controller with CrudController[Address, AddressServiceModule] {
}
这是我的 CrudController
trait CrudController[T, K <: GenericServiceModule[T]] extends Controller {
var service: K = _
def get(uuid: String) = Action.async {
val future = service.genericService.getById(UUID.fromString(uuid))
future.map {
case Some(t) => Ok(Json.toJson(t))
case None => NotFound
}.recover {
case t =>
Logger.error("Something went wrong", t)
InternalServerError(t.getMessage)
}
}
}
然后我得到了
No Json serializer found for type T.
正如我所说,我的地址模型有读写功能
implicit val addressReads = Json.reads[Address]
implicit val addressWrites = Json.writes[Address]
但由于转换器是在编译时验证的,所以我不知道如何解决这种情况。没有机会用相同的逻辑编写 10、20 个 crud 控制器。
有什么想法吗?
更新
只是为了测试,我将 Ok(Json.toJson(t)) 更改为 Ok(t.toString) 然后我遇到了另一个问题...
我的服务上有一个 NullPointer
var service: K = _
我的 GenericServiceModule 如下:
trait GenericServiceModule[T] {
def genericService: GenericCommonService[T]
/**
* Common Services
* @tparam T
*/
trait GenericCommonService[T] {
def getById(uuid: UUID): Future[Option[T]]
def deleteById(uuid: UUID): Future[ResultSet]
def insert(t: T): (UUID, Future[ResultSet])
def update(uuid: UUID, t: T): (UUID, Future[ResultSet])
}
}
我传递给 AddressController 的 AddressServiceModule 如下:
trait AddressServiceModule extends GenericServiceModule[Address] with CassandraService {
object genericService extends GenericCommonService[Address] {
override def getById(uuid: UUID): Future[Option[Address]] = {
Address.select.where(_.id eqs uuid).one()
}
}
有没有办法通过我的 CrudController 注入这个服务?
如何为每个伴随对象使用某种特征来要求 Reads
和 Writes
?
trait CrudObject[T] {
val reads: Reads[T]
val writes: Writes[T]
}
例如:
object Address extends CrudObject[Address] {
implicit val reads: Reads[Address] = Json.reads[Address]
implicit val writes: Writes[Address] = Json.writes[Address]
// other code ..
}
然后在您的通用控制器中,需要引用伴随对象(由 CrudObject
特征标记)和 GenericServiceModule
。这不会完全使隐式解析工作,但是一旦你有了那个引用,你就可以依靠继承来使 Reads
和 Writes
在控制器中可用。
trait CrudController[T] extends Controller {
def service: GenericServiceModule[T]
def companion: CrudObject[T]
implicit def reads: Reads[T] = companion.reads
implicit def writes: Reads[T] = companion.writes
def get(uuid: String) = Action.async {
val future = service.genericService.getById(UUID.fromString(uuid))
future.map {
case Some(t) => Ok(Json.toJson(t))
case None => NotFound
}.recover {
case t =>
Logger.error("Something went wrong", t)
InternalServerError(t.getMessage)
}
}
}
那么您的实现可能如下所示:
object AddressController extends CrudController[Address] {
def service = AddressServiceModule
def companion = Address
}
我正在尝试创建一个通用的 crud 控制器,但我遇到了 json 问题。
我对我的每个域对象都有一个隐式读写,因为我的 crud 控制器是 "generic",我正在为它传递 T,这导致找不到类型 T 的隐式转换器。
这是我的 TestController
object AddressController extends Controller with CrudController[Address, AddressServiceModule] {
}
这是我的 CrudController
trait CrudController[T, K <: GenericServiceModule[T]] extends Controller {
var service: K = _
def get(uuid: String) = Action.async {
val future = service.genericService.getById(UUID.fromString(uuid))
future.map {
case Some(t) => Ok(Json.toJson(t))
case None => NotFound
}.recover {
case t =>
Logger.error("Something went wrong", t)
InternalServerError(t.getMessage)
}
}
}
然后我得到了
No Json serializer found for type T.
正如我所说,我的地址模型有读写功能
implicit val addressReads = Json.reads[Address]
implicit val addressWrites = Json.writes[Address]
但由于转换器是在编译时验证的,所以我不知道如何解决这种情况。没有机会用相同的逻辑编写 10、20 个 crud 控制器。
有什么想法吗?
更新
只是为了测试,我将 Ok(Json.toJson(t)) 更改为 Ok(t.toString) 然后我遇到了另一个问题...
我的服务上有一个 NullPointer
var service: K = _
我的 GenericServiceModule 如下:
trait GenericServiceModule[T] {
def genericService: GenericCommonService[T]
/**
* Common Services
* @tparam T
*/
trait GenericCommonService[T] {
def getById(uuid: UUID): Future[Option[T]]
def deleteById(uuid: UUID): Future[ResultSet]
def insert(t: T): (UUID, Future[ResultSet])
def update(uuid: UUID, t: T): (UUID, Future[ResultSet])
}
}
我传递给 AddressController 的 AddressServiceModule 如下:
trait AddressServiceModule extends GenericServiceModule[Address] with CassandraService {
object genericService extends GenericCommonService[Address] {
override def getById(uuid: UUID): Future[Option[Address]] = {
Address.select.where(_.id eqs uuid).one()
}
}
有没有办法通过我的 CrudController 注入这个服务?
如何为每个伴随对象使用某种特征来要求 Reads
和 Writes
?
trait CrudObject[T] {
val reads: Reads[T]
val writes: Writes[T]
}
例如:
object Address extends CrudObject[Address] {
implicit val reads: Reads[Address] = Json.reads[Address]
implicit val writes: Writes[Address] = Json.writes[Address]
// other code ..
}
然后在您的通用控制器中,需要引用伴随对象(由 CrudObject
特征标记)和 GenericServiceModule
。这不会完全使隐式解析工作,但是一旦你有了那个引用,你就可以依靠继承来使 Reads
和 Writes
在控制器中可用。
trait CrudController[T] extends Controller {
def service: GenericServiceModule[T]
def companion: CrudObject[T]
implicit def reads: Reads[T] = companion.reads
implicit def writes: Reads[T] = companion.writes
def get(uuid: String) = Action.async {
val future = service.genericService.getById(UUID.fromString(uuid))
future.map {
case Some(t) => Ok(Json.toJson(t))
case None => NotFound
}.recover {
case t =>
Logger.error("Something went wrong", t)
InternalServerError(t.getMessage)
}
}
}
那么您的实现可能如下所示:
object AddressController extends CrudController[Address] {
def service = AddressServiceModule
def companion = Address
}