QT implementation of MVC API controller development web API interface serial [5] – enterprise system development real combat serial series technology stack (Vue, element UI, QT, C + +, SQLite)

Time:2021-3-2

Background of the author:

I work in a foreign-funded IT enterprise as the product development manager of e-commerce order processing. I have led the development of many large and small projects, and I am very familiar with the order processing process of e-commerce platform.

The company focuses on the software development and service of shoes and clothing industry, with more than 100 employees. It has branches in Taipei, Guangzhou, Chengdu, Shanghai, Beijing and other countries.

Why write this series?

I have been working in school for more than ten years, using. Net # C # development language, combined with the actual development of the company and the market demand, the shortcomings of the commercial enterprise system developed by net are as follows:

1. The first load of the program is slow because of the compilation of the virtual machine.

2. WinForm interface development is not dazzling and exquisite.

3. WinForm interface designers are hard to find.

4. The program can be decompiled.

5. The installation package is too large, the deployment is troublesome, and the framework

6. Cross platform is not good enough.

Conclusion

Combined with the trend of front-end design in recent years, the final choice is QT + Vue + element UI + SQLite (the database is selected according to the needs)

QT is responsible for interface and hardware processing

SQLite for data storage

Vue + element UI implements the front end.

Results Preview

 

QT implementation of MVC API controller development web API interface serial [5] – enterprise system development real combat serial series technology stack (Vue, element UI, QT, C + +, SQLite)

 

 

Using Microsoftmvc All the students know how to write oneweb api Is very convenient, this article through the use ofqt realization Controller andaction developmentweb api

 

MVC The structure diagram is as follows:

 

 

 

 

downloadQtwebapp (download at the end of this article), integrated into the project, this library is mainly to implementhttp Agreement, and QT Web ApiLibrary support.

 

For stand-alone version, no user installation is requirediis or tomcatTo simplify the difficulty of deployment.

 

 

 

QtWebAppThe directory structure is as follows:

 

 

 

holdQtWebAppUnzip and putBitPos(the project created in the previous chapter) directory.

 

The results are as follows

 

 

 

Open the solution created in the previous section:BitPos

 

In solution explorer, right click Add existing project , as follows:

 

 

 

holdBitPos.vcxproj  Add current project

 

 

 

As shown in the figure below:

 

 

 

choiceQtWebApp , right click “properties

 

 

 

Modify in general optionssdk Version, platform, toolset, configuration type, output as static library, as follows:

 

 

stayqt project settings Option, modify qt installation byWe configured it in the previous sectionqtVersion, as follows:

 

 

 

Compile the source code, which can be successfully compiled at one time, as shown in the following figure:

 

 

 

clickBitPosProject, right click “add” reference

 

 

 

byBitPosadd to Include the directory, because it will be used laterQtWebAppThe header file of.

 

choiceBitPos 》Attributesvc++Catalog contains catalog inputQtWebApp As shown in the figure below:

 

 

 

 

modifyBitPosThe runtime is a static link.

 

 

 

 

Follow the steps above to modify this2The configuration of items isrelease Mode, repeat the operation. otherwisereleaseCompilation will report an error.

 

Next, show how to add an interface for password verification when users log in.

 

This interface has2The parameters areuser_code ,password

 

Return tojson ,The user code and user name are returned , respectivelyuser_code,user_name

 

The request description is as follows:

 

 

 

 

Next, do the operation: addAPI controller And login interfaceLoginHow to do it

 

newly added src Directory, and then create it under the directory controller

 

As shown in the figure below:

 

 

 

 

Selectcontroller Right click to addAdd qt class

 

Enter class name:ApiController

 

As shown in the figure below:

 

 

 

 

 

spotadd As shown in the figure below:

 

 

 

 

clicknext: as shown in the figure below

 

 

 

 

holdBase class Amend to readHttpRequestHandler

 

 

 

Finally, post this2The source codes of these classes are as follows:

 

ApiController.hThe code is as follows:

 

QT implementation of MVC API controller development web API interface serial [5] - enterprise system development real combat serial series technology stack (Vue, element UI, QT, C + +, SQLite)QT implementation of MVC API controller development web API interface serial [5] - enterprise system development real combat serial series technology stack (Vue, element UI, QT, C + +, SQLite)

1 #pragma once
 2 // solve the problem of garbled Chinese.
 3 #pragma execution_character_set("utf-8")
 4 #include 
 5 
 6 using namespace stefanfrings;
 7 
 8 // controller http://localhost :5050/vue-element-admin/api
 9 class ApiController :
