Json-Rpc框架(JsonCpp库使用介绍)
阅读导航
- 引言
- 一、Json数据格式
- 二、JsonCpp介绍
- 三、JsonCpp使用示例
- 四、封装Json工具类
引言
JsonCpp,作为一个广受欢迎的C++ JSON库,以其易用性、高性能和丰富的功能集赢得了众多开发者的青睐。它不仅提供了简洁直观的API用于JSON数据的解析和生成,还通过良好的异常处理机制和类型安全的设计,确保了代码的稳定性和可维护性。在接下来的内容中,我们将详细介绍JsonCpp的基本用法、核心特性以及它是如何与我们的Json-Rpc框架无缝集成的,从而帮助我们更加高效地处理JSON数据,推动项目向前发展。
一、Json数据格式
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,它以易于人阅读和编写的文本格式来存储和表示结构化数据,且这种格式独立于任何编程语言。
🎯例如:我们想表示⼀个同学的学⽣信息
- 💻C++代码表示
char *name = "xx";
int age = 18;
float score[3] = {88.5, 99, 58};
- 💻Json 表⽰
{
"姓名" : "xx",
"年龄" : 18,
"成绩" : [88.5, 99, 58],
"爱好" : {
"书籍" : "西游记",
"运动" : "打篮球"
}
}
JSON是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成。它基于JavaScript的一个子集,但JSON是独立于语言的,并且被许多现代编程语言所支持。JSON的主要数据类型包括:
-
对象:对象在JSON中以花括号
{}
包围,它们由键值对组成,键和值之间通过冒号:
分隔,每对键值对之间使用逗号,
分隔。键必须是字符串,而值可以是字符串、数字、布尔值、数组、对象或null。 -
数组:数组在JSON中以中括号
[]
包围,它们包含了一系列的值,这些值可以是字符串、数字、布尔值、数组、对象或null。数组中的值通过逗号,
分隔。 -
字符串:字符串在JSON中必须使用双引号
""
包围,不能使用单引号。字符串中可以包含转义字符,例如\n
表示换行,\"
表示双引号本身等。 -
数字:JSON中的数字可以是整数或浮点数,不需要额外的引号或格式标记。数字可以非常大或非常精确,且遵循IEEE 754标准。
-
布尔值:布尔值在JSON中表示为
true
或false
,它们不区分大小写,但习惯上写作小写形式。
二、JsonCpp介绍
Jsoncpp 库是一个专注于处理JSON格式数据的C++库,它提供了两个核心功能:序列化和反序列化。
序列化功能允许开发者将C++中的数据结构(如对象、数组等)转换成JSON格式的字符串,这种字符串形式便于数据的存储、传输或网络交换。
反序列化功能则是这一过程的逆操作,它能够将JSON格式的字符串解析回C++中的数据结构,使得程序能够方便地读取和处理这些数据。
⭕Json 数据对象类的表⽰
class Json::Value {
public:
// 赋值操作符重载
Value& operator=(const Value& other);
// 通过字符串键访问成员,支持赋值和获取
Value& operator[](const std::string& key);
Value& operator[](const char* key);
// 移除具有指定键的成员
Value removeMember(const char* key);
// 通过索引访问数组元素(只读)
const Value& operator[](ArrayIndex index) const;
// 向数组末尾添加元素
Value& append(const Value& value);
// 获取数组元素的数量
ArrayIndex size() const;
// 类型转换函数
std::string asString() const; // 转换为std::string
const char* asCString() const; // 转换为const char*
int asInt() const; // 转换为int
float asFloat() const; // 转换为float
bool asBool() const; // 转换为bool
};
📌Jsoncpp 库主要借助三个类以及其对应的少量成员函数完成序列化及反序列化
- 序列化接口
class JSON_API StreamWriter {
virtual int write(Value const& root, std::ostream* sout) = 0;
}
class JSON_API StreamWriterBuilder : public StreamWriter::Factory {
virtual StreamWriter* newStreamWriter() const;
}
- 反序列化接口
class JSON_API CharReader {
virtual bool parse(char const* beginDoc, char const* endDoc, Value* root, std::string* errs) = 0;
}
class JSON_API CharReaderBuilder : public CharReader::Factory {
virtual CharReader* newCharReader() const;
}
三、JsonCpp使用示例
#include <iostream>
#include <sstream>
#include <string>
#include <memory>
#include <jsoncpp/json/json.h>
// 实现数据的序列化,将Json::Value对象转换为JSON格式的字符串
bool serialize(const Json::Value &val, std::string &body) {
std::stringstream ss; // 创建一个字符串流,用于存储序列化后的JSON字符串
// 先实例化一个StreamWriterBuilder对象,它是用于创建StreamWriter对象的工厂
Json::StreamWriterBuilder swb;
// 通过StreamWriterBuilder对象来生成一个StreamWriter对象的智能指针
std::unique_ptr<Json::StreamWriter> sw(swb.newStreamWriter());
// 调用StreamWriter对象的write方法,将Json::Value对象序列化到字符串流中
int ret = sw->write(val, &ss);
if (ret != 0) { // 如果序列化失败(通常ret应为0表示成功)
std::cout << "json serialize failed!\n";
return false;
}
body = ss.str(); // 将字符串流中的内容赋值给body
return true;
}
// 实现json字符串的反序列化,将JSON格式的字符串解析为Json::Value对象
bool unserialize(const std::string &body, Json::Value &val) {
// 实例化CharReaderBuilder对象,它是用于创建CharReader对象的工厂
Json::CharReaderBuilder crb;
// 通过CharReaderBuilder对象生成一个CharReader对象的智能指针
std::string errs; // 用于存储解析过程中可能出现的错误信息
std::unique_ptr<Json::CharReader> cr(crb.newCharReader());
// 调用CharReader对象的parse方法,将JSON字符串解析为Json::Value对象
// 注意:parse方法的第二个参数是字符串的结束位置(指向字符串末尾的下一个位置)
bool ret = cr->parse(body.c_str(), body.c_str() + body.size(), &val, &errs);
if (ret == false) { // 如果解析失败
std::cout << "json unserialize failed : " << errs << std::endl;
return false;
}
return true;
}
int main()
{
// 初始化一些示例数据
const char *name = "小明";
int age = 18;
const char *sex = "男";
float score[3] = {88, 77.5, 66};
// 创建一个Json::Value对象来存储学生信息
Json::Value student;
student["姓名"] = name; // 添加姓名
student["年龄"] = age; // 添加年龄
student["性别"] = sex; // 添加性别
// 添加成绩,需要逐个添加,因为score是一个数组,而Json::Value需要逐个元素处理
for (int i = 0; i < 3; ++i) {
student["成绩"].append(score[i]);
}
// 添加爱好,爱好也是一个Json::Value对象,包含书籍和运动两个字段
Json::Value fav;
fav["书籍"] = "西游记";
fav["运动"] = "打篮球";
student["爱好"] = fav; // 将爱好对象添加到学生信息中
std::string body;
// 序列化学生信息到字符串body中
serialize(student, body);
std::cout << body << std::endl; // 打印序列化后的JSON字符串
// 示例:反序列化一个JSON字符串
std::string str = R"({"姓名":"小黑", "年龄": 19, "成绩":[32, 45, 56]})";
Json::Value stu;
bool ret = unserialize(str, stu);
if (ret == false)
return -1; // 如果反序列化失败,则退出程序
// 访问并打印反序列化后的JSON对象中的信息
std::cout << "姓名: " << stu["姓名"].asString() << std::endl;
std::cout << "年龄: " << stu["年龄"].asInt() << std::endl;
int sz = stu["成绩"].size();
for (int i = 0; i < sz; i++) {
std::cout << "成绩: " << stu["成绩"][i].asFloat() << std::endl;
}
return 0;
}
编译运⾏程序查看序列化和反序列化结果
{
"姓名":"小明",
"年龄":18,
"性别":"男",
"成绩":
[
88.0,
77.5,
66.0
],
"爱好":
{
"书籍":"西游记",
"运动":"打篮球"
}
}
姓名: 小黑
年龄: 19
成绩: 32
成绩: 45
成绩: 56
四、封装Json工具类
#include <iostream>
#include <sstream>
#include <string>
#include <memory>
#include <jsoncpp/json/json.h>
class json_util
{
public:
// 序列化: Json对象 -> 字符串
// 输入输出型参数
// root输入参数:表示要序列化的json对象
// str输出参数: 表示序列化之后的字符串
static bool serialize(const Json::Value &root, std::string &str)
{
Json::StreamWriterBuilder swb;
std::unique_ptr<Json::StreamWriter> sw(swb.newStreamWriter());
std::stringstream ss;
int ret = sw->write(root, &ss);
if (ret != 0) {
std::cout << "Serialize failed!" << std::endl;
return false;
}
str = ss.str();
return true;
}
// 反序列化: 字符串 -> Json对象
// 输入输出型参数
// str输入参数: 表示需要反序列化的字符串
// root输出参数:表示反序列化后的json对象
static bool unserialize(const std::string &str, Json::Value &root)
{
Json::CharReaderBuilder crb;
std::unique_ptr<Json::CharReader> cr(crb.newCharReader());
std::string errs;
bool ret = cr->parse(str.c_str(), str.c_str() + str.size(), &root, &errs);
if (!ret) {
std::cout << "UnSerialize failed! Errors: " << (errs.empty() ? "None" : errs) << std::endl;
return false;
}
return true;
}
};