使用Scala Play框架处理多维JSON [英] Handle multidimensional JSON with scala Play framework

查看:134
本文介绍了使用Scala Play框架处理多维JSON的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用JSON请求将数据从客户端发送到服务器. JSON请求的主体如下所示:

[
 [
  {"x":"0","y":"0","player":0},
  {"x":"0","y":"1","player":0},                      
  {"x":"0","y":"2","player":1}
 ],
 [
  {"x":"1","y":"0","player":0},
  {"x":"1","y":"1","player":2},
  {"x":"1","y":"2","player":0}
 ],
 [
  {"x":"2","y":"0","player":0},
  {"x":"2","y":"1","player":1},
  {"x":"2","y":"2","player":2}
 ]
] 

在服务器端,我想使用Play 2框架将数据转换为Scala 2D列表,如下所示:

List(
 List(0,0,1),
 List(0,2,0),
 List(0,1,2)
)

这是3x3,但可以像50x50左右那样可变.

感谢您的帮助.

解决方案

它可能是不完整的(不知道您是否也要对方阵约束建模),但是类似的事情可能是一个不错的开始:

首先,这是控制器(和模型)部分可以定义的内容

import play.api.libs.json.Json._
import play.api.libs.json._

type PlayerT = (String, String, Int)

implicit val playerTripleReads:Reads[PlayerT] = (
  (__ \ "x").read[String] and
  (__ \ "y").read[String] and
  (__ \ "player").read[Int]
  tupled
)

def getJson = Action(parse.json) { request =>
  request.body.validate[List[List[PlayerT]]].map{
    case xs => Ok(xs.mkString("\n"))
  }.recoverTotal{
    e => BadRequest("Detected error:"+ JsError.toFlatJson(e))
  }
}

在此版本中,您将获得一个列表,其中包含格式为(String, String, Int)的经过验证的元组的列表,该列表已使用PlayerT类型作为别名以保存一些键入内容.

如您所见,通过(使用and组合器)组成三个基本块来手工创建"读取器,并使用tupled运算符将结果弄平.

使用此解决方案,您现在可以按需使用这些元组了,但是IMO代码由于在使用过程中使用_1_2_3会导致可读性差.

因此,这是解决此合理编码问题的另一种方法(实际上甚至更容易...),这将简单地定义一个案例类,以对您的原子数据进行建模

case class Player(x:String, y:String, player:Int)

implicit val playerReads = Json.reads[Player]

def getJson = Action(parse.json) { request =>
  request.body.validate[List[List[Player]]].map{
    case xs => Ok(xs.mkString("\n"))
  }.recoverTotal{
    e => BadRequest("Detected error:"+ JsError.toFlatJson(e))
  }
}

请注意,由于在编译时使用了隐式创建读取器,因此读取器将始终跟随数据表示形式的进一步变化,即case class的字段.

现在,您将能够使用xyplayer字段,而不是_1_2_3.

I am trying to send data from the client to the server using a JSON request. The body of the JSON request looks like this:

[
 [
  {"x":"0","y":"0","player":0},
  {"x":"0","y":"1","player":0},                      
  {"x":"0","y":"2","player":1}
 ],
 [
  {"x":"1","y":"0","player":0},
  {"x":"1","y":"1","player":2},
  {"x":"1","y":"2","player":0}
 ],
 [
  {"x":"2","y":"0","player":0},
  {"x":"2","y":"1","player":1},
  {"x":"2","y":"2","player":2}
 ]
] 

On server side I would like to transform data with Play 2 framework to Scala 2D list like this:

List(
 List(0,0,1),
 List(0,2,0),
 List(0,1,2)
)

this is 3x3 but it can be variable like 50x50 or so.

Thanks for any help.

解决方案

It might be incomplete (don't know if you want to modelize the square matrix contraint as well) but something like that could be a good start:

First here is what the controller (and model) part can define

import play.api.libs.json.Json._
import play.api.libs.json._

type PlayerT = (String, String, Int)

implicit val playerTripleReads:Reads[PlayerT] = (
  (__ \ "x").read[String] and
  (__ \ "y").read[String] and
  (__ \ "player").read[Int]
  tupled
)

def getJson = Action(parse.json) { request =>
  request.body.validate[List[List[PlayerT]]].map{
    case xs => Ok(xs.mkString("\n"))
  }.recoverTotal{
    e => BadRequest("Detected error:"+ JsError.toFlatJson(e))
  }
}

In this version, you'll get a list of list holding validated tuples of the form (String, String, Int) which has been aliased with the PlayerT type to save some typing.

As you may saw, the reader as been created "by-hand" by composing (using the and combinator) three basic blocks and the result is flattened using the tupled operator.

With this solution you're now on track to play with those tuples, but IMO the code will suffer from bad readability, because of the usage of _1, _2 and _3 along the way.

So here is a different approach (which is in fact even easier...) that tackles this problem of sane coding, this will simply defined a `case class that models your atomic data

case class Player(x:String, y:String, player:Int)

implicit val playerReads = Json.reads[Player]

def getJson = Action(parse.json) { request =>
  request.body.validate[List[List[Player]]].map{
    case xs => Ok(xs.mkString("\n"))
  }.recoverTotal{
    e => BadRequest("Detected error:"+ JsError.toFlatJson(e))
  }
}

Note that, the reader will always follow further changes in your data representation, that is the case class's fields thanks to the use of the implicit creation of the reader at compile time.

Now, you'll be able to use x, y and player fields rather than _1, _2 and _3.

这篇关于使用Scala Play框架处理多维JSON的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