Update

  at 2019/07/22 14:16

  发现一个大坑,我们后期是打算用QSS统一堆样式进行美化的,于是我把之前对QLabel进行的setAlignment全部去掉了,打算统一丢进Qss里面,一下子使程序简洁了很多。但是发现QLabel在QSS里面不支持text-align,也找不到其他将其设置为居中的接口。暂时的解决方案是新建一个QLabelCenter类,完全从QLabel继承,但是构造函数里面加上setAlignment。

  附一段加载qss的代码:

void Translation::LoadQss(const QString sRoad){
QFile fQss(sRoad);
fQss.open(QFile::ReadOnly);
setStyleSheet(fQss.readAll());
fQss.close();
}

  sRoad是qss文件的路径。

  

  


  感觉自己花了两天时间完成了一下午的工作量,基本上都是单纯地堆代码,没有什么技术性比较强的活,所以这篇巨水无比。我现在主要的参考资料已经变成官方的手册了:

  https://doc.qt.io/qt-5/classes.html

  目前正在一步一步朝着GMA的样式前进。

  

  用户的存储是在全局的位置放了std::vector<User> g_Users,下面是遍历这个vector的一种比较优雅的做法:

  std::vector<User>::iterator itUserTemp;
  for (itUserTemp = g_Users.begin(); itUserTemp != g_Users.end(); itUserTemp++) {
    //itUserTemp->GetNickname()....
  }

  

  

1. Register

  

  这里的样式结构非常简单,画面整体是竖向排列的,里面再套一个横向排列用来放提示和输入框。文字输入用的是QLineEdit,下拉列表选项用的是QComboBox。

  按照我的写法,Register类中需要存储一下被输入的QLineEdit的指针,还有Register的父元素MainWindow的指针,响应的槽函数放在Register中,这样响应函数可以调用MainWindow的切换界面函数。

  ^_^

QWidget* Register::ShowInformation(bool Show) {
QWidget* pwBox = new QWidget();
QVBoxLayout* pvLayout = new QVBoxLayout(pwBox); //CreateLineInput是预先写好的一个函数,返回一个QWidget,里面横向放了一个QLabel和一个QLineEdit
//m_pleNickname会变成一个指向QLineEdit的指针
pvLayout->addWidget(CreateLineInput(STR_TIP_NICKNAME, m_pleNickname, Show));
m_pleNickname->setMaxLength(); pvLayout->addWidget(CreateLineInput(STR_TIP_PASSWORD, m_plePassword, Show));
m_plePassword->setEchoMode(QLineEdit::Password);
m_plePassword->setMaxLength(); pvLayout->addWidget(CreateLineInput(STR_TIP_PASSWORDCON, m_plePasswordCon, Show));
m_plePasswordCon->setEchoMode(QLineEdit::Password);
m_plePasswordCon->setMaxLength(); pvLayout->addWidget(CreateLineInput(STR_TIP_AGE, m_pleAge, Show)); //CreateGenderInput跟CreateLineInput类似
pvLayout->addWidget(CreateGenderInput(STR_TIP_AGE, m_pleGender, Show)); return pwBox;
}
void Register::Init() {
QVBoxLayout *pvlLayout = new QVBoxLayout(this);//整体竖向排版 QLabel* plMainTitle = new QLabel(this);
plMainTitle->setText(STR_MAINTITLE_REGISTER);//主标题
plMainTitle->setAlignment(Qt::AlignCenter);
pvlLayout->addWidget(plMainTitle, INT_SIZERATE_MAINTITAL);//主标题加入整体的竖向排版 pvlLayout->addWidget(ShowInformation(), INT_SIZERATE_INFORMATION);//调用函数,获得一个QWidget,加进主排版 //按钮部分
QWidget* pwButton = new QWidget(this);
QHBoxLayout* phlButton = new QHBoxLayout(pwButton);
QPushButton* ppbRegister = new QPushButton(pwButton);
ppbRegister->setText(STR_BUTTON_REGISTER);
phlButton->addWidget(ppbRegister, INT_SIZERATE_BUTTON_REGISTER); pvlLayout->addWidget(pwButton, INT_SIZERATE_BUTTON); connect(ppbRegister, SIGNAL(clicked(bool)), this, SLOT(RegisterRequest()));
}

