项目(11)(显示文件内容事件、文件下载流程)

显示文件内容事件

在客户端登录用户界面需要把用户拥有的文件内容罗列出来,因此要获取文件内容,需要向服务器发送请求。

思路

1、获取用户文件个数

客户端

url

http://127.0.0.1:80/myfiles?cmd=count

post数据

{

"user": "kevin",

"token": "xxxx"

}

分析url

  • get请求里面会有?
  • 域名后面——myfiles——是指令
  • ?后面是参数,参数间以&进行间隔

服务器

{
    "num":"27",
    "code":"110"     // token验证
}

 

2、从服务器获取文件信息

客户端

获取用户文件信息

http://127.0.0.1:80/myfiles&cmd=normal

按下载量升序

http://127.0.0.1:80/myfiles?cmd=pvasc

按下载量降序

 http://127.0.0.1:80/myfiles?cmd=pvdesc

post数据

    {

        "user": "yoyo"

        "token": "xxxx"

        "start": 0

        "count": 10

    }

 

服务器

成功

文件列表json

失败

{"code": "015"}

服务器返回的json数据

{ 
    "files": 
        [
            {
                 "user": "yoyo",
                 "md5": "e8ea6031b779ac26c319ddf949ad9d8d",
                 "time": "2017-02-26 21:35:25",
                 "filename": "test.mp4",
                 "share_status": 0,
                 "pv": 0,
                 "url": "http://192.168.31.109:80/group1/M00/00/00/wKgfbViy2Z2AJ-FTAaM3As-g3Z0782.mp4",
                 "size": 27473666,
                 "type": "mp4"
            },
            {
                 "user": "yoyo",
                 "md5": "e8ea6031b779ac26c319ddf949ad9d8d",
                 "time": "2017-02-26 21:35:25",
                 "filename": "test.mp4",
                 "share_status": 0,
                 "pv": 0,
                 "url": "http://192.168.31.109:80/group1/M00/00/00/wKgfbViy2Z2AJ-FTAaM3As-g3Z0782.mp4",
                 "size": 27473666,
                 "type": "mp4"
            }
        ]
}

流程

QT客户端实现代码

// 获取用户文件列表
// cmd取值,Normal:普通用户列表,PvAsc:按下载量升序, PvDesc:按下载量降序
void MyFileWg::getUserFilesList(MyFileWg::Display cmd)
{
    //遍历数目,结束条件处理
    if(m_userFilesCount <= 0) //结束条件,这个条件很重要,函数递归的结束条件
    {
        cout << "获取用户文件列表条件结束";
        refreshFileItems(); //更新item
        return; //中断函数
    }
    else if(m_count > m_userFilesCount) //如果请求文件数量大于用户的文件数目
    {
        m_count = m_userFilesCount;
    }


    QNetworkRequest request; //请求对象

    // 获取登陆信息实例
    LoginInfoInstance *login = LoginInfoInstance::getInstance(); //获取单例

    // 获取用户文件信息 127.0.0.1:80/myfiles&cmd=normal
    // 按下载量升序 127.0.0.1:80/myfiles?cmd=pvasc
    // 按下载量降序127.0.0.1:80/myfiles?cmd=pvdesc
    QString url;

    QString tmp;
    //cmd取值,Normal:普通用户列表,PvAsc:按下载量升序, PvDesc:按下载量降序
    if(cmd == Normal)
    {
        tmp = "normal";
    }
    else if(cmd == PvAsc)
    {
        tmp = "pvasc";
    }
    else if(cmd == PvDesc)
    {
        tmp = "pvdesc";
    }

    url = QString("http://%1:%2/myfiles?cmd=%3").arg(login->getIp()).arg(login->getPort()).arg(tmp);
    request.setUrl(QUrl( url )); //设置url

    //qt默认的请求头
    //request.setRawHeader("Content-Type","text/html");
    request.setHeader(QNetworkRequest::ContentTypeHeader,"application/json");

    /*
    {
        "user": "yoyo"
        "token": "xxxx"
        "start": 0
        "count": 10
    }
    */
    QByteArray data = setFilesListJson( login->getUser(), login->getToken(), m_start, m_count);

    //改变文件起点位置
    m_start += m_count;
    m_userFilesCount -= m_count;

    //发送post请求
    QNetworkReply * reply = m_manager->post( request, data );
    if(reply == NULL)
    {
        cout << "reply == NULL";
        return;
    }

    //获取请求的数据完成时,就会发送信号SIGNAL(finished())
    connect(reply, &QNetworkReply::finished, [=]()
    {
        if (reply->error() != QNetworkReply::NoError) //有错误
        {
            cout << reply->errorString();
            reply->deleteLater(); //释放资源
            return;
        }

        //服务器返回用户的数据
        QByteArray array = reply->readAll();

        reply->deleteLater();

        //token验证失败
        if("111" == m_cm.getCode(array) ) //common.h
        {
            QMessageBox::warning(this, "账户异常", "请重新登陆!!!");
            emit loginAgainSignal(); //发送重新登陆信号

            return; //中断
        }

        //不是错误码就处理文件列表json信息
        if("015" != m_cm.getCode(array) ) //common.h
        {
            //cout << array.data();
            getFileJsonInfo(array);//解析文件列表json信息,存放在文件列表中

            //继续获取用户文件列表
            //递归的分批获取数据
            getUserFilesList(cmd);
        }
    });
}

