QtWebApp
1.下载
https://github.com/fffaraz/QtWebApp
2.功能
- HTTP(S) 1.0 and 1.1 server (web服务器)
- Template engine (模板)
- Buffered logger(日志)
3.使用
1.web
简单例子:post上传文件到nginx的后台数据处理
1 #include "UploadFileNginx.h" 2 #include<QSettings> 3 UploadFileNginx::UploadFileNginx(QWidget *parent) 4 : QMainWindow(parent) 5 { 6 ui.setupUi(this); 7 OnInit(); 8 }0 9 10 UploadFileNginx::~UploadFileNginx() 11 {} 12 void UploadFileNginx::OnInit() 13 { 14 QString configFileName = "UploadFileNginx.ini"; 15 QSettings* listenerSettings = new QSettings(configFileName, QSettings::IniFormat, this); 16 listenerSettings->beginGroup("listener"); 17 AppDataHandler = new HttpRequestHandler(this); 18 AppDataListener = new HttpListener(listenerSettings, AppDataHandler, this); 19 }
1 void HttpRequestHandler::service(HttpRequest& request, HttpResponse& response) 2 { 3 if (request.getMethod() == "GET")//APP数据请求 4 { 5 6 //返回 7 response.setStatus(200, "OK"); 8 response.setHeader("Content-Type", "application/json"); 9 response.write("", true); 10 } 11 else 12 { 13 QByteArray name = request.getParameter("file.name"); 14 QByteArray path = request.getParameter("file.path"); 15 16 17 int index = path.lastIndexOf("/"); 18 if (index != -1) 19 { 20 QString fileName = path.left(index + 1) + name; 21 QFileInfo fileInfo(fileName); 22 if (fileInfo.isFile()) 23 { 24 QFile::remove(fileName); 25 } 26 if (!QFile::rename(path, fileName)) 27 { 28 //失败 29 } 30 } 31 32 33 response.setStatus(200, "OK"); 34 response.setHeader("Content-Type", "application/json"); 35 response.write("", true); 36 } 37 }
2.模板
配置文件webapp1.ini
1 [templates] 2 path=../docroot 3 suffix=.html 4 encoding=UTF-8 5 cacheSize=1000000 6 cacheTime=60000
- path 还是相对于配置文件的文件夹。这是我们用来存储模板文件(不完整的HTML文件,包含可变内容的占位符)的文件夹。
- suffix 是后缀,将被添加到模板名称后面。如果加载模板"wolfi",那么模板引擎将会加载文件 “wolfi.html”。你可以使用任何后缀,它对程序没有任何意义。有些人喜欢使用“ .dhtml”来区分静态和动态HTML文件。因此,它是可配置的。
- encoding 参数是必需的,因为模板文件会被读入QString对象里。我更喜欢UTF-8,因为它支持任何语言的所有字符。我还使用具有UTF-8功能的文本编辑器来编辑它们(Linux下的gedit或Windows下的Notepad ++)。
- 为了提高性能,服务器缓存了QString对象。 CacheSize 指定缓存可能占用的最大内存量。
- cacheTime 指定文件在内存中最多保留多长时间。我们已经为静态文件控制器设置了相同的设置。
我们需要一个 TemplateCache 实例的全局指针,使整个程序都可以访问它。
首先添加到global.h:
1 #ifndef GLOBAL_H 2 #define GLOBAL_H 3 4 #include "httpsessionstore.h" 5 #include "staticfilecontroller.h" 6 #include "templatecache.h" 7 8 using namespace stefanfrings; 9 10 extern HttpSessionStore* sessionStore; 11 extern StaticFileController* staticFileController; 12 extern TemplateCache* templateCache; 13 14 #endif // GLOBAL_H
global.cpp:
1 #include "global.h" 2 3 HttpSessionStore* sessionStore; 4 StaticFileController* staticFileController; 5 TemplateCache* templateCache;
在main.cpp中,我们配置了 TemplateCache:
1 int main(int argc, char *argv[]) 2 { 3 QCoreApplication app(argc, argv); 4 QString configFileName=searchConfigFile(); 5 6 // Session store 7 QSettings* sessionSettings=new QSettings(configFileName,QSettings::IniFormat,&app); 8 sessionSettings->beginGroup("sessions"); 9 sessionStore=new HttpSessionStore(sessionSettings,&app); 10 11 // Static file controller 12 QSettings* fileSettings=new QSettings(configFileName,QSettings::IniFormat,&app); 13 fileSettings->beginGroup("files"); 14 staticFileController=new StaticFileController(fileSettings,&app); 15 16 // Configure template cache 17 QSettings* templateSettings=new QSettings(configFileName,QSettings::IniFormat,&app); 18 templateSettings->beginGroup("templates"); 19 templateCache=new TemplateCache(templateSettings,&app); 20 21 // HTTP server 22 QSettings* listenerSettings=new QSettings(configFileName,QSettings::IniFormat,&app); 23 listenerSettings->beginGroup("listener"); 24 new HttpListener(listenerSettings,new RequestMapper(&app),&app); 25 26 return app.exec(); 27 }
创建一个新类 DataTemplateController,它继承自 HttpRequestHandler。我们将其绑定到路径“/list2”。
datatemplatecontroller.h:
1 #ifndef DATATEMPLATECONTROLLER_H 2 #define DATATEMPLATECONTROLLER_H 3 4 #include "httprequesthandler.h" 5 6 using namespace stefanfrings; 7 8 class DataTemplateController: public HttpRequestHandler { 9 Q_OBJECT 10 public: 11 DataTemplateController(QObject* parent=0); 12 void service(HttpRequest& request, HttpResponse& response); 13 private: 14 QList<QString> list; 15 }; 16 17 #endif // DATATEMPLATECONTROLLER_H
datatemplatecontroller.cpp:
1 #include "datatemplatecontroller.h" 2 #include "template.h" 3 #include "global.h" 4 5 DataTemplateController::DataTemplateController(QObject* parent) 6 : HttpRequestHandler(parent) { 7 list.append("Robert"); 8 list.append("Lisa"); 9 list.append("Hannah"); 10 list.append("Ludwig"); 11 list.append("Miranda"); 12 list.append("Fracesco"); 13 list.append("Kim"); 14 list.append("Jacko"); 15 } 16 17 void DataTemplateController::service(HttpRequest &request, HttpResponse &response) { 18 QByteArray language=request.getHeader("Accept-Language"); 19 response.setHeader("Content-Type", "text/html; charset=UTF-8"); 20 21 Template t=templateCache->getTemplate("files/hello",language); 22 response.write(t.toUtf8(),true); 23 }
requestmapper.h:
1 #ifndef REQUESTMAPPER_H 2 #define REQUESTMAPPER_H 3 4 ... 5 #include "datatemplatecontroller.h" 6 7 using namespace stefanfrings; 8 9 class RequestMapper : public HttpRequestHandler { 10 Q_OBJECT 11 public: 12 ... 13 private: 14 ... 15 DataTemplateController dataTemplateController; 16 }; 17 18 #endif // REQUESTMAPPER_H
requestmapper.cpp:
1 ... 2 void RequestMapper::service(HttpRequest& request, HttpResponse& response) { 3 QByteArray path=request.getPath(); 4 ... 5 else if (path=="/list2") { 6 dataTemplateController.service(request, response); 7 } 8 else if (path.startsWith("/files")) { 9 staticFileController->service(request,response); 10 } 11 ... 12 13 qDebug("RequestMapper: finished request"); 14 }
修改模板
- 变量
html
1 <html> 2 <body> 3 ... 4 <p> 5 List of names: 6 <table> 7 {loop row} 8 <tr> 9 <td>{row.number}</td> 10 <td>{row.name}</td> 11 </tr> 12 {end row} 13 </table> 14 </body> 15 </html>
datatemplatecontroller.cpp
1 void DataTemplateController::service(HttpRequest &request, HttpResponse &response) { 2 HttpSession session=sessionStore->getSession(request,response,true); 3 QString username=session.get("username").toString(); 4 QByteArray language=request.getHeader("Accept-Language"); 5 qDebug("language=%s",qPrintable(language)); 6 7 response.setHeader("Content-Type", "text/html; charset=UTF-8"); 8 9 Template t=templateCache->getTemplate("listdata",language); 10 t.setVariable("name",username.toString()); 11 response.write(t.toUtf8(),true); 12 }
占位符 {name} 被替换为值 “test”
-
条件语句
html
1 <html> 2 <body> 3 {if logged-in} 4 Hello {name} 5 {else logged-in} 6 You are not logged in. 7 <br> 8 Go to the <a href="/login">login</a> page and then try again. 9 {end logged-in} 10 </body> 11 </html>
datatemplatecontroller.cpp
1 void DataTemplateController::service(HttpRequest &request, HttpResponse &response) { 2 HttpSession session=sessionStore->getSession(request,response,true); 3 QString username=session.get("username").toString(); 4 QByteArray language=request.getHeader("Accept-Language"); 5 qDebug("language=%s",qPrintable(language)); 6 7 response.setHeader("Content-Type", "text/html; charset=UTF-8"); 8 9 Template t=templateCache->getTemplate("listdata",language); 10 t.setVariable("name",username); 11 t.setCondition("logged-in",!username.isEmpty()); 12 response.write(t.toUtf8(),true); 13 }
设置条件"logged-in"
判断结果
-
循环
html
1 <html> 2 <body> 3 ... 4 <p> 5 List of names: 6 <table> 7 {loop row} 8 <tr> 9 <td>{row.number}</td> 10 <td>{row.name}</td> 11 </tr> 12 {end row} 13 </table> 14 </body> 15 </html>
datatemplatecontroller.cpp
1 void DataTemplateController::service(HttpRequest &request, HttpResponse &response) { 2 HttpSession session=sessionStore->getSession(request,response,false); 3 QString username=session.get("username").toString(); 4 QByteArray language=request.getHeader("Accept-Language"); 5 qDebug("language=%s",qPrintable(language)); 6 7 response.setHeader("Content-Type", "text/html; charset=UTF-8"); 8 9 Template t=templateCache->getTemplate("listdata",language); 10 t.setVariable("name",username); 11 t.setCondition("logged-in",!username.isEmpty()); 12 t.loop("row",list.size()); 13 for(int i=0; i<list.size(); i++) { 14 QString number=QString::number(i); 15 QString name=list.at(i); 16 t.setVariable("row"+number+".number",number); 17 t.setVariable("row"+number+".name",name); 18 } 19 response.write(t.toUtf8(),true); 20 }
2.日志
ini配置
1 [logging] 2 minLevel=2 3 bufferSize=100 4 fileName=../logs/webapp1.log 5 maxSize=1000000 6 maxBackups=2 7 timestampFormat=dd.MM.yyyy hh:mm:ss.zzz 8 msgFormat={timestamp} {typeNr} {type} {thread} {msg} 9 ;type的取值有: 0=DEBUG, 1=WARNING, 2=CRITICAL, 3=FATAL, 4=INFO
- 你可以通过设置 bufferSize = 0 来禁用缓冲。在这种情况下,只有在设置的 minLevel 及以上的版本才会被写入日志文件。
- 文件名相对于配置文件所在的文件夹。
- maxSize 参数限制日志文件的大小(以字节为单位)。超过此限制时,记录器将开始创建新文件。
- maxBackups 指定在磁盘上应保留多少个旧日志文件。
- timestampFormat 设置了时间戳的格式。
- msgFormat 设置每个消息的格式。以下字段可用:
{timestamp} 创建日期和时间 {typeNr} 消息的类型或级别,数字格式(0-4) {type} 消息格式的消息类型或级别(DEBUG, WARNING, CRITICAL, FATAL, INFO) {thread} 线程的ID号 {msg} 消息文字 {xxx} 自定义的任何记录器变量 QT 5.0和更高版本在调试模式下还有一些其他变量: {file} 生成消息的源代码文件名 {function} 生成消息的功能 {line} 生成消息的行号
我们需要一个 FileLogger 实例的全局指针,使整个程序都可以访问它。首先添加到global.h:
1 #include "httpsessionstore.h" 2 #include "staticfilecontroller.h" 3 #include "templatecache.h" 4 #include "filelogger.h" 5 6 using namespace stefanfrings; 7 8 /** Storage for session cookies */ 9 extern HttpSessionStore* sessionStore; 10 11 /** Controller for static files */ 12 extern StaticFileController* staticFileController; 13 14 /** Cache for template files */ 15 extern TemplateCache* templateCache; 16 17 /** Redirects log messages to a file */ 18 extern FileLogger* logger; 19 20 #endif // GLOBAL_H
global.cpp:
1 #include "global.h" 2 3 HttpSessionStore* sessionStore; 4 StaticFileController* staticFileController; 5 TemplateCache* templateCache; 6 FileLogger* logger;
main.cpp
1 int main(int argc, char *argv[]) 2 { 3 QCoreApplication app(argc, argv); 4 QString configFileName=searchConfigFile(); 5 6 // Configure logging 7 QSettings* logSettings=new QSettings(configFileName,QSettings::IniFormat,&app); 8 logSettings->beginGroup("logging"); 9 logger=new FileLogger(logSettings,10000,&app); 10 logger->installMsgHandler(); 11 12 // Log the library version 13 qDebug("QtWebApp has version %s",getQtWebAppLibVersion()); 14 15 // Session store 16 QSettings* sessionSettings=new QSettings(configFileName,QSettings::IniFormat,&app); 17 sessionSettings->beginGroup("sessions"); 18 sessionStore=new HttpSessionStore(sessionSettings,&app); 19 20 // Static file controller 21 QSettings* fileSettings=new QSettings(configFileName,QSettings::IniFormat,&app); 22 fileSettings->beginGroup("files"); 23 staticFileController=new StaticFileController(fileSettings,&app); 24 25 // Configure template cache 26 QSettings* templateSettings=new QSettings(configFileName,QSettings::IniFormat,&app); 27 templateSettings->beginGroup("templates"); 28 templateCache=new TemplateCache(templateSettings,&app); 29 30 // HTTP server 31 QSettings* listenerSettings=new QSettings(configFileName,QSettings::IniFormat,&app); 32 listenerSettings->beginGroup("listener"); 33 new HttpListener(listenerSettings,new RequestMapper(&app),&app); 34 35 return app.exec(); 36 }
天道酬勤 循序渐进 技压群雄