项目(6)(项目梳理、文件下载流程梳理、QT界面搭建、QT窗口间通信的实现例子、QT中的正则表达式)

项目构架

1、每台web server部署的东西应该完全相同,web server中部署nginx处理静态请求,对于其他请求,nginx会转发给fastcgi程序来处理。

2、一个fastcgi程序处理一个特定的http请求(比如上传图片请求需要有一个上传的cgi程序,比如登录请求需要有一个登录的cgi程序)。上图中绿色的application对应的就是cgi程序

3、使用fastDFS进行分布式存储。fastDFS中有三个角色,client、tracker、storage。上图中绿色的application对应fastDFS中的client。当客户端发送请求,nginx将请求反向代理到一台web server上,web server上的application访问tracker服务来获取相应的storage进程的ip地址和端口号。application根据获取到的ip地址和端口号来与对应的storage进程进行通信(即client从storage中存储资源或者获取资源)

4、mysql中存储用户相应的文件,我们需要在数据库中传存储每个用户名下的文件都是什么。使用cgi程序来控制mysql。

5、redis是缓存数据库,在web端有一些访问量十分拼房的数据,可以将该数据存储在redis中(因为mysql有连接上限且mysql频繁的io操作会比较浪费时间)。比如redis中可以存储被共享的文件的下载量,因为被共享的文件的下载量对于所有用户可见,是一个访问频繁的数据。

6、mysql和redis并不是直接通信的,他们之间的数据同步依靠cgi程序来进行设置。

用户验证的原因

概念:

server端有一个用户登录,就会对该用户进行标志。在客户端用户有一些操作的时候,需要在http请求中把相应的用户标识发送给服务端进行匹配,这样可以避免有些人模拟用户名和密码来进行恶意操作。

文件下载流程梳理

修改前

  1. 客户端发送http请求给nginx
  2. nginx反向代理到web server
  3. 服务器上的application链接tracker来查找客户端请求的数据位置
  4. tracker将存储对应文件的storage服务器的ip地址和端口号返回给application
  5. application根据tracker返回的storage服务的ip地址和端口号去获取客户端请求的数据
  6. application将获取到的数据返回给客户端

修改后

  1. 客户端发送http请求给nginx
  2. nginx反向代理到web server
  3. application进行数据库查询,通过url查找到相应的storage
  4. applicationstorage服务器中相应的文件资源返回给客户端

原理

1、在storage服务器上搭建nginx。

2、由于上传之后会得到文件相应的id,客户端每次上传数据之后,将数据相应的ip+文件id串比如http://192.168.1.3/group/M00/00/00/xxxxx.png)存储在数据库中。

3、当客户端希望获取该文件时,直接通过IP地址+文件id来进行文件获取(客户端发送由ip+文件id构成的url给nginx服务器,通过插件fastdfs-nginx-module直接连接到存储该文件的storage服务器上,“”省去了使用tracker去查询相应的文件在哪一个storage服务器上“”这一步。)

QT

昨天研究了好久qt的安装,最后终于安上了,累死。

Qt客户端整体功能

  1. 登录
  2. 新用户注册
  3. 服务器设置
  4. 展示服务器上的用户文件
  5. 上传文件
  6. 文件秒传
  7. 文件下载
  8. 文件共享
  9. 文件转存
  10. 文件下载量统计

QT界面搭建

1、掌握窗口的布局

  • 水平布局 - QHBoxLayout
  • 垂直布局 - QVBoxLayout
  • 网格布局 - QGridLayout

2、掌握如何绘制窗口背景图

  1. 重写这个类的绘图事件 - paintEvent(这是一个回调的虚函数)
  2. 在这个函数中使用画家类完成绘图操作(在使用画家类时,需要指定的绘图设备, 即当前的对象——QPainter p(this);)

3、掌握鼠标事件(也是回调)的使用

  • mouseMoveEvent()
  • mousePressEvent()

4、自定义窗口

  • 最终是使用这个自定义类来提升一个基类

注意

  • 首先看需要提升的类的数据类型(QPushbutton)
  • 自定义的类需要从QPushbutton派生
  • 使用自定义的子类去完成父类的提升,即把父类提升为子类

5、Qt中样式表的使用

  • 在控件对应的属性窗口中设置样式

QLabel的父类是QFrame,QFrame的父类是QWidget,以此类推

6、Qt窗口间通信

  • 使用信号槽

7、数据校验 - 正则表达式

  • 数字字母下划线
  • 正则表达式对应的类: QRegexp
第一步,构造变量——QRegexp reg("正则表达式");

第二步——reg.exactMatch(需要验证的字符串);

setPattern(const QString &pattern);  //该函数可以重新初始化正则表达式

QT窗口间通信的实现例子

实现图中按钮的相应功能(整个界面分为三个窗口,上边的控制条是一个窗口,下面的输入是一个窗口,整体是一个窗口)

      

窗口的结构关系

父类——login

三个子类

控制条titlewg——他也是login的子类

按钮控件所在的ui文件位置

三个按钮的功能

  • 点击设置按钮,下面的输入窗口会进行切换

       

  • 点击最小化按钮,父类窗口login会最小化
  • 点击关闭按钮,只有在登录页面时才会关闭窗口,其余时候都是退出当前窗口到下一个子类的窗口。

