Files
XdlOrm/doc/qxorm_fr/tutorial_2.html
2026-04-03 11:32:07 +08:00

1119 lines
96 KiB
HTML
Raw Permalink Blame History

<!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 &gt;&gt; Tutoriel &gt;&gt; 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 :&nbsp;</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&lt;T&gt;(...)</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"> &amp;</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">-&gt;</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">-&gt;</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">-&gt;</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">-&gt;</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">-&gt;</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">-&gt;</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">-&gt;</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">-&gt;</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">-&gt;</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">-&gt;</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">-&gt;</span>setCurrentIndex<span class="operator">(</span>cboSerializationType<span class="operator">-&gt;</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">()-&gt;</span>getSerializationType<span class="operator">())));</span>
spinPortNumber<span class="operator">-&gt;</span>setValue<span class="operator">(</span><span class="int">7694</span><span class="operator">);</span>
spinThreadCount<span class="operator">-&gt;</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">()-&gt;</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">-&gt;</span>disconnect<span class="operator">();</span>
m_pThreadPool<span class="operator">.</span>reset<span class="operator">();</span>
txtError<span class="operator">-&gt;</span>setPlainText<span class="operator">(</span><span class="string">""</span><span class="operator">);</span>
txtTransaction<span class="operator">-&gt;</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">()-&gt;</span>setPort<span class="operator">(</span>spinPortNumber<span class="operator">-&gt;</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">()-&gt;</span>setThreadCount<span class="operator">(</span>spinThreadCount<span class="operator">-&gt;</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">()-&gt;</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">-&gt;</span>itemData<span class="operator">(</span>cboSerializationType<span class="operator">-&gt;</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">()-&gt;</span>setCompressData<span class="operator">(</span>chkCompressData<span class="operator">-&gt;</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">()-&gt;</span>setEncryptData<span class="operator">(</span>chkEncryptData<span class="operator">-&gt;</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"> &amp;,</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"> &amp;,</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">-&gt;</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"> &amp;</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">-&gt;</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">-&gt;</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">-&gt;</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">-&gt;</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&lt;INPUT, OUTPUT&gt;</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">&lt;</span>server_infos_input<span class="operator">&gt;</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">&lt;</span>server_infos_output<span class="operator">&gt;</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">&lt;</span>server_infos_input<span class="operator">,</span> server_infos_output<span class="operator">&gt;</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">&lt;</span>server_infos<span class="operator">&gt;</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&lt;INPUT, OUTPUT&gt;</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&lt;server_infos_input&gt; server_infos_input_ptr;</i>.<br>
<i>typedef std::shared_ptr&lt;server_infos_output&gt; server_infos_output_ptr;</i>.<br>
<i>typedef std::shared_ptr&lt;server_infos&gt; 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 &lt;QxOrm_Impl.h&gt;
</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"> &lt;&gt;</span><span class="type"> void</span> register_class<span class="operator">(</span>QxClass<span class="operator">&lt;</span>server_infos_input<span class="operator">&gt; &amp;</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"> &lt;&gt;</span><span class="type"> void</span> register_class<span class="operator">(</span>QxClass<span class="operator">&lt;</span>server_infos_output<span class="operator">&gt; &amp;</span> t<span class="operator">)
{</span> t<span class="operator">.</span>data<span class="operator">(&amp;</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"> &lt;&gt;</span><span class="type"> void</span> register_class<span class="operator">(</span>QxClass<span class="operator">&lt;</span>server_infos<span class="operator">&gt; &amp;</span> t<span class="operator">)
{</span> t<span class="operator">.</span>fct_0<span class="operator">&lt;</span><span class="type">void</span><span class="operator">&gt;(&amp;</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">-&gt;</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&lt;void&gt;(& 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 &lt;QxOrm_Impl.h&gt;
</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"> &lt;&gt;</span><span class="type"> void</span> register_class<span class="operator">(</span>QxClass<span class="operator">&lt;</span>user_service_input<span class="operator">&gt; &amp;</span> t<span class="operator">)
{</span>
t<span class="operator">.</span>data<span class="operator">(&amp;</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">(&amp;</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">(&amp;</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"> &lt;&gt;</span><span class="type"> void</span> register_class<span class="operator">(</span>QxClass<span class="operator">&lt;</span>user_service_output<span class="operator">&gt; &amp;</span> t<span class="operator">)
{</span>
t<span class="operator">.</span>data<span class="operator">(&amp;</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">(&amp;</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"> &lt;&gt;</span><span class="type"> void</span> register_class<span class="operator">(</span>QxClass<span class="operator">&lt;</span>user_service<span class="operator">&gt; &amp;</span> t<span class="operator">)
{</span>
t<span class="operator">.</span>fct_0<span class="operator">&lt;</span><span class="type">void</span><span class="operator">&gt;(&amp;</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">&lt;</span><span class="type">void</span><span class="operator">&gt;(&amp;</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">&lt;</span><span class="type">void</span><span class="operator">&gt;(&amp;</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">&lt;</span><span class="type">void</span><span class="operator">&gt;(&amp;</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">&lt;</span><span class="type">void</span><span class="operator">&gt;(&amp;</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">&lt;</span><span class="type">void</span><span class="operator">&gt;(&amp;</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">&lt;</span><span class="type">void</span><span class="operator">&gt;(&amp;</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">-&gt;</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">-&gt;</span>user<span class="operator"> =</span> input<span class="operator">-&gt;</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">-&gt;</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">-&gt;</span>id<span class="operator"> =</span> input<span class="operator">-&gt;</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">-&gt;</span>id<span class="operator"> =</span> input<span class="operator">-&gt;</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">-&gt;</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">-&gt;</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">-&gt;</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">-&gt;</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">-&gt;</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">-&gt;</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">-&gt;</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">-&gt;</span>getService<span class="operator">()-&gt;</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">-&gt;</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">()-&gt;</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">()-&gt;</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">-&gt;</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>