• 数据库编程——案例开发


    在学习数据库编程总结了笔记,并分享出来。有问题请及时联系博主:Alliswell_WP,转载请注明出处。

    09-数据库编程day06(案例开发)

    目录:
    一、学习目标
    二、MongoDB复习
    三、MongoDB API
    0、复习API构造函数、连接函数、插入、删除
    1、通过API修改数据和查询分析
    2、通过API查询文档
    3、通过API查询文档、内容解析、异常捕捉
    四、案例开发(网盘-服务器端)
    1、案例需求分析、模型设计
    2、搭建框架
    3、MySQL端登录实现
    4、SQL注入问题解决
    5、查看功能实现
    6、MySQL侧实现上传功能
    7、上传文件MongoDB侧实现
    8、MySQL与MongoDB类的调用
    9、上传测试成功
    10、下载功能实现
    11、总结

    一、学习目标

    1. api 实现查询功能.
    2. 案例的数据模型设计
    3. 了解案例实现的核心原理
    4. 案例的程序框架搭建
    5. 了解案例实现的过程

    二、MongoDB复习

    》体系结构:库—集合
    集合:对应关系型数据库的表,键值对的组合
    文档:键值对,json

    》删库分2步:
    ○ 切库use dbname
    ○ 删库db.dropDatabase()

    》文档的新增:
    ---insert
    db.collection_name.insert(json)
    --save 指定了_id时,相当于修改
    --find
    db.collection_name.find({cond},{show})

    db.collection.aggregate() $group   group By col1,col2  —— _id:{col1,col2}
    --按位置,年龄分组,计算人数
    db.Barca.aggregate({ $group:{ _id:{pos:"$pos",age:"$age"},count:{$sum:1}  }   })

    --update
    db.collection_name.update({query},{update},{upsert:false,multi:false})
    --remove
    db.collection_name.remove({query},{justOne:false})

    --index
    db.collection_name.ensureIndex({field:1})  
    db.collection_name.dropIndex({field:1})

    三、MongoDB API

    0、复习API构造函数、连接函数、插入、删除

    1)构造函数
    DBClientConnection(bool auto_connect, 0, double so_timeout);
    auto_connect(IN):连接失败后自动重连
    so_timeout(IN):非连接超时,tcp的读写超时

    2)连接函数
    bool connect(string server, &string errmsg);
    返回值:成功/失败
    server(IN):连接的服务器
    errmsg(OUT):出错信息

    》示例:
    bool auto_connect = true;
    double so_timeout = 3;
    string host = "127.0.0.1";
    string port = "27017";
    string errmsg = "";
    DBClientConnection pConn = new DBClientConnection(auto_connect, 0, so_timeout);
    pConn->connect(host+":"+port, errmsg);

    3)插入
    void insert(const string &ns, BSONObj obj, int flags);
    ns(IN):命名空间,db_name.collection_name
    obj(IN):插入的列
    flags(IN):详见API文档,默认填零即可

    》示例:
    BSONObj insert = BSON("uid"<<10001<<"name"<<"skean1017");
    pConn->insert(db+"."+collection, insert, 0);
    其效果相当于:
    insert into shool.student (uid, name) values (10001, “skean1017″);

    4)删除
    void remove(const string &ns, Query query, bool justOne);
    ns(IN):命名空间,db_name.collection_name
    query(IN):查询条件
    justOne(IN):是否只删除匹配的第一条

    》示例:
    Query query = QUERY("name"<<"skean1017");
    pConn->remove(db+"."+collection, query, true);
    其效果相当于:
    delete from shool.student where name=”skean1017″;

    1、通过API修改数据和查询分析

    --修改

    void update( const string &ns,Query query,BSONObj obj,bool upsert = false, bool multi = false );
    ○ ns  库名.集合名
    ○ obj BSON对象
    ○ upsert 如果条件不成立是否新增,默认false
    ○ multi 是否更新多条,默认false

    》示例:
    Query query = QUERY("uid"<<10001);
    BSONObj obj = BSON("$set"<update(db+"."+collection, query, obj, false, false);
    其效果相当于:
    update shool.student set name=”habadog1203” where uid=10001;

    --查询

    virtual auto_ptr<DBClientCursor> query(const string &ns, Query query=Query() , int nToReturn = 0, int nToSkip = 0,const BSONObj *fieldsToReturn = 0, int queryOptions = 0 , int batchSize = 0 ) {            checkConnection();
    return DBClientBase::query( ns, query, nToReturn, nToSkip, fieldsToReturn, queryOptions , batchSize );    
    }
    —auto_ptr<DBClientCursor>  智能指针,自动释放<>内部的内存数据
    —cusor 游标
    —DBClientCursor 类
    ○ more()如果为真,调用next是安全的
    ○ next()返回BSONObj 对象
    ——query函数参数
    ○ ns 库名.集合名
    ○ query 查询条件
    ○ nToReturn  返回记录数
    ○ nToSkip   跳过的记录数
    ○ fieldsToReturn 要返回的字段

    》示例:
    string db = "shool";
    string collection = "student";
    Query condition = QUERY("age"<<20);
    int limit = 10;
    int offset = 5;
    BSONObj columns = BSON("uid"<<1<<"name"<<1);
    auto_ptr cursor;
    cursor = pConn->query(db+"."+collection, condition, limit, offset, columns, 0, 0);
    其效果相当于:
    select uid,name from shool.student where age=20 limit 5,10;
    对结果集的操作:
    int uid=0;
    string name="";
    while(cursor->more())
    {
        BSONObj p = cursor->next();
        uid = p["uid"].Int();
        name = p["name"].String();
        count << uid << " " << name << endl;
    }

    2、通过API查询文档

    --BSONObj对象
    ○ BSONElement getField(const StringData& name) const;  获得对应字段

    思路:通过getField 获得BSONElement(元素)对象,调用String(),Number()精确获得各个值?

    但是,如果有的数据没有age,这样调用有问题:

    ——解决:需要调用hasField(char*)或hasElement(char*)来判断是否有该元素

    3、通过API查询文档、内容解析、异常捕捉

    》解析文档流程:

    》mongodb的api的异常处理
    mongodb为我们提供了DBException异常类,如果有错误会进行抛出,我们可以通过try catch的方式捕捉该类错误,然后通过打印 what()显示错误详细信息.具体所在头文件: assert_util.h.除了捕获mongo提供的异常信息,还需要捕获标准库的错误信息,最后有一个兜底的所有异常捕捉.
    使用方法:
    catch( mongo::DBException& e ) {
        printf("MONGO Exception(set): %s ", e.what());
        return -1;
    }
    catch (std::exception& e) {
        printf("MONGO Exception(set): %s ", e.what());
        return -1;
    }
    catch (...){
        printf(“MONGO Exception ”);
        return -1;
    }

    》头文件准备:

    --在VS中更改main.cpp

    #include <iostream>
    #include <string>
    #include <mongo/client/dbclient.h>
    
    using namespace std;
    using namespace mongo;
    
    int main(int argc,char *argv[])
    {
        if (argc != 2){
            cout << "./main 1|2|3|4 ---- 1-insert,2-remove,3-update,4-query" << endl;
            return -1;
        }
        int op = atoi(argv[1]);
        
        //构造连接
        DBClientConnection conn(false,0,3);
        std::string errmsg;
        if (!conn.connect("localhost:27018", errmsg)){//模拟一下错误端口27018
            cout << "connect to mongo err" << endl;
            //return -1;
        }
        cout << "connect ok" << endl;
        try{
    
        
            if (op == 1){
                //insert 
                //第一种玩法
                BSONObjBuilder b1;
                b1.append("id", 1);
                b1.append("name", "yekai");//{id:1,name:'yekai'}
                conn.insert("yekai.langzi", b1.obj());
                //第二种玩法
                BSONObjBuilder b2;
                b2 << "id" << 2 << "name" << "fuhongxue";
                conn.insert("yekai.langzi", b2.obj());
                //第三种玩法
                conn.insert("yekai.langzi", BSON("id" << 3 << "name" << "luxiaojia"));
                //第四种玩法
                Query ins("{id:4,name:'lixunhuan',age:50,info:{like:'drink',wuqi:'feidao'}}");
                conn.insert("yekai.langzi", ins.obj);
            }
            else if (op == 2){
                //remove
                //删除id》=2 {id:{$gte:2}}
                Query qry("{id:{$gte:2}}");
                conn.remove("yekai.biancheng", qry);
            }
            else if (op == 3){
                //update 
                Query qry("{id:1}");//查询条件
                //Query bobj("{$set:{name:'fuhongxue'}}");//更新的内容
                Query bobj("{name:'fuhongxue'}");//更新的内容
                conn.update("yekai.langzi", qry, bobj.obj);
            }
            else if (op == 4){
                //query 
                auto_ptr<DBClientCursor> cursor = conn.query("yekai.langzi", Query("{}"));
    
                while (cursor->more()){//判断是否有下一条
                    mongo::BSONObj obj = cursor->next();//取下一条记录,为BSONObj格式
                    //cout << obj << endl;
                    //解析数据
                    cout << "id:" << obj.getField("id").Number() << ",name:" << obj.getField("name").String();
                    if (obj.hasElement("age")){//是否存在该元素
                        cout << ",age:" << obj.getField("age").Number();
                    }
                    
                    if (obj.hasElement("info")){
                        cout << ",info:{ like:" << obj["info"]["like"].String() << ",wuqi:" << obj["info"]["wuqi"].String()<<"}";//使用重载操作符[]
                    }
                    cout << endl;
                }
            }
        }
        catch (mongo::DBException& e) {
            printf("MONGO Exception(set): %s
    ", e.what());
            return -1;
        }
        catch (std::exception& e) {
            printf("MONGO STD Exception(set): %s
    ", e.what());
            return -1;
        }
        catch (...){
            printf("MONGO Exception
    ");
            return -1;
        }
    
        return 0;
    }
    main.cpp

    原终端改变前后数据(>db.langzi.find())对比。

    将main.cpp传至Linux上,然后打开另一个终端重新编译,执行shell>./main 4)

    四、案例开发(网盘-服务器端)

    1、案例需求分析、模型设计

    》需求总体描述
    开发类似于网盘功能,支持文件(图片,视频,mp3等)的上传和下载(MongoDB的优势)。

    》功能需求
    支持多用户
    1)用户的校验,必须是注册用户,用户名和密码正确才能上传和下载。(注册部分正常需要web前端开发,该案列不做注册部分功能,直接在mysql的用户表增加记录即可)。
    2)查看登陆用户上传的文件信息。(支持命令行的方式查看即可,不需要做web前端),实现管理台。
    3)上传文件
    4)下载上传过的文件到本地。
    5)删除上传的文件。(可根据情况是否添加,不是必须)


    》技术实现要求
    Mysql+mongo
    用mysql存储用户的信息,文件上传和下载的对应关系(本地和mongo中文件的对应关系)
    Mongo存放文件。

    》流程
    需求接收-需求分析-概要设计-详细设计-编码-测试-上线-维护-------------下线

    》可行性分析:
      工期评估 人月
      技术可行性:
      ○ BSONObj storeFile( const string& fileName , const string& remoteName="" , const string& contentType="");  上传GridFS
      ○ gridfs_offset write( const string& where ) const; 下载GridFile

    功能设计,模块设计,模型设计

    》设计功能:
    ○ 用户验证
    ○ 上传
    ○ 下载
    ○ 查看
    ○ 删除(二期)

    》模块设计:
    ○ 设计2个类
      ▪ mysql 操作mysql数据库  用户验证,保存文件信息,查询文件信息
      ▪ mongo 操作mongo数据库  存文件,下载文件

    》模型设计:
    ○ 参考功能
    ○ 用户验证  设计用户信息表

    用户信息表:用户id,用户姓名,密码,手机号,公司,邮箱,备注

    create table t_user_info( user_id varchar(30),
    user_name varchar(50),
    pass_word varchar(16),
    remark varchar(100)
    );
    ○ 文件信息查看设计文件信息表(mysql)

    文件信息表:本地文件名,文件类型,大小,上传时间,修改时间,下载次数,用户id,mongo文件名,备注

    create table t_file_info(
    file_id int primary key auto_increment,
    local_file_name varchar(50),
    mongo_file_name varchar(50),
    file_size int,
    upload_date timestamp,
    user_id  varchar(30),
    remark varchar(100)
    );

    打开VS2015,新建项目:选择“Visusl C++”,右侧选择“空项目”,名称:ods,位置改为project所在目录(我的为 F:Download6-数据库编程day06(案例开发)4-源码project);

    创建成功后,在“ods”右键选择“属性”,选择“VC++目录”进行配置:选择“包含目录”,在其后加入到include一级的目录(最好是相对路径,我的为 ....mongoinclude);

    在“ods”右键添加源文件:main.cpp,然后编写代码。

    》建库建表(Linux登录MySQL)

    shell>mysql -u root -p(输入密码)
    mysql> show databases;
    mysql> create database ods character set utf8;(建库:ods—online database store)
    mysql> use ods;(切库)
    mysql> create table t_user_info( user_id varchar(30), user_name varchar(50), pass_word varchar(16), remark varchar(100) );
    mysql> create table t_file_info( file_id int primary key auto_increment, local_file_name varchar(50), mongo_file_name varchar(50), file_size int, upload_date timestamp, user_id  varchar(30), remark varchar(100) );

    2、搭建框架

    》(管理台)设计指令:
    -上传upload srcfile mongofile
    -下载download mongofile desfile
    -查看  list
    -退出 quit
    -删除 delete mongofile  localfile(二期)

    》编写main.cpp

    #include <iostream>
    #include <vector>
    #include <string>
    
    using namespace std;
    
    void splitString(const char *Src, char delim, vector<string> &vsplit)
    {
        string tmp = Src;
        vsplit.clear();
        int index = 0;
        size_t last = 0;
        last = tmp.find_first_not_of(delim, last);//找到第一个不为分隔符的字符
        index = tmp.find_first_of(delim, last);//找到第一个分隔符
        while (index != string::npos)//npos代表字符串的结尾
        {
            string target = tmp.substr(last, index - last);
            vsplit.push_back(target);
    
            //last = index +1;
            last = tmp.find_first_not_of(delim, index);
            index = tmp.find_first_of(delim, last);
    
        }
        if (index == string::npos && tmp.length() > last)//到末尾了,如果整个长度大于last坐标,说明还有最后一个字符要放到vector
        {
            vsplit.push_back(tmp.substr(last));
        }
    #if 1
        cout << vsplit.size() << endl;
        for (size_t i = 0; i < vsplit.size(); i++)
        {
            cout << "i=" << i << "," << vsplit[i].c_str() << endl;
        }
    #endif
    }
    
    /*
    - 上传 upload srcfile mongofile
    - 下载 download mongofile desfile
    - 查看  list
    - 退出 quit
    删除 delete mongofile  localfile(二期)
    */
    
    int main(int argc,char *argv[])
    {
        if (argc != 3){
            cout << "./main user passwd" << endl;
            return -1;
        }
        string line;
        vector<string> vCmd;
    
        while (1){//进入管理台
            cout << "ods>";
            getline(cin, line);//获取行,指令
            splitString(line.c_str(), ' ', vCmd);//拆分命令
            if (vCmd[0].compare("quit") == 0){
                //quit
                cout << "bye bye" << endl;
                break;
            }
            else if (vCmd[0].compare("upload") == 0){
                //上传
    
            }
            else if (vCmd[0].compare("download") == 0){
                //下载
    
            }
            else if (vCmd[0].compare("list") == 0){
                //查看
    
            }
    
        }
        return 0;
    }
    main.cpp

    shell>mkdir day06
    上传main.cpp至day06文件夹下
    shell>g++ main.cpp -o main
    shell>./main 11 22
    ods>list

    3、MySQL端登录实现

    shell>locate mysql.h(然后把/usr/include的mysql目录及其下文件下载到project目录下,然后在ods的属性页的“VC++”目录,包含目录,添加:....mysql)

    在VS的“ods”处右键“添加类”,然后保持默认(左侧选择“Visual C++”下的“C++”,右侧C++类),点击“添加”;类名输入:CCMysql,点击“完成”,会生成CMysql.h和CMysql.cpp:


    》添加用户和密码:
    mysql> desc t_user_info;
    mysql> insert into t_user_info values('yekai','叶开','123','bianchenglangzi');
    mysql> insert into t_user_info values('fuhongxue','傅红雪','456','bianchenglangzi');


    编写CMysql.h

    #pragma once
    
    
    class CCMysql
    {
    public:
        CCMysql();
        int UserLogin(const char *User,const char *Passwd);
        ~CCMysql();
    };
    CMysql.h

    编写CMysql.cpp

    #include "CMysql.h"
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <mysql.h>
    
    MYSQL *mysql = NULL;
    
    CCMysql::CCMysql()
    {
        mysql = mysql_init(NULL);
        if (mysql == NULL){
            printf("mysql init err");
            exit(1);
        }
        mysql = mysql_real_connect(mysql, "localhost", "root", "123", "ods", 0, NULL, 0);
        if (mysql == NULL){
            printf("mysql connect err");
            exit(1);
        }
    }
    
    
    CCMysql::~CCMysql()
    {
        if (mysql){
            mysql_close(mysql);
        }
    }
    //用户登陆
    int CCMysql::UserLogin(const char *User, const char *Passwd)
    {
        //用户名和密码匹配
        //执行该sql:select * from t_user_info where user_id='yekai' and pass_word='123';
        //如果有结果集,代表匹配
        char rSql[512] = { 0 };
        
        sprintf(rSql, "select user_id from t_user_info where user_id='%s' and pass_word='%s'", User, Passwd);
        printf("%s
    ", rSql);
        if (mysql_query(mysql, rSql)){
            printf("mysql exe err:%s
    ", rSql);
            return -1;
        }
        
        MYSQL_RES *result = mysql_store_result(mysql);//取结果集
        if (result != NULL){//该指针为空并非代表准确,有结果集,但结果集没有记录
            return (int)result->row_count;
        }
        return 0;// 代表结果不匹配
    }
    CMysql.cpp

    》编译:

    shell>touch makefile

    shell>vi makefile

    #SrcFiles=$(wildcard *.c)
    
    IncPath=/usr/include/mysql
    LibPath=/usr/lib64/mysql
    PubLib=-lmysqlclient -lstdc++ -ldl -lpthread -lrt
    
    all:main
    main:main.cpp CMysql.cpp
        gcc -o $@ $^ -I$(IncPath) -L$(LibPath) $(PubLib)
    
    clean:
        -rm -f main

    》扩展:SQL注入

    mysql> ./main yekai " 0' or '1=1"

    4、SQL注入问题解决

    》分析:SQL注入在于登录语句中含有or,所以如果判断密码处含有or,报错。

    #include "CMysql.h"
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <mysql.h>
    
    MYSQL *mysql = NULL;
    
    CCMysql::CCMysql()
    {
        mysql = mysql_init(NULL);
        if (mysql == NULL){
            printf("mysql init err");
            exit(1);
        }
        mysql = mysql_real_connect(mysql, "localhost", "root", "123", "ods", 0, NULL, 0);
        if (mysql == NULL){
            printf("mysql connect err");
            exit(1);
        }
    }
    
    
    CCMysql::~CCMysql()
    {
        if (mysql){
            mysql_close(mysql);
        }
    }
    //用户登陆
    int CCMysql::UserLogin(const char *User, const char *Passwd)
    {
        //用户名和密码匹配
        //执行该sql:select * from t_user_info where user_id='yekai' and pass_word='123';
        //如果有结果集,代表匹配
        if (strstr(Passwd, " or ")){
            printf("zhe yang bu hao!
    ");
            return 0;
        }
        char rSql[512] = { 0 };
        
        sprintf(rSql, "select user_id from t_user_info where user_id='%s' and pass_word='%s'", User, Passwd);
        printf("%s
    ", rSql);
        if (mysql_query(mysql, rSql)){
            printf("mysql exe err:%s
    ", rSql);
            return -1;
        }
        
        MYSQL_RES *result = mysql_store_result(mysql);//取结果集
        if (result != NULL){//该指针为空并非代表准确,有结果集,但结果集没有记录
            return (int)result->row_count;
        }
        return 0;// 代表结果不匹配
    }
    CMysql.cpp

    5、查看功能实现

    CMysql.h中增加:

        int ListFileInfo(const char *User);

    CMysql.cpp中增加:

    int CCMysql::ListFileInfo(const char *User)
    {
        //select * from t_file_info where user_id='yekai';
        //执行上面的sql,显示结果集
        char rSql[512] = { 0 };
        sprintf(rSql, "select * from t_file_info where user_id='%s'", User);
        if (mysql_query(mysql, rSql)){
            printf("query err:%s
    ", rSql);
            return -1;
        }
    
        MYSQL_RES *result = mysql_store_result(mysql);//取结果集
        if (result != NULL){//该指针为空并非代表准确,有结果集,但结果集没有记录
            MYSQL_ROW row;
            unsigned int num_fields;
            unsigned int i;
    
            num_fields = mysql_num_fields(result);
            while ((row = mysql_fetch_row(result)))
            {
                unsigned long *lengths;
                lengths = mysql_fetch_lengths(result);
                for (i = 0; i < num_fields; i++)
                {
                    printf("%s	",  row[i] ? row[i] : "NULL");
                }
                printf("
    ");
            }
        }
        
    
        return 0;
    }

    main.cpp中增加:

    #include "CMysql.h"        

    else if (vCmd[0].compare("list") == 0){ //查看 //cout << vCmd[0] << endl; cmysql.ListFileInfo(argv[1]); }

    mysql> insert into t_file_info(local_file_name,mongo_file_name,file_size,user_id,remark) ('xxx.11','yyy.11',1024,'yekai','upload sucess');
    mysql> insert into t_file_info(local_file_name,mongo_file_name,file_size,user_id,remark) ('xxx.22','yyy.2',10240,'fuhongxue','upload sucess');

    打开另一个终端,查看:

    6、MySQL侧实现上传功能

    》查看文件信息,看需要上传哪些信息

    (t_file_info表增加status状态信息)

    mysql> alter table t_file_info add column status varchar(2);

    》上传设计:

    第一步:
      先插入对应关系,状态填0,代表正在上传,
    第二步:
      mongo上传文件
    第三步:
      更新文件对应关系,文件大小,status 上传成功 1,remark 上传成功

    上传和下载一块做:(打开另一个终端方便查看,先输入update语句测试)

    CMysql.h中增加:

        int UploadFile(const char *User,const char *LocalFile,const char *MongoFile);
        int UpdateFileInfo(myulong FileSize, const char *User, const char *LocalFile, const char *MongoFile);

    CMysql.cpp中增加:

    int CCMysql::UploadFile(const char *User, const char *LocalFile, const char *MongoFile)
    {
        //insert into t_file_info(local_file_name, mongo_file_name, file_size, user_id,status, remark)
        //values('xxx.11', 'yyy.11', 1024, 'yekai', '0','upload sucess');
        //需要执行上述insert语句,代表上传文件状态
        char rSql[512] = { 0 };
        sprintf(rSql, "insert into t_file_info(local_file_name, mongo_file_name, file_size, user_id,status, remark)" 
                      "values('%s', '%s', 0, '%s', '0','uploading')", LocalFile, MongoFile, User);
    
        if (mysql_query(mysql, rSql)){
            printf("run upload err:%s
    ", rSql);
            return -1;
        }
    
        return 0;
    }
    
    int CCMysql::UpdateFileInfo(myulong FileSize, const char *User, const char *LocalFile, const char *MongoFile)
    {
        //update t_file_info set file_size=1011,status='1',remark='upload sucess' 
        //where user_id='yekai' and local_file_name='xxx.11' and mongo_file_name='yyy.11';
        char rSql[512] = { 0 };
        sprintf(rSql, "update t_file_info set file_size=%lld,status='1',remark='upload sucess'"
            "where user_id='%s' and local_file_name='%s' and mongo_file_name='%s'", FileSize, User, LocalFile, MongoFile);
        if (mysql_query(mysql, rSql)){
            printf("run update err:%s
    ", rSql);
            return -1;
        }
        return 0;
    }

    main.cpp中增加:

            else if (vCmd[0].compare("upload") == 0){
                //上传
                cout << "upoload:" << vCmd[1] << "," << vCmd[2] << endl;
                //1. mysql 执行  insert
                cmysql.UploadFile(argv[1], vCmd[1].c_str(), vCmd[2].c_str());
                //2. mongo 上传 文件
    
                //3. mysql 执行 update
                //stat 
                cmysql.UpdateFileInfo(llsize, argv[1], vCmd[1].c_str(), vCmd[2].c_str());
            }

    7、上传文件MongoDB侧实现

    在VS的“ods”处右键“添加类”,然后保持默认(左侧选择“Visual C++”下的“C++”,右侧C++类),点击“添加”;类名输入:CCMongo,点击“完成”,会生成CMongo.h和CMongo.cpp:

    CMongo.h中增加:

    #pragma once
    #include <iostream>
    #include <mongo/client/dbclient.h>
    #include <string>
    using namespace std;
    
    
    class CCMongo
    {
    public:
        CCMongo();
        int UploadFile(const char *LocalFile, const char *MongoFile);
        ~CCMongo();
    };
    CMongo.h

    CMongo.cpp中增加:

    #include "CMongo.h"
    #include <stdlib.h>
    
    
    using namespace mongo;
    DBClientConnection *conn = NULL;
    
    CCMongo::CCMongo()
    {
        conn = new DBClientConnection(false, 0, 3);
        std::string errmsg;
        if (!conn->connect("localhost", errmsg)){
            cout << "connect to mongo err:" << errmsg << endl;
            exit(1);
        }
    }
    
    
    CCMongo::~CCMongo()
    {
        if (conn){
            delete conn;
            conn = NULL;
        }
    }
    
    mongoulong CCMongo::UploadFile(const char *LocalFile, const char *MongoFile)
    {
        //构造 GridFS对象
        mongo::GridFS gfs(*conn, "ods");
        //上传文件
        gfs.storeFile(LocalFile, MongoFile);
    
        return 0;
    }
    CMongo.cpp

    8、MySQL与MongoDB类的调用

    》获取文件大小及更改:

    CMongo.h中增加及修改:

    #pragma once
    #include <iostream>
    #include <mongo/client/dbclient.h>
    #include <string>
    using namespace std;
    
    typedef unsigned long long mongoulong;
    
    class CCMongo
    {
    public:
        CCMongo();
        mongoulong UploadFile(const char *LocalFile, const char *MongoFile);
        ~CCMongo();
    };

    CMongo.cpp中增加及修改:

    #include "CMongo.h"
    #include <stdlib.h>
    
    
    using namespace mongo;
    DBClientConnection *conn = NULL;
    
    CCMongo::CCMongo()
    {
        conn = new DBClientConnection(false, 0, 3);
        std::string errmsg;
        if (!conn->connect("localhost", errmsg)){
            cout << "connect to mongo err:" << errmsg << endl;
            exit(1);
        }
    }
    
    
    CCMongo::~CCMongo()
    {
        if (conn){
            delete conn;
            conn = NULL;
        }
    }
    
    mongoulong CCMongo::UploadFile(const char *LocalFile, const char *MongoFile)
    {
        //构造 GridFS对象
        mongo::GridFS gfs(*conn, "ods");
        //上传文件
        mongo::BSONObj obj = gfs.storeFile(LocalFile, MongoFile);
    
        //GridFile findFile( BSONObj query ) const;
        return gfs.findFile(obj).getContentLength();//返回文件大小
        //return 0;
    }

    main.cpp中增加:

    #include "CMongo.h"
    
            else if (vCmd[0].compare("upload") == 0){
                //上传
                cout << "upoload:" << vCmd[1] << "," << vCmd[2] << endl;
                //1. mysql 执行  insert
                cmysql.UploadFile(argv[1], vCmd[1].c_str(), vCmd[2].c_str());
                //2. mongo 上传 文件
                myulong llsize  =cmongo.UploadFile(vCmd[1].c_str(), vCmd[2].c_str());
                //3. mysql 执行 update
                //stat 也可以使用其获取文件大小
                cmysql.UpdateFileInfo(llsize, argv[1], vCmd[1].c_str(), vCmd[2].c_str());
            }

    9、上传测试成功

    makefile中更改:

    #SrcFiles=$(wildcard *.c)
    
    
    IncPath=-I/usr/include/mysql -I/home/itcast/driver/mongo/include -I/home/itcast/driver/boost/include
    LibPath=-L/usr/lib64/mysql -L/home/itcast/driver/boost/lib -L/home/itcast/driver/mongo/lib
    PubLib=-lmysqlclient  -ldl -lpthread -lrt -lmongoclient -lboost_thread -lboost_filesystem -lboost_program_options
    
    all:main
    main:main.cpp CMysql.cpp CMongo.cpp
        g++ -o $@ $^ $(IncPath) $(LibPath) $(PubLib)
    
    clean:
        -rm -f main

    上传文件后重新编译

    上传一张图片到day06后测试(如:ywbg.jpg)

    打开另一个终端,登录mysql查看是否上传成功:

    再打开第三个终端,登录MongoDB查看mongo端是否上传成功

    10、下载功能实现

    CMongo.h中增加:

        int downloadFile(const char *MongoFile,const char *DesFile);

    CMongo.cpp中增加:

    int CCMongo::downloadFile(const char *MongoFile, const char *DesFile)
    {
        //通过gridfs 查找文件获得 gridfile 对象,write 就ok了
        //构造 GridFS对象
        mongo::GridFS gfs(*conn, "ods");
        gfs.findFile(MongoFile).write(DesFile);
        return 0;
    }

    main.cpp中增加

            else if (vCmd[0].compare("download") == 0){
                //下载
                cout << "download:" << vCmd[1] << "," << vCmd[2] << endl;
                cmongo.downloadFile(vCmd[1].c_str(), vCmd[2].c_str());
            }

    上传文件,编译登录:

    1)测试下载文件(先测试下载一张图片,如:刚才上传的ywbg.jpg)

    另打开一个终端,查看是否下载成功:

    将图片(下载)到本地Windows系统查看,(点击)看是否正常在Windows显示:

    2)测试下载文件(先上传一部电影到day06,然后测试下载一部电影,如:hzw763.mp4)

    再打开一个终端(第2个终端),切换到day06目录下,查看文件大小。然后登录MongoDB(当前只有之前上传成功的图片ywbg.jpg)

    然后在原终端(即登录yekai 123)上传文件

    然后打开第三个终端,登录mysql查看文件上传状态:(注意:此时文件大小为0!

    等待原终端(即登录yekai 123)上传成功:(出现ods> 即上传成功)

    在之前打开的第3个终端(登录MySQL那个)查看文件上传状态:

    查看第2个终端(登录MongoDB的那个)查看文件上传情况:

    测试下载:

    在原终端(即登录yekai 123)下载hzw763.mp4

    查看第2个终端(登录MongoDB的那个,退出quit,然后查看)查看文件下载情况:

    将电影(下载)到本地Windows系统查看,(点击)看是否正常在Windows播放。

    11、总结

    1)MySQL库和MongoDB库本身没有关系,是通过上传下载建立的联系。

    2)MD5,MongoDB上传成功后会生成一个md5,可以通过md5去判断在当前文件夹文件是否已经下载。

    3)删除(二期),在MySQL和MongoDB两个数据库都要删除,在两个数据库都留一个接口,根据命令行设计删除指令,然后在main函数调用一下。

    在学习数据库编程总结了笔记,并分享出来。有问题请及时联系博主:Alliswell_WP,转载请注明出处。

  • 相关阅读:
    【原】无脑操作:IDEA + maven + SpringBoot + JPA + EasyUI实现CRUD及分页
    【原】无脑操作:IDEA + maven + SpringBoot + JPA + Thymeleaf实现CRUD及分页
    【原】无脑操作:Windows 10 + MySQL 5.5 安装使用及免安装使用
    【原】无脑操作:eclipse + maven搭建SSM框架
    【原】无脑操作:eclipse创建maven工程时,如何修改默认JDK版本?
    【原】Java学习笔记031
    【原】Java学习笔记030
    【原】Java学习笔记029
    【原】Java学习笔记028
    【原】Java学习笔记027
  • 原文地址:https://www.cnblogs.com/Alliswell-WP/p/CPlusPlus_Database_06.html
Copyright © 2020-2023  润新知