记录完成MFC大作业中遇到的问题和一些解决办法。调用的API来源为23、实时汇率API接口,免费好用_roll圈圈的博客-CSDN博客_汇率api;用到的库有curl、nlohmann_json。
Visual Studio(VS2017)编译并使用curl C/C++ HTTP GET POST libcurl(二、调用示例)_路过人间本尊的博客-CSDN博客_vs2017编译curl
VS2022编译和使用curl网络库_含影的博客-CSDN博客_curl vs 编译
c++ 使用nlohmann_json库解析json文件_山水一的博客-CSDN博客
libcurl使用easy模式阻塞卡死等问题的完美解决---超时设置_指尖上星空的博客-CSDN博客_libcurl 超时
这里用到curl库,需要自己编译(也有编译好的库)和VS环境配置。一开始想用自己编译的curl库,但bat文件无法再电脑上运行,用Shell运行会报错:Error: This batch file should only be used with a curl git repository。后来改用编译好的库成功配置好环境。
已编译好的库下载,这里用的适用VS2019-2022,debug x64,其他配置可以返回父目录下载。windows.php.net - /downloads/php-sdk/deps/vs16/x64/
将下载文件夹中的 include 和 lib 文件夹复制到工程目录下(若附加多个库,建议外面套一个文件夹命名为curl,防止混乱)
GitHub - nlohmann/json: JSON for Modern C++
下载 nlohmann_json,复制其中的三个文件夹 include、single_include、tests 到工程目录下(同样建议外面套一个文件夹命名为nlohmann_json)。
然后是修改工程属性。在解决方案资源管理器找到项目(图中为calculator),右键弹出选项,选择“属性”。
注意:
以下两个目录位置可能有出入,根据你之前复制的库文件的路径写即可;
$(ProjectDir)\ :这个前缀含义是在项目文件中查找,用这个可以防止工程文件移动带来的找不到库文件的问题。
【VC++目录】--【包含目录】
$(ProjectDir)\include;$(ProjectDir)\nlohmannjson\single_include;$(ProjectDir)\nlohmannjson\include;$(IncludePath)
【VC++目录】--【库目录】
$(ProjectDir)\lib;$(ProjectDir)\bin;$(ProjectDir)\nlohmannjson\tests\thirdparty\doctest;$(ProjectDir)\nlohmannjson\tests\thirdparty\fifo_map;$(LibraryPath)
【链接器】--【输入】--【附加依赖项】
//(curl库的)
libcurl_a.lib
Ws2_32.lib
Wldap32.lib
winmm.lib
Crypt32.lib
Normaliz.lib
//(nlohmannjson的)
kernel32.lib
user32.lib
gdi32.lib
winspool.lib
shell32.lib
ole32.lib
oleaut32.lib
uuid.lib
comdlg32.lib
advapi32.lib
【C/C++】--【预处理器】
CURL_STATICLIB //用于配置curl环境
_CRT_SECURE_NO_WARNINGS //解决fopen不安全的问题
void get_api_to_file() //从网页api获取汇率信息并写入json文件
{
CURL* curl = NULL;
CURLcode res = CURLE_OK;
FILE* fp;
fp = fopen("rate.json", "w");
struct curl_slist* headers = NULL;
headers = curl_slist_append(headers, "charsets = utf-8"); //加了这个命令行还是会出现中文乱码,这里暂时也没有好的解决办法
curl_global_init(CURL_GLOBAL_ALL);
//初始化easy handler句柄
curl = curl_easy_init();
if (curl) {
//设置post请求的url地址
curl_easy_setopt(curl, CURLOPT_URL, "这里填网页API的URL");
//设置HTTP头
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
//写入文件fp
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
//设置发送超时时间,防止出现阻塞(easy模式会有阻塞情况)
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3);
//执行单条请求
res = curl_easy_perform(curl);
if (res != CURLE_OK) {
//curl_easy_strerror进行出错打印
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
}
curl_slist_free_all(headers);
//这个调用用来结束一个会话.与curl_easy_init配合着用
curl_easy_cleanup(curl);
//在结束libcurl使用的时候,用来对curl_global_init做的工作清理。类似于close的函数
curl_global_cleanup();
fclose(fp);
}
return;
}
从API获取到的数据是Json格式,需要进行解析方便使用。
在头文件中先根据API的json样式定义好结构体。
//准备好带解析汇率信息的格式
struct rate_unit
{
string name;
string nameDesc;
string from;
string to;
string price;
CString fromDesc;
CString toDesc;
};
struct all
{
int code;
string msg;
rate_unit rate_[24];
int size;
};
在.cpp中重载解析json的函数
//以下两个from_json函数是为了解析从网页api获取含汇率信息的json文件
void from_json(const json& j, all& a)
{
j.at("code").get_to(a.code);
j.at("msg").get_to(a.msg);
for (int i = 0; i < j["data"].size(); i++)
{
a.rate_[i].name = j["data"][i].at("name");
a.rate_[i].nameDesc = j["data"][i].at("nameDesc");
a.rate_[i].from = j["data"][i].at("from");
a.rate_[i].to = j["data"][i].at("to");
a.rate_[i].price = j["data"][i].at("price");
}
a.size = j["data"].size();
}
void from_json(const json& j, rate_unit& d)
{
j.at("name").get_to(d.name);
j.at("nameDesc").get_to(d.nameDesc);
j.at("from").get_to(d.from);
j.at("to").get_to(d.to);
j.at("price").get_to(d.price);
}
将其解析,数据储存在all类型结构体s内
get_api_to_file();
ifstream jfile("rate.json");
json nj;
jfile >> nj;
//解析json文件到all类型的struct
from_json(nj, s);