文件下载流程

流程图

在文件位置右键菜单,选择“下载”,触发下载事件。

文件被加入到下载队列之前的一些操作

// 添加需要下载的文件到下载任务列表
void MyFileWg::addDownloadFiles()
{
    //切换界面
    emit gotoTransfer(TransferStatus::Download);
    //获取当前被点击的item
    QListWidgetItem *item = ui->listWidget->currentItem();
    if(item == NULL)
    {
        cout << "item == NULL";
        return;
    }

    //获取下载列表实例
    DownloadTask *p = DownloadTask::getInstance();
    //获取单例失败
    if(p == NULL)
    {
        cout << "DownloadTask::getInstance() == NULL";
        return;
    }

    //循环遍历用户所有的文件
    for(int i = 0; i < m_fileList.size(); ++i)
    {
        //找到要被下载的那个文件
        if(m_fileList.at(i)->item == item)
        {

            //弹出保存文件对话框,选择文件的保存路径
            QString filePathName = QFileDialog::getSaveFileName(this, 
                    "选择保存文件路径", m_fileList.at(i)->filename );
            if(filePathName.isEmpty())
            {
                cout << "filePathName.isEmpty()";
                return;
            }

            /*
               下载文件:
                    成功:{"code":"009"}
                    失败:{"code":"010"}
            */
            //cout << filePathName;

            //追加任务到下载队列
            //参数:info:下载文件信息, filePathName:文件保存路径
            //成功:0
            //失败:
            //  -1: 下载的文件是否已经在下载队列中
            //  -2: 打开文件失败
            int res = p->appendDownloadList(m_fileList.at(i), filePathName); //追加到下载列表
            if(res == -1)
            {
                QMessageBox::warning(this, "任务已存在", "任务已经在下载队列中!!!");
            }
            else if(res == -2) //打开文件失败
            {
                m_cm.writeRecord(m_fileList.at(i)->user, m_fileList.at(i)->filename, "010"); //下载文件失败,记录
            }

            break; //中断条件很重要
        }
    }
}

将文件添加到任务队列的实现代码

