前提
之前一直有个问题没有弄清楚,就是“记录类型的用户数据是如何存储的”。经过搜索、学习和思考,现在终于弄清楚了。因此有了这篇博文。
从问题出发
问题其实前面已经说了,我们再具体一些。比如我们玩一个游戏,游戏里面每个玩家都有“背包”, 如果这个“背包”的容量很大(比如1000格),甚至是没有限制,玩家获得多少道具,背包就可以多大。 从开发者的角度来看,该怎么实现?有限的1000个,不会有人想在数据库建1000个列用来存储1000格上的道具吧。 那更进一步,无限背包怎么实现呢? 这就是我们的问题,引申一下, 这类用户的背包、消费记录、通话记录、聊天记录等记录类型的数据是怎么存储的呢?
JSON和XML
经过一番查询,目前业内用于存储这类记录数据的方式不限于以下两种:即存储在JSON或者XML这类有结构的文件中。
以下是一个用XML存储数据的简单例子:
<?xml version="1.0" ?>
<user>
<field id="name">
<value>David</value>
</field>
<field id="country">
<value>China</value>
</field>
<field id="email">
<value>mymail@myaddress.com</value>
</field>
</user>
专精JSON
因为后台请求的响应一直在用JSON,所以就专精JSON吧,我们的用户记录也用它来做。
上述问题中,我们主要想要实现的就是一个“无限数组”,或者Java中的ArrayList这样一种结构,下面看一个简单的例子:
{
"contacters": [
{
"id": "10101",
"name": "张三",
"age": 22,
"singleOrNot": true
},
{
"id": "10102",
"name": "李四",
"age": 24
}
]
}
根据JSON的语法规则,方括号[ ]用来定义数组,两个数组元素之间用逗号隔开。
如代码中所示,contacters
是一个数组,里面存了两个联系人张三
和李四
JSON文件读与写
说到底,这些数据是存在JSON文件中的,一般情况下,一个json文件的名称形如a.json
。为了便于读写,我们一般将它命名为用户ID,如193746825.json
。
(1)读JSON文件
我一般用的逻辑是,客户端从服务器上下载193746825.json
文件,然后读取出其中的JSON字符串。
(2)正向映射
正向映射,即将JSON字符串映射为Java里的对象,因为没有找到可以做JSON映射的框架,所以只能自己写,针对上述例子的正向映射代码如下:
try {//注①
JsonNode userRecode = JsonLoader.fromString(AppGlobal.userRecord); //注②
JsonNode contacters = userRecode.get("contacters");
for (int i = 0; i < contacters.size(); i++) {
JsonNode contacter = contacters.get(i);
Contacter c = Contacter.newInstance(contacter.get("name").asText());
c.setId(contacter.get("id").asText()); //注③
c.setAge(contacter.get("age") == null ? -1 : contacter.get("age").asInt());
c.setSingleOrNot(contacter.get("singleOrNot") == null ? true : contacter.get("singleOrNot").asBoolean());
AppGlobal.CONTACTERS.add(c); //注④
}
} catch (IOException e) {
e.printStackTrace();
}
注释:
①首先需要定义好一个Contacter类,里面的属性和JSON文件中的属性一致;
②userRecoed是从服务器上下载下来的JSON字符串,通过JsonLoader.fromString
函数构建顶层的JSONObject,然后再进一层,读取contacters
表示的联系人数组;
③id、name和age、singleOrNot的操作是有区别的,其中前两个属性不需要判断存不存在,因为一个联系人必然具有id和名字,否则不算是一个联系人,但是用户存没有存该联系人的年龄和是否单身这种属性就不一定了,因此后两个属性要判断存不存在;
④映射好一个联系人对象,就存到全局的联系人列表中去。
(3)反向映射
当用户修改了联系人,我们就需要更新服务器上的json文件,这时就需要把上述的Java对象映射为JSON字符串,这里就需要在Contacter类里面写一个toString
或者toJsonString
函数:
public String toJsonString() {
StringBuilder result = new StringBuilder("{");
result.append("\"id\": \"").append(id).append("\",");
result.append("\"name\": \"").append(name).append("\"");
if (-1 != age)
result.append(",\"age\": \"").append(String.valueOf(age)).append("\"");
if (singleOrNot)
result.append(",\"singleOrNot\": ").append(String.valueOf(singleOrNot));
result.append("}");
return result.toString();
}
(4)写JSON文件
接下来就是这个流程的最后一步,数据回写。按照我的想法,直接上传文件覆盖原文件是超级危险的操作!那么我们就用请求的方式,把变更后的JSON字符串发到服务器,服务器端验证了发来的JSON字符串之后再写到相应的文件中去。
后记
本来还想写一下JSON的验证,但是感觉验证方面的篇幅也会比较长,所以决定放在下一篇博文里来介绍。
这一片博文里最重要的就是“正向映射”和“反向映射”的两段代码。 我在网上实在没有找到JSON的双向映射方面的框架,最多只能找到把JSON文件静态转换为Java类文件的那种“映射”。因此就决定都自己写吧。
希望可以给大家做一个参考。如果你知道有现成的框架可以做这件事,请告诉我,谢谢!