实现步骤

第一步:titlewg.h中声明信号(信号不需要实现,只要声明即可)

技巧,如果该事件在当前窗口处理不了,就把信号发送出去。权力越多的类,能够实现的功能就越多,让外面的父类去对事件进行处理。

signals:
    //做信号,用于界面右上角的通知
    void showSetWg();    //设置按钮
    void closeWindow();  //关闭按钮

第二步:titlewg.cpp中,设置三个按钮的触发事件

    // 按钮功能实现。如果使用lambda表达式,则参数this可以省略
    //因为默认lambda表达式就属于当前类,而this指针指向的是当前类对象,因此this参数可以不写
    connect(ui->set, &QToolButton::clicked, this,[=]()
    {
        // 发送自定义信号
        emit showSetWg();
    });
    connect(ui->min, &QToolButton::clicked, [=]()
    {
        //点击最小化按钮,使得父类窗口最小化
         m_parent->showMinimized(); 
    });
    connect(ui->close, &QToolButton::clicked, [=]()
    {
        //关闭窗口按钮
        emit closeWindow();
    });

第三步:在login中处理子类发送过来的信号

Login::Login(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Login)
{
    ui->setupUi(this);

    // 去掉创建的边框
    this->setWindowFlags(Qt::FramelessWindowHint | windowFlags());

    // 设置当前窗口所有的字体
    this->setFont(QFont(QString::fromLocal8Bit("新宋体"), 12, QFont::Bold, false));

    // 处理titlewidget发送过来的信号
    connect(ui->title_wg, &TitleWg::closeWindow, [=]()
    {
        // 关闭时是分情况的,只有当前页面是登录页面才能直接关闭窗口。
        //判断当前stackedWidget显示的页面
        //设置页面切换到登录页面
        if(ui->stackedWidget->currentWidget() == ui->set_page)
        {
            // 切换到登录
            ui->stackedWidget->setCurrentWidget(ui->login_page);
            // 清空控件数据
        }
        //注册页面切换到登录页面
        else if(ui->stackedWidget->currentWidget() == ui->reg_page)
        {
            // 切换到登录
            ui->stackedWidget->setCurrentWidget(ui->login_page);
             // 清空控件数据
            ui->name_reg->clear();
        }
        //当前界面是登录界面,则直接关闭窗口
        else
        {
            this->close();
        }
    });
    
    //显示设置界面,即——“服务器设置”界面
    connect(ui->title_wg, &TitleWg::showSetWg, [=]()
    {
        //setCurrentWidget是当前窗口的指针,也可以使用setCurrentIndex——当前窗口的编号
        //设置切换到set_page页面
        ui->stackedWidget->setCurrentWidget(ui->set_page);
    });

}

补充——查看窗口编号的方法

QT中的正则表达式

使用正则表达式实现数据校验功能。检测用户注册的用户名、密码、邮箱是否合法。

1、用户名

#define USER_REG        "^[a-zA-Z\\d_@#-\*]\{3,16\}$"
  • ^——代表字符的开始,说明字符串开始必须是[a-zA-Z\\d_@#-\*]的其中之一
  •  \d——代表 0-9 (\\d对应的是一个 \d,其中一个 \是转义)
  • 这句正则表达式的意思就是开头可以是大小写字母,或者0-9的数字,或者_,或者@,或者#,或者-,或者*
  • *——在正则表达式里面比较特殊,因此需要加上转义
  •  \{ ——也是对 { 做了转义
  • $ ——是结束的意思
  •  {3,16}—— 说明字符最少要3个,最多16个

2、密码(与用户名相似)

#define PASSWD_REG      "^[a-zA-Z\\d_@#-\*]\{6,18\}$"

3、电话

#define PHONE_REG       "1\\d\{10\}"
  • 第一位是1,后面是0-9的10个数字

4、email

#define EMAIL_REG       "^[a-zA-Z\\d\._-]\+@[a-zA-Z\\d_\.-]\+(\.[a-zA-Z0-9_-]\+)+$"

5、IP

#define IP_REG          "((2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)"
  • ()之间是一个整体
  • 2[0-4]——开头可以是2,第二个字符是0-4之间的数
  • \d——代表0-9
  • |——或者的艺术
  • 25[0-5]——第一位是2,第二位是5,第三位是0-5
  • [01]——出现0或者1
  • ?——代表出现一次
  • {3}表示出现三次

6、端口

#define PORT_REG        "^[1-9]$|(^[1-9][0-9]$)|(^[1-9][0-9][0-9]$)|(^[1-9][0-9][0-9][0-9]$)|(^[1-6][0-5][0-5][0-3][0-5]$)"
  • ^[1-9]$——字符串的第一位和结尾必须是1-9
  • |——或者
  • ^[1-9][0-9]$——开始是1-9,结尾是0-9

分析——在构造初始化的时候,可以构造一个正则表达式,比如验证用户名。那么在验证邮箱的时候,需要再创建一个对象吗?

不需要,有一个函数可以重新初始化正则表达式

void setPattern(const QString &pattern);

猜你喜欢

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