【问题标题】:Scala convert model object to DTOScala 将模型对象转换为 DTO
【发布时间】:2017-02-22 11:09:22
【问题描述】:

我是 scala 新手,并试图理解它的基本概念。通过使用 play/scala/slick 我试图实现一个简单的应用程序,它允许用户对其他用户执行 CRUD 操作。所以我面临的问题是我不明白我应该如何使用隐式转换将模型对象转换为 DTO 对象。
这是我到目前为止所得到的:

Application.scala(控制器类):

//returns list of users  
def users = Action.async {
    val userList = userDAO.all()
    userList
      .map { list => Ok(list.map(elem => Json.toJson(elem))) }
      .recover { case _ => InternalServerError }
}   

User.scala(模型对象,代表数据库中的条目):

case class User(id: Long, login: String, password: String) extends BaseEntity

UserDto.scala(DTO,对象,代表用户列表中的User):

case class UserDto(id: Long, login: String) {
  implicit def userWriter = Json.writes[UserDto]

  implicit def user2UserDto(user: User): UserDto = UserDto(user.id, user.login)
}  

在上面的代码中,在 #1 标记处,我收到一条错误消息,指出 User 无法转换为 json。确切的错误消息:Error:(40, 53) No Json serializer found for type Application.this.userDAO.Entity。尝试为此类型实现隐式写入或格式。 .map { list => Ok(list.map(elem => Json.toJson(elem))) }。我应该如何以及在哪里实现从 User 到 UserDto 的转换,以便它工作而不是丑陋?

例如,在 Java 中,我将使用 public User to() 和 public static UserDto from(User user) 实现每个 Dto 对象,以便我可以转换它们。我应该在 scala 中做同样的事情还是有更优雅的方式来完成这项任务?

版本 users 方法的编辑版本:

def users = Action.async {
  val userList = userDAO.all()
  userList
    .map { list => Ok(list.map(elem => Json.toJson(elem : UserDto))) }
    .recover { case _ => InternalServerError }
}  

有以下编译错误:

Error:(41, 24) not enough arguments for method apply: (implicit writeable: play.api.http.Writeable[Seq[play.api.libs.json.JsValue]])play.api.mvc.Result in class Status.
Unspecified value parameter writeable.
      .map { list => Ok(list.map(elem => Json.toJson(elem : UserDto))) }  


Error:(41, 24) Cannot write an instance of Seq[play.api.libs.json.JsValue] to HTTP response. Try to define a Writeable[Seq[play.api.libs.json.JsValue]]
      .map { list => Ok(list.map(elem => Json.toJson(elem : UserDto))) }  

编译器似乎在UserDto 对象中没有看到userWriter。

【问题讨论】:

  • userList .map { list => Ok(userList.map(list => list.map(elem => Json.toJson(elem)))) } 为什么映射userList 但不使用其中的任何项目,而是为每个项目再次映射它? list.map(elem => Json.toJson(elem)) 也可以写成list.map(Json.toJson)。请在致电toJson 时提供您收到的确切错误消息。
  • @sirius,我在编译时添加了一条错误消息。请查看更新的答案。

标签: scala playframework functional-programming implicit-conversion


【解决方案1】:

不要定义案例类内部的隐含。在companion object 中定义它们:

case class UserDto(id: Long, login: String)

object UserDto {
  implicit def userWriter = Json.writes[UserDto]

  implicit def user2UserDto(user: User): UserDto = UserDto(user.id, user.login)
}

当您在案例类中定义它们时,它们成为实例方法,只能从该类的实例中使用。当您在伴随对象上定义它们时,它们是全局定义的(不绑定到实例),它们等效于 java 中的静态方法。从那里开始,scala 的隐式解析机制can find them。

【讨论】:

  • 谢谢你,阿尔瓦罗!我修复了这个错误,但不幸的是编译错误并没有消失。
  • 为了让隐式工作,它需要这个路径:User -> UserDTO -> Writes[UserDTO]。但是隐式不会自动像那样链接。您需要将User 显式转换为UserDTO,或者通过提供类型说明来帮助编译器:Json.toJson(elem : UserDTO)
  • 非常感谢,阿尔瓦罗。我能够解决这个问题,但是编译器开始抱怨writes...我更新了代码,这是错误:Error:(41, 24) Cannot write an instance of Seq[play.api.libs.json.JsValue] to HTTP response. Try to define a Writeable[Seq[play.api.libs.json.JsValue]] .map { list => Ok(list.map(elem => Json.toJson(elem : UserDto))) }。迁移到 scala 真的很难..
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多