//追加任务到下载队列
//参数:info:下载文件信息, filePathName:文件保存路径
//成功:0
//失败:
//  -1: 下载的文件是否已经在下载队列中
//  -2: 打开文件失败
int DownloadTask::appendDownloadList( FileInfo *info, QString filePathName, bool isShare)
{
    //遍历查看一下,下载的文件是否已经在下载队列中
    for(int i = 0; i != list.size(); ++i)
    {
        if( list.at(i)->user == info->user && list.at(i)->filename == info->filename)
        {
            cout << info->filename << " 已经在下载队列中 ";
            return -1;
        }
    }

    QFile *file = new QFile(filePathName); //文件指针分配空间

    if(!file->open(QIODevice::WriteOnly))
    { 
        //如果打开文件失败,则删除 file,并使 file 指针为 NULL,然后返回
        cout << "file open error";

        delete file;
        file = NULL;
        return -2;
    }

    //动态创建节点
    DownloadInfo *tmp = new DownloadInfo;
    tmp->user = info->user;   //用户
    tmp->file = file;         //文件指针
    tmp->filename = info->filename; //文件名字
    tmp->md5 = info->md5;           //文件md5
    tmp->url = info->url;           //下载网址
    tmp->isDownload = false;        //没有在下载
    tmp->isShare = isShare;         //是否为共享文件下载

    DataProgress *p = new DataProgress; //创建进度条
    p->setFileName(tmp->filename); //设置文件名字

    //获取布局
    DownloadLayout *downloadLayout = DownloadLayout::getInstance();
    QVBoxLayout *layout = (QVBoxLayout*)downloadLayout->getDownloadLayout();

    tmp->dp = p;
    // 添加到布局, 最后一个是弹簧, 插入到弹簧上边
    layout->insertWidget(layout->count()-1, p);

    cout << info->url <<  QString::fromLocal8Bit("已经添加到下载列表");

    //插入到下载任务队列中
    list.append(tmp);

    return 0;
}

文件下载

// 下载文件处理,取出下载任务列表的队首任务,下载完后,再取下一个任务
void MyFileWg::downloadFilesAction()
{
    DownloadTask *p = DownloadTask::getInstance();
    if(p == NULL)
    {
        cout << "DownloadTask::getInstance() == NULL";
        return;
    }

    if( p->isEmpty() ) //如果队列为空,说明没有任务
    {
        return;
    }

    if( p->isDownload() ) //当前时间没有任务在下载,才能下载,单任务
    {
        return;
    }

    //看是否是共享文件下载任务,不是才能往下执行, 如果是,则中断程序
    if(p->isShareTask() == true)
    {
        return;
    }

    DownloadInfo *tmp = p->takeTask(); //取下载任务


    QUrl url = tmp->url;
    QFile *file = tmp->file;
    QString md5 = tmp->md5;
    QString user = tmp->user;
    QString filename = tmp->filename;
    DataProgress *dp = tmp->dp;

    //发送get请求,请求资源,比post简洁多了
    QNetworkReply * reply = m_manager->get( QNetworkRequest(url) );
    if(reply == NULL)
    {
        p->dealDownloadTask(); //删除任务
        cout << "get err";
        return;
    }

    //获取请求的数据完成时,就会发送信号SIGNAL(finished())
    connect(reply, &QNetworkReply::finished, [=]()
    {
        cout << "下载完成";
        reply->deleteLater();

        p->dealDownloadTask();//删除下载任务

        m_cm.writeRecord(user, filename, "010"); //下载文件成功,记录

        dealFilePv(md5, filename); //下载文件pv字段处理
    });

    //当有可用数据时,reply 就会发出readyRead()信号,我们这时就可以将可用的数据保存下来
    connect(reply, &QNetworkReply::readyRead, [=]()
    {
        //如果文件存在,则写入文件
        if (file != NULL)
        {
            file->write(reply->readAll());
        }
    });

    //有可用数据更新时
    connect(reply, &QNetworkReply::downloadProgress, [=](qint64 bytesRead, qint64 totalBytes)
    {
        dp->setProgress(bytesRead, totalBytes);//设置进度
    }
    );
}

猜你喜欢

转载自blog.csdn.net/qq_29996285/article/details/87910367