1119 lines
96 KiB
HTML
1119 lines
96 KiB
HTML
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||
<html>
|
||
|
||
<head>
|
||
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
|
||
<title>QxOrm : C++ Qt ORM Object Relational Mapping database library - QxEntityEditor : C++ Qt entities graphic
|
||
editor (data model designer and source code generator)</title>
|
||
<link rel='stylesheet' type='text/css' href='./resource/qxorm_style.css'>
|
||
<script type="text/javascript" src="./resource/jquery.min.js"></script>
|
||
<script type="text/javascript" src="./resource/qxorm_script.js"></script>
|
||
</head>
|
||
|
||
<body>
|
||
<table border="0" style="width: 80%" align="center">
|
||
<col>
|
||
<col>
|
||
<col>
|
||
<col>
|
||
<col>
|
||
<tbody>
|
||
<tr>
|
||
<td><a href="./home.html"><img alt="QxOrm" src="./resource/logo_qxorm_and_qxee.png" align="left"
|
||
border="0"></a></td>
|
||
<td align="right" style="vertical-align:bottom">
|
||
<div id="qx_search">
|
||
<gcse:search></gcse:search>
|
||
</div>
|
||
</td>
|
||
<td width="15"></td>
|
||
<td align="right" style="vertical-align:bottom">
|
||
<img alt="Windows" src="./resource/logo_windows.gif" width="35" height="35">
|
||
<img alt="Linux" src="./resource/logo_linux.gif" width="35" height="35">
|
||
<img alt="Macintosh" src="./resource/logo_mac.gif" width="35" height="35">
|
||
</td>
|
||
<td width="70"><img alt="C++" src="./resource/logo_cpp.gif" width="50" height="50" align="right"></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<hr style="width: 80%" align="center" size="1" color="#100D5A">
|
||
<table border="0" style="width: 80%" align="center">
|
||
<col>
|
||
<col>
|
||
<col>
|
||
<col>
|
||
<col>
|
||
<col>
|
||
<tbody>
|
||
<tr>
|
||
<td align="center"><a href="./home.html" class="btn_nav">Accueil</a></td>
|
||
<td align="center"><a href="./download.html" class="btn_nav">T<EFBFBD>l<EFBFBD>chargement</a></td>
|
||
<td align="center"><a href="./quick_sample.html" class="btn_nav">Exemple rapide</a></td>
|
||
<td align="center" onmouseover="showHideElementById('menu_tuto', true);"
|
||
onmouseout="showHideElementById('menu_tuto', false);">
|
||
<a href="./tutorial.html" class="btn_nav">Tutoriel (4)</a>
|
||
<table class="table_menu_tuto">
|
||
<tbody>
|
||
<tr>
|
||
<td>
|
||
<div id="menu_tuto" class="div_menu_tuto">
|
||
<a href="./tutorial_3.html" class="btn_sub_menu">install QxOrm</a><br />
|
||
<a href="./tutorial.html" class="btn_sub_menu">qxBlog</a><br />
|
||
<a href="./tutorial_2.html" class="btn_sub_menu">qxClientServer</a><br />
|
||
<a href="./tutorial_4.html" class="btn_sub_menu">QxEntityEditor videos</a>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</td>
|
||
<td align="center" onmouseover="showHideElementById('menu_manual', true);"
|
||
onmouseout="showHideElementById('menu_manual', false);">
|
||
<a href="./manual.html" class="btn_nav">Manuel (2)</a>
|
||
<table class="table_menu_manual">
|
||
<tbody>
|
||
<tr>
|
||
<td>
|
||
<div id="menu_manual" class="div_menu_manual">
|
||
<a href="./manual.html" class="btn_sub_menu">Manuel QxOrm</a><br />
|
||
<a href="./manual_qxee.html" class="btn_sub_menu">Manuel QxEntityEditor</a><br />
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</td>
|
||
<td align="center"><a href="./link.html" class="btn_nav">Forum</a></td>
|
||
<td align="center"><a href="./customer.html" class="btn_nav">Nos clients</a></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<hr style="width: 80%" align="center" size="1" color="#100D5A">
|
||
<table border="0" style="width: 80%" align="center">
|
||
<col>
|
||
<col>
|
||
<col>
|
||
<col>
|
||
<col>
|
||
<col>
|
||
<tbody>
|
||
<tr>
|
||
<td align="left" valign="top">
|
||
<font size="2" class="txt_with_shadow">QxOrm >> Tutoriel >> qxClientServer</font>
|
||
</td>
|
||
<td align="right" valign="top">
|
||
<table cellspacing="0" cellpadding="1">
|
||
<col>
|
||
<col>
|
||
<tbody>
|
||
<tr>
|
||
<td align="right" valign="top">
|
||
<font size="2" class="txt_with_shadow">Version courante : </font>
|
||
</td>
|
||
<td align="left" valign="top">
|
||
<font size="2" class="txt_with_shadow">QxOrm 1.5.0 - <a href="../doxygen/index.html"
|
||
target="_blank">documentation en ligne de la biblioth<74>que QxOrm</a> - <a
|
||
href="https://github.com/QxOrm/QxOrm" target="_blank">GitHub</a></font>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td align="right" valign="top">
|
||
<font size="2" class="txt_with_shadow"></font>
|
||
</td>
|
||
<td align="left" valign="top">
|
||
<font size="2" class="txt_with_shadow">QxEntityEditor 1.2.8</font>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</td>
|
||
<td width="10px"></td>
|
||
<td width="40px" height="30px"><a href="../qxorm_fr/tutorial_2.html"><img alt="Version fran<61>aise du site"
|
||
src="./resource/FR.png" width="40" height="30" border="0"></a></td>
|
||
<td width="40px" height="30px"><a href="../qxorm_en/tutorial_2.html"><img alt="Web site english version"
|
||
src="./resource/GB.png" width="40" height="30" border="0"></a></td>
|
||
<td width="40px" height="30px"><a href="http://sites.google.com/site/qxormpostgres/" target="_blank"><img
|
||
alt="" src="./resource/ES.png" width="40" height="30" border="0"></a></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<table border="1" frame="vsides" rules="cols" style="width: 80%" align="center" cellpadding="6" bgcolor="#F2F2F4">
|
||
<col>
|
||
<tbody>
|
||
<tr>
|
||
<td align="justify">
|
||
<table border="0" cellpadding="4">
|
||
<col>
|
||
<col>
|
||
<tbody>
|
||
<tr>
|
||
<td>
|
||
<font class="txt_with_shadow" color="#0B0B61" size="4"><i>S<EFBFBD>lection du tutoriel : </i></font>
|
||
</td>
|
||
<td align="left">
|
||
<a href="./tutorial.html" class="btn_tuto">Tuto n<>1 : qxBlog</a>
|
||
<a href="./tutorial_2.html" class="btn_tuto_selected">Tuto n<>2 : qxClientServer</a>
|
||
<a href="./tutorial_3.html" class="btn_tuto">Tuto n<>3 : install QxOrm</a>
|
||
<a href="./tutorial_4.html" class="btn_tuto">Tuto n<>4 : video QxEntityEditor</a>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<hr style="width: 100%" align="center" size="1" color="#100D5A">
|
||
<br>
|
||
<table border="0" style="width: 100%" align="center">
|
||
<col>
|
||
<col>
|
||
<tbody>
|
||
<tr>
|
||
<td>Le tutoriel <b>qxClientServer</b> a pour objectif d'expliquer le fonctionnement du module <a
|
||
href="../doxygen/html/group___qx_service.html" target="_blank"><b>QxService</b></a> de la
|
||
biblioth<74>que <b>QxOrm</b>.<br>
|
||
Le module <b>QxService</b> permet de cr<63>er rapidement un <b>serveur d'applications C++</b>
|
||
performant (notion de <i>services</i> avec <i>demande</i> du client et <i>r<EFBFBD>ponse</i> du
|
||
serveur).<br>
|
||
Les sources du projet <b>qxClientServer</b> sont disponibles dans le dossier
|
||
<i>./test/qxClientServer/</i> de la distribution de <b>QxOrm</b>.<br>
|
||
Il est conseill<6C> d'avoir lu <a href="./tutorial.html">le tutoriel <b>qxBlog</b></a> avant de
|
||
lire cet article, notamment tout ce qui concerne la fonction de mapping de <b>QxOrm</b> :
|
||
<b><i>void qx::register_class<T>(...)</i></b>.<br>
|
||
<br>
|
||
<b>Remarque :</b> pour activer le module <b>QxService</b> (n<>cessaire pour compiler les
|
||
sources de ce tutoriel), il faut d<>finir l'option de compilation <b>_QX_ENABLE_QT_NETWORK</b>
|
||
dans le fichier de configuration <i>QxOrm.pri</i>.
|
||
Pour plus de d<>tails sur ces options de compilation, <a
|
||
href="./manual.html#manual_220">rendez-vous sur le manuel utilisateur de la biblioth<74>que
|
||
QxOrm</a>.
|
||
<br><br>
|
||
Le r<>sultat final de ce tutoriel comporte deux ex<65>cutables et une couche service :
|
||
<ul>
|
||
<li><i>qxServer</i> : serveur d'applications C++ avec une interface utilisateur pour
|
||
param<61>trer le serveur et un champ pour afficher la derni<6E>re transaction effectu<74>e entre
|
||
le client et le serveur ;</li>
|
||
<li><i>qxClient</i> : interface utilisateur contenant plusieurs boutons pour ex<65>cuter
|
||
diff<66>rentes requ<71>tes au serveur ;</li>
|
||
<li><i>qxService</i> : couche service, le serveur et le client partagent cette m<>me couche
|
||
pour transf<73>rer les donn<6E>es et appeler les services.</li>
|
||
</ul>
|
||
Le tutoriel <b>qxClientServer</b> est constitu<74> des <20>tapes suivantes :
|
||
<ul>
|
||
<li><a href="#tuto_10">1- Cr<43>ation de l'interface serveur : <i>qxServer</i></a>
|
||
<ul>
|
||
<li><a href="#tuto_101">1.1- Description du fichier <i>main_dlg.h</i></a></li>
|
||
<li><a href="#tuto_102">1.2- Description du fichier <i>main_dlg.cpp</i>, m<>thode
|
||
<i>init()</i></a></li>
|
||
<li><a href="#tuto_103">1.3- Description du fichier <i>main_dlg.cpp</i>, m<>thode
|
||
<i>loadServices()</i></a></li>
|
||
<li><a href="#tuto_104">1.4- Description du fichier <i>main_dlg.cpp</i>, m<>thode
|
||
<i>onClickStartStop()</i></a></li>
|
||
<li><a href="#tuto_105">1.5- Description du fichier <i>main_dlg.cpp</i>, m<>thodes
|
||
<i>onError()</i> et <i>onTransactionFinished()</i></a></li>
|
||
<li><a href="#tuto_106">1.6- R<>sultat obtenu pour le projet <i>qxServer</i></a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#tuto_20">2- Cr<43>ation de la couche service : <i>qxService</i></a>
|
||
<ul>
|
||
<li><a href="#tuto_201">2.1- Ecriture du premier service : r<>cup<75>rer la date-heure
|
||
courante du serveur</a></li>
|
||
<li><a href="#tuto_202">2.2- Description du fichier <i>server_infos.h</i></a></li>
|
||
<li><a href="#tuto_203">2.3- Description du fichier <i>server_infos.cpp</i></a></li>
|
||
<li><a href="#tuto_204">2.4- Ecriture du second service : op<6F>rations avec une classe
|
||
persistante</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a href="#tuto_30">3- Cr<43>ation de l'interface cliente : <i>qxClient</i></a>
|
||
<ul>
|
||
<li><a href="#tuto_301">3.1- Description de la m<>thode
|
||
<i>onClickBtnDateTime()</i></a></li>
|
||
<li><a href="#tuto_302">3.2- Description de la m<>thode
|
||
<i>onClickBtnDateTimeAsync()</i></a></li>
|
||
<li><a href="#tuto_303">3.3- Description de la m<>thode
|
||
<i>onClickBtnAddUser()</i></a></li>
|
||
<li><a href="#tuto_304">3.4- Description de la m<>thode
|
||
<i>onClickBtnGetAllUsers()</i></a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
<i>Remarque :</i> ce tutoriel est <20>galement disponible sur le site <a
|
||
href="http://marty-lionel.developpez.com/tutoriels/qt/qxorm-tutoriel-qxclientserver/"
|
||
target="_blank">www.developpez.com</a>.<br>
|
||
</td>
|
||
<td width="200" align="center" valign="top"><a href="./resource/qt_ambassador_logo.png"
|
||
target="_blank"><img alt="qt_ambassador" src="./resource/qt_ambassador_logo_150x150.png"
|
||
width="150" height="150" border="0"></a><br>
|
||
<b>
|
||
<font size="2">QxOrm library has been accepted into the <a
|
||
href="http://forum.qt.io/category/24/qt-ambassador-program" target="_blank">Qt
|
||
Ambassador Program</a></font>
|
||
</b>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<br>
|
||
<img alt="gui_qxClientServer" src="./resource/gui_qxClientServer.jpg" width="1056" height="727"
|
||
style="border:0px solid #100D5A; border-color:#100D5A;">
|
||
<br><br>
|
||
<b>Remarque :</b> pour plus de d<>tails sur la notion de socket, de thread et de r<>seau, le site de
|
||
<b>Qt</b> propose des tutoriels sur l'utilisation du module <a
|
||
href="http://doc.qt.io/qt-5/qtnetwork-index.html" target="_blank"><b>QtNetwork</b></a> :
|
||
<ul>
|
||
<li><a href="http://doc.qt.io/qt-5/qtnetwork-fortuneclient-example.html" target="_blank"><i>Fortune
|
||
Client</i></a> ;</li>
|
||
<li><a href="http://doc.qt.io/qt-5/qtnetwork-blockingfortuneclient-example.html"
|
||
target="_blank"><i>Blocking Fortune Client</i></a> ;</li>
|
||
<li><a href="http://doc.qt.io/qt-5/qtnetwork-fortuneserver-example.html" target="_blank"><i>Fortune
|
||
Server</i></a> ;</li>
|
||
<li><a href="http://doc.qt.io/qt-5/qtnetwork-threadedfortuneserver-example.html"
|
||
target="_blank"><i>Threaded Fortune Server</i></a>.</li>
|
||
</ul>
|
||
<br>
|
||
<b><a name="tuto_10"><u>
|
||
<font color="#100D5A">1- Cr<43>ation de l'interface serveur : <i>qxServer</i></font>
|
||
</u></a></b>
|
||
<br><br>
|
||
Le projet <i>qxServer</i> contient une seule fen<65>tre : l'interface utilisateur a <20>t<EFBFBD> r<>alis<69>e avec
|
||
l'outil <b>Qt Designer</b> propos<6F> par la biblioth<74>que Qt.<br>
|
||
Cette interface a pour seul objectif d'afficher <20> l'utilisateur la derni<6E>re transaction client-serveur,
|
||
et de pouvoir configurer certains param<61>tres du serveur.<br>
|
||
Pour une utilisation r<>elle (logiciel de production), il est conseill<6C> de proposer un syt<79>me de
|
||
<i>log</i> plut<75>t qu'un affichage <20> l'utilisateur.<br>
|
||
Une interface la plus minimaliste possible (voire aucune interface) est de mani<6E>re g<>n<EFBFBD>rale la solution
|
||
la plus optimale pour un serveur d'applications.<br>
|
||
Les fichiers <i>main_dlg.h</i> et <i>main_dlg.cpp</i> correspondent au code C++ de l'interface du projet
|
||
<i>qxServer</i>.<br>
|
||
<br>
|
||
<a name="tuto_101"><u>
|
||
<font color="#100D5A">1.1- Description du fichier <i>main_dlg.h</i></font>
|
||
</u></a>
|
||
<br><br>
|
||
<table border="1" bgcolor="#FFFFFF">
|
||
<col>
|
||
<tbody>
|
||
<tr>
|
||
<td title="main_dlg.h">
|
||
<pre><span class="pre">#ifndef _QX_SERVER_MAIN_DLG_H_
|
||
#define _QX_SERVER_MAIN_DLG_H_
|
||
|
||
#include "../qt/ui/include/ui_qxServer.h"
|
||
</span><span class="keyword">
|
||
class</span> main_dlg<span class="operator"> :</span><span class="keyword"> public</span> QWidget<span class="operator">,</span><span class="keyword"> private</span> Ui<span class="operator">::</span>dlgServer<span class="operator">
|
||
{</span> Q_OBJECT<span class="keyword">
|
||
|
||
private</span><span class="operator">:</span>
|
||
|
||
qx<span class="operator">::</span>service<span class="operator">::</span>QxThreadPool_ptr m_pThreadPool<span class="operator">;</span><span class="comment"> // Liste de threads pour recevoir les requ<71>tes des clients
|
||
</span><span class="keyword">
|
||
public</span><span class="operator">:</span>
|
||
|
||
main_dlg<span class="operator">(</span>QWidget<span class="operator"> *</span> parent<span class="operator"> =</span> NULL<span class="operator">) :</span> QWidget<span class="operator">(</span>parent<span class="operator">),</span> Ui<span class="operator">::</span>dlgServer<span class="operator">() {</span> main_dlg<span class="operator">::</span>init<span class="operator">(); }</span><span class="keyword">
|
||
virtual</span><span class="operator"> ~</span>main_dlg<span class="operator">() { ; }</span><span class="keyword">
|
||
|
||
private</span><span class="operator">:</span><span class="type">
|
||
|
||
void</span> init<span class="operator">();</span><span class="type">
|
||
void</span> loadServices<span class="operator">();</span><span class="keyword">
|
||
|
||
private</span> Q_SLOTS<span class="operator">:</span><span class="type">
|
||
|
||
void</span> onClickStartStop<span class="operator">();</span><span class="type">
|
||
void</span> onCboIndexChanged<span class="operator">(</span><span class="type">int</span> index<span class="operator">);</span><span class="type">
|
||
void</span> onError<span class="operator">(</span><span class="keyword">const</span> QString<span class="operator"> &</span> err<span class="operator">,</span> qx<span class="operator">::</span>service<span class="operator">::</span>QxTransaction_ptr transaction<span class="operator">);</span><span class="type">
|
||
void</span> onServerIsRunning<span class="operator">(</span><span class="type">bool</span> bIsRunning<span class="operator">,</span> qx<span class="operator">::</span>service<span class="operator">::</span>QxServer<span class="operator"> *</span> pServer<span class="operator">);</span><span class="type">
|
||
void</span> onTransactionFinished<span class="operator">(</span>qx<span class="operator">::</span>service<span class="operator">::</span>QxTransaction_ptr transaction<span class="operator">);
|
||
|
||
};</span><span class="pre">
|
||
|
||
#endif // _QX_SERVER_MAIN_DLG_H_</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<br>
|
||
La variable <i>m_pThreadPool</i> de type <i>qx::service::QxThreadPool_ptr</i> contient toute la logique
|
||
du serveur d'applications.<br>
|
||
Cette logique est g<>r<EFBFBD>e de mani<6E>re automatique par la biblioth<74>que <b>QxOrm</b>.<br>
|
||
La m<>thode <i>init()</i> permet d'initialiser les param<61>tres par d<>faut du serveur, de connecter les
|
||
<20>v<EFBFBD>nements <b>SIGNAL-SLOT</b> et de lancer automatiquement le serveur.<br>
|
||
Nous allons voir tout ceci plus en d<>tails avec l'impl<70>mentation des m<>thodes dans le fichier
|
||
<i>main_dlg.cpp</i>...<br>
|
||
<br>
|
||
<a name="tuto_102"><u>
|
||
<font color="#100D5A">1.2- Description du fichier <i>main_dlg.cpp</i>, m<>thode <i>init()</i></font>
|
||
</u></a>
|
||
<br><br>
|
||
<table border="1" bgcolor="#FFFFFF">
|
||
<col>
|
||
<tbody>
|
||
<tr>
|
||
<td title="main_dlg::init()">
|
||
<pre><span class="type">void</span> main_dlg<span class="operator">::</span>init<span class="operator">()
|
||
{</span>
|
||
setupUi<span class="operator">(</span><span class="keyword">this</span><span class="operator">);</span>
|
||
|
||
QObject<span class="operator">::</span>connect<span class="operator">(</span>btnStartStop<span class="operator">,</span> SIGNAL<span class="operator">(</span>clicked<span class="operator">()),</span><span class="keyword"> this</span><span class="operator">,</span> SLOT<span class="operator">(</span>onClickStartStop<span class="operator">()));</span>
|
||
QObject<span class="operator">::</span>connect<span class="operator">(</span>cboSerializationType<span class="operator">,</span> SIGNAL<span class="operator">(</span>currentIndexChanged<span class="operator">(</span><span class="type">int</span><span class="operator">)),</span><span class="keyword"> this</span><span class="operator">,</span> SLOT<span class="operator">(</span>onCboIndexChanged<span class="operator">(</span><span class="type">int</span><span class="operator">)));</span>
|
||
|
||
cboSerializationType<span class="operator">-></span>addItem<span class="operator">(</span><span class="string">"0- serialization_binary"</span><span class="operator">,</span> QVariant<span class="operator">((</span><span class="type">int</span><span class="operator">)</span>qx<span class="operator">::</span>service<span class="operator">::</span>QxConnect<span class="operator">::</span>serialization_binary<span class="operator">));</span>
|
||
cboSerializationType<span class="operator">-></span>addItem<span class="operator">(</span><span class="string">"1- serialization_xml"</span><span class="operator">,</span> QVariant<span class="operator">((</span><span class="type">int</span><span class="operator">)</span>qx<span class="operator">::</span>service<span class="operator">::</span>QxConnect<span class="operator">::</span>serialization_xml<span class="operator">));</span>
|
||
cboSerializationType<span class="operator">-></span>addItem<span class="operator">(</span><span class="string">"2- serialization_text"</span><span class="operator">,</span> QVariant<span class="operator">((</span><span class="type">int</span><span class="operator">)</span>qx<span class="operator">::</span>service<span class="operator">::</span>QxConnect<span class="operator">::</span>serialization_text<span class="operator">));</span>
|
||
cboSerializationType<span class="operator">-></span>addItem<span class="operator">(</span><span class="string">"3- serialization_portable_binary"</span><span class="operator">,</span> QVariant<span class="operator">((</span><span class="type">int</span><span class="operator">)</span>qx<span class="operator">::</span>service<span class="operator">::</span>QxConnect<span class="operator">::</span>serialization_portable_binary<span class="operator">));</span>
|
||
cboSerializationType<span class="operator">-></span>addItem<span class="operator">(</span><span class="string">"4- serialization_wide_binary"</span><span class="operator">,</span> QVariant<span class="operator">((</span><span class="type">int</span><span class="operator">)</span>qx<span class="operator">::</span>service<span class="operator">::</span>QxConnect<span class="operator">::</span>serialization_wide_binary<span class="operator">));</span>
|
||
cboSerializationType<span class="operator">-></span>addItem<span class="operator">(</span><span class="string">"5- serialization_wide_xml"</span><span class="operator">,</span> QVariant<span class="operator">((</span><span class="type">int</span><span class="operator">)</span>qx<span class="operator">::</span>service<span class="operator">::</span>QxConnect<span class="operator">::</span>serialization_wide_xml<span class="operator">));</span>
|
||
cboSerializationType<span class="operator">-></span>addItem<span class="operator">(</span><span class="string">"6- serialization_wide_text"</span><span class="operator">,</span> QVariant<span class="operator">((</span><span class="type">int</span><span class="operator">)</span>qx<span class="operator">::</span>service<span class="operator">::</span>QxConnect<span class="operator">::</span>serialization_wide_text<span class="operator">));</span>
|
||
cboSerializationType<span class="operator">-></span>addItem<span class="operator">(</span><span class="string">"7- serialization_polymorphic_binary"</span><span class="operator">,</span> QVariant<span class="operator">((</span><span class="type">int</span><span class="operator">)</span>qx<span class="operator">::</span>service<span class="operator">::</span>QxConnect<span class="operator">::</span>serialization_polymorphic_binary<span class="operator">));</span>
|
||
cboSerializationType<span class="operator">-></span>addItem<span class="operator">(</span><span class="string">"8- serialization_polymorphic_xml"</span><span class="operator">,</span> QVariant<span class="operator">((</span><span class="type">int</span><span class="operator">)</span>qx<span class="operator">::</span>service<span class="operator">::</span>QxConnect<span class="operator">::</span>serialization_polymorphic_xml<span class="operator">));</span>
|
||
cboSerializationType<span class="operator">-></span>addItem<span class="operator">(</span><span class="string">"9- serialization_polymorphic_text"</span><span class="operator">,</span> QVariant<span class="operator">((</span><span class="type">int</span><span class="operator">)</span>qx<span class="operator">::</span>service<span class="operator">::</span>QxConnect<span class="operator">::</span>serialization_polymorphic_text<span class="operator">));</span>
|
||
cboSerializationType<span class="operator">-></span>setCurrentIndex<span class="operator">(</span>cboSerializationType<span class="operator">-></span>findData<span class="operator">(</span>QVariant<span class="operator">((</span><span class="type">int</span><span class="operator">)</span>qx<span class="operator">::</span>service<span class="operator">::</span>QxConnect<span class="operator">::</span>getSingleton<span class="operator">()-></span>getSerializationType<span class="operator">())));</span>
|
||
|
||
spinPortNumber<span class="operator">-></span>setValue<span class="operator">(</span><span class="int">7694</span><span class="operator">);</span>
|
||
spinThreadCount<span class="operator">-></span>setValue<span class="operator">(</span>qx<span class="operator">::</span>service<span class="operator">::</span>QxConnect<span class="operator">::</span>getSingleton<span class="operator">()-></span>getThreadCount<span class="operator">());</span>
|
||
onServerIsRunning<span class="operator">(</span><span class="bool">false</span><span class="operator">,</span> NULL<span class="operator">);</span>
|
||
onClickStartStop<span class="operator">();
|
||
}</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<br>
|
||
L'<27>v<EFBFBD>nement <i>onClickStartStop()</i> permet de d<>marrer/arr<72>ter le serveur.<br>
|
||
Le serveur d'applications peut s<>rialiser les r<>ponses <20> envoyer aux clients de plusieurs fa<66>ons : ce
|
||
param<61>tre est disponible avec la combobox <i>cboSerializationType</i>.<br>
|
||
Pour plus d'informations sur les diff<66>rents types de s<>rialisation support<72>s par la biblioth<74>que QxOrm,
|
||
<a href="../qxorm_fr/manual.html#manual_60">suivre ce lien du manuel utilisateur</a>.<br>
|
||
D'une mani<6E>re g<>n<EFBFBD>rale, la s<>rialisation binaire est fortement conseill<6C>e pour une transaction r<>seau car
|
||
elle est plus rapide <20> ex<65>cuter et permet de limiter le traffic sur le r<>seau.<br>
|
||
On d<>finit <20>galement le port d'<27>coute du serveur d'applications avec le champ <i>spinPortNumber</i>.<br>
|
||
Un param<61>tre important est le <b>nombre de threads</b> disponibles sur le serveur d'applications : cel<65>
|
||
correspond aux <b>nombres de clients pouvant se connecter au serveur simultan<61>ment</b>.<br>
|
||
La valeur par d<>faut de ce param<61>tre est <i>30</i>, vous pouvez modifier cette valeur suivant la charge
|
||
estim<69>e de votre serveur d'applications.<br>
|
||
Si le nombre de clients d<>passe le nombre de threads disponibles, la requ<71>te est mise en attente : d<>s
|
||
qu'un thread se lib<69>re, alors la requ<71>te s'ex<65>cute normalement.<br>
|
||
Tout ceci est g<>r<EFBFBD> automatiquement par la biblioth<74>que <b>QxOrm</b> : il est juste important de faire une
|
||
estimation de la charge que pourra avoir votre serveur d'applications.<br>
|
||
Enfin, l'appel <20> <i>onClickStartStop()</i> permet de d<>marrer automatiquement le serveur d<>s l'ex<65>cution
|
||
du programme <i>qxServer</i>.<br>
|
||
<br>
|
||
<a name="tuto_103"><u>
|
||
<font color="#100D5A">1.3- Description du fichier <i>main_dlg.cpp</i>, m<>thode
|
||
<i>loadServices()</i>
|
||
</font>
|
||
</u></a>
|
||
<br><br>
|
||
<table border="1" bgcolor="#FFFFFF">
|
||
<col>
|
||
<tbody>
|
||
<tr>
|
||
<td title="main_dlg::loadServices()">
|
||
<pre><span class="type">void</span> main_dlg<span class="operator">::</span>loadServices<span class="operator">()
|
||
{</span><span class="comment">
|
||
// N<>cessaire pour <20>tre certain de charger les DLL contenant les services : cr<63>ation d'un service fant<6E>me pour chaque DLL
|
||
// Il peut <20>tre int<6E>ressant <20> ce niveau de cr<63>er un m<>canisme de plugins pour charger les diff<66>rents services
|
||
</span> server_infos dummy_01<span class="operator">;</span> Q_UNUSED<span class="operator">(</span>dummy_01<span class="operator">);
|
||
}</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<br>
|
||
La m<>thode <i>loadServices()</i> est l'unique d<>pendance avec les services propos<6F>s par le serveur
|
||
d'applications.<br>
|
||
Elle sert uniquement <20> cr<63>er une instance fant<6E>me pour <20>tre certain que la DLL contenant la liste des
|
||
services soient correctement charg<72>e au d<>marrage de l'application.<br>
|
||
Pour un logiciel en production, il peut <20>tre int<6E>ressant <20> ce niveau de proposer <b>un syst<73>me de
|
||
plugins</b> pour charger les diff<66>rents services.<br>
|
||
<br>
|
||
<a name="tuto_104"><u>
|
||
<font color="#100D5A">1.4- Description du fichier <i>main_dlg.cpp</i>, m<>thode
|
||
<i>onClickStartStop()</i>
|
||
</font>
|
||
</u></a>
|
||
<br><br>
|
||
<table border="1" bgcolor="#FFFFFF">
|
||
<col>
|
||
<tbody>
|
||
<tr>
|
||
<td title="main_dlg::onClickStartStop()">
|
||
<pre><span class="type">void</span> main_dlg<span class="operator">::</span>onClickStartStop<span class="operator">()
|
||
{</span><span class="flow">
|
||
if</span><span class="operator"> (</span>m_pThreadPool<span class="operator">)
|
||
{</span>
|
||
m_pThreadPool<span class="operator">-></span>disconnect<span class="operator">();</span>
|
||
m_pThreadPool<span class="operator">.</span>reset<span class="operator">();</span>
|
||
txtError<span class="operator">-></span>setPlainText<span class="operator">(</span><span class="string">""</span><span class="operator">);</span>
|
||
txtTransaction<span class="operator">-></span>setPlainText<span class="operator">(</span><span class="string">""</span><span class="operator">);</span>
|
||
onServerIsRunning<span class="operator">(</span><span class="bool">false</span><span class="operator">,</span> NULL<span class="operator">);
|
||
}</span><span class="flow">
|
||
else</span><span class="operator">
|
||
{</span>
|
||
qx<span class="operator">::</span>service<span class="operator">::</span>QxConnect<span class="operator">::</span>getSingleton<span class="operator">()-></span>setPort<span class="operator">(</span>spinPortNumber<span class="operator">-></span>value<span class="operator">());</span>
|
||
qx<span class="operator">::</span>service<span class="operator">::</span>QxConnect<span class="operator">::</span>getSingleton<span class="operator">()-></span>setThreadCount<span class="operator">(</span>spinThreadCount<span class="operator">-></span>value<span class="operator">());</span>
|
||
qx<span class="operator">::</span>service<span class="operator">::</span>QxConnect<span class="operator">::</span>getSingleton<span class="operator">()-></span>setSerializationType<span class="operator">((</span>qx<span class="operator">::</span>service<span class="operator">::</span>QxConnect<span class="operator">::</span>serialization_type<span class="operator">)
|
||
(</span>cboSerializationType<span class="operator">-></span>itemData<span class="operator">(</span>cboSerializationType<span class="operator">-></span>currentIndex<span class="operator">()).</span>toInt<span class="operator">()));</span>
|
||
qx<span class="operator">::</span>service<span class="operator">::</span>QxConnect<span class="operator">::</span>getSingleton<span class="operator">()-></span>setCompressData<span class="operator">(</span>chkCompressData<span class="operator">-></span>isChecked<span class="operator">());</span>
|
||
qx<span class="operator">::</span>service<span class="operator">::</span>QxConnect<span class="operator">::</span>getSingleton<span class="operator">()-></span>setEncryptData<span class="operator">(</span>chkEncryptData<span class="operator">-></span>isChecked<span class="operator">());</span>
|
||
|
||
m_pThreadPool<span class="operator">.</span>reset<span class="operator">(</span><span class="keyword">new</span> qx<span class="operator">::</span>service<span class="operator">::</span>QxThreadPool<span class="operator">());</span>
|
||
QObject<span class="operator">::</span>connect<span class="operator">(</span>m_pThreadPool<span class="operator">.</span>get<span class="operator">(),</span> SIGNAL<span class="operator">(</span>error<span class="operator">(</span><span class="keyword">const</span> QString<span class="operator"> &,</span> qx<span class="operator">::</span>service<span class="operator">::</span>QxTransaction_ptr<span class="operator">)),</span><span class="keyword"> this</span><span class="operator">,</span>
|
||
SLOT<span class="operator">(</span>onError<span class="operator">(</span><span class="keyword">const</span> QString<span class="operator"> &,</span> qx<span class="operator">::</span>service<span class="operator">::</span>QxTransaction_ptr<span class="operator">)));</span>
|
||
QObject<span class="operator">::</span>connect<span class="operator">(</span>m_pThreadPool<span class="operator">.</span>get<span class="operator">(),</span> SIGNAL<span class="operator">(</span>serverIsRunning<span class="operator">(</span><span class="type">bool</span><span class="operator">,</span> qx<span class="operator">::</span>service<span class="operator">::</span>QxServer<span class="operator"> *)),</span><span class="keyword"> this</span><span class="operator">,</span>
|
||
SLOT<span class="operator">(</span>onServerIsRunning<span class="operator">(</span><span class="type">bool</span><span class="operator">,</span> qx<span class="operator">::</span>service<span class="operator">::</span>QxServer<span class="operator"> *)));</span>
|
||
QObject<span class="operator">::</span>connect<span class="operator">(</span>m_pThreadPool<span class="operator">.</span>get<span class="operator">(),</span> SIGNAL<span class="operator">(</span>transactionFinished<span class="operator">(</span>qx<span class="operator">::</span>service<span class="operator">::</span>QxTransaction_ptr<span class="operator">)),</span><span class="keyword"> this</span><span class="operator">,</span>
|
||
SLOT<span class="operator">(</span>onTransactionFinished<span class="operator">(</span>qx<span class="operator">::</span>service<span class="operator">::</span>QxTransaction_ptr<span class="operator">)));</span>
|
||
m_pThreadPool<span class="operator">-></span>start<span class="operator">();
|
||
}</span><span class="operator">
|
||
}</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<br>
|
||
La m<>thode <i>onClickStartStop()</i> permet de d<>marrer/arr<72>ter le serveur d'applications : elle s'occupe
|
||
de cr<63>er une instance de type <i>qx::service::QxThreadPool_ptr</i> ou bien de la d<>truire.<br>
|
||
Si la variable <i>m_pThreadPool</i> est valoris<69>e, alors cel<65> signifie que l'on souhaite arr<72>ter le
|
||
serveur : <i>m_pThreadPool.reset();</i>.<br>
|
||
Sinon, le serveur est arr<72>t<EFBFBD> donc on souhaite le d<>marrer :<br>
|
||
<br>
|
||
<i>m_pThreadPool.reset(new qx::service::QxThreadPool());</i>.<br>
|
||
<i>m_pThreadPool->start();</i>.<br>
|
||
<br>
|
||
Le param<61>trage du serveur est effectu<74> gr<67>ce au singleton
|
||
<i>qx::service::QxConnect::getSingleton()</i>.<br>
|
||
Enfin, l'interface utilisateur s'abonne aux <20>v<EFBFBD>nements envoy<6F>s par le serveur d'applications (m<>canisme
|
||
<b>SIGNAL-SLOT</b> de Qt) pour r<>cup<75>rer une erreur ou bien afficher la derni<6E>re transaction
|
||
client-serveur.<br>
|
||
<br>
|
||
<a name="tuto_105"><u>
|
||
<font color="#100D5A">1.5- Description du fichier <i>main_dlg.cpp</i>, m<>thodes <i>onError()</i> et
|
||
<i>onTransactionFinished()</i>
|
||
</font>
|
||
</u></a>
|
||
<br><br>
|
||
<table border="1" bgcolor="#FFFFFF">
|
||
<col>
|
||
<tbody>
|
||
<tr>
|
||
<td title="main_dlg::onError(), main_dlg::onTransactionFinished()">
|
||
<pre><span class="type">void</span> main_dlg<span class="operator">::</span>onError<span class="operator">(</span><span class="keyword">const</span> QString<span class="operator"> &</span> err<span class="operator">,</span> qx<span class="operator">::</span>service<span class="operator">::</span>QxTransaction_ptr transaction<span class="operator">)
|
||
{</span><span class="flow">
|
||
if</span><span class="operator"> (</span>err<span class="operator">.</span>isEmpty<span class="operator">()) {</span> txtError<span class="operator">-></span>setPlainText<span class="operator">(</span><span class="string">""</span><span class="operator">);</span><span class="flow"> return</span><span class="operator">; }</span>
|
||
QString errText<span class="operator"> =</span> QDateTime<span class="operator">::</span>currentDateTime<span class="operator">().</span>toString<span class="operator">(</span><span class="string">"dd.MM.yyyy hh:mm"</span><span class="operator">) +</span><span class="string"> " : "</span><span class="operator"> +</span> err<span class="operator">;</span><span class="flow">
|
||
if</span><span class="operator"> (</span>transaction<span class="operator">) {</span> errText<span class="operator"> +=</span> QString<span class="operator">(</span><span class="string">"\r\n\r\n"</span><span class="operator">) +</span> qx<span class="operator">::</span>serialization<span class="operator">::</span>xml<span class="operator">::</span>to_string<span class="operator">(*</span> transaction<span class="operator">); }</span>
|
||
txtError<span class="operator">-></span>setPlainText<span class="operator">(</span>errText<span class="operator">.</span>replace<span class="operator">(</span><span class="string">"\t"</span><span class="operator">,</span><span class="string"> " "</span><span class="operator">));
|
||
}</span><span class="type">
|
||
|
||
void</span> main_dlg<span class="operator">::</span>onTransactionFinished<span class="operator">(</span>qx<span class="operator">::</span>service<span class="operator">::</span>QxTransaction_ptr transaction<span class="operator">)
|
||
{</span><span class="flow">
|
||
if</span><span class="operator"> (!</span> transaction<span class="operator">) {</span> txtTransaction<span class="operator">-></span>setPlainText<span class="operator">(</span><span class="string">""</span><span class="operator">);</span><span class="flow"> return</span><span class="operator">; }</span>
|
||
QString text<span class="operator"> =</span> qx<span class="operator">::</span>serialization<span class="operator">::</span>xml<span class="operator">::</span>to_string<span class="operator">(*</span> transaction<span class="operator">);</span>
|
||
txtTransaction<span class="operator">-></span>setPlainText<span class="operator">(</span>text<span class="operator">.</span>replace<span class="operator">(</span><span class="string">"\t"</span><span class="operator">,</span><span class="string"> " "</span><span class="operator">));
|
||
}</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<br>
|
||
Toutes les transactions entre client et serveur sont repr<70>sent<6E>es par la classe
|
||
<i>qx::service::QxTransaction_ptr</i>.<br>
|
||
Cette classe contient toutes les informations n<>cessaires <20> l'ex<65>cution d'un service (identifiant unique,
|
||
date-heure, requ<71>te du client, service <20> ex<65>cuter, r<>ponse du serveur, code et message d'erreur,
|
||
etc.).<br>
|
||
La transaction est s<>rialis<69>e au format XML (ou JSON) avant d'<27>tre affich<63>e <20> l'utilisateur dans le champ
|
||
<i>txtTransaction</i>.<br>
|
||
Cette s<>rialisation est ind<6E>pendante de la r<>ponse envoy<6F>e au client qui, par d<>faut, est au format
|
||
binaire.<br>
|
||
<br>
|
||
<a name="tuto_106"><u>
|
||
<font color="#100D5A">1.6- R<>sultat obtenu pour le projet <i>qxServer</i></font>
|
||
</u></a>
|
||
<br><br>
|
||
<b>Et... c'est tout</b> : vous pouvez constater que l'<27>criture d'un serveur d'applications est
|
||
extr<74>mement simple avec la biblioth<74>que <b>QxOrm</b>.<br>
|
||
Votre serveur d'applications est pr<70>t pour proposer de multiples services aux diff<66>rents clients.<br>
|
||
Voici le r<>sultat obtenu :<br>
|
||
<br>
|
||
<img alt="gui_qxServer" src="./resource/gui_qxServer.jpg" width="560" height="426"
|
||
style="border:0px solid #100D5A; border-color:#100D5A;">
|
||
<br>
|
||
<br><br>
|
||
<b><a name="tuto_20"><u>
|
||
<font color="#100D5A">2- Cr<43>ation de la couche service : <i>qxService</i></font>
|
||
</u></a></b>
|
||
<br><br>
|
||
La couche service doit <20>tre partag<61>e entre le client et le serveur.<br>
|
||
La compilation du projet <i>qxService</i> cr<63>e deux DLL (ou fichiers <i>*.so</i> sous Linux) :
|
||
<i>qxServiceClient</i> et <i>qxServiceServer</i>.<br>
|
||
Une option de compilation <i>_QX_SERVICE_MODE_CLIENT</i> permet de faire la distinction entre le client
|
||
et le serveur.<br>
|
||
L'outil <i>qmake</i> de Qt et le syst<73>me de fichiers <i>*.pro</i> et <i>*.pri</i> permettent de cr<63>er
|
||
facilement ce type d'architecture :<br>
|
||
<ul>
|
||
<li>Le fichier <a href="./resource/qxService.pri"><i>qxService.pri</i></a> correspond au tronc commun
|
||
des deux DLL, c'est-<2D>-dire l'ensemble des d<>pendances et des fichiers <20> compiler ;</li>
|
||
<li>Le fichier <a href="./resource/qxServiceClient.pro"><i>qxServiceClient.pro</i></a> est sp<73>cifique
|
||
au mode client : d<>finition de l'option de compilation <i>_QX_SERVICE_MODE_CLIENT</i> et du nom de
|
||
la DLL ;</li>
|
||
<li>Le fichier <a href="./resource/qxServiceServer.pro"><i>qxServiceServer.pro</i></a> est sp<73>cifique
|
||
au mode serveur : d<>finition du nom de la DLL.</li>
|
||
</ul>
|
||
Il est important de signaler que ce m<>canisme permet au programme client de partager les m<>mes fichiers
|
||
que le programme serveur.<br>
|
||
<b>La partie cliente n'a aucun code <20> <20>crire pour pouvoir appeler un service</b> : le serveur peut livrer
|
||
la liste des fichiers de type <i>headers</i>, les <i>.dll</i> et <i>.lib</i> (ou <i>*.so</i> sous
|
||
Linux).<br>
|
||
<br>
|
||
<a name="tuto_201"><u>
|
||
<font color="#100D5A">2.1- Ecriture du premier service : r<>cup<75>rer la date-heure courante du
|
||
serveur</font>
|
||
</u></a>
|
||
<br><br>
|
||
Le premier service propos<6F> par notre serveur d'applications de test est relativement simple : <b>il
|
||
consiste <20> renvoyer aux clients la date-heure courante du serveur</b>.<br>
|
||
Ce service est disponible avec la classe <i>server_infos</i> : fichiers <i>server_infos.h</i> et
|
||
<i>server_infos.cpp</i>.<br>
|
||
Une m<>me classe peut proposer plusieurs services : la classe <i>server_infos</i> pourrait par exemple
|
||
renvoyer en plus de la date-heure courante, un nom de machine, une fr<66>quence processeur du serveur,
|
||
etc.<br>
|
||
Chaque classe service poss<73>de des param<61>tres d'entr<74>e (demande du client) et des param<61>tres de sortie
|
||
(r<>ponse du serveur).<br>
|
||
Une classe param<61>tre (entr<74>e ou sortie) doit h<>riter de la classe <b>qx::service::IxParameter</b> et doit
|
||
<20>tre s<>rialisable.<br>
|
||
Une classe service doit h<>riter du template <b>qx::service::QxService<INPUT, OUTPUT></b> et doit
|
||
d<>finir une liste de m<>thodes (services disponibles).<br>
|
||
Il est conseill<6C> d'<27>crire les classes param<61>tres d'entr<74>e, param<61>tres de sortie et services dans le m<>me
|
||
fichier.<br>
|
||
<br>
|
||
<a name="tuto_202"><u>
|
||
<font color="#100D5A">2.2- Description du fichier <i>server_infos.h</i></font>
|
||
</u></a>
|
||
<br><br>
|
||
<table border="1" bgcolor="#FFFFFF">
|
||
<col>
|
||
<tbody>
|
||
<tr>
|
||
<td title="server_infos.h">
|
||
<pre><span class="pre">#ifndef _QX_SERVICE_SERVER_INFOS_H_
|
||
#define _QX_SERVICE_SERVER_INFOS_H_
|
||
</span><span class="comment">
|
||
/* -- Liste des param<61>tres d'entr<74>e du service -- */</span><span class="keyword">
|
||
|
||
class</span> QX_SERVICE_DLL_EXPORT server_infos_input<span class="operator"> :</span><span class="keyword"> public</span> qx<span class="operator">::</span>service<span class="operator">::</span>IxParameter<span class="operator">
|
||
{ ; };</span>
|
||
|
||
QX_REGISTER_HPP_QX_SERVICE<span class="operator">(</span>server_infos_input<span class="operator">,</span> qx<span class="operator">::</span>service<span class="operator">::</span>IxParameter<span class="operator">,</span><span class="int"> 0</span><span class="operator">)</span><span class="keyword">
|
||
typedef</span> std<span class="operator">::</span>shared_ptr<span class="operator"><</span>server_infos_input<span class="operator">></span> server_infos_input_ptr<span class="operator">;</span><span class="comment">
|
||
|
||
/* -- Liste des param<61>tres de sortie du service -- */</span><span class="keyword">
|
||
|
||
class</span> QX_SERVICE_DLL_EXPORT server_infos_output<span class="operator"> :</span><span class="keyword"> public</span> qx<span class="operator">::</span>service<span class="operator">::</span>IxParameter<span class="operator">
|
||
{</span><span class="keyword"> public</span><span class="operator">:</span> QDateTime current_date_time<span class="operator">; };</span>
|
||
|
||
QX_REGISTER_HPP_QX_SERVICE<span class="operator">(</span>server_infos_output<span class="operator">,</span> qx<span class="operator">::</span>service<span class="operator">::</span>IxParameter<span class="operator">,</span><span class="int"> 0</span><span class="operator">)</span><span class="keyword">
|
||
typedef</span> std<span class="operator">::</span>shared_ptr<span class="operator"><</span>server_infos_output<span class="operator">></span> server_infos_output_ptr<span class="operator">;</span><span class="comment">
|
||
|
||
/* -- D<>finition du service -- */</span><span class="keyword">
|
||
|
||
typedef</span> qx<span class="operator">::</span>service<span class="operator">::</span>QxService<span class="operator"><</span>server_infos_input<span class="operator">,</span> server_infos_output<span class="operator">></span> server_infos_base_class<span class="operator">;</span><span class="keyword">
|
||
class</span> QX_SERVICE_DLL_EXPORT server_infos<span class="operator"> :</span><span class="keyword"> public</span> server_infos_base_class<span class="operator">
|
||
{</span><span class="keyword">
|
||
public</span><span class="operator">:</span>
|
||
server_infos<span class="operator">() :</span> server_infos_base_class<span class="operator">(</span><span class="string">"server_infos"</span><span class="operator">) { ; }</span><span class="keyword">
|
||
virtual</span><span class="operator"> ~</span>server_infos<span class="operator">() { ; }</span><span class="type">
|
||
void</span> get_current_date_time<span class="operator">();
|
||
};</span>
|
||
|
||
QX_REGISTER_HPP_QX_SERVICE<span class="operator">(</span>server_infos<span class="operator">,</span> qx<span class="operator">::</span>service<span class="operator">::</span>IxService<span class="operator">,</span><span class="int"> 0</span><span class="operator">)</span><span class="keyword">
|
||
typedef</span> std<span class="operator">::</span>shared_ptr<span class="operator"><</span>server_infos<span class="operator">></span> server_infos_ptr<span class="operator">;</span><span class="pre">
|
||
|
||
#endif // _QX_SERVICE_SERVER_INFOS_H_</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<br>
|
||
Le fichier <i>server_infos.h</i> poss<73>de trois classes :
|
||
<ul>
|
||
<li><b><i>server_infos_input</i></b> : h<>rite de <i>qx::service::IxParameter</i> et correspond aux
|
||
param<61>tres d'entr<74>e du service (demande du client). Notre service de test n'a pas besoin de
|
||
param<61>tres en entr<74>e, donc cette classe ne contient aucune propri<72>t<EFBFBD> ;</li>
|
||
<li><b><i>server_infos_output</i></b> : h<>rite de <i>qx::service::IxParameter</i> et correspond aux
|
||
param<61>tres de sortie du service (r<>ponse du serveur). Cette classe contient une seule propri<72>t<EFBFBD>, la
|
||
date-heure courante du serveur (<i>QDateTime current_date_time</i>) ;</li>
|
||
<li><b><i>server_infos</i></b> : h<>rite de <i>qx::service::QxService<INPUT, OUTPUT></i> et
|
||
contient la liste des services disponibles : une seule m<>thode pour r<>cup<75>rer la date-heure
|
||
courante du serveur.</li>
|
||
</ul>
|
||
Ces trois classes doivent <20>tre enregistr<74>es dans le contexte QxOrm, de la m<>me fa<66>on qu'une classe
|
||
persistante (voir <a href="./tutorial.html">le tutoriel <b>qxBlog</b></a>).<br>
|
||
C'est pourquoi nous utilisons la macro <i>QX_REGISTER_HPP_QX_SERVICE</i> pour ces trois classes.<br>
|
||
De plus, pour simplifier l'<27>criture des pointeurs, la gestion de la m<>moire et <20>viter les probl<62>mes de
|
||
fuites m<>moires, nous utilisons les pointeurs intelligents de la biblioth<74>que standard :
|
||
<i>std::shared_ptr</i>.<br>
|
||
Le module <b>QxService</b> travaille essentiellement avec des pointeurs intelligents, c'est pourquoi il
|
||
est fortement conseill<6C> de cr<63>er les <i>typedef</i> correspondants, par exemple :<br>
|
||
<br>
|
||
<i>typedef std::shared_ptr<server_infos_input> server_infos_input_ptr;</i>.<br>
|
||
<i>typedef std::shared_ptr<server_infos_output> server_infos_output_ptr;</i>.<br>
|
||
<i>typedef std::shared_ptr<server_infos> server_infos_ptr;</i>.<br>
|
||
<br>
|
||
Enfin, le constructeur du service doit indiquer en param<61>tre le nom de la classe sous forme de cha<68>ne de
|
||
caract<63>res : ceci est indispensable pour le moteur d'<i>introspection</i> de QxOrm pour pouvoir
|
||
instancier dynamiquement les services correspondant aux requ<71>tes des clients.<br>
|
||
<br>
|
||
<a name="tuto_203"><u>
|
||
<font color="#100D5A">2.3- Description du fichier <i>server_infos.cpp</i></font>
|
||
</u></a>
|
||
<br><br>
|
||
<table border="1" bgcolor="#FFFFFF">
|
||
<col>
|
||
<tbody>
|
||
<tr>
|
||
<td title="server_infos.cpp">
|
||
<pre><span class="pre">#include "../../include/precompiled.h"
|
||
|
||
#include "../../include/service/server_infos.h"
|
||
|
||
#include <QxOrm_Impl.h>
|
||
</span>
|
||
QX_REGISTER_CPP_QX_SERVICE<span class="operator">(</span>server_infos_input<span class="operator">)</span>
|
||
QX_REGISTER_CPP_QX_SERVICE<span class="operator">(</span>server_infos_output<span class="operator">)</span>
|
||
QX_REGISTER_CPP_QX_SERVICE<span class="operator">(</span>server_infos<span class="operator">)</span><span class="keyword">
|
||
|
||
namespace</span> qx<span class="operator"> {</span><span class="keyword">
|
||
|
||
template</span><span class="operator"> <></span><span class="type"> void</span> register_class<span class="operator">(</span>QxClass<span class="operator"><</span>server_infos_input<span class="operator">> &</span> t<span class="operator">)
|
||
{</span> Q_UNUSED<span class="operator">(</span>t<span class="operator">); }</span><span class="keyword">
|
||
|
||
template</span><span class="operator"> <></span><span class="type"> void</span> register_class<span class="operator">(</span>QxClass<span class="operator"><</span>server_infos_output<span class="operator">> &</span> t<span class="operator">)
|
||
{</span> t<span class="operator">.</span>data<span class="operator">(&</span> server_infos_output<span class="operator">::</span>current_date_time<span class="operator">,</span><span class="string"> "current_date_time"</span><span class="operator">); }</span><span class="keyword">
|
||
|
||
template</span><span class="operator"> <></span><span class="type"> void</span> register_class<span class="operator">(</span>QxClass<span class="operator"><</span>server_infos<span class="operator">> &</span> t<span class="operator">)
|
||
{</span> t<span class="operator">.</span>fct_0<span class="operator"><</span><span class="type">void</span><span class="operator">>(&</span> server_infos<span class="operator">::</span>get_current_date_time<span class="operator">,</span><span class="string"> "get_current_date_time"</span><span class="operator">); }
|
||
|
||
}</span><span class="comment"> // namespace qx
|
||
</span><span class="pre">
|
||
#ifdef _QX_SERVICE_MODE_CLIENT
|
||
</span><span class="type">
|
||
void</span> server_infos<span class="operator">::</span>get_current_date_time<span class="operator">()
|
||
{</span> qx<span class="operator">::</span>service<span class="operator">::</span>execute_client<span class="operator">(</span><span class="keyword">this</span><span class="operator">,</span><span class="string"> "get_current_date_time"</span><span class="operator">); }</span><span class="pre">
|
||
|
||
#else // _QX_SERVICE_MODE_CLIENT
|
||
</span><span class="type">
|
||
void</span> server_infos<span class="operator">::</span>get_current_date_time<span class="operator">()
|
||
{</span>
|
||
server_infos_output_ptr output<span class="operator"> =</span> server_infos_output_ptr<span class="operator">(</span><span class="keyword">new</span> server_infos_output<span class="operator">());</span>
|
||
output<span class="operator">-></span>current_date_time<span class="operator"> =</span> QDateTime<span class="operator">::</span>currentDateTime<span class="operator">();</span>
|
||
setOutputParameter<span class="operator">(</span>output<span class="operator">);</span>
|
||
setMessageReturn<span class="operator">(</span><span class="bool">true</span><span class="operator">);
|
||
}</span><span class="pre">
|
||
|
||
#endif // _QX_SERVICE_MODE_CLIENT</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<br>
|
||
Le fichier <i>server_infos.cpp</i> contient l'impl<70>mentation du service pour le mode client et le mode
|
||
serveur : c'est la macro <i>_QX_SERVICE_MODE_CLIENT</i> qui fait la distinction entre client et serveur
|
||
au moment de la compilation du projet.<br>
|
||
La macro <i>QX_REGISTER_CPP_QX_SERVICE</i> permet d'enregistrer les trois classes dans le contexte QxOrm,
|
||
de la m<>me fa<66>on qu'une classe persistante (voir le tutoriel <b>qxBlog</b>).<br>
|
||
Ensuite, nous <20>crivons la m<>thode de mapping <i>void qx::register_class(...)</i> pour les trois classes
|
||
du service :
|
||
<ul>
|
||
<li>Les deux classes de param<61>tres enregistrent les propri<72>t<EFBFBD>s utilis<69>es pour effectuer une demande du
|
||
client (aucune pour notre service de test), et les propri<72>t<EFBFBD>s qui seront renvoy<6F>es pour la r<>ponse
|
||
du serveur (date-heure courante : <i>t.data(& server_infos_output::current_date_time,
|
||
"current_date_time");</i>) ;</li>
|
||
<li>La classe service doit enregistrer la liste des m<>thodes disponibles, dans notre cas :
|
||
<i>t.fct_0<void>(& server_infos::get_current_date_time, "get_current_date_time");</i>.
|
||
</li>
|
||
</ul>
|
||
<b>Remarque :</b> toutes les m<>thodes de type service doivent avoir la m<>me signature : <b>pas de valeur
|
||
de retour, et pas d'argument</b> (par exemple : <i>void my_service()</i>).<br>
|
||
En effet, dans un service, les param<61>tres d'entr<74>e sont disponibles par la m<>thode
|
||
<i>getInputParameter()</i> (de type <i>server_infos_input_ptr</i> dans notre exemple).<br>
|
||
Les param<61>tres de sortie peuvent <20>tre valoris<69>s par la m<>thode <i>setOutputParameter()</i> (de type
|
||
<i>server_infos_output_ptr</i> dans notre exemple).<br>
|
||
Une valeur de retour de type <i>qx_bool</i> permet d'indiquer que la transaction s'est d<>roul<75>e
|
||
normalement, ou bien qu'une erreur quelconque est survenue (avec libell<6C> et code de l'erreur).<br>
|
||
Il est tr<74>s important d'<27>crire <i>setMessageReturn(true);</i> <20> la fin de chaque m<>thode service pour
|
||
indiquer que tout s'est bien d<>roul<75>.<br>
|
||
<br>
|
||
La derni<6E>re partie de notre fichier contient l'impl<70>mentation de la m<>thode
|
||
<i>server_infos::get_current_date_time()</i> pour le mode client et serveur :
|
||
<ul>
|
||
<li>Pour le mode client, le code est tr<74>s simple et sera le m<>me pour tous les services :
|
||
<i>qx::service::execute_client(this, "get_current_date_time");</i> ;
|
||
</li>
|
||
<li>Pour le mode serveur, notre service de test est tr<74>s simple : on valorise la date-heure courante,
|
||
on la transf<73>re dans les param<61>tres de sortie, puis on indique que la transaction s'est d<>roul<75>e
|
||
sans aucune erreur.</li>
|
||
</ul>
|
||
<a name="tuto_204"><u>
|
||
<font color="#100D5A">2.4- Ecriture du second service : op<6F>rations avec une classe persistante
|
||
</font>
|
||
</u></a>
|
||
<br><br>
|
||
Le projet <i>qxService</i> contient un second exemple de service plus complet avec une classe persistante
|
||
(classe <i>user</i>), et des actions sur une base de donn<6E>es (<i>SELECT, INSERT, UPDATE, DELETE,
|
||
etc.</i>).<br>
|
||
Ce deuxi<78>me exemple fait transiter sur le r<>seau des structures complexes : <b>pointeurs</b>,
|
||
<b>pointeurs intelligents</b>, <b>collections</b>, <b>crit<EFBFBD>res de recherche</b>, etc.<br>
|
||
Nous ne d<>taillerons pas ce second service dans le tutoriel, le principe <20>tant identique au premier
|
||
service :<br>
|
||
<br>
|
||
<table border="1" bgcolor="#FFFFFF">
|
||
<col>
|
||
<tbody>
|
||
<tr>
|
||
<td title="user_service.cpp">
|
||
<pre><span class="pre">#include "../../include/precompiled.h"
|
||
|
||
#include "../../include/service/user_service.h"
|
||
|
||
#include "../../include/dao/user_manager.h"
|
||
|
||
#include <QxOrm_Impl.h>
|
||
</span>
|
||
QX_REGISTER_CPP_QX_SERVICE<span class="operator">(</span>user_service_input<span class="operator">)</span>
|
||
QX_REGISTER_CPP_QX_SERVICE<span class="operator">(</span>user_service_output<span class="operator">)</span>
|
||
QX_REGISTER_CPP_QX_SERVICE<span class="operator">(</span>user_service<span class="operator">)</span><span class="keyword">
|
||
|
||
namespace</span> qx<span class="operator"> {</span><span class="keyword">
|
||
|
||
template</span><span class="operator"> <></span><span class="type"> void</span> register_class<span class="operator">(</span>QxClass<span class="operator"><</span>user_service_input<span class="operator">> &</span> t<span class="operator">)
|
||
{</span>
|
||
t<span class="operator">.</span>data<span class="operator">(&</span> user_service_input<span class="operator">::</span>id<span class="operator">,</span><span class="string"> "id"</span><span class="operator">);</span>
|
||
t<span class="operator">.</span>data<span class="operator">(&</span> user_service_input<span class="operator">::</span>user<span class="operator">,</span><span class="string"> "user"</span><span class="operator">);</span>
|
||
t<span class="operator">.</span>data<span class="operator">(&</span> user_service_input<span class="operator">::</span>criteria<span class="operator">,</span><span class="string"> "criteria"</span><span class="operator">);
|
||
}</span><span class="keyword">
|
||
|
||
template</span><span class="operator"> <></span><span class="type"> void</span> register_class<span class="operator">(</span>QxClass<span class="operator"><</span>user_service_output<span class="operator">> &</span> t<span class="operator">)
|
||
{</span>
|
||
t<span class="operator">.</span>data<span class="operator">(&</span> user_service_output<span class="operator">::</span>user<span class="operator">,</span><span class="string"> "user"</span><span class="operator">);</span>
|
||
t<span class="operator">.</span>data<span class="operator">(&</span> user_service_output<span class="operator">::</span>list_of_users<span class="operator">,</span><span class="string"> "list_of_users"</span><span class="operator">);
|
||
}</span><span class="keyword">
|
||
|
||
template</span><span class="operator"> <></span><span class="type"> void</span> register_class<span class="operator">(</span>QxClass<span class="operator"><</span>user_service<span class="operator">> &</span> t<span class="operator">)
|
||
{</span>
|
||
t<span class="operator">.</span>fct_0<span class="operator"><</span><span class="type">void</span><span class="operator">>(&</span> user_service<span class="operator">::</span>insert<span class="operator">,</span><span class="string"> "insert"</span><span class="operator">);</span>
|
||
t<span class="operator">.</span>fct_0<span class="operator"><</span><span class="type">void</span><span class="operator">>(&</span> user_service<span class="operator">::</span>update<span class="operator">,</span><span class="string"> "update"</span><span class="operator">);</span>
|
||
t<span class="operator">.</span>fct_0<span class="operator"><</span><span class="type">void</span><span class="operator">>(&</span> user_service<span class="operator">::</span>remove<span class="operator">,</span><span class="string"> "remove"</span><span class="operator">);</span>
|
||
t<span class="operator">.</span>fct_0<span class="operator"><</span><span class="type">void</span><span class="operator">>(&</span> user_service<span class="operator">::</span>remove_all<span class="operator">,</span><span class="string"> "remove_all"</span><span class="operator">);</span>
|
||
t<span class="operator">.</span>fct_0<span class="operator"><</span><span class="type">void</span><span class="operator">>(&</span> user_service<span class="operator">::</span>fetch_by_id<span class="operator">,</span><span class="string"> "fetch_by_id"</span><span class="operator">);</span>
|
||
t<span class="operator">.</span>fct_0<span class="operator"><</span><span class="type">void</span><span class="operator">>(&</span> user_service<span class="operator">::</span>fetch_all<span class="operator">,</span><span class="string"> "fetch_all"</span><span class="operator">);</span>
|
||
t<span class="operator">.</span>fct_0<span class="operator"><</span><span class="type">void</span><span class="operator">>(&</span> user_service<span class="operator">::</span>get_by_criteria<span class="operator">,</span><span class="string"> "get_by_criteria"</span><span class="operator">);
|
||
}
|
||
|
||
}</span><span class="comment"> // namespace qx
|
||
</span><span class="pre">
|
||
#ifdef _QX_SERVICE_MODE_CLIENT
|
||
</span><span class="type">
|
||
void</span> user_service<span class="operator">::</span>insert<span class="operator">() {</span> qx<span class="operator">::</span>service<span class="operator">::</span>execute_client<span class="operator">(</span><span class="keyword">this</span><span class="operator">,</span><span class="string"> "insert"</span><span class="operator">); }</span><span class="type">
|
||
void</span> user_service<span class="operator">::</span>update<span class="operator">() {</span> qx<span class="operator">::</span>service<span class="operator">::</span>execute_client<span class="operator">(</span><span class="keyword">this</span><span class="operator">,</span><span class="string"> "update"</span><span class="operator">); }</span><span class="type">
|
||
void</span> user_service<span class="operator">::</span>remove<span class="operator">() {</span> qx<span class="operator">::</span>service<span class="operator">::</span>execute_client<span class="operator">(</span><span class="keyword">this</span><span class="operator">,</span><span class="string"> "remove"</span><span class="operator">); }</span><span class="type">
|
||
void</span> user_service<span class="operator">::</span>remove_all<span class="operator">() {</span> qx<span class="operator">::</span>service<span class="operator">::</span>execute_client<span class="operator">(</span><span class="keyword">this</span><span class="operator">,</span><span class="string"> "remove_all"</span><span class="operator">); }</span><span class="type">
|
||
void</span> user_service<span class="operator">::</span>fetch_by_id<span class="operator">() {</span> qx<span class="operator">::</span>service<span class="operator">::</span>execute_client<span class="operator">(</span><span class="keyword">this</span><span class="operator">,</span><span class="string"> "fetch_by_id"</span><span class="operator">); }</span><span class="type">
|
||
void</span> user_service<span class="operator">::</span>fetch_all<span class="operator">() {</span> qx<span class="operator">::</span>service<span class="operator">::</span>execute_client<span class="operator">(</span><span class="keyword">this</span><span class="operator">,</span><span class="string"> "fetch_all"</span><span class="operator">); }</span><span class="type">
|
||
void</span> user_service<span class="operator">::</span>get_by_criteria<span class="operator">() {</span> qx<span class="operator">::</span>service<span class="operator">::</span>execute_client<span class="operator">(</span><span class="keyword">this</span><span class="operator">,</span><span class="string"> "get_by_criteria"</span><span class="operator">); }</span><span class="pre">
|
||
|
||
#else // _QX_SERVICE_MODE_CLIENT
|
||
</span><span class="type">
|
||
void</span> user_service<span class="operator">::</span>insert<span class="operator">()
|
||
{</span>
|
||
user_service_input_ptr input<span class="operator"> =</span> getInputParameter<span class="operator">();</span><span class="flow">
|
||
if</span><span class="operator"> (!</span> input<span class="operator">) {</span> setMessageReturn<span class="operator">(</span><span class="int">0</span><span class="operator">,</span><span class="string"> "invalid input parameter to call service 'user_service::insert()'"</span><span class="operator">);</span><span class="flow"> return</span><span class="operator">; }</span>
|
||
QSqlError err<span class="operator"> =</span> user_manager<span class="operator">().</span>insert<span class="operator">(</span>input<span class="operator">-></span>user<span class="operator">);</span><span class="flow">
|
||
if</span><span class="operator"> (</span>err<span class="operator">.</span>isValid<span class="operator">()) {</span> setMessageReturn<span class="operator">(</span><span class="int">0</span><span class="operator">,</span> err<span class="operator">.</span>text<span class="operator">());</span><span class="flow"> return</span><span class="operator">; }</span>
|
||
user_service_output_ptr output<span class="operator"> =</span> user_service_output_ptr<span class="operator">(</span><span class="keyword">new</span> user_service_output<span class="operator">());</span>
|
||
output<span class="operator">-></span>user<span class="operator"> =</span> input<span class="operator">-></span>user<span class="operator">;</span>
|
||
setOutputParameter<span class="operator">(</span>output<span class="operator">);</span>
|
||
setMessageReturn<span class="operator">(</span><span class="bool">true</span><span class="operator">);
|
||
}</span><span class="type">
|
||
|
||
void</span> user_service<span class="operator">::</span>update<span class="operator">()
|
||
{</span>
|
||
user_service_input_ptr input<span class="operator"> =</span> getInputParameter<span class="operator">();</span><span class="flow">
|
||
if</span><span class="operator"> (!</span> input<span class="operator">) {</span> setMessageReturn<span class="operator">(</span><span class="int">0</span><span class="operator">,</span><span class="string"> "invalid input parameter to call service 'user_service::update()'"</span><span class="operator">);</span><span class="flow"> return</span><span class="operator">; }</span>
|
||
QSqlError err<span class="operator"> =</span> user_manager<span class="operator">().</span>update<span class="operator">(</span>input<span class="operator">-></span>user<span class="operator">);</span><span class="flow">
|
||
if</span><span class="operator"> (</span>err<span class="operator">.</span>isValid<span class="operator">()) {</span> setMessageReturn<span class="operator">(</span><span class="int">0</span><span class="operator">,</span> err<span class="operator">.</span>text<span class="operator">()); }</span><span class="flow">
|
||
else</span><span class="operator"> {</span> setMessageReturn<span class="operator">(</span><span class="bool">true</span><span class="operator">); }
|
||
}</span><span class="type">
|
||
|
||
void</span> user_service<span class="operator">::</span>remove<span class="operator">()
|
||
{</span>
|
||
user_service_input_ptr input<span class="operator"> =</span> getInputParameter<span class="operator">();</span><span class="flow">
|
||
if</span><span class="operator"> (!</span> input<span class="operator">) {</span> setMessageReturn<span class="operator">(</span><span class="int">0</span><span class="operator">,</span><span class="string"> "invalid input parameter to call service 'user_service::remove()'"</span><span class="operator">);</span><span class="flow"> return</span><span class="operator">; }</span>
|
||
user_ptr user_tmp<span class="operator"> =</span> user_ptr<span class="operator">(</span><span class="keyword">new</span> user<span class="operator">());</span>
|
||
user_tmp<span class="operator">-></span>id<span class="operator"> =</span> input<span class="operator">-></span>id<span class="operator">;</span>
|
||
QSqlError err<span class="operator"> =</span> user_manager<span class="operator">().</span>remove<span class="operator">(</span>user_tmp<span class="operator">);</span><span class="flow">
|
||
if</span><span class="operator"> (</span>err<span class="operator">.</span>isValid<span class="operator">()) {</span> setMessageReturn<span class="operator">(</span><span class="int">0</span><span class="operator">,</span> err<span class="operator">.</span>text<span class="operator">()); }</span><span class="flow">
|
||
else</span><span class="operator"> {</span> setMessageReturn<span class="operator">(</span><span class="bool">true</span><span class="operator">); }
|
||
}</span><span class="type">
|
||
|
||
void</span> user_service<span class="operator">::</span>remove_all<span class="operator">()
|
||
{</span>
|
||
QSqlError err<span class="operator"> =</span> user_manager<span class="operator">().</span>remove_all<span class="operator">();</span><span class="flow">
|
||
if</span><span class="operator"> (</span>err<span class="operator">.</span>isValid<span class="operator">()) {</span> setMessageReturn<span class="operator">(</span><span class="int">0</span><span class="operator">,</span> err<span class="operator">.</span>text<span class="operator">()); }</span><span class="flow">
|
||
else</span><span class="operator"> {</span> setMessageReturn<span class="operator">(</span><span class="bool">true</span><span class="operator">); }
|
||
}</span><span class="type">
|
||
|
||
void</span> user_service<span class="operator">::</span>fetch_by_id<span class="operator">()
|
||
{</span>
|
||
user_service_input_ptr input<span class="operator"> =</span> getInputParameter<span class="operator">();</span><span class="flow">
|
||
if</span><span class="operator"> (!</span> input<span class="operator">) {</span> setMessageReturn<span class="operator">(</span><span class="int">0</span><span class="operator">,</span><span class="string"> "invalid input parameter to call service 'user_service::fetch_by_id()'"</span><span class="operator">);</span><span class="flow"> return</span><span class="operator">; }</span>
|
||
user_ptr user_output<span class="operator"> =</span> user_ptr<span class="operator">(</span><span class="keyword">new</span> user<span class="operator">());</span>
|
||
user_output<span class="operator">-></span>id<span class="operator"> =</span> input<span class="operator">-></span>id<span class="operator">;</span>
|
||
QSqlError err<span class="operator"> =</span> user_manager<span class="operator">().</span>fetch_by_id<span class="operator">(</span>user_output<span class="operator">);</span><span class="flow">
|
||
if</span><span class="operator"> (</span>err<span class="operator">.</span>isValid<span class="operator">()) {</span> setMessageReturn<span class="operator">(</span><span class="int">0</span><span class="operator">,</span> err<span class="operator">.</span>text<span class="operator">());</span><span class="flow"> return</span><span class="operator">; }</span>
|
||
user_service_output_ptr output<span class="operator"> =</span> user_service_output_ptr<span class="operator">(</span><span class="keyword">new</span> user_service_output<span class="operator">());</span>
|
||
output<span class="operator">-></span>user<span class="operator"> =</span> user_output<span class="operator">;</span>
|
||
setOutputParameter<span class="operator">(</span>output<span class="operator">);</span>
|
||
setMessageReturn<span class="operator">(</span><span class="bool">true</span><span class="operator">);
|
||
}</span><span class="type">
|
||
|
||
void</span> user_service<span class="operator">::</span>fetch_all<span class="operator">()
|
||
{</span>
|
||
list_of_users_ptr list_of_users_output<span class="operator"> =</span> list_of_users_ptr<span class="operator">(</span><span class="keyword">new</span> list_of_users<span class="operator">());</span>
|
||
QSqlError err<span class="operator"> =</span> user_manager<span class="operator">().</span>fetch_all<span class="operator">(</span>list_of_users_output<span class="operator">);</span><span class="flow">
|
||
if</span><span class="operator"> (</span>err<span class="operator">.</span>isValid<span class="operator">()) {</span> setMessageReturn<span class="operator">(</span><span class="int">0</span><span class="operator">,</span> err<span class="operator">.</span>text<span class="operator">());</span><span class="flow"> return</span><span class="operator">; }</span>
|
||
user_service_output_ptr output<span class="operator"> =</span> user_service_output_ptr<span class="operator">(</span><span class="keyword">new</span> user_service_output<span class="operator">());</span>
|
||
output<span class="operator">-></span>list_of_users<span class="operator"> =</span> list_of_users_output<span class="operator">;</span>
|
||
setOutputParameter<span class="operator">(</span>output<span class="operator">);</span>
|
||
setMessageReturn<span class="operator">(</span><span class="bool">true</span><span class="operator">);
|
||
}</span><span class="type">
|
||
|
||
void</span> user_service<span class="operator">::</span>get_by_criteria<span class="operator">()
|
||
{</span>
|
||
user_service_input_ptr input<span class="operator"> =</span> getInputParameter<span class="operator">();</span><span class="flow">
|
||
if</span><span class="operator"> (!</span> input<span class="operator">) {</span> setMessageReturn<span class="operator">(</span><span class="int">0</span><span class="operator">,</span><span class="string"> "invalid input parameter to call service 'user_service::get_by_criteria()'"</span><span class="operator">);</span><span class="flow"> return</span><span class="operator">; }</span>
|
||
list_of_users_ptr list_of_users_output<span class="operator"> =</span> list_of_users_ptr<span class="operator">(</span><span class="keyword">new</span> list_of_users<span class="operator">());</span>
|
||
QSqlError err<span class="operator"> =</span> user_manager<span class="operator">().</span>get_by_criteria<span class="operator">(</span>input<span class="operator">-></span>criteria<span class="operator">,</span> list_of_users_output<span class="operator">);</span><span class="flow">
|
||
if</span><span class="operator"> (</span>err<span class="operator">.</span>isValid<span class="operator">()) {</span> setMessageReturn<span class="operator">(</span><span class="int">0</span><span class="operator">,</span> err<span class="operator">.</span>text<span class="operator">());</span><span class="flow"> return</span><span class="operator">; }</span>
|
||
user_service_output_ptr output<span class="operator"> =</span> user_service_output_ptr<span class="operator">(</span><span class="keyword">new</span> user_service_output<span class="operator">());</span>
|
||
output<span class="operator">-></span>list_of_users<span class="operator"> =</span> list_of_users_output<span class="operator">;</span>
|
||
setOutputParameter<span class="operator">(</span>output<span class="operator">);</span>
|
||
setMessageReturn<span class="operator">(</span><span class="bool">true</span><span class="operator">);
|
||
}</span><span class="pre">
|
||
|
||
#endif // _QX_SERVICE_MODE_CLIENT
|
||
</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<br>
|
||
A ce niveau du tutoriel, notre serveur d'applications C++ est termin<69> et propose plusieurs services.<br>
|
||
Il reste <20> pr<70>sent <20> <20>crire le code client qui va appeler tous les services que nous avons mis en
|
||
place...<br>
|
||
<br><br>
|
||
<b><a name="tuto_30"><u>
|
||
<font color="#100D5A">3- Cr<43>ation de l'interface cliente : <i>qxClient</i></font>
|
||
</u></a></b>
|
||
<br><br>
|
||
De la m<>me fa<66>on que le projet <i>qxServer</i>, le projet <i>qxClient</i> poss<73>de une interface
|
||
utilisateur construite avec l'outil <b>Qt Designer</b> de la biblioth<74>que Qt.<br>
|
||
Cette interface poss<73>de plusieurs boutons pour appeler l'ensemble des services propos<6F>s par notre serveur
|
||
d'applications.<br>
|
||
L'interface permet <20>galement d'indiquer une adresse ip et un num<75>ro de port pour se connecter au serveur
|
||
d'applications.<br>
|
||
<br>
|
||
<img alt="gui_qxClient" src="./resource/gui_qxClient_01.jpg" width="549" height="405"
|
||
style="border:0px solid #100D5A; border-color:#100D5A;">
|
||
<br><br>
|
||
<a name="tuto_301"><u>
|
||
<font color="#100D5A">3.1- Description de la m<>thode <i>onClickBtnDateTime()</i></font>
|
||
</u></a>
|
||
<br><br>
|
||
Comment r<>cup<75>rer la date-heure courante du serveur d'applications ?<br>
|
||
Voici le code qui s'ex<65>cute lorsque l'utilisateur clique sur le bouton <i>Get Server DateTime</i> :<br>
|
||
<br>
|
||
<table border="1" bgcolor="#FFFFFF">
|
||
<col>
|
||
<tbody>
|
||
<tr>
|
||
<td title="main_dlg::onClickBtnDateTime()">
|
||
<pre><span class="type">void</span> main_dlg<span class="operator">::</span>onClickBtnDateTime<span class="operator">()
|
||
{</span><span class="comment">
|
||
// Cr<43>ation d'une instance de service et appel <20> la m<>thode pour recevoir la date-heure courante du serveur
|
||
</span> server_infos service<span class="operator">;</span>
|
||
service<span class="operator">.</span>get_current_date_time<span class="operator">();</span><span class="comment">
|
||
// Affiche la derni<6E>re transaction au format XML (ou JSON)
|
||
</span> updateLastTransactionLog<span class="operator">(</span>service<span class="operator">.</span>getTransaction<span class="operator">());</span><span class="operator">
|
||
}</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<br>
|
||
<b>Comme vous pouvez le constater, la partie cliente n'a aucun code sp<73>cifique <20> <20>crire pour pouvoir
|
||
appeler un service</b>.<br>
|
||
Il suffit d'instancier un service, puis d'appeler la m<>thode qui nous int<6E>resse :
|
||
<i>get_current_date_time()</i>.<br>
|
||
La m<>thode <i>updateLastTransactionLog()</i> permet d'afficher la derni<6E>re transaction client-serveur (au
|
||
format XML ou JSON) ex<65>cut<75>e.<br>
|
||
Si une erreur s'est produite, alors un message appara<72>t <20> l'<27>cran pour le signaler <20> l'utilisateur.<br>
|
||
Pour savoir si le service s'est ex<65>cut<75> correctement, il faut utiliser la m<>thode :
|
||
<i>service.getMessageReturn();</i> (de type <i>qx_bool</i> qui peut contenir un code et un libell<6C> d'une
|
||
<20>ventuelle erreur).<br>
|
||
Enfin, pour r<>cup<75>rer la r<>ponse du serveur (donc sa date-heure courante), il faut utiliser la m<>thode :
|
||
<i>service.getOutputParameter();</i> (de type <i>user_service_output_ptr</i>).<br>
|
||
<br>
|
||
<a name="tuto_302"><u>
|
||
<font color="#100D5A">3.2- Description de la m<>thode <i>onClickBtnDateTimeAsync()</i></font>
|
||
</u></a>
|
||
<br><br>
|
||
<table border="1" bgcolor="#FFFFFF">
|
||
<col>
|
||
<tbody>
|
||
<tr>
|
||
<td title="main_dlg::onClickBtnDateTimeAsync(), main_dlg::onDateTimeAsyncFinished()">
|
||
<pre><span class="type">void</span> main_dlg<span class="operator">::</span>onClickBtnDateTimeAsync<span class="operator">()
|
||
{</span><span class="flow">
|
||
if</span><span class="operator"> (</span>m_pDateTimeAsync<span class="operator">) {</span> qDebug<span class="operator">(</span><span class="string">"[QxOrm] '%s' transaction is already running"</span><span class="operator">,</span><span class="string"> "server_infos::get_current_date_time"</span><span class="operator">);</span><span class="flow"> return</span><span class="operator">; }</span><span class="comment">
|
||
// Cr<43>ation d'une instance de service et appel <20> la m<>thode pour recevoir la date-heure courante du serveur (mode asynchrone)
|
||
</span> server_infos_ptr service<span class="operator"> =</span> server_infos_ptr<span class="operator">(</span><span class="keyword">new</span> server_infos<span class="operator">());</span>
|
||
m_pDateTimeAsync<span class="operator">.</span>reset<span class="operator">(</span><span class="keyword">new</span> qx<span class="operator">::</span>service<span class="operator">::</span>QxClientAsync<span class="operator">());</span>
|
||
QObject<span class="operator">::</span>connect<span class="operator">(</span>m_pDateTimeAsync<span class="operator">.</span>get<span class="operator">(),</span> SIGNAL<span class="operator">(</span>finished<span class="operator">()),</span><span class="keyword"> this</span><span class="operator">,</span> SLOT<span class="operator">(</span>onDateTimeAsyncFinished<span class="operator">()));</span>
|
||
m_pDateTimeAsync<span class="operator">-></span>setService<span class="operator">(</span>service<span class="operator">,</span><span class="string"> "get_current_date_time"</span><span class="operator">);</span>
|
||
m_pDateTimeAsync<span class="operator">-></span>start<span class="operator">();
|
||
}</span><span class="type">
|
||
|
||
void</span> main_dlg<span class="operator">::</span>onDateTimeAsyncFinished<span class="operator">()
|
||
{</span><span class="flow">
|
||
if</span><span class="operator"> (!</span> m_pDateTimeAsync<span class="operator"> || !</span> m_pDateTimeAsync<span class="operator">-></span>getService<span class="operator">()) {</span><span class="flow"> return</span><span class="operator">; }</span>
|
||
updateLastTransactionLog<span class="operator">(</span>m_pDateTimeAsync<span class="operator">-></span>getService<span class="operator">()-></span>getTransaction<span class="operator">());</span>
|
||
m_pDateTimeAsync<span class="operator">.</span>reset<span class="operator">();
|
||
}</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<br>
|
||
Ce second exemple correspond au bouton <i>Get Server DateTime Async</i> de l'interface utilisateur.<br>
|
||
Il montre comment appeler un service de mani<6E>re asynchrone, c'est-<2D>-dire <b>sans bloquer l'IHM</b> en
|
||
attendant la r<>ponse du serveur.<br>
|
||
La biblioth<74>que <b>QxOrm</b> propose la classe <i>qx::service::QxClientAsync</i> pour simplifier les
|
||
appels asynchrones.<br>
|
||
<br>
|
||
Le m<>canisme des appels asynchrones avec le module <b>QxService</b> est tr<74>s simple :
|
||
<ul>
|
||
<li>cr<EFBFBD>ation d'une instance d'un service ;</li>
|
||
<li>cr<EFBFBD>ation d'une instance de type <i>qx::service::QxClientAsync</i> ;</li>
|
||
<li>connexion <20> l'<27>v<EFBFBD>nement <i>finished</i> (pour indiquer qu'une r<>ponse du serveur vient d'arriver)
|
||
;</li>
|
||
<li>passage de l'instance du service et de la m<>thode <20> appeler (sous forme de chaine de caract<63>res) <20>
|
||
l'objet <i>qx::service::QxClientAsync</i> ;</li>
|
||
<li>d<EFBFBD>marrage de la transaction avec l'appel de la m<>thode <i>start()</i>.</li>
|
||
</ul>
|
||
<a name="tuto_303"><u>
|
||
<font color="#100D5A">3.3- Description de la m<>thode <i>onClickBtnAddUser()</i></font>
|
||
</u></a>
|
||
<br><br>
|
||
<table border="1" bgcolor="#FFFFFF">
|
||
<col>
|
||
<tbody>
|
||
<tr>
|
||
<td title="main_dlg::onClickBtnAddUser()">
|
||
<pre><span class="type">void</span> main_dlg<span class="operator">::</span>onClickBtnAddUser<span class="operator">()
|
||
{</span><span class="comment">
|
||
// Cr<43>ation des param<61>tres d'entr<74>e contenant l'utilisateur <20> ajouter en BDD
|
||
</span> user_service_input_ptr input<span class="operator"> =</span> user_service_input_ptr<span class="operator">(</span><span class="keyword">new</span> user_service_input<span class="operator">());</span>
|
||
input<span class="operator">-></span>user<span class="operator"> =</span> fileUser<span class="operator">();</span><span class="comment">
|
||
// Cr<43>ation d'une instance de service et association des param<61>tres d'entr<74>e
|
||
</span> user_service service<span class="operator">;</span>
|
||
service<span class="operator">.</span>setInputParameter<span class="operator">(</span>input<span class="operator">);</span>
|
||
service<span class="operator">.</span>insert<span class="operator">();</span><span class="comment">
|
||
// Si la transaction s'est d<>roul<75>e correctement, on affiche l'identifiant qui vient d'<27>tre ajout<75> en BDD
|
||
</span> user_ptr output<span class="operator"> = (</span>service<span class="operator">.</span>isValidWithOutput<span class="operator">() ?</span> service<span class="operator">.</span>getOutputParameter<span class="operator">()-></span>user<span class="operator"> :</span> user_ptr<span class="operator">());</span><span class="flow">
|
||
if</span><span class="operator"> (</span>output<span class="operator">) {</span> fillUser<span class="operator">(</span>output<span class="operator">); }</span><span class="comment">
|
||
// Affiche la derni<6E>re transaction au format XML (ou JSON)
|
||
</span> updateLastTransactionLog<span class="operator">(</span>service<span class="operator">.</span>getTransaction<span class="operator">());</span><span class="operator">
|
||
}</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<br>
|
||
Ce 3<>me exemple correspond au bouton <i>Add</i> dans la section <i>User transaction</i>.<br>
|
||
Il permet <20> l'utilisateur d'ajouter une nouvelle personne dans la base de donn<6E>es.<br>
|
||
Cet exemple nous montre comment passer une structure (classe <i>user</i>) en param<61>tre d'entr<74>e d'un
|
||
service.<br>
|
||
La m<>thode <i>fileUser()</i> permet de cr<63>er une instance de type <i>user</i> et de valoriser ses
|
||
propri<72>t<EFBFBD>s en fonction des champs de l'IHM.<br>
|
||
Cette instance est ensuite utilis<69>e comme param<61>tre d'entr<74>e de notre service.<br>
|
||
Si la transaction s'est d<>roul<75>e correctement, le param<61>tre de retour (r<>ponse du serveur) contient lui
|
||
aussi une instance de type <i>user</i> avec le nouvel identifiant qui vient d'<27>tre ajout<75> en base de
|
||
donn<6E>es.<br>
|
||
On utilise alors la m<>thode <i>fillUser()</i> pour mettre <20> jour l'interface utilisateur en fonction de
|
||
la r<>ponse du serveur et afficher ainsi le nouvel identifiant.<br>
|
||
<br>
|
||
<a name="tuto_304"><u>
|
||
<font color="#100D5A">3.4- Description de la m<>thode <i>onClickBtnGetAllUsers()</i></font>
|
||
</u></a>
|
||
<br><br>
|
||
<table border="1" bgcolor="#FFFFFF">
|
||
<col>
|
||
<tbody>
|
||
<tr>
|
||
<td title="main_dlg::onClickBtnGetAllUsers()">
|
||
<pre><span class="type">void</span> main_dlg<span class="operator">::</span>onClickBtnGetAllUsers<span class="operator">()
|
||
{</span><span class="comment">
|
||
// Cr<43>ation d'une instance de service
|
||
</span> user_service service<span class="operator">;</span>
|
||
service<span class="operator">.</span>fetch_all<span class="operator">();</span><span class="comment">
|
||
// Si la transaction s'est d<>roul<75>e correctement, affiche un message avec le nombre d'utilisateurs stock<63>s en BDD
|
||
</span> list_of_users_ptr output<span class="operator"> = (</span>service<span class="operator">.</span>isValidWithOutput<span class="operator">() ?</span> service<span class="operator">.</span>getOutputParameter<span class="operator">()-></span>list_of_users<span class="operator"> :</span> list_of_users_ptr<span class="operator">());</span><span class="flow">
|
||
if</span><span class="operator"> (</span>output<span class="operator">) {</span> QMessageBox<span class="operator">::</span>information<span class="operator">(</span><span class="keyword">this</span><span class="operator">,</span><span class="string"> "qxClient - get all users"</span><span class="operator">,</span><span class="string"> "database contains '"</span><span class="operator"> +</span> QString<span class="operator">::</span>number<span class="operator">(</span>output<span class="operator">-></span>size<span class="operator">()) +</span><span class="string"> "' user(s)."</span><span class="operator">); }</span><span class="comment">
|
||
// Affiche la derni<6E>re transaction au format XML (ou JSON)
|
||
</span> updateLastTransactionLog<span class="operator">(</span>service<span class="operator">.</span>getTransaction<span class="operator">());</span><span class="operator">
|
||
}</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<br>
|
||
Ce 4<>me exemple correspond au bouton <i>Get All</i> de la section <i>User transaction</i>.<br>
|
||
Il permet de r<>cup<75>rer la liste de tous les <i>user</i> pr<70>sents dans la base de donn<6E>es.<br>
|
||
Le param<61>tre de retour est une liste fortement typ<79>e : il est possible d'utiliser les collections des
|
||
biblioth<74>ques <i>stl</i>, <i>boost</i>, <i>Qt</i> ou <i>qx::QxCollection</i>.<br>
|
||
Le module <b>QxService</b> permet donc d'<b><EFBFBD>changer des structures complexes entre client et
|
||
serveur</b>.<br>
|
||
<br>
|
||
A pr<70>sent, bon courage avec le module <b>QxService</b>... ;o)
|
||
<br>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<br>
|
||
<hr style="width: 80%" align="center" size="1" color="#100D5A">
|
||
<table border="0" style="width: 80%" align="center">
|
||
<col>
|
||
<col>
|
||
<col>
|
||
<tbody>
|
||
<tr>
|
||
<td align="left" valign="middle">
|
||
<img alt="QxOrm" src="./resource/logo_qxorm_small.png" width="168" height="40">
|
||
</td>
|
||
<td align="center" valign="middle">
|
||
<font size="2"><EFBFBD> 2011-202XDL Teamty - <a href="mailto:ic-east.com">ic-east.com</a></font>
|
||
</td>
|
||
<td align="right" valign="middle">
|
||
<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
|
||
<input type="hidden" name="cmd" value="_s-xclick">
|
||
<input type="hidden" name="hosted_button_id" value="2K4Z58ZYAYJ6S">
|
||
<input type="image" src="./resource/paypal_support_qxorm_library.gif" border="0" name="submit"
|
||
alt="Support QxOrm library - PayPal">
|
||
<img alt="" border="0" src="https://www.paypalobjects.com/fr_FR/i/scr/pixel.gif" width="1" height="1">
|
||
</form>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</body>
|
||
|
||
</html> |