显示文件内容事件
在客户端登录用户界面需要把用户拥有的文件内容罗列出来,因此要获取文件内容,需要向服务器发送请求。
思路
1、获取用户文件个数
客户端
url |
|
post数据 |
{ "user": "kevin", "token": "xxxx" } |
分析url
- get请求里面会有?
- 域名后面——myfiles——是指令
- ?后面是参数,参数间以&进行间隔
服务器
{
"num":"27",
"code":"110" // token验证
}
2、从服务器获取文件信息
客户端
获取用户文件信息 |
|
按下载量升序 |
|
按下载量降序 |
|
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);//设置进度
}
);
}