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 }

 

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。