10     public HttpRequestHandler
11 {
12 
13     Q_OBJECT 
14 public:
15     Q_INVOKABLE ApiController(const ApiController & v)
16     {
17         *this = v;
18     }
19     Q_INVOKABLE ApiController &operator=(const ApiController &v)
20     {
21                 return *this;  
22     }
23      
24     Q_INVOKABLE ApiController()
25     {
26 
27     }
28 
29 // action login interface. http://localhost :5050/vue-element-admin/api/login
30     Q_INVOKABLE  void Login(HttpRequest & request, HttpResponse & response);
31  
32     Q_INVOKABLE void  ApiResult(const QString& msg, int code,HttpRequest & request, HttpResponse & response);
33     /** Generates the response */
34     Q_INVOKABLE void service(HttpRequest& request, HttpResponse& response);
35 
36     void Result(QString msg, int code, HttpResponse & response);
37 
38     ~ApiController();
39 };

View Code

 

 

ApiController.cppThe code is as follows:

QT implementation of MVC API controller development web API interface serial [5] - enterprise system development real combat serial series technology stack (Vue, element UI, QT, C + +, SQLite)QT implementation of MVC API controller development web API interface serial [5] - enterprise system development real combat serial series technology stack (Vue, element UI, QT, C + +, SQLite)

1 #include "ApiController.h"
 2 #include 
 3 #include 
 4 #include 
 5 #include 
 6 
 7  
 8  
 9 
10 
11  
12 
13 Q_INVOKABLE void ApiController::Login(HttpRequest & request, HttpResponse & response)
14 {
15     //request.
16 
17 // get the form of the post request.
18     QMultiMap forms = request.getParameterMap();
19 // get the user in the form submitted by the user_ code 
20     auto usercode = forms.value("user_code").trimmed();
21     if (usercode.isEmpty())
22     {
23 result ("user code cannot be empty! ", 1, response);
24         return;
25     }
26 // get the password in the form submitted by the user 
27     auto password = forms.value("password").trimmed();
28     if (password.isEmpty())
29     {
30 result ("password cannot be empty! ", 1, response);
31         return;
32     }
33 // second judgment
34     QByteArray hash = QCryptographicHash::hash(password, QCryptographicHash::Algorithm::Sha256).toBase64();
35 
36 // verify the user code and password.
37 
38     QJsonObject object
39     {
40         {"code", 0},
41         {"msg", QJsonValue::Null}
42     };
43     QJsonObject user
44     {
45         {"user_code", "admin"},
46         {"user_name", "admin"}
47     };
48     object.insert("user", user);
49 
50     QJsonDocument usermodel(object);
51 
52 // user information is returned.
53     QByteArray body = usermodel.toJson(QJsonDocument::JsonFormat::Indented);
54 
55     response.write(body, true);
56 }
57 
58 
59 Q_INVOKABLE void ApiController::service(HttpRequest & request, HttpResponse & response)
60 { 
61      
62 }
63 
64 void ApiController::Result(QString msg, int code, HttpResponse & response)
65 {
66     QJsonObject object
67     {
68         {"code", code},
69         {"msg", QJsonValue(msg)}
70     };
71   
72 
73     QJsonDocument usermodel(object);
74 
75     QByteArray body = usermodel.toJson(QJsonDocument::JsonFormat::Indented);
76 
77     response.write(body, true);
78 }
79 
80 Q_INVOKABLE void ApiController::ApiResult(const QString& msg,int code,HttpRequest & request, HttpResponse & response)
81 { 
82     Result(msg, code, response);
83 }
84 
85 
86 
87 ApiController::~ApiController()
88 {
89 }

View Code

These twoThe code of each file belongs to the business code, which is relatively simple. It realizes the verification of user login, user name and password,There are notes on it, so we won’t focus on it here.

 

Add general controller processing class requestmapper.cpp, which is not business related.

The main function is to receive the request, find the controller and interface method, and forward the request

QT implementation of MVC API controller development web API interface serial [5] - enterprise system development real combat serial series technology stack (Vue, element UI, QT, C + +, SQLite)QT implementation of MVC API controller development web API interface serial [5] - enterprise system development real combat serial series technology stack (Vue, element UI, QT, C + +, SQLite)