2. Login

  

  和Register非常相似,用一个User* g_pCurrentUser来指向当前的已登录用户。

  

  

  ^_^

QWidget* Login::ShowInformation(bool Show) {
QWidget* pwBox = new QWidget();
QVBoxLayout* pvLayout = new QVBoxLayout(pwBox); //CreateLineInput是写好的一个创建输入提示和输入框的函数
pvLayout->addWidget(CreateLineInput(STR_TIP_NICKNAME, m_pleNickname, Show));
pvLayout->addWidget(CreateLineInput(STR_TIP_PASSWORD, m_plePassword, Show));
m_plePassword->setEchoMode(QLineEdit::Password);
return pwBox;
}
void Login::Init() {
//竖直布局
QVBoxLayout *pvlLayout = new QVBoxLayout(this); //加入主标题
pvlLayout->addWidget(new QLabelCenter(STR_MAINTITLE_LOGIN), INT_SIZERATE_MAINTITAL); //加入输信息模块
pvlLayout->addWidget(ShowInformation(), INT_SIZERATE_INFORMATION); //加入按钮模块
QPushButton* ppbLogin = new QPushButton(STR_BUTTON_LOGIN);
connect(ppbLogin, SIGNAL(clicked(bool)), this, SLOT(LoginRequest()));
pvlLayout->addWidget(ppbLogin, INT_SIZERATE_BUTTON_LOGIN); QPushButton* ppbRegister = new QPushButton(STR_BUTTON_REGISTER);
connect(ppbRegister, SIGNAL(clicked(bool)), this, SLOT(RegisterRequest()));
pvlLayout->addWidget(ppbRegister, INT_SIZERATE_BUTTON_REGISTER);
}

3. Database

  我们需要在程序开启时从数据库加载表里的用户,程序关闭时把相关数据存入数据库。

  我专门写了一个Database类,初始化时传入地址、账号、密码之类的初始信息,当然为了方便你也可以把数据库写成全局的函数,初始信息写死。

  每次存数据先把数据库里的表清空:TRUNCATE Users,然后再逐个用户INSERT INTO Users。取数据直接SELECT即可。

  后来听说直接清空之后存数据给的分会低,已有的数据只进行update效率比较高,mark起来以后改

  ^_^

