CppCMS的編譯和使用
請參考我的相關文章。
將C++對象轉換成JSON字符串
假定有一個類response,兩個字段,一個是status,0代表正確。其他代表錯誤。另一個是message字段,表示操作結果的具體信息。代碼如下:
class response {
public:
//0 is ok
//other values are wrong
int status;
string message;
};
現在需要將response對象的數據轉換成JSON格式字符串。還需要寫一個模板類來,代碼如下:
namespace cppcms {
namespace json {
template<>
struct traits<response> {
static void set(value &v, response const& in) {
v.set("status", in.status);
v.set("message", in.message);
}
};
}
}
好,現在編寫調用代碼,並查看運行結果。
#include <cppcms/json.h>
...
int main(int argc, char** argv) {
response r1;
r1.status=0;
r1.message="ok";
cout<< cppcms::json::value(r1)<<endl;
response r2;
r2.status=1;
r2.message="unknown error";
cout<< cppcms::json::value(r2)<<endl;
return 0;
}
運行結果:
{"message":"ok","status":0}
{"message":"unknown error","status":1}
cppcms::json::value類代碼分析
之所以很容易就轉換成JSON串,是因為使用了value類。現在來分析一下上面的調用代碼裡面是如何工作的。
1.cppcms::json::value(r1) 創建了匿名對象value,value的構造函數內部調用了set_value方法。參數v此時就是response對象。
template<typename T>
value(T const &v)
{
set_value(v);
}
2.set_value方法調用了traits<T>::set(this,v),這個就是前面我們重載的模板方法。
template<typename T>
void set_value(T const &v)
{
traits<T>::set(this,v);
}
3.剩下的事情目的很明確了,需要將value對象的值轉換成JSON字符串,然後輸出到流中。Artyom重載了operator<<函數,底層實現函數如下:
std::ostream &operator<<(std::ostream &out,value const &v)
{
v.save(out);
return out;
}
void value::save(std::ostream &out,int how) const
{
int tabs=(how & readable) ? 0 : -1;
write(out,tabs);
}
void value::write(std::ostream &out,int tabs) const
{
std::locale original(out.getloc());
out.imbue(std::locale("C"));
try {
write_value(out,tabs);
}
catch(...) {
out.imbue(original);
throw;
}
out.imbue(original);
}
void value::write_value(std::ostream &out,int tabs) const
{
switch(type()) {
case json::is_undefined:
throw bad_value_cast("Can't write undefined value to stream");
case json::is_null:
out<<"null";
break;
case json::is_number:
out<<std::setprecision(std::numeric_limits<double>::digits10+1)<<number();
break;
case json::is_string:
out<<escape(str());
break;
case json::is_boolean:
out<< (boolean() ? "true" : "false") ;
break;
case json::is_array:
{
json::array const &a=array();
unsigned i;
indent(out,'[',tabs);
for(i=0;i<a.size();) {
a[i].write_value(out,tabs);
i++;
if(i<a.size())
indent(out,',',tabs);
}
indent(out,']',tabs);
}
break;
case json::is_object:
{
json::object const &obj=object();
object::const_iterator p,end;
p=obj.begin();
end=obj.end();
indent(out,'{',tabs);
while(p!=end) {
out<<escape(p->first);
indent(out,':',tabs);
p->second.write_value(out,tabs);
++p;
if(p!=end)
indent(out,',',tabs);
}
indent(out,'}',tabs);
}
break;
default:
throw bad_value_cast("Unknown type found: internal error");
}
}
上面的代碼包含了很多細節,很多都可以獨立成文描述。這裡主要是為了搞明白cppcms::json::value內部的設計原理,便於更好的使用。就暫時追蹤到這裡。
將JSON字符串轉換成C++對象
下面的代碼演示了如何將流裡面的JSON串放入value對象,然後通過get方法查找,"null"是假定找不到的時候的默認值。
stringstream stream;
stream << "{\"message\":\"ok\",\"status\":0}";
cppcms::json::value value2;
stream >> value2;
string m = value2.get("message","null");
也可以用更嚴格的get方法的重載,沒有默認值,如果找不到就會拋出bad_cast異常。
///
/// Get an object of type T from the path \a path. Throws bad_value_cast if such path does not
/// exists of conversion can't be done
///
template<typename T>
T get(std::string const &path) const
{
return at(path).get_value<T>();
}
我不喜歡寫篇幅很大的文章,本篇主要描述如何使用,順便挖了一下源代碼。後面會陸續深挖CppCMS的源代碼。
摘自 sheismylife的專欄