1 /**
  2   @file
  3   @author Stefan Frings
  4 */
  5 
  6 #include 
  7 #include "requestmapper.h"
  8 #include "controller/ApiController.h"
  9 #include 
 10 
 11 // static variables
 12 QMultiMap RequestMapper :: Area;
 13 template 
 14 int RegisterController(const char *typeName,const QString& area)
 15 { 
 16     QByteArray tmp=typeName;  
 17     tmp = tmp.toLower();
 18     auto type= tmp.constData();
 19      
 20     int v=qRegisterMetaType(type);
 21     if (!area.isEmpty())
 22     {
 23         RequestMapper::RegisterArea(area, type);
 24     }
 25     return v;
 26 }
 27 template 
 28 int RegisterController(const QString& area)
 29 {
 30     return RegisterController(T::staticMetaObject.className(), area); 
 31 }
 32 RequestMapper::RequestMapper(QObject* parent)
 33     :HttpRequestHandler(parent)
 34 {
 35     qDebug("RequestMapper: created");
 36 // register the API controller in Vue element admin domain. The access format is:
 37     // http://localhost : 5050 / {domain} / {controller}
 38 // for example http://localhost :5050/vue-element-admin/api
 39     RegisterController("apicontroller", "vue-element-admin"); 
 40 }
 41 
 42 
 43 RequestMapper::~RequestMapper()
 44 {
 45     qDebug("RequestMapper: deleted");
 46 }
 47 
 48  void RequestMapper::RegisterArea(const QString &area, const QString& classname)
 49 {
 50     Area.insertMulti(area, classname);
 51 }
 52 
 53 // find the controller and call the interface method.
 54 void RequestMapper::service(HttpRequest& request, HttpResponse& response)
 55 {
 56     QByteArray path=request.getPath().toLower();
 57     qDebug("RequestMapper: path=%s",path.data());
 58     fprintf(stderr, "request: %s\n", path.data());
 59 // cross domain access is realized. JS calls API to provide support.
 60     response.setHeader("Connection", "keep-alive");
 61     auto origin = request.getHeader("Origin");
 62     response.setHeader("Access-Control-Allow-Origin", origin);
 63     response.setHeader("Access-Control-Allow-Methods", "POST,GET,OPTIONS");
 64     response.setHeader("Access-Control-Allow-Headers", "X-PINGOTHER,Content-Type,x-token");
 65     response.setHeader("Access-Control-Max-Age", "86400");
 66     response.setHeader("Vary", "Accept-Encoding,Origin");
 67     response.setHeader("Keep-Alive", "timeout=2,max=99");
 68     //set api header 
 69     response.setHeader("Content-Type", "application/json; charset=utf-8");
 70     //response.setHeader("Access-Control-Allow-Origin", "*");   // also important , if not set , the html application wont run.
 71     if (request.getMethod() == "OPTIONS")
 72     {
 73         response.setStatus(200,"OK"); 
 74         qDebug("RequestMapper: finished request"); 
 75         // Clear the log buffer
 76      
 77         return;
 78     }
 79     else
 80     {
 81 
 82     }
 83 
 84     // For the following pathes, each request gets its own new instance of the related controller. 
 85         QByteArrayList items = path.split('/');
 86         QByteArray areaname;
 87         QByteArray controlname;
 88         QByteArray actionname;
 89         QByteArray a, b, c;
 90 
 91         for (int i = 0; i < items.length(); i++)
 92         {
 93             QByteArray first = items[i];
 94             if (first.isEmpty())
 95                 continue;
 96             else
 97             {
 98                 //get control and action of name.
 99                 a = first;
100                 if(i+1 controls;
109 // determine whether it is a route.
110         if (Area.contains(a))
111         {
112             areaname = a;
113             controlname = b;
114             actionname = c;
115             controls=Area.values(a);
116         }
117         else
118         {
119             controlname = a;
120             actionname = b;
121         }
122 
123         QString className = (controlname + "Controller").toLower();
124         
125         int id = QMetaType::type(className.toLatin1());
126         HttpRequestHandler* result = NULL;
127 // judge area
128         if (id != QMetaType::UnknownType)
129         { 
130             if (controls.count() > 0 && !controls.contains(className))
131             {
132                  
133                 qDebug("RequestMapper: finished request"); 
134                  
135                 return;
136             }
137         }
138 
139         if (id != QMetaType::UnknownType)
140         {
141             result = static_cast(QMetaType::create(id));
142             const QMetaObject * theMetaObject = result->metaObject(); 
143             int nMetathodCount = theMetaObject->methodCount();
144             QByteArray method;
145 // search method
146             for (int nMetathodIndex = 0; nMetathodIndex < nMetathodCount; nMetathodIndex++)
147             {
148                 QByteArray oneMethod = theMetaObject->method(nMetathodIndex).name(); 
149                 if (actionname.compare(oneMethod, Qt::CaseSensitivity::CaseInsensitive)==0)
150                 { 
151                     method = oneMethod;
152                     break;
153                 } 
154             }
155             if (!method.isEmpty())
156             {
157                 auto token=request.getHeader("X - Token");
158 // determine whether the token is available.
159                 auto v = QMetaObject::invokeMethod(result, method.data(), Qt::DirectConnection,
160                     Q_ARG(HttpRequest &, request),
161                     Q_ARG(HttpResponse &, response));
162                 if (!v)
163                     qDebug() << method.data()<

View Code

Special note: when a new controller is added, you only need to requestmapper.cpp

File registration controller.

On bitposProjects main.cppThe source code is modified as follows:

QT implementation of MVC API controller development web API interface serial [5] - enterprise system development real combat serial series technology stack (Vue, element UI, QT, C + +, SQLite)QT implementation of MVC API controller development web API interface serial [5] - enterprise system development real combat serial series technology stack (Vue, element UI, QT, C + +, SQLite)

1 #include "BitPos.h"
 2 #include 
 3 #include 
 4 #include 
 5 #include 
 6 #include 
 7 #include "src/requestmapper.h"
 8 using namespace stefanfrings;
 9 
10 /** Search the configuration file */
11 QString searchConfigFile()
12 {
13     QString binDir = QCoreApplication::applicationDirPath();
14     QString appName = QCoreApplication::applicationName();
15     QString fileName(appName + ".ini");
16 
17     QStringList searchList;
18     searchList.append(binDir);
19     searchList.append(binDir + "/etc");
20     searchList.append(binDir + "/../etc");
21     searchList.append(binDir + "/../../etc"); // for development without shadow build
22     searchList.append(binDir + "/../" + appName + "/etc"); // for development with shadow build
23     searchList.append(binDir + "/../../" + appName + "/etc"); // for development with shadow build
24     searchList.append(binDir + "/../../../" + appName + "/etc"); // for development with shadow build
25     searchList.append(binDir + "/../../../../" + appName + "/etc"); // for development with shadow build
26     searchList.append(binDir + "/../../../../../" + appName + "/etc"); // for development with shadow build
27     searchList.append(QDir::rootPath() + "etc/opt");
28     searchList.append(QDir::rootPath() + "etc");
29 
30     foreach(QString dir, searchList)
31     {
32         QFile file(dir + "/" + fileName);
33         if (file.exists())
34         {
35             // found
36             fileName = QDir(file.fileName()).canonicalPath();
37             qDebug("Using config file %s", qPrintable(fileName));
38             return fileName;
39         }
40     }
41 
42     // not found
43     foreach(QString dir, searchList)
44     {
45         qWarning("%s/%s not found", qPrintable(dir), qPrintable(fileName));
46     }
47     qFatal("Cannot find config file %s", qPrintable(fileName));
48 }
49 
50 int main(int argc, char* argv[])
51 {
52     QApplication a(argc, argv); 
53     // Find the configuration file
54     QString configFileName = searchConfigFile();
55      
56     // Configure and start the TCP listener
57     QSettings* listenerSettings = new QSettings(configFileName, QSettings::IniFormat, &a);
58     listenerSettings->beginGroup("listener");
59     new HttpListener(listenerSettings, new RequestMapper(&a), &a); 
60 // browser
61     QWebEngineView view;
62 // set access address
63     view.setUrl(QUrl("http://localhost:5050/vue-element-admin/api/Login?user_code=333&password=3445"));
64 // the browser window is displayed.
65     view.show(); 
66     return a.exec();
67 }

View Code

The file directory is as follows:

Press F5After running, you can see the interface return (you can also use the browser to see the interface return), as shown in the following figure:

 

 

If you add more module interfaces later, you just need to add the controller according to the template and add the method in the controller according to the operation.

 

So far, QTAfter the demonstration of interface development, the next section explains how to use postmanDebug the interface.

The following article is mainly related to technology, ask for source code, technical communication, compile error, please add QQGroup 561506606There is no need to verify the clustering.

Click the link to join the group chat】:https://jq.qq.com/?_wv=1027&k=CCmkgYYu