cJson 学习笔记
cJson 学习笔记
一、前言
思考这么一个问题:对于不同的设备如何进行数据交换?可以考虑使用轻量级别的 JSON 格式。
那么需要我们手写一个 JSON 解析器吗?这大可不必,因为已经有前辈提供了开源的轻量级的 JSON 解析器——cJSON。我们会用就可以了,当然你也可以深入源码进行学习。
下图则向我们展示了如何通过 cJSON 实现 Client 与 Server 的数据交换:
- Client 在发送数据之前,通过 cJSON 将自己的专属数据格式 Data_ClientFormat 转化为了通用格式 JSON
- 服务端在收到 JSON 数据后,通过 cJSON 将其转化为服务端的专属数据格式 Data_ServerFormat
- 反之同理
在介绍 cJSON 之前,先来对 JSON 这个数据格式有个简单了解。
二、JSON 简介
1.1 什么是 JSON
JSON 指的是 JavaScript 对象表示法(JavaScript Object Notation)。但它并不是编程语言,而是一种可以在服务器和客户端之间传输的数据交换格式。
1.2 JSON 结构
JSON 的两种数据结构:
- 对象:A collection of key/value pairs(一个无序的 key / value 对的集合)
- 数组:An ordered list of values(一 / 多个 value 的有序列表)
从上述描述中,我们可以获得如下四种信息:
- 对象(Object)
- 数组(Array)
- 键(key)
- 值(Value)
1.3 JSON 对象
JSON 对象具体格式如下图所示:
- 一个对象以
{
开始,以}
结束,是若干「key / value 对」的集合 - key 和 value 使用
:
分隔 - key / value 对之间使用
,
分隔
注意事项:
- 键:必须是 string 类型
- 值:可以是合法的 JSON 数据类型(字符串、数值、对象、数组、布尔值或 null)
如,这是一个合法的 JSON 对象:
{
"name" : "张三"
}
这也是一个合法的 JSON 对象:
{
"name" : "张三",
"age" : 18,
"sex" : "男"
}
1.4 JSON 数组
JSON 数组具体格式如下图所示:
- 一个数组以
[
开始,]
结束,是若干 value 的有序集合 - 多个 value 以
,
分隔
如,这是一个合法的 JSON 数组:
[
"张三",
18,
"男"
]
该数组包含三个 value,分别为 string、number、string
这也是一个合法的 JSON 数组:
[
{
"name" : "张三",
"age" : 18,
"sex" : "男"
},
{
"name" : "李四",
"age" : 19,
"sex" : "男"
}
]
该数组包含两个 Object,每个 Object 又包含若干 key / value。
1.5 JSON 值
值(value)可以是:
- 字符串:必须用双引号括起来
- 数 值:十进制整数或浮点数
- 对 象:键 / 值对的集合
- 数 组:值的集合
- 布尔值:true 或 false
- null
value 可以是简单的用双引号引起来的 string 串,也可以是一个数值;或布尔值(true or false),或 null。
当然也可以是复杂的 object 或 array,这些取值是可以嵌套的。
在「1.4 JSON 数组」中,第二个例子就是一个嵌套的举例,当然也可以这么嵌套:
{
"class_name" : "计科一班",
"student_num" : 2,
"student_info" :
[
{
"name" : "张三",
"age" : 18,
"sex" : "男"
},
{
"name" : "李四",
"age" : 19,
"sex" : "男"
}
]
}
三、cJSON 使用教程
3.1 cJSON 使用说明
源码下载:https://www.aliyundrive.com/s/GgcJZvHBdPq
编译环境:CentOS 7
源码中包含 cJSON.h 和 cJSON.c,以及一个测试程序 main.c,测试程序的功能是输出一个 JSON 字符串:
{
"name": "张三",
"age": 18,
"sex": "男"
}
你可以通过下面两种方法运行该程序:
$ gcc -g -Wall *.c -l m
,会默认生成一个 a.out 文件,执行该文件即可- 将 cJSON.c 打包成静态库 / 动态库,然后在编译 main.c 的时候将其链接上就可以了
由于源码中使用了 pow 函数,所以一定要链接上 math 库,也就是 -l m 指令。
如果在编译过程中报好多 warning(如下图所示)警告:
不要慌,这并不影响程序的运行,如果你想消除这些警告,不妨将 cJSON.c 格式化一下(用 VSCode 按下alt+shift+F)。
至于原理,不妨参考这篇文章:gcc编译警告关于(warning: XXX...[-Wmisleading-indentation] if(err)之类的问题)
3.2 cJSON structure
首先,我们先对 cJSON 的结构体有个初步了解,其定义如下:
typedef struct cJSON
{
struct cJSON *next, *prev;
struct cJSON *child;
int type;
char *valuestring;
int valueint;
double valuedouble;
char *string;
} cJSON;
- type:用于区分 JSON 类型
- 0 表示 false
- 1 表示 true
- 2 表示 null
- 3 表示 number
- 4 表示 string
- 5 表示 array
- 6 表示 object
- string :代表「键 / 值对」的键
- value*:代表「键 / 值对」的值,搭配 type 使用
- 只有当 type 值为 4 时,valuestring 字段才有效
- 只有当 type 值为 3 时,valueint 或 valuedouble 字段才有效
由于我在实际使用过程中未涉及 bool、null,所以举例中暂不涉及这两种类型。
3.3 反序列化 JSON 字符串
在正式讲解之前,让我们先看一下与反序列化相关的函数:
函数 | 解释说明 | 返回值 |
---|---|---|
cJSON_Parse | 将 JSON 字符串反序列化为 cJSON 结构体 | cJSON * |
cJSON_GetObjectItem | 获取 JSON 对象中的指定项 | cJSON * |
cJSON_GetArrayItem | 获取 JSON 数组中的第 i 个 JSON 项 | cJSON * |
cJSON_GetArraySize | 获取 JSON 数组的大小(该数组中包含的 JSON 项个数) | int |
cJSON_Delete | 删除 cJSON 结构体 | void |
3.3.1 一个简单的例子
对于一个 JSON 字符串:
{
"name": "张三",
"age": 18,
"sex": "男"
}
我们可以在代码中通过调用cJSON_Parse(const char *value)
函数将 JSON 字符串 value 反序列化为 cJSON 结构体:
cJSON *root = cJSON_Parse(pcJson); // pcJson 为从文件中获取的 JSON 字符串
if (NULL == root)
{
printf("fail to call cJSON_Parse\n");
exit(0);
}
反序列化后的 JSON 字符串,大概长这个样子:
- 图中的灰色虚线是假想的,实际是不存在的
- 用来表明 name、age、sex 都是 root 的 child,只不过实际的 child 仅仅指向了第一个节点,也就是 name
那么我们如何获取 name、age、sex 对应的值呢?可以通过调用cJSON *cJSON_GetObjectItem()
函数从 object 中获取。
cJSON *pName = cJSON_GetObjectItem(root, "name");
printf("name [%s]\n", pName->valuestring);
cJSON *pAge = cJSON_GetObjectItem(root, "age");
printf("age [%d]\n", pAge->valueint);
cJSON *pSex = cJSON_GetObjectItem(root, "sex");
printf("sex [%s]\n", pSex->valuestring);
cJSON *cJSON_GetObjectItem(cJSON *object, const char *string)
:从 object 的所有 child 中检索键为 string 的 JSON 项- 如果找到则返回相应的 JSON 项
- 反之返回 NULL。
完整代码如下:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
#include "cJSON.h"
#define STRING_LEN_MAX 2048
void GetJSONFromFile(const char *FILENAME, char **ppcJson)
{
FILE *fp = fopen(FILENAME, "r");
if (NULL == fp)
{
printf("file open error\n");
exit(0);
}
char *pcJson = (char *)malloc(STRING_LEN_MAX);
memset(pcJson, 0, STRING_LEN_MAX);
do
{
fgets(pcJson + strlen(pcJson), STRING_LEN_MAX - strlen(pcJson), fp);
} while (!feof(fp));
*ppcJson = pcJson;
fclose(fp);
}
int main()
{
char *pcJson;
GetJSONFromFile("test.json", &pcJson); // 从文件 test.json 中获取 JSON 字符串
cJSON *root = cJSON_Parse(pcJson);
if (NULL == root)
{
printf("fail to call cJSON_Parse\n");
exit(0);
}
cJSON *pName = cJSON_GetObjectItem(root, "name");
printf("name [%s]\n", pName->valuestring);
cJSON *pAge = cJSON_GetObjectItem(root, "age");
printf("age [%d]\n", pAge->valueint);
cJSON *pSex = cJSON_GetObjectItem(root, "sex");
printf("sex [%s]\n", pSex->valuestring);
cJSON_Delete(root); // 手动调用 cJSON_Delete 进行内存回收
return 0;
}
3.3.2 一个有一丢丢复杂的例子
对于一个复杂些的 JSON 字符串:
{
"class_name": "计科一班",
"stu_num" : 2,
"stu_info" :
[
{
"name": "张三",
"age": 18,
"sex": "男"
},
{
"name": "李四",
"age": 20,
"sex": "男"
}
]
}
反序列化该字符串依旧很简单,只需我们在代码中调用cJSON_Parse()
即可,而难点在于如何解析。
先来看一下该字符串反序列化后长啥样:
对于 class_name 以及 stu_name,我们可以很容易就解析出来:
cJSON *pClassName = cJSON_GetObjectItem(root, "class_name");
printf("class name [%s]\n", pClassName->valuestring);
cJSON *pStuNum = cJSON_GetObjectItem(root, "stu_num");
printf("stu num [%d]\n", pStuNum->valueint);
那么如何获取更深层次的 name、age 以及 sex 呢?
通过 JSON 字符串可以知道,stu_info 是一个 JSON 数组,那么我们首先要做的是将这个数组从 root 中摘出来:
cJSON *pArray = cJSON_GetObjectItem(root, "stu_info");
if (NULL == pArray)
{
printf("not find stu_info\n");
goto err;
}
接着将该数组中的各个项依次取出。
cJSON *item_0 = cJSON_GetArrayItem(pArray, 0);
cJSON *item_1 = cJSON_GetArrayItem(pArray, 1);
cJSON_GetArrayItem(cJSON *array, int item)
:从 JSON 数组 array 中获取第 item 项(下标从 0 开始)如果存在,则返回相应的 JSON 项
反之返回 NULL。
最后,将 name、age、sex 分别从 item_0 / item_1 中取出即可。
上述操作只是为了讲解如何获取更深层次的 JSON 项,实际操作中会这么写:
int iArraySize = cJSON_GetArraySize(pArray);
for (i = 0; i < iArraySize; i++)
{
printf("******** Stu[%d] info ********\n", i + 1);
cJSON *item = cJSON_GetArrayItem(pArray, i);
cJSON *pName = cJSON_GetObjectItem(item, "name");
printf("name [%s]\n", pName->valuestring);
cJSON *pAge = cJSON_GetObjectItem(item, "age");
printf("age [%d]\n", pAge->valueint);
cJSON *pSex = cJSON_GetObjectItem(item, "sex");
printf("sex [%s]\n", pSex->valuestring);
}
就跟剥洋葱似的,先将外层的 stu_info 剥出来,然后在剥出内层的 item,最后将 name、age、sex 从 item 中分离出来。
对于更多层次的 JSON 处理,也是同样的操作,你只需要保证在解析你所需的 JSON 项前,其父节点已被解析。
完整代码如下:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
#include "cJSON.h"
#define STRING_LEN_MAX 2048
void GetJSONFromFile(const char *FILENAME, char **ppcJson)
{
FILE *fp = fopen(FILENAME, "r");
if (NULL == fp)
{
printf("file open error\n");
exit(0);
}
char *pcJson = (char *)malloc(STRING_LEN_MAX);
memset(pcJson, 0, STRING_LEN_MAX);
do
{
fgets(pcJson + strlen(pcJson), STRING_LEN_MAX - strlen(pcJson), fp);
} while (!feof(fp));
*ppcJson = pcJson;
fclose(fp);
}
int main()
{
char *pcJson;
GetJSONFromFile("test.json", &pcJson);
cJSON *root = cJSON_Parse(pcJson);
if (NULL == root)
{
printf("fail to call cJSON_Parse\n");
exit(0);
}
cJSON *pClassName = cJSON_GetObjectItem(root, "class_name");
printf("class name [%s]\n", pClassName->valuestring);
cJSON *pStuNum = cJSON_GetObjectItem(root, "stu_num");
printf("stu num [%d]\n", pStuNum->valueint);
cJSON *pArray = cJSON_GetObjectItem(root, "stu_info");
if (NULL == pArray)
{
printf("not find stu_info\n");
goto err;
}
int i;
int iArraySize = cJSON_GetArraySize(pArray);
for (i = 0; i < iArraySize; i++)
{
printf("******** Stu[%d] info ********\n", i + 1);
cJSON *item = cJSON_GetArrayItem(pArray, i);
cJSON *pName = cJSON_GetObjectItem(item, "name");
printf("name [%s]\n", pName->valuestring);
cJSON *pAge = cJSON_GetObjectItem(item, "age");
printf("age [%d]\n", pAge->valueint);
cJSON *pSex = cJSON_GetObjectItem(item, "sex");
printf("sex [%s]\n", pSex->valuestring);
}
err:
cJSON_Delete(root); // 手动调用 cJSON_Delete 进行内存回收
return 0;
}
3.4 序列化 cJSON 结构体
前面我们一直在介绍如何将一个 JSON 字符串反序列化为 cJSON 结构体,下面我们来介绍一下如何将 cJSON 结构体序列化为 JSON 字符串。
首先,我们要先有一个 cJSON 结构体,构造 cJSON 结构体的相关函数如下:
函数 | 解释说明 | 返回值 |
---|---|---|
cJSON_CreateObject | 创建一个 object 类型的 JSON 项 | cJSON * |
cJSON_CreateArray | 创建一个 array 类型的 JSON 项 | cJSON * |
cJSON_CreateString | 创建一个值为 string 类型的 JSON 项 | cJSON * |
cJSON_CreateNumber | 创建一个值为 number 类型的 JSON 项 | cJSON * |
cJSON_AddItemToObject | 将 JSON 项添加到 object 中 | void |
cJSON_AddItemToArray | 将 JSON 项添加到 array 中 | void |
cJSON_AddNumberToObject | 创建一个值为 number 类型的 JSON 项并添加到 JSON 对象中 | void |
cJSON_AddStringToObject | 创建一个值为 string 类型的 JSON 项并添加到 JSON 对象中 | void |
cJSON_Print | 将 cJSON 结构体序列化为 JSON 字符串(有格式) | char * |
cJSON_PrintUnformatted | 将 cJSON 结构体序列化为 JSON 字符串(无格式) | char * |
cJSON_Delete | 删除 cJSON 结构体 | void |
3.4.1 一个简单的例子
假设我们想要获取的 JSON 字符串为:
{
"name": "张三",
"age": 18,
"sex": "男"
}
我们该如何构造 cJSON 结构体呢?
还记得这个 JSON 字符串反序列化的样子吗?不记得也没关系,因为我马上就要张贴了
根据图示可知,我们要先有一个根节点 root。
由于本次样例中的 JSON 字符串是一个 JSON 对象,所以我们需要通过cJSON_CreateObject()
函数来创建一个 object 类型的 root:
cJSON *root = cJSON_CreateObject();
接下来我们需要将 name、age、sex 分别加入到 root 中:
- 通过
cJSON_AddStringToObject()
将字符串类型的 name、sex 加入到 root 中 - 通过
cJSON_AddNumberToObject()
将数值类型的 age 加入到 root 中
具体操作如下:
cJSON_AddStringToObject(root, "name", "张三");
cJSON_AddNumberToObject(root, "age", 18);
cJSON_AddStringToObject(root, "sex", "男");
cJSON_AddStringToObject(object,name,s)
:将键值对(name / s)加入到 object 中cJSON_AddNumberToObject(object,name,n)
:将键值对(name / n)加入到 object 中
经过上述操作,我们就可以得到如图 6 所示的 cJSON 结构体。那如何获取基于该结构体的 JSON 字符串呢?
很简单,调用函数cJSON_Print()
或cJSON_PrintUnformatted()
即可实现:
char *pJsonFormatted = cJSON_Print(root);
puts(pJsonFormatted);
char *pJsonUnformatted = cJSON_PrintUnformatted(root);
puts(pJsonUnformatted);
cJSON_Print()
和cJSON_PrintUnformatted()
,这两个 API 的区别在于:一个是没有格式的,也就是转换出的字符串中间不会有换行、对齐之类的格式存在。而 cJSON_Print 打印出来是我们看起来很舒服的格式,仅此而已。
完整代码如下:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
#include "cJSON.h"
int main()
{
cJSON *root = cJSON_CreateObject();
cJSON_AddStringToObject(root, "name", "张三");
cJSON_AddNumberToObject(root, "age", 18);
cJSON_AddStringToObject(root, "sex", "男");
char *pJsonFormatted = cJSON_Print(root);
puts(pJsonFormatted);
char *pJsonUnformatted = cJSON_PrintUnformatted(root);
puts(pJsonUnformatted);
cJSON_Delete(root); // 手动调用 cJSON_Delete 进行内存回收
// 记得回收 pJsonFormatted 和 pJsonUnformatted
if (NULL != pJsonFormatted)
{
free(pJsonFormatted);
}
if (NULL != pJsonUnformatted)
{
free(pJsonUnformatted);
}
return 0;
}
3.4.2 一个有一丢丢复杂的例子
这次我们要获取的 JSON 字符串为:
{
"class_name": "计科一班",
"stu_num" : 2,
"stu_info" :
[
{
"name": "张三",
"age": 18,
"sex": "男"
},
{
"name": "李四",
"age": 20,
"sex": "男"
}
]
}
对应的反序列化后的模样如下图所示:
具体做法为:
- 首先创建一个 root
- 将第二层的 class_name、stu_num、stu_info 加入到 root 中
- 构造两个 JSON 项 item_0 和 item_1,并将 name、age、sex 分别加入其中
- 最后将 JSON 项 加入到 stu_info 中
大功告成,具体代码如下:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
#include "cJSON.h"
int main()
{
// 步骤一
cJSON *root = cJSON_CreateObject();
// 步骤二
cJSON_AddStringToObject(root, "class_name", "计科一班");
cJSON_AddNumberToObject(root, "stu_num", 2);
cJSON *pArray = cJSON_CreateArray();
cJSON_AddItemToObject(root, "stu_info", pArray);
// 步骤三
cJSON *pObject_1 = cJSON_CreateObject();
cJSON_AddStringToObject(pObject_1, "name", "张三");
cJSON_AddNumberToObject(pObject_1, "age", 18);
cJSON_AddStringToObject(pObject_1, "sex", "男");
cJSON *pObject_2 = cJSON_CreateObject();
cJSON_AddStringToObject(pObject_2, "name", "李四");
cJSON_AddNumberToObject(pObject_2, "age", 19);
cJSON_AddStringToObject(pObject_2, "sex", "男");
// 步骤四
cJSON_AddItemToArray(pArray, pObject_1);
cJSON_AddItemToArray(pArray, pObject_2);
char *pJson = cJSON_Print(root);
puts(pJson);
cJSON_Delete(root); // 手动调用 cJSON_Delete 进行内存回收
if (NULL != pJson) // 回收 pJson
{
free(pJson);
}
return 0;
}
参考资料
- cJSON 使用笔记 - 鱼竿的传说 - 博客园 (cnblogs.com)
- 使用 CJSON 在C语言中进行 JSON 的创建和解析的实例讲解 - fengbohello - 博客园 (cnblogs.com)
- cJSON学习笔记_xukai871105的博客-CSDN博客
- 认识Json本质 & 一个较复杂Json串的解析实例 - 灰信网(软件开发博客聚合) (freesion.com)
- 零基础学习cJSON 源码详解与应用(一)如何学习cJSON_killer-p的博客-CSDN博客
cJson 学习笔记的更多相关文章
- cJSON学习笔记
1.JSON格式简述 JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.易于人阅读和编写,同时也易于机器解析和生成.它基于JavaScript(Standa ...
- cJSON学习笔记 续集
0.前言 本文试图说明怎样使用CJSON构造各种各样的JSON数据包.在前段时间已经写过一篇cJSON的文章,所以本文成为"续集". [相关博文] [前端学 ...
- js学习笔记:webpack基础入门(一)
之前听说过webpack,今天想正式的接触一下,先跟着webpack的官方用户指南走: 在这里有: 如何安装webpack 如何使用webpack 如何使用loader 如何使用webpack的开发者 ...
- PHP-自定义模板-学习笔记
1. 开始 这几天,看了李炎恢老师的<PHP第二季度视频>中的“章节7:创建TPL自定义模板”,做一个学习笔记,通过绘制架构图.UML类图和思维导图,来对加深理解. 2. 整体架构图 ...
- PHP-会员登录与注册例子解析-学习笔记
1.开始 最近开始学习李炎恢老师的<PHP第二季度视频>中的“章节5:使用OOP注册会员”,做一个学习笔记,通过绘制基本页面流程和UML类图,来对加深理解. 2.基本页面流程 3.通过UM ...
- 2014年暑假c#学习笔记目录
2014年暑假c#学习笔记 一.C#编程基础 1. c#编程基础之枚举 2. c#编程基础之函数可变参数 3. c#编程基础之字符串基础 4. c#编程基础之字符串函数 5.c#编程基础之ref.ou ...
- JAVA GUI编程学习笔记目录
2014年暑假JAVA GUI编程学习笔记目录 1.JAVA之GUI编程概述 2.JAVA之GUI编程布局 3.JAVA之GUI编程Frame窗口 4.JAVA之GUI编程事件监听机制 5.JAVA之 ...
- seaJs学习笔记2 – seaJs组建库的使用
原文地址:seaJs学习笔记2 – seaJs组建库的使用 我觉得学习新东西并不是会使用它就够了的,会使用仅仅代表你看懂了,理解了,二不代表你深入了,彻悟了它的精髓. 所以不断的学习将是源源不断. 最 ...
- CSS学习笔记
CSS学习笔记 2016年12月15日整理 CSS基础 Chapter1 在console输入escape("宋体") ENTER 就会出现unicode编码 显示"%u ...
- HTML学习笔记
HTML学习笔记 2016年12月15日整理 Chapter1 URL(scheme://host.domain:port/path/filename) scheme: 定义因特网服务的类型,常见的为 ...
随机推荐
- git 根据历史 commitID 拉分支
1. git log -g 查看已commit的信息 2. 根据commit信息找到对应的commitID 3. 执行一下命令来创建新的分支 ### 1. 方法一:创建一个基于commitId的分支, ...
- mysql8.0及以上修改Root密码
ALTER user 'root'@'localhost' IDENTIFIED BY 'Cliu123#' //1.不需要flush privileges来刷新权限. //2.密码要包含大写字母,小 ...
- springboot 集成 docsify 实现随身文档
需求分析 文档可以和项目一起进行版本管理 文档可以在线访问 文档可以与springboot项目集成,不需要分开部署 MarkDown支持 文档跟随,打包jar也可以访问 技术选型 对于网上已有的方案, ...
- windows清理必看
清理缓存 代码如下 介绍此文件夹都是缓存文件全选删除即可 ctrl+A全选shift+del强制删除(不会添加到回收站) %temp% 找到C盘右击属性选择想要删除的文件进行清理即可 清理完点击清理系 ...
- 三分钟,带你了解PLM
PLM应用于单一地点或者多个地点的企业内部.以及在产品研发领域具有协作关系的企业之间的.支持产品全生命周期的信息的创建.管理.分发和应用的综合性的应用解决方案,能够集成与产品相关的流程.应用系统和信息 ...
- 使用Vite快速构建Vue3+ts+pinia脚手架
一.前言 vue3的快速更新,很多IT发展快的地区在22开始都已经提上日程,小编所在的青岛好像最近才有点风波.vue3的人才在青岛还是比较稀缺的哈,纯属小编自己的看法,可能小编是个井底之蛙!! vue ...
- Python 代码智能感知 —— 类型标注与特殊的注释(献给所有的Python人)
[原文地址:https://xiaokang2022.blog.csdn.net/article/details/126936985] 一个不会写好的类型标注和注释的Python程序员,是让使用T ...
- rabbitmq的内存节点和磁盘节点
RabbitMQ集群里有内存节点与磁盘节点之分. 所谓内存节点,就是将元数据(metadata)都放在内存里,磁盘节点就是放在磁盘上.(内存节点将全部的队列,交换器,绑定关系,用户,权限,和vhost ...
- 18. Fluentd输出插件:out_stdout用法详解
stdout即标准输出,out_stdout将收到的日志事件打印到标准输出. 如果Fluentd以daemon方式在后台运行,out_stdout会将事件输出到Fluentd的运行日志中. 这个插件在 ...
- 8_Quartz
一. 引言 1.1 简介 Quartz: http://www.quartz-scheduler.org/ 是一个 定时任务调度框架 ,比如我们遇到这样的问题 想在30分钟后, 查看订单是否支付, 未 ...