简单介绍
关于RapidJSON,网上有很多资料,RapidJSON是腾讯开源的一个高效的C++ JSON解析器及生成器,它是只有头文件的C++库。RapidJSON是跨平台的,支持Windows, Linux, Mac OS X及iOS, Android。它的源码在https://github.com/Tencent/rapidjson/。这里也不过多介绍如何使用RapidJson,网上有很多如何使用,只介绍自己使用过程中遇到的问题,及其解决问题的方式。
应用环境说明
在我们的日常开发中,大多数项目都需要与数据库打交道,在多人同时开发一个项目时,不同的人有不同的分工,一般的MS项目,通常至少有一个负责数据库的开发,然后将数据库的操作封装成具体的接口,在给后端应用开发人员使用,这样,不管后端开发人员与数据库接口的开发人员是不是使用同一语言开发都无关紧要,只要数据库开发人员提供完善的接口给应用开发人员即可,比如我现在所在的公司,数据库开发人员使用的mysql + mybits + java语言提供接口(类似这种形式的接口:http://192.168.2.161:8080/JMVC/asset_excute/getFormworkById.r?formworkId=1),接口形式遵从http协议,如果直接使用网页访问接口,返回的实际上就是JSON数据(查询数据库的结果),作为一名C++后台开发人员,很多时候都是获取这些JSON数据,然后展示给用户,如何在C++调用这种接口呢,我也很少去摸索,目前使用的是比较出名的libcurl,关于libcurl的使用和说明这里就不介绍了,网上有很多,如果你足够牛逼和网络知识足够(PS:本文适合新手,估计看到的写一个网络协议搞定这个也不会看这个博客了),如果热爱学习,这里有很多C++开源库和工具,真是一些好东西:开源库集合。
错误说明
在项目开发中,前端需要存取一些数据项(代码里封装成一个结构体P_PLANDRILL_TEMPLATE_W,结构体如下图所示,结构体中包含id和一些字符串字段,另外还包含一个vector,对应JSON数据的结构体数组)
在以下代码中,我们通过Rapidjson的Document类,解析我们想要解析一段json文本(对应结构体的字段,代码里的PC_JSON_TEMPLATE2,其中T_DUTYRESPONSE_TEMPLATE的chDutyUserNames和chPlanDrillRecord字段没有对应,formworkDivides的title对应chDutyName,duty对应chDutyResponse,其中C_NEW_PLANDRILL_OPERATION_Handler是我的一个类)
static const char* PC_JSON_TEMPLATE1 = "{
\"id\":0,\"title\":\"\",\"purpose\":\"\",
\"objective\":\"\",\"scene\":\"\",\"createUser\":\"\"}";//测试数据json数据1
static const char* PC_JSON_TEMPLATE2 = "{
\"id\":0,\"title\":\"\",\"purpose\":\"\",\"objective\":\"\",\"scene\":\"\",\"
createUser\":\"\",\"formworkDivides\":[{\"title\":\"\",\"duty\":\"\"},{\"title\":"",\"duty\":""}]}";//测试json数据2
int C_NEW_PLANDRILL_OPERATION_Handler::ExcuteRequest(void * pReqParam, int nReqSize, int * pnResultCount)
{
//分析参数
if (nReqSize != sizeof(P_PLANDRILL_TEMPLATE_W) || pReqParam == NULL)
{
return ERR_CODE_WRONG_PARAM;
}
auto p_PLANDRILL_TEMPLATE = static_cast<LP_PLANDRILL_TEMPLATE_W>(pReqParam);//获取从客户端传来的参数
m_dutyResponseSize = p_PLANDRILL_TEMPLATE->listDutyResponse.size();
//构造参数
Document doc; //Document 是rapidJson库的核心文档类,请参考官网使用说明
//以下注释的代码,是错误说明,没有通过该种方式成功设置值,
//~~目前不知道是rapidjson自身的问题,还是我使用的问题(以上PC_JSON_TEMPLATE2格式没有问题)
//也可能是我使用的rapidjson版本比较老,rapidjson的确存在这个问题,但是已经修复这个问题~~
//如果使用PC_JSON_TEMPLATE2,在运行时,走到if处会抛出异常,并不能正确设置值,目前还没找到原因
//doc.Parse(PC_JSON_TEMPLATE1);
//char pcUTF[2048] = { 0 };
//if (doc.HasMember("id") && doc["id"].IsInt())
//{
// g_pLogger->WriteLog("有id字段并且id字段是int", "", 0, "");
// doc["id"].SetInt(p_PLANDRILL_TEMPLATE->id);//设置id字
//}
//以下代码能够正确设置从前端获取的值,并通过libcurl将数据存到数据库
doc.SetObject();
Document::AllocatorType& allocator = doc.GetAllocator();//生成一个分配器
doc.AddMember("id", p_PLANDRILL_TEMPLATE->id, allocator);
doc.AddMember("title", StringRef(p_PLANDRILL_TEMPLATE->chTitle), allocator);
doc.AddMember("purpose", StringRef(p_PLANDRILL_TEMPLATE->chPurpose), allocator);
doc.AddMember("objective", StringRef(p_PLANDRILL_TEMPLATE->chObjective), allocator);
doc.AddMember("scene", StringRef(p_PLANDRILL_TEMPLATE->chScene), allocator);
doc.AddMember("createUser", StringRef(p_PLANDRILL_TEMPLATE->chCreateUser), allocator);
//生成职务列表
rapidjson::Value ObjectArray(rapidjson::kArrayType);
for (int i = m_dutyResponseSize - 1; i >= 0; --i)
{
rapidjson::Value obj(rapidjson::kObjectType);
obj.AddMember("title", StringRef(p_PLANDRILL_TEMPLATE->listDutyResponse[i].chDutyName), allocator);
obj.AddMember("duty", StringRef(p_PLANDRILL_TEMPLATE->listDutyResponse[i].chDutyResponse), allocator);
ObjectArray.PushBack(obj, allocator);
}
doc.AddMember("formworkDivides", ObjectArray, allocator);
StringBuffer s;
Writer<StringBuffer> writer(s);
doc.Accept(writer);
//发送请求并解析
//调用libcurl保存数据到数据库
int nRet = DoRequest(JSON_SERVER_URI, IS_POST_METHOD, s.GetString() , s.GetSize());
if (nRet == 0)
{
*pnResultCount = m_szResultCount;
}
}
结论
我目前在使用rapidjson过程中,就遇到过这样的一个问题,及其遇到问题的解决方式都在代码里做了详细说明,如果网友有跟我一样的情况,可以参考该博客使用Rapidjson生成JSON的使用方式RapidJSON生成json格式文件,而不应该使用字符串拼接的方式或者将其字符串写死来进行解析,这样很有可能就会导致莫名其妙的错误
PS:该文只是自己使用rapidjson的一点心得体会和使用过程中遇到的问题,适合刚刚学习rapidjson的同学。另外希望大家能够共同学习,把在工作中遇到的问题提出来,大家一起解决。