项目(8)(服务器配置事件、保存配置文件信息、注册事件、server端部署流程、sourceinsight的使用、服务端注册事件)

服务器配置事件

点击确定按钮触发事件:

  1. 获取控件数据
  2. 正则判断数据是否合法
  3. 跳转到登录界面
  4. 将信息写入配置文件

实现代码(正则表达式——QT中的正则表达式

// 服务器设置
void Login::on_set_ok_btn_clicked()
{
    //获取控件数据
    QString ip = ui->address_server->text();
    QString port = ui->port_server->text();

    // 数据判断
    // 服务器IP
    // \\d 和 \\. 中第一个\是转义字符, 这里使用的是标准正则
    QRegExp regexp(IP_REG);
    if(!regexp.exactMatch(ip))
    {
        QMessageBox::warning(this, "警告", "您输入的IP格式不正确, 请重新输入!");
        //清空数据
        ui->address_server->clear();
        //为了用户友好,设置焦点
        ui->address_server->setFocus();
        return;
    }
    // 端口号,通过setPattern重新设置正则规则
    regexp.setPattern(PORT_REG);
    if(!regexp.exactMatch(port))
    {
        QMessageBox::warning(this, "警告", "您输入的端口格式不正确, 请重新输入!");
        return;
    }

    // 跳转到登陆界面
    ui->stackedWidget->setCurrentWidget(ui->login_page);
    // 将配置信息写入配置文件中
    m_cm.writeWebInfo(ip, port);
}

保存配置文件信息

1、配置文件格式

	{
	    "login": {
	        "pwd": "wqq2b4Ild/w=",
	        "remember": "yes",
	        "user": "Mi/CvL0kLkQ="
	    },
	    "type_path": {
	        "path": "conf/fileType"
	    },
	    "web_server": {
	        "ip": "192.168.1.27",
	        "port": "80"
	    }
	}
扫描二维码关注公众号,回复: 5307797 查看本文章

2、实现代码:

// 服务器信息,写入配置文件
void Common::writeWebInfo(QString ip, QString port, QString path)
{
    // web_server信息,QVariant可以放任意数据类型
    QMap<QString, QVariant> web_server;
    web_server.insert("ip", ip);
    web_server.insert("port", port);

    // type_path信息
    QMap<QString, QVariant> type_path;
    type_path.insert("path", m_typePath);

    // login信息
    QString user = getCfgValue("login", "user");
    QString pwd = getCfgValue("login", "pwd");
    QString remember = getCfgValue("login", "remember");


    QMap<QString, QVariant> login;
    login.insert("user", user);
    login.insert("pwd", pwd);
    login.insert("remember", remember);


    // QVariant类作为一个最为普遍的Qt数据类型的联合
    // QVariant为一个万能的数据类型--可以作为许多类型互相之间进行自动转换。
    QMap<QString, QVariant> json;
    json.insert("web_server", web_server);
    json.insert("type_path", type_path);
    json.insert("login", login);


    QJsonDocument jsonDocument = QJsonDocument::fromVariant(json);
    if ( jsonDocument.isNull() == true)
    {
        cout << " QJsonDocument::fromVariant(json) err";
        return;
    }

    //读取文件
    QFile file(path);
    //如果文件不存在
    if( false == file.open(QIODevice::WriteOnly) )
    {
        cout << "file open err";
        return;
    }

    file.write(jsonDocument.toJson());
    file.close();
}

项目中的注册事件

点击注册按钮之后触发的事件

  1. 取数据
  2. 校验
  3. 组织发给server端的数据——将用户输入的注册信息转换成json对象
  4. 将数据post给server
  5. 读取server回复的信息,针对不同的回复信息做出相应的处理

确定客户端发送给server端的数据格式

post url:http://127.0.0.1:80/reg

post数据格式:

{
    userName:xxxx,
    nickName:xxx,
    firstPwd:xxx,
    phone:xxx,
    email:xxx
}

server端nginx添加相应事件的处理

location /reg
{
    fastcgi_pass 127.0.0.1:9999;
    include fastcgi.conf;
}

设置本机处理相应事件的cgi进程监听9999端口即可。

确定server端返回值的数据格式

成功

{"code":"002"}

该用户已存在

{"code":"003"}

失败

{"code":"004"}

QT中代码

1、login.h中声明将注册信息打包成json格式字符串的函数

 QByteArray getRegisterJson(QString name, QString nick, QString passwd, QString phone, QString email);

2、在login.cpp中实现该函数

// 将注册信息打包成json格式字符串
QByteArray Login::getRegisterJson(QString name, QString nick, QString passwd, QString phone, QString email)
{
//    {
//        userName:xxxx,
//        nickName:xxx,
//        firstPwd:xxx,
//        phone:xxx,
//        email:xxx
//     }

    QMap<QString, QVariant> reg;
    reg.insert("userName", name);
    reg.insert("nickName", nick);
    reg.insert("firstPwd", passwd);
    reg.insert("phone", phone);
    reg.insert("email", email);

    QJsonDocument doc = QJsonDocument::fromVariant(reg);
    cout << "reg json" << doc.toJson();

    return doc.toJson();
}

注册事件整体代码

// 注册
void Login::on_reg_btn_clicked()
{
    // 取值 从输入框取得数据
    QString name = ui->name_reg->text();
    QString nickName = ui->nike_name->text();
    QString passwd = ui->passwd_reg->text();
    QString pwd_confirm = ui->pwd_confirm_reg->text();
    QString phone = ui->phone->text();
    QString email = ui->email->text();
    QString address = ui->address->text();
    QString port = ui->port->text();
    
    // 数据校验
    QRegExp regexp(USER_REG);
    if(!regexp.exactMatch(name))
    {
        QMessageBox::warning(this ,"警告","用户名格式不正确");
        //清除输入框中的内容
        ui->name_reg->clear();
        //光标定位到这里
        ui->name_reg->setFocus();
    }

     regexp.setPattern(USER_REG);
     if(!regexp.exactMatch(nickName))
     {
         QMessageBox::warning(this ,QString::fromLocal8Bit("警告"),QString::fromLocal8Bit("昵称格式不正确"));
         //清除输入框中的内容
         ui->nike_name->clear();
         //光标定位到这里
         ui->nike_name->setFocus();
     }

    regexp.setPattern(PASSWD_REG);
    if(!regexp.exactMatch(passwd))
    {
        QMessageBox::warning(this ,QString::fromLocal8Bit("警告"),QString::fromLocal8Bit("密码格式不正确"));
        //清除输入框中的内容
        ui->passwd_reg->clear();
        //光标定位到这里
        ui->passwd_reg->setFocus();
    }


    regexp.setPattern(PASSWD_REG);
    if(!regexp.exactMatch(pwd_confirm))
    {
        QMessageBox::warning(this ,QString::fromLocal8Bit("警告"),QString::fromLocal8Bit("密码格式不正确"));
        //清除输入框中的内容
        ui->pwd_confirm_reg->clear();
        //光标定位到这里
        ui->pwd_confirm_reg->setFocus();
    }


    regexp.setPattern(PHONE_REG);
    if(!regexp.exactMatch(phone))
    {
        QMessageBox::warning(this ,QString::fromLocal8Bit("警告"),QString::fromLocal8Bit("手机号码格式不正确"));
        //清除输入框中的内容
        ui->phone->clear();
        //光标定位到这里
        ui->phone->setFocus();
    }


    regexp.setPattern(EMAIL_REG);
    if(!regexp.exactMatch(email))
    {
        QMessageBox::warning(this ,QString::fromLocal8Bit("警告"),QString::fromLocal8Bit("邮箱格式不正确"));
        //清除输入框中的内容
        ui->email->clear();
        //光标定位到这里
        ui->email->setFocus();
    }



    // 组织要发送的json字符串
    QByteArray data = setRegisterJson(name, nickName, m_cm.getStrMd5(passwd), phone, email);


    // 发送 http 请求协议给server - > post请求
    //manager的作用是发送post数据
    QNetworkAccessManager *manager = Common::getNetManager();
    //制作http协议头。这里使用post的四种格式里面的"application/json"格式来发送数据,因为我们发送的是json数据
    QNetworkRequest request;
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
    //将携带的数据大小写入header中
    request.setHeader(QNetworkRequest::ContentLengthHeader, data.size());
    //设置server的url(注意——http://一定要写)
    QString url = QString("http://%1:%2/reg").arg(address).arg(port);
    request.setUrl(QUrl(url));
    QNetworkReply* reply = manager->post(request, data);
    
    
    // 读server发回的数据
    connect(reply, &QNetworkReply::readyRead, [=]()
    {
        QByteArray json = reply->readAll();

//      成功 	     {"code":"002"}
//      该用户已存在  {"code":"003"}
//      失败         {"code":"004"}
 
       QString status = m_cm.getCode(json);
        if("002" == status)
        {
            // 成功提示
            QMessageBox::information(this, "恭喜", "用户名注册成功");
            // 清空注册页面
            ui->name_reg->clear();
            ui->nike_name->clear();
            ui->passwd_reg->clear();
            ui->pwd_confirm_reg->clear();
            ui->phone->clear();
            ui->email->clear();
            // 将数据设置到登录窗口控件中
            ui->user_login->setText(name);
            ui->passwd_login->setText(passwd);
            // 切换到登录页面
            ui->stackedWidget->setCurrentWidget(ui->login_page);
        }
        else if("003" == status)
        {
            QMessageBox::warning(this, "注册失败", QString("[%1]该用户已经存在!!!").arg(name));
        }
        else
        {
            QMessageBox::warning(this, "注册失败", "注册失败!!!");
        }
        // 释放资源
        reply->deleteLater();
    });

}

补充:post发送数据的四种格式—— 项目(5)(部署web页面实现文件上传操作、post提交数据的四种格式、上传文件流程梳理、安装插件fastdfs-nginx-module、安装storage服务器)

注册用户需要使用的json数据包

// 注册用户需要使用的json数据包
QByteArray Login::setRegisterJson(QString userName, QString nickName,
         QString firstPwd, QString phone, QString email)
{
    QMap<QString, QVariant> reg;
    reg.insert("userName", userName);
    reg.insert("nickName", nickName);
    reg.insert("firstPwd", firstPwd);
    reg.insert("phone", phone);
    reg.insert("email", email);

    /*json数据如下
        {
            userName:xxxx,
            nickName:xxx,
            firstPwd:xxx,
            phone:xxx,
            email:xxx
        }
    */
    QJsonDocument jsonDocument = QJsonDocument::fromVariant(reg);
    if ( jsonDocument.isNull() )
    {
        cout << " jsonDocument.isNull() ";
        return "";
    }

    return jsonDocument.toJson();
}

项目server端部署流程

1、设置redis.conf

第一步:关闭绑定ip,如此,可以远程登录

第二步:关闭保护模式,也是为了远程登录

第三步:设置redis进程为守护进程

第四步:设置pid运行的文件目录

第五步:设置log日志的输出位置

第六步:设置数据持久化的保存位置(数据是就花默认以rdb的形式存储)

2、设置json配置文件

配置文件的好处——方便修改。代码中通过读取配置文件信息来进行相关环境的配置(比如设置redis的ip地址和端口号)。

如果服务器变了,我们无需修改代码,只要修改json配置文件即可。

{
	"redis":
	{
		"ip": "127.0.0.1",
		"port": "6379"
	},
	
	"mysql":
	{
		"ip": "127.0.0.1",
		"port": "3306",
		"database": "cloud_disk",
		"user": "root",
		"password": "root"
	},
	
	"dfs_path":
	{
		"client": "/etc/fdfs/client.conf"
	},
	
	"web_server":
	{
		"ip": "xx.xx.xx.xx",
		"port": "80"
	},
	
	"storage_web_server":
	{
		"ip": "xx.xx.xx.xx",
		"port": "80"
	}
	
}

3、配置nginx.conf文件

将相应的事件绑定好

location / {
    root   zyFile2;
    index  demo.html;
}
        
location /login{
    fastcgi_pass 127.0.0.1:10000;
    include fastcgi.conf;
}

location /reg{
    fastcgi_pass 127.0.0.1:10001;
    include fastcgi.conf;
}

location /upload{
    fastcgi_pass localhost:10002;
     include fastcgi.conf;
}

location /md5{
    fastcgi_pass 127.0.0.1:10003;
    include fastcgi.conf;
}
       

location /myfiles{
    fastcgi_pass 127.0.0.1:10004;
    include fastcgi.conf;
}
		
location /dealfile{
    fastcgi_pass 127.0.0.1:10005;
    include fastcgi.conf;
}

location /sharefiles{
    fastcgi_pass 127.0.0.1:10006;
    include fastcgi.conf;
}

location /dealsharefile{
    fastcgi_pass 127.0.0.1:10007;
    include fastcgi.conf;
}

公共类common介绍

声明

class Common : public QObject
{
    //不写这个宏,也就没办法使用QT里面的信号槽
    Q_OBJECT

public:
    Common(QObject* parent = 0);
    ~Common();

    // 让窗口在屏幕中央显示
    void moveToCenter(QWidget *tmp);

    // 从配置文件中得到相对应的参数
    QString getCfgValue(QString title, QString key, QString path = CONFFILE);

    // 通过读取文件, 得到文件类型, 存放在typeList
    void getFileTypeList();

    // 得到文件后缀,参数为文件类型,函数内部判断是否有此类型,如果有,使用此类型,没有,使用other.png
    QString getFileType(QString type);

    // 登录信息,写入配置文件
    void writeLoginInfo(QString user, QString pwd, bool isRemeber, QString path = CONFFILE);

    // 服务器信息,写入配置文件
    void writeWebInfo(QString ip, QString port, QString path=CONFFILE);

    // 获取某个文件的md5码
    QString getFileMd5(QString filePath);

    // 将某个字符串加密成md5码
    QString getStrMd5(QString str = "");

    // 产生分隔线
    QString getBoundary();

    // 得到服务器回复的状态码, 返回值为 "000", 或 "001"
    QString getCode(QByteArray json);

    // 传输数据记录到本地文件,user:操作用户,name:操作的文件, code: 操作码, path: 文件保存的路径
    void writeRecord(QString user, QString name, QString code, QString path = RECORDDIR);

    // 得到http通信类对象
    static QNetworkAccessManager* getNetManager();
public:
    static QStringList  m_typeList;

private:
    // 文件类型路径
    static QString      m_typePath;
    // 主要保存文件类型的后缀
    // http类
    static QNetworkAccessManager *m_netManager;
};

QT中的小技巧

如果一个类,不想有界面。可以设置他继承QObject,因为只有Object派生的类,才可以使用QT里面的信号槽

实现——让窗口在屏幕中央显示

// 窗口在屏幕中央显示
void Common::moveToCenter(QWidget *tmp)
{
     // 显示窗口
     tmp->show();
     // 屏幕中间显示
     // 使用qApp->desktop();也可以
     //通过desktop()获取当前桌面的宽度和高度
     QDesktopWidget* desktop = QApplication::desktop();
     // 移动窗口 desktop->width() - tmp->width():(当前屏幕的宽度-当前窗口的宽度)/2
     tmp->move((desktop->width() - tmp->width())/2, (desktop->height() - tmp->height())/2);
}

实现——从配置文件中得到相对应的参数

/* -------------------------------------------*/
/**
 * @brief           从配置文件中得到相对应的参数
 *
 * @param title     配置文件title名称[title]
 * @param key       key
 * @param path      配置文件路径
 *
 * @returns
 *                  success: 得到的value
 *                  fail:    空串
 */
/* -------------------------------------------*/
QString Common::getCfgValue(QString title, QString key, QString path)
{
    QFile file(path);

    // 只读方式打开
    if( false == file.open(QIODevice::ReadOnly) )
    {
        // 打开失败
        cout << "file open err";
        return "";
    }

    QByteArray json = file.readAll(); // 读取所有内容
    file.close(); // 关闭文件

    //判断操作过程中是否出现错误
    QJsonParseError error;

    // 将来源数据json转化为JsonDocument
    // 由QByteArray对象构造一个QJsonDocument对象,用于我们的读写操作
    QJsonDocument doc = QJsonDocument::fromJson(json, &error);
    if (error.error == QJsonParseError::NoError) // 没有出错
    {
        //如果转换失败或者是空的
        if (doc.isNull() || doc.isEmpty())
        {
            cout << "doc.isNull() || doc.isEmpty()";
            return "";
        }

        if( doc.isObject()) // 如果对象不为空
        {
            // QJsonObject json对象,描述json数据中{}括起来部分
            QJsonObject obj = doc.object();// 取得最外层这个大对象

            //title是我们要解析的子对象的键
            QJsonObject tmp = obj.value( title ).toObject();
            QStringList list = tmp.keys(); // 取出key列表
            //遍历key列表,查找我们要找的那个key(即传入的参数key)
            for(int i = 0; i < list.size(); ++i)
            {
                if( list.at(i) == key )
                {
                    return tmp.value( list.at(i) ).toString();
                }
            }

        }
    }
    else
    {
        cout << "err = " << error.errorString();
    }

    //其他情况返回空串
    return "";
}

实现——登录信息,写入配置文件

// 登录信息,写入配置文件
void Common::writeLoginInfo(QString user, QString pwd, bool isRemeber, QString path)
{
    // web_server信息
    QString ip = getCfgValue("web_server", "ip");
    QString port = getCfgValue("web_server", "port");

    QMap<QString, QVariant> web_server;
    web_server.insert("ip", ip);
    web_server.insert("port", port);

    // type_path信息
    QMap<QString, QVariant> type_path;
    type_path.insert("path", m_typePath);

    // login信息
    QMap<QString, QVariant> login;

    // 登陆信息加密
    int ret = 0;

    // 登陆用户加密
    unsigned char encUsr[1024] = {0};
    int encUsrLen;
    // toLocal8Bit(), 转换为本地字符集,如果windows则为gbk编码,如果linux则为utf-8编码
    ret = DesEnc((unsigned char *)user.toLocal8Bit().data(), user.toLocal8Bit().size(), encUsr, &encUsrLen);
    if(ret != 0)//加密失败
    {
        cout << "DesEnc err";
        return;
    }

    // 用户密码加密
    unsigned char encPwd[512] = {0};
    int encPwdLen;
    // toLocal8Bit()——可以将QString转成QByteArray.QByteArray调用data函数转成char*
    //DesEnc是一个类,里面有两个功能,加密和解密(自己实现的类)
    ret = DesEnc((unsigned char *)pwd.toLocal8Bit().data(), pwd.toLocal8Bit().size(), encPwd, &encPwdLen);
    if(ret != 0)
    {
        cout << "DesEnc err";
        return;
    }

    // 再次加密
    // base64转码加密,目的将加密后的二进制转换为base64字符串
    login.insert("user",  QByteArray((char *)encUsr, encUsrLen).toBase64());
    login.insert("pwd", QByteArray((char *)encPwd, encPwdLen).toBase64() );
    if(isRemeber == true)
    {
         login.insert("remember", "yes");
    }
    else
    {
        login.insert("remember", "no");
    }

    // QVariant类作为一个最为普遍的Qt数据类型的联合
    // QVariant为一个万能的数据类型--可以作为许多类型互相之间进行自动转换。
    QMap<QString, QVariant> json;
    json.insert("web_server", web_server);
    json.insert("type_path", type_path);
    json.insert("login", login);


    QJsonDocument jsonDocument = QJsonDocument::fromVariant(json);
    if ( jsonDocument.isNull() == true)
    {
        cout << " QJsonDocument::fromVariant(json) err";
        return;
    }

    //打开配置文件
    QFile file(path);

    if( false == file.open(QIODevice::WriteOnly) )
    {
        cout << "file open err";
        return;
    }

    //json内容写入文件,覆盖原来的内容
    file.write(jsonDocument.toJson());
    file.close();
}

实现——服务器信息,写入配置文件

// 服务器信息,写入配置文件
void Common::writeWebInfo(QString ip, QString port, QString path)
{
    // web_server信息,QVariant可以放任意数据类型
    QMap<QString, QVariant> web_server;
    web_server.insert("ip", ip);
    web_server.insert("port", port);

    // type_path信息
    QMap<QString, QVariant> type_path;
    type_path.insert("path", m_typePath);

    // login信息
    QString user = getCfgValue("login", "user");
    QString pwd = getCfgValue("login", "pwd");
    QString remember = getCfgValue("login", "remember");


    QMap<QString, QVariant> login;
    login.insert("user", user);
    login.insert("pwd", pwd);
    login.insert("remember", remember);


    // QVariant类作为一个最为普遍的Qt数据类型的联合
    // QVariant为一个万能的数据类型--可以作为许多类型互相之间进行自动转换。
    QMap<QString, QVariant> json;
    json.insert("web_server", web_server);
    json.insert("type_path", type_path);
    json.insert("login", login);


    QJsonDocument jsonDocument = QJsonDocument::fromVariant(json);
    if ( jsonDocument.isNull() == true)
    {
        cout << " QJsonDocument::fromVariant(json) err";
        return;
    }

    //读取文件
    QFile file(path);
    //如果文件不存在
    if( false == file.open(QIODevice::WriteOnly) )
    {
        cout << "file open err";
        return;
    }

    file.write(jsonDocument.toJson());
    file.close();
}

实现——获取某个文件的md5码

// 获取某个文件的md5码
QString Common::getFileMd5(QString filePath)
{
    //读入文件
    QFile localFile(filePath);

    if (!localFile.open(QFile::ReadOnly))
    {
        qDebug() << "file open error.";
        return 0;
    }

    QCryptographicHash ch(QCryptographicHash::Md5);

    quint64 totalBytes = 0;
    quint64 bytesWritten = 0;
    quint64 bytesToWrite = 0;
    quint64 loadSize = 1024 * 4; //每次读4k
    QByteArray buf;

    totalBytes = localFile.size();
    bytesToWrite = totalBytes;

    while (1)
    {
        if(bytesToWrite > 0)
        {
            //每次读4k。不要readall
            buf = localFile.read(qMin(bytesToWrite, loadSize));
            ch.addData(buf);
            bytesWritten += buf.length();
            bytesToWrite -= buf.length();
            buf.resize(0);
        }
        else
        {
            break;
        }

        if(bytesWritten == totalBytes)
        {
            break;
        }
    }

    localFile.close();
    QByteArray md5 = ch.result();
    //md5是16进制数组成的,因此需要转换
    return md5.toHex();
}

实现——将某个字符串加密成md5码

// 将某个字符串加密成md5码
QString Common::getStrMd5(QString str)
{
    QByteArray array;
    //md5加密
    array = QCryptographicHash::hash ( str.toLocal8Bit(), QCryptographicHash::Md5 );

    return array.toHex();
}

实现——得到服务器回复的状态码

// 得到服务器回复的状态码, 返回值为 "000", 或 "001"
QString Common::getCode(QByteArray json)
{
    QJsonParseError error;

    // 将来源数据json转化为JsonDocument
    // 由QByteArray对象构造一个QJsonDocument对象,用于我们的读写操作
    QJsonDocument doc = QJsonDocument::fromJson(json, &error);
    if (error.error == QJsonParseError::NoError)
    {
        if (doc.isNull() || doc.isEmpty())
        {
            cout << "doc.isNull() || doc.isEmpty()";
            return "";
        }

        if( doc.isObject() )
        {
            // 取得最外层这个大对象
            QJsonObject obj = doc.object();
            return obj.value( "code" ).toString();
        }

    }
    else
    {
        cout << "err = " << error.errorString();
    }

    return "";
}

实现——得到http通信类对象

注意:

该函数在类中被声明为静态的,因为——

一个项目里,只有一个QNetworkAccessManager,我们未来保证他的唯一性,因此将其设置为静态,而不是将其设置为全局变量。因为全局变量不安全。

  • 静态变量在用的时候需要先在类外初始化。
  • 静态变量在程序运行结束时被释放,因此new出来的QNetworkAccessManager不需要我们操心他什么时候被释放。
// 初始化变量
QString Common::m_typePath = FILETYPEDIR;
QStringList Common::m_typeList = QStringList();
QNetworkAccessManager* Common::m_netManager = new QNetworkAccessManager;

QNetworkAccessManager *Common::getNetManager()
{
    // 该对象一般一个应用程序中有一个就够了,无需new多个
    return  m_netManager;
}

debug小技巧

//自己定义的cout,cout可以输出文件名和行数,方便我们debug
#define cout qDebug() << "[ " << __FILE__ << ":"  << __LINE__ << " ] "

sourceinsight的使用

第一步:创建新项目

第二步:选择要看的代码的范围

第三步,开始看代码

服务端注册事件

#include "fcgi_config.h"
#include "fcgi_stdio.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "make_log.h" //日志头文件
#include "util_cgi.h"
#include "deal_mysql.h"
#include "cfg.h"
#include "cJSON.h"
#include <sys/time.h>

#define REG_LOG_MODULE       "cgi"
#define REG_LOG_PROC         "reg"


//解析用户注册信息的json包
int get_reg_info(char *reg_buf, char *user, char *nick_name, char *pwd, char *tel, char *email)
{
    int ret = 0;

    /*json数据如下
    {
        userName:xxxx,
        nickName:xxx,
        firstPwd:xxx,
        phone:xxx,
        email:xxx
    }
    */

    //解析json包
    //解析一个json字符串为cJSON对象
    cJSON * root = cJSON_Parse(reg_buf);
    if(NULL == root)
    {
        LOG(REG_LOG_MODULE, REG_LOG_PROC, "cJSON_Parse err\n");
        ret = -1;
        goto END;
    }

    //返回指定字符串对应的json对象
    //用户
    cJSON *child1 = cJSON_GetObjectItem(root, "userName");
    if(NULL == child1)
    {
        LOG(REG_LOG_MODULE, REG_LOG_PROC, "cJSON_GetObjectItem err\n");
        ret = -1;
        goto END;
    }

    //LOG(REG_LOG_MODULE, REG_LOG_PROC, "child1->valuestring = %s\n", child1->valuestring);
    strcpy(user, child1->valuestring); //拷贝内容

    //昵称
    cJSON *child2 = cJSON_GetObjectItem(root, "nickName");
    if(NULL == child2)
    {
        LOG(REG_LOG_MODULE, REG_LOG_PROC, "cJSON_GetObjectItem err\n");
        ret = -1;
        goto END;
    }
    strcpy(nick_name, child2->valuestring); //拷贝内容

    //密码
    cJSON *child3 = cJSON_GetObjectItem(root, "firstPwd");
    if(NULL == child3)
    {
        LOG(REG_LOG_MODULE, REG_LOG_PROC, "cJSON_GetObjectItem err\n");
        ret = -1;
        goto END;
    }
    strcpy(pwd, child3->valuestring); //拷贝内容

    //电话
    cJSON *child4 = cJSON_GetObjectItem(root, "phone");
    if(NULL == child4)
    {
        LOG(REG_LOG_MODULE, REG_LOG_PROC, "cJSON_GetObjectItem err\n");
        ret = -1;
        goto END;
    }
    strcpy(tel, child4->valuestring); //拷贝内容

    //邮箱
    cJSON *child5 = cJSON_GetObjectItem(root, "email");
    if(NULL == child5)
    {
        LOG(REG_LOG_MODULE, REG_LOG_PROC, "cJSON_GetObjectItem err\n");
        ret = -1;
        goto END;
    }
    strcpy(email, child5->valuestring); //拷贝内容

END:
    if(root != NULL)
    {
        cJSON_Delete(root);//删除json对象
        root = NULL;
    }

    return ret;
}

//注册用户,成功返回0,失败返回-1, 该用户已存在返回-2
int user_register( char *reg_buf )
{
    int ret = 0;
    MYSQL *conn = NULL;

    //获取数据库用户名、用户密码、数据库标示等信息
    char mysql_user[256] = {0};
    char mysql_pwd[256] = {0};
    char mysql_db[256] = {0};
    ret = get_mysql_info(mysql_user, mysql_pwd,  mysql_db);
    if(ret != 0)
    {
        goto END;
    }
    LOG(REG_LOG_MODULE, REG_LOG_PROC, "mysql_user = %s, mysql_pwd = %s, mysql_db = %s\n", mysql_user, mysql_pwd, mysql_db);

    //获取注册用户的信息
    char user[128];
    char nick_name[128];
    char pwd[128];
    char tel[128];
    char email[128];
    ret = get_reg_info(reg_buf, user, nick_name, pwd, tel, email);
    if(ret != 0)
    {
        goto END;
    }
    LOG(REG_LOG_MODULE, REG_LOG_PROC, "user = %s, nick_name = %s, pwd = %s, tel = %s, email = %s\n", user, nick_name, pwd, tel, email);

    //connect the database
    conn = msql_conn(mysql_user, mysql_pwd, mysql_db);
    if (conn == NULL)
    {
        LOG(REG_LOG_MODULE, REG_LOG_PROC, "msql_conn err\n");
        ret = -1;
        goto END;
    }

    //设置数据库编码,主要处理中文编码问题
    mysql_query(conn, "set names utf8");

    char sql_cmd[SQL_MAX_LEN] = {0};

    sprintf(sql_cmd, "select * from user where name = '%s'", user);

    //查看该用户是否存在
    int ret2 = 0;
    //返回值: 0成功并保存记录集,1没有记录集,2有记录集但是没有保存,-1失败
    ret2 = process_result_one(conn, sql_cmd, NULL); //指向sql查询语句
    if(ret2 == 2) //如果存在
    {
        LOG(REG_LOG_MODULE, REG_LOG_PROC, "【%s】该用户已存在\n");
        ret = -2;
        goto END;
    }

    //当前时间戳
    struct timeval tv;
    struct tm* ptm;
    char time_str[128];

    //使用函数gettimeofday()函数来得到时间。它的精度可以达到微妙
    gettimeofday(&tv, NULL);
    ptm = localtime(&tv.tv_sec);//把从1970-1-1零点零分到当前时间系统所偏移的秒数时间转换为本地时间
    //strftime() 函数根据区域设置格式化本地时间/日期,函数的功能将时间格式化,或者说格式化一个时间字符串
    strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", ptm);

    //sql 语句, 插入注册信息
    sprintf(sql_cmd, "insert into user (name, nickname, password, phone, createtime, email) values ('%s', '%s', '%s', '%s', '%s', '%s')", user, nick_name, pwd, tel, time_str ,email);

    if(mysql_query(conn, sql_cmd) != 0)
    {
        LOG(REG_LOG_MODULE, REG_LOG_PROC, "%s 插入失败:%s\n", sql_cmd, mysql_error(conn));
        ret = -1;
        goto END;
    }

END:
    if(conn != NULL)
    {
        mysql_close(conn); //断开数据库连接
    }

    return ret;
}

int main()
{
    //阻塞等待用户连接
    while (FCGI_Accept() >= 0)
    {
        char *contentLength = getenv("CONTENT_LENGTH");
        int len;

        printf("Content-type: text/html\r\n\r\n");

        if( contentLength == NULL )
        {
            len = 0;
        }
        else
        {
            len = atoi(contentLength); //字符串转整型
        }

        if (len <= 0)//没有登陆用户信息
        {
            printf("No data from standard input.<p>\n");
            LOG(REG_LOG_MODULE, REG_LOG_PROC, "len = 0, No data from standard input\n");
        }
        else //获取登陆用户信息
        {
            char buf[4*1024] = {0};
            int ret = 0;
            char *out = NULL;
            ret = fread(buf, 1, len, stdin); //从标准输入(web服务器)读取内容
            if(ret == 0)
            {
                LOG(REG_LOG_MODULE, REG_LOG_PROC, "fread(buf, 1, len, stdin) err\n");
                continue;
            }

            LOG(REG_LOG_MODULE, REG_LOG_PROC, "buf = %s\n", buf);

            //注册用户,成功返回0,失败返回-1, 该用户已存在返回-2
            /*
            注册:
                成功:{"code":"002"}
                该用户已存在:{"code":"003"}
                失败:{"code":"004"}
            */
            ret = user_register( buf );
            if (ret == 0) //登陆成功
            {
                //返回前端注册情况, 002代表成功
                out = return_status("002");//util_cgi.h
            }
            else if(ret == -1)
            {
                //返回前端注册情况, 004代表失败
                out = return_status("004");//util_cgi.h
            }
            else if(ret == -2)
            {
               out = return_status("003");//util_cgi.h
            }

            if(out != NULL)
            {
                printf(out); //给前端反馈信息
                free(out); //记得释放
            }
        }

    }

    return 0;
}

猜你喜欢

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