Tutorial Flex écrit par Benjamin Michotte. Publiez vous aussi sur flex-tutorial!
Dans le cadre d'un projet professionnel, j'ai du mettre en place une infrastructure assez intéressante, mais également assez complexe à mettre en œuvre. Côté serveur, il s'agit d'un environnement Spring-Hibernate-BlazeDS-MySQL et côté client une interface Flex 4.
Ce tutoriel va vous expliquer comment créer ce genre de projet. Je me baserai sur le fait que vous avez des connaissances (même de base) dans ces différents framework. Si ce n'est pas le cas, je vous renvois aux différents sites des framework cités. Je vous invite également à lire d'abord les tutoriels de Fabien concernant BlazeDS.
Concernant les différents (nombreux) jars à télécharger côté serveur, je vous invite à vous rendre sur leurs site respectifs et suivre les dépendances. Un fichier de configuration Maven est disponible pour ceux qui l'utilise sur http://benjamin.produweb.eu/pom.xml. Notez que le fichier n'est en rien optimisé au niveau des dépendances, il a été créé en mode "ah, il me faut aussi ça, hop, je l'ajoute".
Versions utilisées pour ce tutoriel :
- Spring 3.0.0RC2
- Hibernate 3.2.6.ga
- BlazeDS 4.0.0.11835 (que vous trouverez caché sur http://flexorg.wip3.adobe.com/blazeds/trunk/11835/blazeds-bin-4.0.0.11835.zip )
- Flash Builder 4 beta 2
Notez toutefois qu'entre la théorie et la pratique, il y a, malheureusement, quelques petites modifications (osons dire bidouillages) que vous devrez faire à cause de quelques bugs.
Vous remarquez également que nous créons un interface puis une classe l'implémentant pour le DAO et le Service, c'est dû à Spring et à son architecture (nécessité pour les @Autowired).
Création de notre projet Java
Côté serveur, nous allons créer une classe Produit (qui contient un id, un nom et un prix), un DAO qui implémentera les méthodes de base (ajout, suppression, listing, …) vers nos produits et un service que nous appellerons depuis Flex.
Produit.java
Une petite classe somme toute assez simple.
package tuto.pojo;
public class Produit
{
private Long id;
private String name;
private Double price;
public Produit()
{
}
public Long getId()
{
return id;
}
public void setId(Long id)
{
this.id = id;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public Double getPrice()
{
return price;
}
public void setPrice(Double price)
{
this.price = price;
}
}
Comme vous pouvez le voir, nous implémentons juste les méthodes get et set sur les champs de la classe. Nous laisserons Hibernate faire la magie du reste.
Pour cela, modifions notre classe pour expliquer à Hibernate quoi faire.
Tout d'abord, nous signalons que la classe Produit deviendra la table produits dans notre base de données.
@Entity
@Table(name = "produits")
public class Produit
{
Nous désignons également l'id en tant que tel, en spécifiant que Hibernate doit créer un id incrémental.
@Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(nullable = false) private Long id;
N'oubliez pas également d'ajouter la configuration dans votre fichier applicationContext.xml, à savoir
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/> <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/> <context:annotation-config /> <context:component-scan base-package="tuto"/>
Nous aurons donc une table dans notre base de données s'appelant produits, avec 3 champs dont id qui est la clé primaire de la table.
A présent, occupons nous du DAO. Cette classe sert de "pont" entre notre service et notre classe Produit. C'est ici que nous allons implémenter les méthodes pour ajouter, modifier, supprimer et lister nos produits.
Création de l'interface ProduitsDAO
public interface ProduitsDAO extends Serializable
{
void add(Produit produit);
void update(Produit produit);
void delete(Produit produit);
Collection<Produit> getAll();
}
Notre classe ProduitsDAOImpl, qui implémente ProduitsDAO, étend HibernateDaoSupport, ce qui nous permettra de récupérer la session Spring, les méthodes d'accès à la base de données, …
package tuto.dao;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import tuto.pojo.Produit;
import java.util.Collection;
@Repository("produitsDAO")
@Transactional(propagation = Propagation.REQUIRED)
public class ProduitsDAOImpl extends HibernateDaoSupport
{
@Autowired
public ProduitsDAOImpl(@Qualifier("sessionFactory") final SessionFactory sessionFactory)
{
super.setSessionFactory(sessionFactory);
}
}
Nous avons donc déclaré notre classe ProduitsDAO en tant que transactionnelle… cela nous évitera pas mal de soucis au niveau de la "session", les habitués de Spring comprendront très bien de quoi je veux parler.
Implémentons ensuite les méthodes add, update, delete et getAll.
public void add(Produit produit)
{
getHibernateTemplate().save(produit);
}
public void update(Produit produit)
{
getHibernateTemplate().update(produit);
}
public void delete(Produit produit)
{
getHibernateTemplate().delete(produit);
}
public Collection<Produit> getAll()
{
return getHibernateTemplate().loadAll(Produit.class);
}
Rien de plus simple, nous nous contentons d'appeler les méthodes de notre classe mère pour déléguer tout le boulot d'appel à la base de données.
Si nous résumons, actuellement, nous avons la classe Produit qui représente notre produit, la classe ProduitDAO qui permet d'accéder aux données de la base et les transmettre.
Nous allons donc créer notre service, avec un "lien" vers notre DAO.
Création du service ProduitsService
public interface ProduitsService
{
@RemotingInclude
void addProduit(Produit produit);
@RemotingInclude
void updateProduit(Produit produit);
@RemotingInclude
void deleteProduit(Produit produit);
@RemotingInclude
Collection<Produit> getAll();
}
Implémentant maintenant la classe en elle-même.
L'annotation @Autowired permet de préciser à Spring qu'il doit instancier cet objet automatiquement.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import tuto.dao.ProduitsDAO;
@Service("produitsService")
@Scope("singleton")
@Component
public class ProduitsServiceImpl implements ProduitsService
{
@Autowired
private ProduitsDAO produitsDAO;
public ProduitsService()
{
}
}
Implémentons donc les méthodes. Pour rappel, notre code côté Flex appelera ProduitsService. ProduitsService, quant à lui, appelera notre DAO qui chargera et listera les données de notre base.
@RemotingInclude
public void addProduit(Produit produit)
{
produitsDAO.add(produit);
}
@RemotingInclude
public void updateProduit(Produit produit)
{
produitsDAO.update(produit);
}
@RemotingInclude
public void deleteProduit(Produit produit)
{
produitsDAO.delete(produit);
}
@RemotingInclude
public Collection<Produit> getAll()
{
return produitsDAO.getAll();
}
Nous précisons, avec le @RemotingInclude que les méthodes pourront être appelées "à distance". Utilisez @RemotingExclude si vous voulez "cacher" des méthodes.
N'oubliez pas d'ajouter le service dans votre fichier remoting-config.xml (voir les tutoriaux de Fabien sur BlazeDS) de la manière suivante :
<destination id="produitsService">
<properties>
<source>tuto.service.ProduitsServiceImpl</source>
</properties>
</destination>
N'oubliez pas non plus d'ajouter la configuration vers votre base de données dans votre fichier applicationContext.xml
Comme vous pouvez le voir, la mise en place d'une telle architecture est somme toute assez simple.
Création de notre projet Flex
En créant votre projet, sélectionnez J2EE comme Application Server Yype et sélectionnez BlazeDS.

Configurez ensuite le chemin vers votre Application Server.

Premier problème, vous devriez avoir une erreur vous signalant que "Server root is not pointing to a BlazeDS server root folder."
Passez outre cette erreur et terminez le projet.
Ouvrez la vue "Data/Services" et cliquez sur "Connect to Data/Service", sélectionnez BlazeDS… et appréciez l'erreur vous disant que votre serveur n'est pas un serveur BlazeDS…
Modifiez donc votre fichier web.xml pour y ajouter le code suivant
<servlet>
<servlet-name>RDSDispatchServlet</servlet-name>
<servlet-class>flex.rds.server.servlet.FrontEndServlet</servlet-class>
<init-param>
<param-name>useAppserverSecurity</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>10</load-on-startup>
</servlet>
<servlet-mapping id="RDS_DISPATCH_MAPPING">
<servlet-name>RDSDispatchServlet</servlet-name>
<url-pattern>/CFIDE/main/ide.cfm</url-pattern>
</servlet-mapping>
Relancez votre tomcat, cela devrait passer et vous devriez avoir une fenêtre comme celle-ci

Dans cette fenêtre, vous pouvez préciser le package dans lequel vous voulez voir les classes implémentant le service et les datas.
Cliquez sur Finish. Flash Builder va vous créer tout ce qu'il vous faut pour "attaquer" votre service.

Créons donc une petite application qui va recevoir nos produits et les ajouter dans un datagrid.
Flash Builder facilite vraiment la vie des développeurs. Passez donc en "Design view", placez votre datagrid sur la scène, ensuite, "glissez-déposez" la méthode "getAll()" dans votre datagrid…
J'ai envie de dire que c'est tout… eh bien oui en fait, c'est aussi simple que ça
Testons pour voir

Bon, effectivement, c'est joli, mais ça manque de données. Flash Builder vous permet (encore) de vous simplifier la vie avec un "Test Operation" (l'icone avec la flèche et les deux engrenages dans la vue Data/Services).
Sélectionnez donc "addProduit(arg0:Produit) et cliquez sur le test.
En sélectionnant le texte "Enter Value" du produit à ajouter, vous aurez même la possibilité d'encoder votre produit sous forme d'un "Object", Flash Builder se chargera de la conversion vers la classe AS3 Produit.
{
id: 1,
price: 3.5,
name: "Mon premier produit"
}
Cliquez sur Test, la réponse devrait apparaître : "void"
Sélectionnez ensuite la méthode getAll(), cliquez sur Test

Finalement assez simple non ?
Séance bidouille
En début de tutorial, j'avais précisé qu'entre la théorie et la pratique, certaines petites choses pouvaient changer. Que ce soit un bug (ou une "feature" non terminée) de Flash Builder ou de Spring, voici les bricolages que j'ai du faire pour que cette application fonctionne réellement.
En précisant dans votre applicationContext.xml que hibernate et spring doivent se baser sur une configuration annotée et qu'il doit scanner le package "tuto", vous ne devriez pas avoir de problèmes… et pourtant, vous devrez renseigner vous-même les classes annotées, comme suit :
<bean id="sessionFactory"> <property ...>...</property> <property name="annotatedClasses"> <list> <value>tuto.Produit</value> </list> </property> </bean>
Avec notre configuration du service, nous arriverons bel et bien à appeler nos méthodes… par contre, notre dao, pourtant "Autowired" n'aura pas été initialisé.
Pour contrer ce bug (connu apparement) de Spring, nous devons modifier notre service comme tel
@Service("produitsService")
@Scope("singleton")
@Component
@RemotingDestination
public class ProduitsService
{
}
Et là ou cela devient amusant, c'est que si vous laissez votre configuration telle quelle, vous aurez une erreur de Spring au lancement de tomcat vous signalant que vous avez défini deux fois produitsService.
Pas de soucis vous direz-vous, il suffit de le supprimer de notre fichier remoting-config.xml. Effectivement, sauf qu'à ce moment, Flash Builder ne sera plus capable de trouver votre service.
Pour corriger, tout cela, j'ai été obligé de prendre mes ciseaux, un peu de colle et du scotch, et faire quelque chose de pas joli joli.
Notre fichier remoting-config.xml devient donc
<destination id="produits"> <properties> <source>tuto.service.ProduitsService</source> </properties> </destination>
Maintenant, c'est du côté de Flash Builder que vous aurez un soucis car la destination produits ne sera pas connue de Spring.
Fermez Flash Builder, ouvrez le répertoire de votre projet Flex et allez dans le répertoire .model.
Editez le fichier .fml et cherchez produits que vous remplacerez par produitsService. Oui, je sais, c'est horrible, mais au moins, cela fonctionne…
Autres Tutoriaux Flex liés:
- Flex BlazeDS – Intégration BlazeDS / Spring: le livre blanc (PDF)
- Flex HTTPService – HTTPService en ActionScript, Remote Proxy
- Flex Tips – Le Metatag Event pour déclarer la propagation d'un évènement par un composant AS / MXML
- Flash Builder 4 – Nouvelles fonctionnalités en beta sur Adobe Labs
- Flex Best Practices – MVC (Model View Controller) par l'exemple









Wouaa, j'ai pas encore testé, mais c'est bien la première fois que je vois un tuto sur un projet Flex/Java JEE avec toutes ces techno.
j'ai pas encore regardé en détail, mais j'ai qd mm envie de te poser qq questions :
-il serais possible de mettre plutot du Flex 3 au niveau client ?
-tu utilises du xml entre le client et le serveur ?
un grand merci en tt cas !
Concernant Flex 3, oui, c'est tout à fait possible de faire la même chose, à la différence qu'il n'y a pas de générateur pour les classes et que le panneau "services" pour tester les requêtes n'existe pas dans Flex 3.
Pour le transfert entre client et serveur, non, c'est de l'AMF qui est utilisé.
Hello,
Merci bcp pour ce magnifique tutoriel!
Ca fait 2 mois que je me bats pour faire marcher exactement le même projet. Et tout marche enfin depuis hier ! Donc j'ai eu ton tuto trop tard …
Les seules différences sont :
- je génére mes POJO à partir des tables MYSQL avec hibernate, j'ai donc une autre couche model qui fait le lien entre les tables et les "view bean"
- j'utilise flex 3 avec caingorm pour mieux séparer le design de l'appel au service
- Je n'utilise pas les annotations pour spécifié mes services, je fais tout en fichier de conf (sauf pour le mapping hibernate) et donc je n'ai pas eu la même bidouille que toi à faire
- Je me suis amusé, je sotcke les fichiers uploadés via amazon S3.
J'ai teste en cloud computing via amzon S2 et google app engine, ca marche nickel.
Je te rassure mon maven est du même style que le tien, j'ajoute si j'ai besoin
Merci!
Bonjour,
Merci bien pour le tutoriel, rien à dire .
SVP Pa2bra pourriez vous expliquer bien qui ce que vous avez fait avec Flex 3? je n'ai pas bien compris ce que vous avez fait avec?? merci d'avance
slt je trouve que votre tuto est tres intéressant,
bon je suis débutant en flex et j'ai kke questions à poser.
j'ai crée un projet EJB sur netbeans et je l'ai déployer sur un serveur glassfish, et en utilisant BlaseDS et flex3 je ve consommer les objets crée.
alors au début jé fais un HelloWorld
code java:
public String getMsg(String name) {
return "hello "+name;
}
code MXML :
jusqu'à mnt tt est parfait.
par example ajouter, supprimer, modifier ... .
voici mon problème :
je veux consommer mes EJB (mes services)et manipuler des objets et j'ai pas trouver comment
alors si kk1 pe m'aider et merci d'avance
Superbe tutoriel, ne serait-ce que parce que ça rassure sur le fait que ça fonctionne. Par contre pour la configuration côté server j'ai très vite été largué parce que tu fais des références un peu vagues aux tutoriels de Fabien. Est-ce qu'il te serait possible de publier ton projet tutorial en entier pour qu'on puisse s'en inspirer?
-- Merci pour l'article ! Pour ma part j'ai montré à cette adresse http://bit.ly/a05odS que les opérations de base pour la persistance des données sont toutes identiques quelques soit l’objet à sauvegarder, les méthodes en question sont celles d’un CRUD : enregistrement (Create), lecture (Read), mise à jour (Update) et suppression (Delete).
-- La plupart du temps ces méthodes sont répétées et redéfinies dans chacun des DAO de notre application, la seule différence notable est le type des objets que ces méthodes prennent en paramètre, cependant avec Java 5 et les generics pourquoi ne pas les écrire une fois pour toutes dans un DAO générique ? cela est possible et est considéré comme une bonne pratique, la redondance des données étant à éviter à tout prix.
Wow! Great article!!
Just one question about the maven part - i cant find blazeds 4 on any maven rep. where did you get it ?
Hello Laskab,
I think you need to install it by yourself.
You can proceed as follow :
Download the zip and do like that :
mvn install:install-file -Dpackaging=jar -DgroupId=com.adobe.blazeds -Dversion=4.0.0.14593 -DartifactId=blazeds-common -Dfile=flex-messaging-common.jar
mvn install:install-file -Dpackaging=jar -DgroupId=com.adobe.blazeds -Dversion=4.0.0.14593 -DartifactId=blazeds-core -Dfile=flex-messaging-core.jar
mvn install:install-file -Dpackaging=jar -DgroupId=com.adobe.blazeds -Dversion=4.0.0.14593 -DartifactId=blazeds-proxy -Dfile=flex-messaging-proxy.jar
mvn install:install-file -Dpackaging=jar -DgroupId=com.adobe.blazeds -Dversion=4.0.0.14593 -DartifactId=blazeds-remoting -Dfile=flex-messaging-remoting.jar
mvn install:install-file -Dpackaging=jar -DgroupId=com.adobe.blazeds -Dversion=4.0.0.14593 -DartifactId=blazeds-rds-server -Dfile=flex-rds-server.jar
By looking at flex-rds-server.jar manifest file, it seems it isn't a component of blazeds. I think it shouldn't be renamed in blazeds-rds-server and its version is not 4.0.0.xxxx
Here is flex-rds-server.jar manifest file :
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.7.0
Created-By: 1.5.0_15-b04 (Sun Microsystems Inc.)
Implementation-Version: 272564
Implementation-Vendor: Adobe Systems Inc.
Compared to flex-messaging-core.jar for example :
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.7.0
Created-By: 1.5.0_15-b04 (Sun Microsystems Inc.)
Sealed: false
Implementation-Title: BlazeDS - Community Edition
Implementation-Version: 4.0.0.14931
Implementation-Vendor: Adobe Systems Inc.
What do you think ?