//存数据
void Database::SaveData(std::vector<User>& Users) {
MYSQL MysqlTemp;
MYSQL* pSock;
mysql_init(&MysqlTemp);
if ((pSock = mysql_real_connect(&MysqlTemp, HOST, USERNAME, PASSWORD, DB, PORT, UNIX_SOCKET, CLIENT_FLAG)) == nullptr) {
#ifdef DEBUG_MOD
qDebug() << "Fail to connect mysql.\n";
qDebug() << mysql_error(&MysqlTemp) << endl;
#endif
return;
} std::string sQuery;
if (mysql_query(&MysqlTemp, "TRUNCATE Users") != ) {
#ifdef DEBUG_MOD
qDebug() << "Fail to query : " << QString::fromStdString(sQuery) << endl;
#endif
} std::vector<User>::iterator itUserTemp;
#ifdef DEBUG_MOD
qDebug() << "Save : " << Users.size() << endl;
#endif
for (itUserTemp = Users.begin(); itUserTemp != Users.end(); itUserTemp++) {
//设置好语句
sQuery = "INSERT INTO Users (ID, Nickname, Password, Introduction, Certificate, Gender, Age, Score) VALUES (";
sQuery += std::to_string(itUserTemp->GetId()) + ", ";
sQuery += "'" + itUserTemp->GetNickname() + "', ";
sQuery += "'" + itUserTemp->GetPassword() + "', ";
sQuery += "'" + itUserTemp->GetIntroduction() + "', ";
sQuery += "'" + itUserTemp->GetCertificate() + "', ";
sQuery += std::to_string(int(itUserTemp->GetGender())) + ", ";
sQuery += std::to_string(itUserTemp->GetAge()) + ", ";
sQuery += std::to_string(itUserTemp->GetScore()) + ")"; if (mysql_query(&MysqlTemp, sQuery.data()) != ) {
#ifdef DEBUG_MOD
qDebug() << "Fail to query : " << QString::fromStdString(sQuery) << endl;
#endif
}
}
mysql_close(pSock);
} //取数据
void Database::LoadData(std::vector<User>& Users) {
MYSQL MysqlTemp;
MYSQL* pSock;
mysql_init(&MysqlTemp);
if ((pSock = mysql_real_connect(&MysqlTemp, HOST, USERNAME, PASSWORD, DB, PORT, UNIX_SOCKET, CLIENT_FLAG)) == nullptr) {
#ifdef DEBUG_MOD
qDebug() << "Fail to connect mysql.\n";
qDebug() << mysql_error(&MysqlTemp) << endl;
#endif
return;
}
std::string sQuery = "SELECT ID, Nickname, Password, Introduction, Certificate, Gender, Age, Score FROM Users";
if (mysql_query(&MysqlTemp, sQuery.data()) != ){
#ifdef DEBUG_MOD
qDebug() << "Fail to query : " << QString::fromStdString(sQuery) << endl;
#endif
return;
}
MYSQL_RES * result;
MYSQL_ROW row;
if ((result = mysql_store_result(&MysqlTemp)) == NULL) {
#ifdef DEBUG_MOD
qDebug() << "Fail to store result!" << endl;
#endif
return;
} Users.clear();
//逐行取数据
while ((row = mysql_fetch_row(result)) != NULL) {
User UserTemp(atoi(row[]), std::string(row[]), std::string(row[]), std::string(row[]),
std::string(row[]), Gender(atoi(row[])), atoi(row[]), atoi(row[])); Users.push_back(UserTemp);
}
#ifdef DEBUG_MOD
qDebug() << "Load : " << Users.size() << endl;
#endif
mysql_close(pSock);
}

4. Leaderboard

  

  反正只是一个大作业而已就不打算做什么翻页的功能了,直接一个滚动条滑到底好了。

  首先是一个竖直的布局,有一个MainTitle(QLabel)和一个Leaderboard(QScrollArea)。QScrollArea里面先套了一个QWidget,在这个QWidget里面放竖直布局,竖直布局里面每行是一个水平布局,存放个人信息。值得注意的是QScrollArea需要执行一下setWidgetResizable(true),否则会有显示错误……

  

  ^_^

namespace QtLeaderboard {
QWidget* CreateTips() {
QWidget* pwTips = new QWidget();
QHBoxLayout* phlTipsLayout = new QHBoxLayout(pwTips);
phlTipsLayout->addWidget(new QLabel(SET_TIP_HEAD), INT_SIZERATE_HEAD); phlTipsLayout->addWidget(new QLabel(SET_TIP_NICKNAME), INT_SIZERATE_NICKNAME); phlTipsLayout->addWidget(new QLabel(SET_TIP_INTRO), INT_SIZERATE_INTRO); phlTipsLayout->addWidget(new QLabel(SET_TIP_SCORE), INT_SIZERATE_SCORE); return pwTips;
} QWidget* CreatePersonal(std::vector<User>::iterator itUserTemp) {
QWidget* pPersonal = new QWidget();
pPersonal->setFixedHeight(INT_PERSONAL_HEIGHT); QHBoxLayout* phlPersonalLayout = new QHBoxLayout(pPersonal); QLabel* plHead = new QLabel(pPersonal); {
QImage Head(QString::fromStdString(itUserTemp->GetHead()));
Head = Head.scaled(INT_HEAD_WIDTH, INT_HEAD_HEIGHT);
plHead->setPixmap(QPixmap::fromImage(Head));
plHead->setAlignment(Qt::AlignCenter);
} phlPersonalLayout->addWidget(plHead, INT_SIZERATE_HEAD); phlPersonalLayout->addWidget(new QLabel(QString::fromStdString(itUserTemp->GetNickname())), INT_SIZERATE_NICKNAME); phlPersonalLayout->addWidget(new QLabel(QString::fromStdString(itUserTemp->GetIntroduction())), INT_SIZERATE_INTRO); phlPersonalLayout->addWidget(new QLabel(QString::number(itUserTemp->GetScore())), INT_SIZERATE_SCORE); return pPersonal;
} QScrollArea* CreateBoard() {
QScrollArea* psaBoard = new QScrollArea();
QWidget* pwBoard = new QWidget(psaBoard); pwBoard->setFixedHeight(g_Users.size() * INT_PERSONAL_HEIGHT + INT_TIP_HEIGHT);
QVBoxLayout* pvlBoardLayout = new QVBoxLayout(pwBoard); pvlBoardLayout->addWidget(QtLeaderboard::CreateTips()); //逐个用户添加信息
std::vector<User>::iterator itUserTemp;
//sort(g_Users.begin(), g_Users.end(), User::SortByScore);
for (itUserTemp = g_Users.begin(); itUserTemp != g_Users.end(); itUserTemp++) {
pvlBoardLayout->addWidget(QtLeaderboard::CreatePersonal(itUserTemp));
} psaBoard->setWidget(pwBoard);
psaBoard->setWidgetResizable(true); return psaBoard;
}
}
void Leaderboard::Init() {
QVBoxLayout *pvlMainLayout = new QVBoxLayout(this); //加入主标题
pvlMainLayout->addWidget(new QLabel(STR_MAINTITLE_LEADERBOARD), INT_SIZERATE_MAINTITAL); //加入排行榜界面
pvlMainLayout->addWidget(QtLeaderboard::CreateBoard(), INT_SIZERATE_BOARD);
}

