当要在代码中连接数据库时,往往需要登录用户的信息,而实际使用时登录用户常常变化,硬编码到代码中,改起来十分麻烦。所以使用Json
技术将我们封装好的用户管理类序列化
并储存到文件中,既能够持久化
,还实现了软编码
,使用户仅需方便地修改文件内容就能修改用户信息了。
用户配置类设计
第三方库
这里用到了两个第三方库
-ljsoncpp
Json的第三方库
-lmysqlcppconn
数据库的第三方库
编译指令如下
1
| g++ -o $@ $^ -std=c++11 -ljsoncpp -lmysqlcppconn
|
代码实现
作为MySQL
用户配置,至少要支持储存如下信息
然后核心功能如下
- 成员变量的访问和设置
- 将配置写入文件
- 从文件读入配置
根据如上要求,我们设计的核心代码如下
DBUserConfig.hpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| #pragma once #include <jsoncpp/json/json.h> #include <string> #include <fstream> #include <sstream>
class DBUserConfig { public: DBUserConfig(const std::string &file = "./userConfig", const std::string &user = "root", const std::string &password = "", const std::string &database = "", const std::string &ip = "127.0.0.1", size_t port = 3306) : _file(file), _user(user),_password(password), _database(database), _ip(ip), _port(port) { }
void writeFile();
bool readFile();
private: std::string _file; std::string _user; std::string _password; std::string _database; std::string _ip; size_t _port; };
|
关于成员变量的设置和访问的代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| void setFile(const std::string &file) { _file = file; } void setUser(const std::string &user) { _user = user; } void setPassword(const std::string & password){ _password = password; } void setDatabase(const std::string &database) { _database = database; } void setIp(const std::string &ip) { _ip = ip; } void setPort(size_t port) { _port = port; }
std::string User() { return _user; } std::string Password() {return _password; } std::string DataBase() { return _database; } std::string Ip() { return _ip; } size_t Port() { return _port; }
|
除此之外,我们再实现额外的三个函数
Address
返回地址(ip+端口号),函数内自动实现字符串拼接
writeFile
实现打开配置文件并写入
readFile
实现读取配置文件并获取配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| std::string Address() { std::string ret = _ip; ret += ":"; ret += std::to_string(_port); return ret; }
void writeFile() { Json::Value root;
root["user"] = _user; root["database"] = _database; root["ip"] = _ip; root["port"] = _port; root["password"] = _password;
Json::StyledWriter w; std::ofstream ofs(_file,std::ios::out);
ofs<< w.write(root); ofs.close(); }
bool readFile() { std::ifstream ifs(_file,std::ios::in); if(!ifs.is_open())return false; std::string str; std::stringstream buf; buf<<ifs.rdbuf(); str = buf.str(); ifs.close();
Json::Value root; Json::Reader reader; bool ret = reader.parse(str,root); if(!ret) { return false; } _user = root["user"].asString(); _database = root["database"].asString(); _ip = root["ip"].asString(); _port = root["port"].asUInt(); _password = root["password"].asString(); return true; }
|
特别的,在上面的代码中,我们用到了stringstream
和jsoncpp
来实现相关的操作
jsoncpp
的Json::Value
类可以用来描述一个类(更多的是类似于结构体),通过key-value
的方式把成员变量按需存储和读取,完成DBUserConfig
类的序列化和反序列化。
stringstream
则是使用了一个小技巧来直接读取文件的全部内容。当然这主要用于配置文件这种比较小的文件,对于非常大的文件,可能需要逐行或按块读取文件,以避免内存问题。
一点读取文件的小技巧
1 2 3 4 5 6 7
| std::ifstream ifs(_file,std::ios::in); if(!ifs.is_open())return false; std::string str; std::stringstream buf; buf<<ifs.rdbuf(); str = buf.str(); ifs.close();
|
整个文件的全部代码如下
DBUserConfig.hpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
| #pragma once #include <jsoncpp/json/json.h> #include <string> #include <fstream> #include <sstream>
class DBUserConfig { public: DBUserConfig(const std::string &file = "./userConfig", const std::string &user = "root", const std::string &password = "", const std::string &database = "", const std::string &ip = "127.0.0.1", size_t port = 3306) : _file(file), _user(user),_password(password), _database(database), _ip(ip), _port(port) { }
void setFile(const std::string &file) { _file = file; } void setUser(const std::string &user) { _user = user; } void setPassword(const std::string & password){ _password = password; } void setDatabase(const std::string &database) { _database = database; } void setIp(const std::string &ip) { _ip = ip; } void setPort(size_t port) { _port = port; }
std::string Address() { std::string ret = _ip; ret += ":"; ret += std::to_string(_port); return ret; } std::string User() { return _user; } std::string Password() {return _password; } std::string DataBase() { return _database; } std::string Ip() { return _ip; } size_t Port() { return _port; }
void writeFile() { Json::Value root;
root["user"] = _user; root["database"] = _database; root["ip"] = _ip; root["port"] = _port; root["password"] = _password;
Json::StyledWriter w; std::ofstream ofs(_file,std::ios::out);
ofs<< w.write(root); ofs.close(); }
bool readFile() { std::ifstream ifs(_file,std::ios::in); if(!ifs.is_open())return false; std::string str; std::stringstream buf; buf<<ifs.rdbuf(); str = buf.str(); ifs.close();
Json::Value root; Json::Reader reader; bool ret = reader.parse(str,root); if(!ret) { return false; } _user = root["user"].asString(); _database = root["database"].asString(); _ip = root["ip"].asString(); _port = root["port"].asUInt(); _password = root["password"].asString(); return true; }
private: std::string _file; std::string _user; std::string _password; std::string _database; std::string _ip; size_t _port; };
|
代码测试和连接测试
我们来写个main.cpp
和makefile
main.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| #include "DBUserConfig.hpp" #include <iostream> #include <memory> #include <mysql_driver.h> #include <mysql_connection.h> #include <cppconn/statement.h> #include <cppconn/resultset.h>
using namespace std;
int main() { DBUserConfig dbu; bool ret = dbu.readFile(); if(!ret) { cout<<"start write\n"; dbu.setFile("./userConfig"); dbu.setIp("127.0.0.1"); dbu.setPort(3306); dbu.setUser("conn"); dbu.setDatabase("testDB"); dbu.setPassword("12345678"); } sql::mysql::MySQL_Driver* driver; driver = sql::mysql::get_mysql_driver_instance();
std::unique_ptr<sql::Connection> conn(driver->connect(dbu.Address(),dbu.User(),dbu.Password()));
cout<<conn->getClientInfo()<<endl;
dbu.writeFile(); return 0; }
|
makefile
1 2 3 4 5 6
| mycmd:main.cpp g++ -o $@ $^ -std=c++11 -ljsoncpp -lmysqlcppconn
.PHONY:clean clean: rm -f mycmd
|
接下来我们来编译执行并测试代码
结果如下
可以看到,当读不到配置文件时,自动写入了用户配置信息,并成功连接上了数据库
紧接着我们再运行一次
可以看到直接读取了配置文件并成功连接上了数据库
End
以上就是一个用户配置类的小组件开发。