- JsValue可以理解为是Json对象(更准确的其实JsObject才是Json对象, JsValue更像是Json值的表示)
- Ok是Play框架中的响应返回,表示正确响应,可传参数作为响应信息,如Ok(Json.obj(“Ok” -> “OK”))
- 隐式参数和对象不需要手动传入,只要它们在当前上下文是可见的即可自动引用,一般在伴生对象或包对象中。
- Scala无真正的基本类型,这里说的基本是数值,数值的数组,数值的集合(集合元素也必须数值的)
- 对于不确定的情况需要尽量使用带Opt结尾的方法,否则对None值调用get会报错。
- Scala把所有Java基本类型都映射成了Scala对象,Scala中一切都是对象,都能进行函数调用,其中有的比如String、Class等等是直接使用了Java的String、Class
下面对于给定数据进行说明
val queryParamsRequest: Map[String, Seq[String]] = Map("clickId" -> Seq("1", "2", "3", "4"), "currTime" -> Seq("5", "4", "3", "2"))
toJson
可以对简单类型数据直接序列化,而不需任何其他操作
val jsValue = Json.toJson(queryParamsRequest)
得到的是JsValue
查看toJson
源码,如下
def toJson[T](o: T)(implicit tjs: Writes[T]): JsValue = tjs.writes(o)
该方法使用隐式参数Writes
来完成写入。实际上这里是因为Scala默认定义了一些用于基础类型的Writes
trait DefaultWrites extends LowPriorityWrites {
import scala.language.implicitConversions
/**
* Serializer for Int types.
*/
implicit object IntWrites extends Writes[Int] {
def writes(o: Int) = JsNumber(o)
}
......
implicit object DoubleWrites extends Writes[Double] {
def writes(o: Double) = JsNumber(o)
}
...... 此处省略,还有数组等,
其中JsNumber
是JsValue
的子类
case class JsNumber(value: BigDecimal) extends JsValue
也就是默认所有的基本类型即使不传入任何参数也是可以使用toJson
方法将其转换为JsValue
。反之,如果有不是基本类型的,则需要自己提供隐式的Writes
,假设有class如下
case class AppConfig(title: String, baseUri: URI)
URI是java.net.URI
类 那现在肯定无法自动序列化为json,此时可以自定义一个隐式参数如下
implicit val appConfigWrites = new Writes[AppConfig] {
def writes(appConfig: AppConfig) = Json.obj(
"title" -> appConfig.title,
"baseUri" -> appConfig.baseUri.toString
//对于不能转换为String的这里要增加 额外处理
)
}
PS:如果想从给定的json字符串中读取出AppConfig对象则需要Reads
,这是反序列化,可能会出错,一般使用Option
implicit val appConfigReads: Reads[AppConfig] = (
(JsPath \ "title").read[String] and
(JsPath \ "baseUri").read[String].map(x => new URI((x)))
) (AppConfig.apply _)
你也可以同时定义序列化和反序列化,有了Writes
对象或Format
对象实现了writes
方法,就可以在网络中将DTO对象进行传输。(以Json字符串传输)
new Format[AppConfig] {
override def writes(o: AppConfig): JsValue = ???
//实现这两个方法。代码和上面的类似。如果是DTO对象,一般不实现Reads,可以在
//被调用时就抛出异常
override def reads(json: JsValue): JsResult[AppConfig] = ???
}
如果想直接写入Play的Ok()中,还需要增加一个Writeable
隐式对象,如下
implicit def jsonWritable[A](implicit writes: Writes[A], codec: play.api.mvc.Codec): Writeable[A] = {
implicit val contentType = ContentTypeOf[A](Some(ContentTypes.JSON))
val transform = Writeable.writeableOf_JsValue.transform compose writes.writes
Writeable(transform)
}
现在接着上面序列化Map,得到JsValue后可以转换为String
val jsonQueryParams = Json.stringify(jsValue)
println("序列化成字符串 => " + jsonQueryParams)
如果你想字符串是易于观看的,可以选择格式化展现,如下
val prettyPrint = Json.prettyPrint(jsValue)
println("JsValue格式化成字符串 => " + prettyPrint)
这里格式化使用的是JacksonJson 如果想从给定的json字符串反序列成JsValue,可以执行解析操作,如下
val json = Json.parse(jsonQueryParams)
println("反序列的Json值 => " + json)
这里从字符串解析使用的也是JacksonJson,最后想将字符串解析成Map
val queryParamResult = json.validate[Map[String, Seq[String]]].getOrElse(Map())
不是确定类型的情况下最好使用 validateOpt
如果想打印map的key和value可以使用for
for ((k, v) <- queryParamResult) {
println(k, v)
}
上面序列化和反序列化Map的结果
序列化成字符串 => {"clickId":["1","2","3","4"],"currTime":["5","4","3","2"]}
JsValue格式化成字符串 => {
"clickId" : [ "1", "2", "3", "4" ],
"currTime" : [ "5", "4", "3", "2" ]
}
反序列的Json值 => {"clickId":["1","2","3","4"],"currTime":["5","4","3","2"]}
文档信息
- 本文作者:梦境迷离
- 本文链接:https://blog.dreamylost.cn/scala/Scala-Play%E4%B8%AD%E5%BA%8F%E5%88%97%E5%8C%96%E6%93%8D%E4%BD%9C.html
- 版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)