5. Personal

  个人界面……写得还蛮久

  

  

  亮点是实现了一个上传头像的功能吧,但是用Qt的getOpenFileName,QImage自带load和save,很容易就造出来了。

  ^_^

QWidget* Personal::CreateMainInfor() {
QWidget* pwBox = new QWidget();
QVBoxLayout* pvMainLayout = new QVBoxLayout(pwBox); QLabelCenter* plHead = new QLabelCenter();
QImage Head = g_pCurrentUser->GetHead();
Head = Head.scaled(INT_HEAD_WIDTH, INT_HEAD_HEIGHT);
plHead->setPixmap(QPixmap::fromImage(Head));
pvMainLayout->addWidget(plHead, INT_SIZERATE_HEAD); pvMainLayout->addWidget(new QLabelCenter(QString::fromStdString(g_pCurrentUser->GetNickname())), INT_SIZERATE_NICKNAME); pvMainLayout->addWidget(new QLabelCenter(QString::fromStdString(g_pCurrentUser->GetIntroduction())), INT_SIZERATE_INTRO); return pwBox;
}
QWidget* Personal::CreateSingleInfor(QString sTip, QString sInfor) {
QWidget* pwBox = new QWidget();
QHBoxLayout* phLayout = new QHBoxLayout(pwBox); phLayout->addWidget(new QLabelCenter(sTip), INT_SIZERATE_SIN_TIP);
phLayout->addWidget(new QLabelCenter(sInfor), INT_SIZERATE_SIN_INFOR);
phLayout->addStretch(INT_SIZERATE_SIN_SPACE); return pwBox;
}
QWidget* Personal::CreateInfor() {
QWidget* pwBox = new QWidget();
QVBoxLayout* pvLayout = new QVBoxLayout(pwBox); pvLayout->addWidget(CreateSingleInfor(STR_TIP_AGE, QString::number(g_pCurrentUser->GetAge())));
pvLayout->addWidget(CreateSingleInfor(STR_TIP_GENDER, STR_GENDER[g_pCurrentUser->GetGender()]));
pvLayout->addWidget(CreateSingleInfor(STR_TIP_CERITI, QString::fromStdString(g_pCurrentUser->GetCertificate())));
pvLayout->addWidget(CreateSingleInfor(STR_TIP_SCORE, QString::number(g_pCurrentUser->GetScore())));
pvLayout->addWidget(CreateSingleInfor(STR_TIP_BALANCE, QString::number(g_pCurrentUser->GetBalance()))); return pwBox;
}
QWidget* Personal::CreateSingleModifyPassword() {
QWidget* pwBox = new QWidget();
QHBoxLayout* phLayout = new QHBoxLayout(pwBox); QWidget* pwTip = new QWidget();
QVBoxLayout* pvLayoutTip = new QVBoxLayout(pwTip);
pvLayoutTip->addWidget(new QLabelCenter(STR_TIP_PASSWORD));
pvLayoutTip->addWidget(new QLabelCenter(STR_TIP_PASSWORDCON));
phLayout->addWidget(pwTip, INT_SIZERATE_MOD_TIP); QWidget* pwEdit = new QWidget();
QVBoxLayout* pvLayoutEdit = new QVBoxLayout(pwEdit);
QLineEdit* pleInputPass = new QLineEdit();
pvLayoutEdit->addWidget(pleInputPass);
pleInputPass->setEchoMode(QLineEdit::Password);
QLineEdit* pleInputCon = new QLineEdit();
pvLayoutEdit->addWidget(pleInputCon);
pleInputCon->setEchoMode(QLineEdit::Password);
phLayout->addWidget(pwEdit, INT_SIZERATE_MOD_INPUT); QPushButton* ppbButton = new QPushButton(STR_TIP_SIN_MODITY);
phLayout->addWidget(ppbButton, INT_SIZERATE_MOD_BUTTON); connect(ppbButton, &QPushButton::clicked, [=]() {
if (pleInputPass->text() != pleInputCon->text()) {
QMessageBox::information(this, STR_MODIFY_FAIL, STR_PASSWORD_UNMATCH);
return;
}
if (g_pCurrentUser->ChangePassword(pleInputPass->text().toStdString()) == true) {
m_pParentTrans->ChangeContent(new Personal(m_pParentTrans));
}
else {
QMessageBox::information(this, STR_MODIFY_FAIL, STR_MODIFY_FAIL_TEXT);
return;
}
});
return pwBox;
}
QWidget* Personal::CreateSingleModify(QString sTip, bool(User::*pChange)(std::string)) {
QWidget* pwBox = new QWidget();
QHBoxLayout* phLayout = new QHBoxLayout(pwBox); phLayout->addWidget(new QLabelCenter(sTip), INT_SIZERATE_MOD_TIP);
QLineEdit* pleInput = new QLineEdit();
phLayout->addWidget(pleInput, INT_SIZERATE_MOD_INPUT);
QPushButton* ppbButton = new QPushButton(STR_TIP_SIN_MODITY);
phLayout->addWidget(ppbButton, INT_SIZERATE_MOD_BUTTON);
connect(ppbButton, &QPushButton::clicked, [=]() {
if ((g_pCurrentUser->*pChange)(pleInput->text().toStdString()) == true) {
m_pParentTrans->ChangeContent(new Personal(m_pParentTrans));
}
else {
QMessageBox::information(this, STR_MODIFY_FAIL, STR_MODIFY_FAIL_TEXT);
return;
}
}); return pwBox;
}
QWidget* Personal::CreateSingleModifyGender() {
QWidget* pwBox = new QWidget();
QHBoxLayout* phLayout = new QHBoxLayout(pwBox); phLayout->addWidget(new QLabelCenter(STR_TIP_GENDER), INT_SIZERATE_MOD_TIP);
QComboBox* pcbInput = GetInformation::CreateGenderCom();
phLayout->addWidget(pcbInput, INT_SIZERATE_MOD_INPUT);
QPushButton* ppbButton = new QPushButton(STR_TIP_SIN_MODITY);
phLayout->addWidget(ppbButton, INT_SIZERATE_MOD_BUTTON);
connect(ppbButton, &QPushButton::clicked, [=]() {
if (g_pCurrentUser->ChangeGender(pcbInput->currentIndex()) == true) {
m_pParentTrans->ChangeContent(new Personal(m_pParentTrans));
}
else {
QMessageBox::information(this, STR_MODIFY_FAIL, STR_MODIFY_FAIL_TEXT);
return;
}
}); return pwBox;
}
QScrollArea* Personal::CreateModify() {
QScrollArea* psaBox = new QScrollArea(); QWidget* pwBox = new QWidget();
QVBoxLayout* pvLayout = new QVBoxLayout(pwBox);
QPushButton* ppbUploadHead = new QPushButton(STR_HEAD_UPLOAD);
connect(ppbUploadHead, &QPushButton::clicked, [this]() {
QString filename = QFileDialog::getOpenFileName(this, STR_CHOOSE_IMAGE, "/", STR_IMAGE_FILTER);
if (filename.isEmpty())
return;
else
{
QImage Image;
if (!(Image.load(filename)))
{
QMessageBox::information(this, STR_LOAD_FAIL, STR_LOAD_FAIL_TEXT);
return;
}
QString sSavePath = QCoreApplication::applicationDirPath() + STR_HEAD_PATH;
Image.save(sSavePath + QString::number(g_pCurrentUser->GetId()) + STR_HEAD_TYPE);
m_pParentTrans->UpdateMenu();
m_pParentTrans->ChangeContent(new Personal(m_pParentTrans));
}
});
pvLayout->addWidget(ppbUploadHead, INT_SIZERATE_MOD_UPLOAD); pvLayout->addWidget(CreateSingleModifyPassword(), INT_SIZERATE_MOD_INTRO);
pvLayout->addWidget(CreateSingleModify(STR_TIP_AGE, &(User::ChangeAge)), INT_SIZERATE_MOD_AGE);
pvLayout->addWidget(CreateSingleModify(STR_TIP_INTRO, &(User::ChangeIntro)), INT_SIZERATE_MOD_INTRO);
pvLayout->addWidget(CreateSingleModify(STR_TIP_CERITI, &(User::ChangeCeriti)), INT_SIZERATE_MOD_CERITI);
pvLayout->addWidget(CreateSingleModifyGender(), INT_SIZERATE_MOD_GENDER); psaBox->setWidget(pwBox);
psaBox->setWidgetResizable(true);
return psaBox;
}
QTabWidget* Personal::CreateTab() {
QTabWidget* pwTabBox = new QTabWidget(); //标签页暂时只有这俩元素
pwTabBox->addTab(CreateInfor(), STR_TAB_INFOR);
pwTabBox->addTab(CreateModify(), STR_TAB_MODIFY); return pwTabBox;
} void Personal::Init() {
if (g_pCurrentUser == NULL) {
m_pParentTrans->ChangeContent(new Index(m_pParentTrans));
return;
}
QVBoxLayout *pvlMainLayout = new QVBoxLayout(this); //主题拆成两块,主信息展示和标签页
pvlMainLayout->addWidget(CreateMainInfor(), INT_SIZERATE_INFOR); pvlMainLayout->addWidget(CreateTab(), INT_SIZERATE_TAB);
}

