cJson 库的使用
作者: 苏丙榅
链接: cJson 库的使用 | 爱编程的大丙 (subingwen.cn)
来源: 爱编程的大丙
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
cJson库在stm32上的移植及相关动态内存的分配和释放请看野火B站教程13分49秒:第21章-MQTT协议3_哔哩哔哩_bilibili
视频来源:野火 LwIP视频教学 配套书籍《LwIP应用开发实战指南》 配套源码 基于STM32 以太网教学 网络教学视频 著作权归作者所有。
实际运用中添加了cJSON库很可能编译不过,需要设置STM32的堆栈内存大小(调小一些就可以编译通过),这里没有一个建议值,需要根据整个项目需要用到的堆栈大小进行分配。堆原来为0xa000=40960;调整太小也可能导致堆栈溢出,程序跑飞或死机。
堆栈设置可以参考博客:(28条消息) STM32堆栈空间大小设置_智小星的博客-CSDN博客_stm32堆栈大小
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
常见JSON格式请求示例
一、请求参数
{
"deviceno":"12345678",
"data":{
"cardd":"7000",
"Type":5,
"Time":"2023-05-30 14:15:16",
"checkMode":0
}
}
如果请求参数如上:示例如下:
void send_test_num(void) { // 创建JSON对象 cJSON *root = cJSON_CreateObject(); cJSON_AddStringToObject(root, "deviceno", "12345678"); cJSON *data = cJSON_CreateObject(); cJSON_AddStringToObject(data, "card", "7000"); cJSON_AddNumberToObject(data, "Type", 5); cJSON_AddStringToObject(data, "Time", "2023-05-30 14:15:16"); cJSON_AddNumberToObject(data, "Mode", 0); cJSON_AddItemToObject(root, "data", data); char* parmas=cJSON_Print(root); memset(url,0x0,sizeof(url)); getFullUrl("xiaogeng/test/api/sendvalue",url,sizeof(url)); log_info("Send_Token,url:xiaogeng/test/api/sendvalue"); string* responseStr = post(url, parmas,usrcfg->Timeout); cJSON_free(parmas);//需要释放 cJSON_Delete(root);//需要释放 //cJSON_Delete(data);//不能释放,否则会有问题,像这种包含在root里面的只需要释放最外层即可,如果要验证可以在释放root后打印data的值看看是不是没有了 if (responseStr) { log_info("receive http msg test:%s\n",responseStr->ptr); unsigned char response=Parse_Test_num(responseStr->ptr); free(responseStr->ptr); responseStr->ptr=NULL; free(responseStr); responseStr=NULL; return response; } return 0; }
二、响应参数如下,则示例代码如下
unsigned char Pars_test(const char *content)
{
int code = 0;
int version = 0;
cJSON *root = cJSON_Parse(content);
if (!root)
{
return 0;
}
int ret = getKeyValueInt(root,"code",&code);
if(code == 0){
cJSON *jsonmap = cJSON_GetObjectItem(root,"data");//注意这个不用释放---------如果释放会报指针错误-------程序崩溃,释放最外层root即可
if(jsonmap)
{
getKeyValueInt(jsonmap,"version",&version);
memset(savecfg,0,sizeof(savecfg));
sprintf(savecfg,"{\"version\":%d}",version);
cJSON *roottmp = cJSON_Parse(savecfg);
if(roottmp){
//{“version”:1}
cJSON_Delete(roottmp);//需要释放
}
}
}
cJSON_Delete(root);//需要释放
return version;
}
三、如下是一些常用转换
/**
* @brief cJSON获取int值
*
* @param root cJSON
* @param key Key值
* @param _dest int指针
* @return u8 获取成功返回8,类型不是int返回-8,key不存在返回0
*/
int getKeyValueInt(cJSON *root,const char *key, int *_dest)
{
if (isHasKey(root, key))
{
if(cJSON_GetObjectItem(root, key)->type == cJSON_Number)
{
*_dest=cJSON_GetObjectItem(root, key)->valueint;
return 8;
}
else
{
return -8;
}
}
else
{
return 0;
}
}
/**
* @brief cJSON获取int值(Key类型是任意的)
*
* @param root cJSON
* @param key Key值
* @param _dest int指针
* @return u8 key是按int获取的则返回8,按string获取的返回16,类型错误的返回-1,key不存在返回0
*/
int getKeyValueAuto(cJSON *root,const char *key, int *_dest)
{
if (isHasKey(root, key))
{
if(cJSON_GetObjectItem(root, key)->type == cJSON_Number)
{
//strcpysafe(_dest,cJSON_GetObjectItem(root, key)->valuestring,_destSizeof);
*_dest=cJSON_GetObjectItem(root, key)->valueint;
return 8;
}
else if(cJSON_GetObjectItem(root, key)->type == cJSON_String)
{
*_dest=atoi(cJSON_GetObjectItem(root, key)->valuestring);
return 16;
}
else if(cJSON_GetObjectItem(root, key)->type == cJSON_True)
{
*_dest=1;
return 1;
}
else if(cJSON_GetObjectItem(root, key)->type == cJSON_False)
{
*_dest=0;
return 1;
}
else
{
return -1;
}
}
else
{
return 0;
}
}
/**
* @brief cJSON获取Double值(Double是八字节,long是四字节,long long是八字节)
*
* @param root cJSON
* @param key Key值
* @param _dest long指针
* @return u8 获取成功返回8,类型不是Number返回-8,key不存在返回0
*/
int getKeyValueDouble(cJSON *root,const char *key, double *_dest)
{
if (isHasKey(root, key))
{
if(cJSON_GetObjectItem(root, key)->type == cJSON_Number)
{
*_dest=cJSON_GetObjectItem(root, key)->valuedouble;
return 8;
}
else
{
return -8;
}
}
else
{
return 0;
}
}
/**
* @brief cJSON获取字符串
*
* @param root cJSON
* @param key Key值
* @param _dest 目标数组
* @param _destSizeof 目标数组长度,可输入sizeof(_dest)
* @return u8 获取成功返回16,类型不是String返回-16,key不存在返回0
*/
int getKeyValueString(cJSON *root, const char *key, char *_dest, size_t _destSizeof)
{
if (isHasKey(root, key))
{
if(cJSON_GetObjectItem(root, key)->type == cJSON_String)
{
memset(_dest,0x0,_destSizeof);
strcpysafe(_dest,cJSON_GetObjectItem(root, key)->valuestring,_destSizeof);
return 16;
}
else
{
return -16;
}
}
else
{
return 0;
}
}
四、数组相关操作
if (isHasKey(jsonmap2, "cards")){
cJSON *myEmparray = cJSON_CreateArray();//转换为我们下发白名单格式字符串
int count = cJSON_GetArraySize(cJSON_GetObjectItem(jsonmap2,"cards"));//卡号数组 可以获取到数组有多少个元素
for (int i = 0; i < count; i++)
{
cJSON *item = cJSON_GetArrayItem(cJSON_GetObjectItem(jsonmap2,"cards"), i); //获取每个数组元素的值
if(item){
cJSON *objId = cJSON_CreateObject();
u8 card[20]={0x0},userId[20]={0x0},tmpbuf[20]={0x0};
getKeyValueString(item,"card",card,sizeof(card));
//getKeyValueString(item,"userId",userId,sizeof(userId)); //由于userId只是预留,因此employeeid改为卡号+Floor值
sprintf(userId,"%s2",card);
//{"EmployeeId":"1001","Name":"张三","Number":"Cerb01","ICCard":"999985","QRCard":"18012345678","StartTime":"2020-01-01 00:01:01","EndTime":"2049-12-30 23:59:59","DeleteFlag":"0","Times":0}
cJSON_AddStringToObject(objId, "EmployeeId", userId);
cJSON_AddStringToObject(objId, "Name", "");
cJSON_AddStringToObject(objId, "Number", hourInterval_str);//Number用于存在时段
cJSON_AddStringToObject(objId, "ICCard", card);
//cJSON_AddStringToObject(objId, "QRCard", card);
cJSON_AddStringToObject(objId, "StartTime", "2018-01-01 01:01:01");
cJSON_AddStringToObject(objId, "EndTime", dateEnd);
cJSON_AddStringToObject(objId, "DeleteFlag", itoa(type_str,tmpbuf,10));
cJSON_AddNumberToObject(objId, "Times", 0);
cJSON_AddStringToObject(objId, "Floor", "2");
cJSON_AddItemToArray(myEmparray, objId);
}
}
char *pStr = cJSON_Print(myEmparray);
printf("my emp json:%s\n",pStr);
cJSON_free(pStr);
//调用标准版的白名单插入函数。先检查格式是否正确
ArrayItemEmpsToDB(myEmparray,CONFIGTYPE_T,NULL);
cJSON_Delete(myEmparray);
}