我正在尝试在 Play2 中实现一个控制器,它为我的数据库表公开了一个简单的 REST 样式的 api。我使用squeryl进行数据库访问,并使用spray-json 将对象转换为 json
我的想法是有一个通用控制器来完成所有的工作,所以我在中设置了以下路线conf/routes
:
GET /:tableName controllers.Crud.getAll(tableName)
GET /:tableName/:primaryKey controllers.Crud.getSingle(tableName, primaryKey)
..和以下控制器:
object Crud extends Controller {
def getAll(tableName: String) = Action {..}
def getSingle(tableName: String, primaryKey: Long) = Action {..}
}
(是的,缺少创建/更新/删除,但让我们先阅读工作)
我已经通过扩展的 squeryl 将表映射到案例类Schema
:
object MyDB extends Schema {
val accountsTable = table[Account]("accounts")
val customersTable = table[Customer]("customers")
}
我已经告诉 spray-json 我的案例类,所以它知道如何转换它们。
object MyJsonProtocol extends DefaultJsonProtocol {
implicit val accountFormat = jsonFormat8(Account)
implicit val customerFormat = jsonFormat4(Customer)
}
到目前为止一切顺利,只要我直接使用表实例,它实际上工作得很好。当我尝试生成代码时,问题就出现了,这样我最终得到了一个用于访问所有表的控制器:我遇到了一些无法编译的代码,我不确定下一步是什么。
这似乎是 spray-json 的类型问题,当我试图在我的getAll
函数中将对象列表转换为 json 时会发生这种问题。
这是我的一般尝试:
def getAll(tableName: String) = Action {
val json = inTransaction {
// lookup table based on url
val table = MyDB.tables.find( t => t.name == tableName).get
// execute select all and convert to json
from(table)(t =>
select(t)
).toList.toJson // causes compile error
}
// convert json to string and set correct content type
Ok(json.compactPrint).as(JSON)
}
编译错误:
[error] /Users/code/api/app/controllers/Crud.scala:29:
Cannot find JsonWriter or JsonFormat type class for List[_$2]
[error] ).toList.toJson
[error] ^
[error] one error found
我猜这个问题可能是 json-library 需要在编译时知道我要扔给它的模型类型,但我不确定(注意List[_$2]
那个编译错误)。我已尝试对编译并返回结果的代码进行以下更改:
- 删除通用的表查找 (
MyDB.tables.find(.....).get
) 并改用特定的表实例,例如MyDB.accountsTable
. 证明 JSON 序列化工作。但是,这不是通用的,需要一个唯一的控制器和 db 中每个表的路由配置。 - 在调用 toJson 之前将对象列表从 db 查询转换为字符串。即:
toList.toJson
-->toList.toString.toJson
。证明表的通用查找有效但不是正确的 json 响应,因为它是字符串序列化的对象列表。
有人想吗?