c++小学期大作业攻略(三)用户系统的更多相关文章

  1. c++小学期大作业攻略(一)环境配置

    UPDATE at 2019/07/20 20:21 更新了Qt连接mysql的方法,但是是自己仿照连VS的方法摸索出来的,简单测试了一下能work但是不保证后期不会出问题.如果你在尝试过程中出现了任 ...

  2. c++小学期大作业攻略(二)整体思路+主界面

    写在前面:如果我曾经说过要在第一周之内写完大作业,那……肯定是你听错了.不过如果我在写的时候有攻略看的话应该可以轻松地在4~5天内做完,然后觉得写攻略的人是个小天使吧(疯狂暗示).出于给大家自由发挥的 ...

  3. c++小学期大作业攻略(四)任务系统+站内信

    虽然比最早的预定晚了整整一个星期但这核心功能最后一篇终于还是来了. 如果你已经经历了用户系统的洗礼,相信代码实现应该已经没有太大的难度,所以我们重点关注一下设计好的流程. 一.任务系统 首先是新建任务 ...

  4. c++小学期大作业攻略(五)基于QSS的样式美化

    这回真的是最后一篇了. 前面说过,我们开发过程中暂时不搭理样式问题,等最后再一起处理,那么现在就是最后处理时刻了!看到网上说QSS跟CSS差不多,我还觉得自己可以干回老本行了,结果用起来发现,QSS是 ...

  5. c++小学期大作业攻略(零)建议+代码结构(持续更新)

    当前已经做好的exe,数据库是连服务器的,但是头像是存在本地的文件系统里面: https://cloud.tsinghua.edu.cn/d/059ef6b1f9a149ce879b/files/?p ...

  6. 攻略三战的完美体验3Castle Fantisia阿兰·梅希亚战争艾伦西战记它包含重做版本(这是新的艾伦·梅希亚大战)

    (城堡幻想曲3,纠正大家个错误哦,不是圣魔大战3,圣魔大战是城堡幻想曲2,圣魔大战不是个系列,艾伦西亚战记==艾伦希亚战记,一个游戏日文名:タイトル キャッスルファンタジア -エレンシア戦記-リニュー ...

  7. Cross-Site Scripting XSS 跨站攻击全攻略 分类: 系统架构 2015-07-08 12:25 21人阅读 评论(2) 收藏

    原文:http://a1pass.blog.163.com/blog/static/2971373220087295449497/ 题记:这是我在<黑客X档案>08年第5期发表的一篇文章, ...

  8. 内连接、左外连接、右外连接、全外连接、交叉连接(CROSS JOIN)-----小知识解决大数据攻略

    早就听说了内连接与外连接,以前视图中使用过.这次自考也学习了,只是简单理解,现在深入探究学习(由于上篇博客的出现)与实践: 概念 关键字: 左右连接 数据表的连接有: 1.内连接(自然连接): 只有两 ...

  9. react hooks 全面转换攻略(三) 全局存储解决方案

    针对 react hooks 的新版本解决方案 一.redux维持原方案 若想要无缝使用原来的 redux,和其配套的中间件 promise,thunk,saga 等等的话 可以使用 redux-re ...

随机推荐

  1. SpringBoot打可执行war包

    1. 主程序类: @SpringBootApplication public class Application extends SpringBootServletInitializer { @Ove ...

  2. 图书推荐《图解HTTP》

    作品简介 本书对互联网基盘——HTTP协议进行了全面系统的介绍.作者由HTTP协议的发展历史娓娓道来,严谨细致地剖析了HTTP协议的结构,列举诸多常见通信场景及实战案例,最后延伸到Web安全.最新技术 ...

  3. Vue笔记--同局域网下访问本地项目

    正常开发中有时间提测比较麻烦.通常让测试小姐姐连接开发本地开启的服务器访问本地项目(在同一局域网下). 其实一般项目IDE已经实现这些功能例如webstorm和vscode,有时候需要单独配置下. 但 ...

  4. vuePress自动部署到Github Page脚本踩坑

    背景 照着官网的教程来就行了,踩了个小坑,记录一下,希望对你有帮助 这是部署后的效果 小坑1 如图所示,官网推荐部署命令 然而windows 没有bash 指令, 直接运行报错 两个解决方法: 项目根 ...

  5. js 过滤字符 和检测 特殊字符【转】

    // var str1 = str.replace(/\[\\'\\"\\\\\\/\\b\\f\\n\\r\\t\]/g, '');// 去掉转义字符 // var str2= str.r ...

  6. PHP基础(谈一谈Session&Cookie)

    cookie和sessiond的主要区别 (1).保存位置稍有区别 cookie数据存放在客户的浏览器上,服务器端不用保存.session数据放在服务器上,本地内存也有一份. (2).安全性不同 co ...

  7. [基础]斯坦福cs231n课程视频笔记(二) 神经网络的介绍

    目录 Introduction to Neural Networks BP Nerual Network Convolutional Neural Network Introduction to Ne ...

  8. Dart Flutter

    下载Flutter Google下载地址: https://storage.googleapis.com/dart-archive/channels/stable/release/2.3.0/sdk/ ...

  9. Error: EACCES: permission denied, mkdir

    今天在全局安装飞冰的时候,出现标题的错误 想到是权限不够的问题,其实飞冰官网也有解决的办法,就是更改npm的默认路径.我之前就是用了更改默认路径的方法,然后后来又恢复了默认路径,所以还是用默认路径加权 ...

  10. 在linux下配置jupyter notebook,本地浏览器访问

    1.安装jupyter notebook pip install jupyter 2.生成配置文件 jupyter notebook --generate-config 3.设置登陆密码并生成秘钥 s ...