Créer une application CRUD avec
Hibernate JSF EJB 3.0
orm.xml
persistence.xml
Si vous remarquez que le fichier faces-config.xml est inexistant, vous devez suivre ces étapes :
web.xml
Dans cet article, je vais vous montrer comment
développer une application CRUD permet d'effectuer les opérations de
listing, ajout, modification et suppression sur une entité donnée. La mise en place d'une telle
application nécessite la réalisation de deux parties essentielles, la première sera pour pouvoir effectuer les opérations CRUD sur une
source de données et une deuxième partie permet de fournir une interface graphique pour réaliser ces
opérations.
Outils :
Eclipse 3.7 (Indigo) Télécharger
JBoss 4.2 Télécharger
MySql 5.0 Télecharger
Installation et préparation d'environnement
- Installer MySQL
- Télécharger puis décompresser JBoss ensuite le copier le dans le répertoire C:/JBoss
- Télécharger puis décompresser Eclipse ensuite le copier le dans le répertoire C:/Eclipse
Maintenant, on va commencer la création de notre application. Tout d’abord, On va commencer par la création des EJB coté
serveur. Ces EJB représentent la couche métier de l’application.
Création d’un EJB Project :
Créer un nouveau projet et choisir « EJB Project ». Donner un nom à votre projet ex : JavaOnlineEJB
Après avoir entré le nom du projet, une
configuration du serveur d’application est nécessaire.
Cliquer sur new Runtime, une fenêtre s’ouvre. Spécifier le serveur d’application
à utiliser (JBoss v4.2 dans notre cas)
et la version du EJB puis cliquer sur Next.
Vérifier la version du module EJB (3.0 pour
notre cas) puis cliquer sur finish.
Maintenant, après avoir créé votre projet. Vous
devez obtenir cette arborescence :
Fichiers de configuration :
Dans ejbModule/META-INF , il faut créer deux
fichiers : orm.xml et persistence.xml
orm.xml
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm
http://java.sun.com/xml/ns/persistence/orm_1_0.xsd"
version="1.0">
</entity-mappings>
|
<?xml version="1.0"
encoding="UTF-8"?>
<persistence version="1.0"
xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="Demo">
<jta-data-source>java:/MySqlDS</jta-data-source>
<properties>
<property name="hibernate.hbm2ddl.auto" value="update" />
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"></property>
</properties>
</persistence-unit>
</persistence>
|
Création
des entités et des beans :
Créer deux package :
-
- org.formation.entity
-
- org.formation.beans
On crée maintenant les entités (une seule
classe ‘entité’ pour ce tutoriel) :
User.java
Click droite sur le package entity à new àClass
User.java
package
org.formation.entity;
import
java.io.Serializable;
import
javax.persistence.Entity;
import
javax.persistence.GeneratedValue;
import
javax.persistence.GenerationType;
import
javax.persistence.Id;
import
javax.persistence.Table;
@Entity
@Table(name="user")
public class User implements Serializable
{
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private int id;
private String name;
private String reference;
private String country;
private String login;
private String password;
private boolean state;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String
getName() {
return name;
}
public void
setName(String name) {
this.name = name;
}
public String
getReference() {
return reference;
}
public void
setReference(String reference) {
this.reference =
reference;
}
public String
getCountry() {
return country;
}
public void
setCountry(String country) {
this.country = country;
}
public String
getLogin() {
return login;
}
public void
setLogin(String login) {
this.login = login;
}
public String
getPassword() {
return password;
}
public void
setPassword(String password) {
this.password = password;
}
public boolean isState() {
return state;
}
public void setState(boolean state) {
this.state = state;
}
}
|
On crée maintenant le session bean :
Click droite sur le package
org.formation.beans à
new à Session
Bean (EJB 3.x)
Donner un nom au Bean (généralement nom de
l’entité + Bean : UserBean dans ce cas), puis cocher Remote et Local dans
‘Create business interface’. Cliquer next puis
finish.
On obtient cette arborescence :
UserBeanLocal.java
package org.formation.beans;
import java.util.List;
import javax.ejb.Local;
import
org.formation.entity.User;
@Local
public interface UserBeanLocal
{
void addUser(User user);
void
updateUser(User user);
void
deleteUser(User user);
User getById(int id);
List<User>
getlistUser();
}
|
UserBeanRemote.java
package
org.formation.beans;
import java.util.List;
import javax.ejb.Remote;
import
org.formation.entity.User;
@Remote
public interface UserBeanRemote
{
void
addUser(User user);
void updateUser(User
user);
void deleteUser(User user);
User getById(int id);
List<User>
getlistUser();
}
|
UserBean.java
package
org.formation.beans;
import java.util.List;
import
javax.ejb.Stateless;
import
javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import
org.formation.entity.User;
import org.hibernate.Criteria;
import org.hibernate.Session;
/**
* Session Bean implementation
class UserBean
*/
@Stateless
public class UserBean implements UserBeanRemote, UserBeanLocal {
@PersistenceContext(unitName="Demo")
EntityManager em;
UserBean() { }
@Override
public void
addUser(User user) {
em.persist(user);
}
@Override
public void updateUser(User
user) {
em.merge(user);
}
@Override
public void
deleteUser(User user) {
try
{
user = em.find(User.class,user.getId());
em.remove(user);
}
catch(Exception
e) {}
}
@Override
public User
getById(int id) {
return em.find(User.class,id);
}
@Override
public
List<User> getlistUser() {
Session session =
(Session) em.getDelegate();
Criteria criteria =
session.createCriteria(User.class);
List<User>
users = criteria.list();
return users;
}
}
|
Préparation
du serveur:
On ajoute le jar qui permet la connexion avec
la base des données MySql dans jboss\server\default\lib
Ensuite, on crée le fichier MySqlDS.xml et on
le place dans jboss\server\default\deploy
Mysql-ds.xml
<?xml version="1.0" encoding="UTF-8"?>
<datasources>
<local-tx-datasource>
<jndi-name>MySqlDS</jndi-name>
<connection-url>jdbc:mysql://localhost:3306/mabase</connection-url>
<driver-class>com.mysql.jdbc.Driver</driver-class>
<user-name>root</user-name>
<password>root</password>
<exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter</exception-sorter-class-name>
<metadata>
<type-mapping>mySQL</type-mapping>
</metadata>
</local-tx-datasource>
</datasources>
|
Revenant à Eclipse, cliquer sur Servers puis
ajouter un nouveau serveur :
Click droite --> New --> Server
Une fenêtre s’ouvre ‘New Server’
Cliquer sur Next deux fois.
Sélectionner JavaOnlineEJB puis cliquer sur
Add puis sur finish.
On
obtient çà:
Click droite sur JBoss v4.2 at localhost puis
start.
N.B: Vérifier la création des tables dans votre base des données.
Passons, maintenant, à la création du partie client.
Dans cette partie, on va crée la
partie client du projet. Cette partie consiste à développer les interfaces graphiques de
l’application, d’une part, c’est la couche présentation. D’autre part, on va développer
les contrôleurs qui assurent la communication entre la couche présentation et
la couche métier.
Pour commencer, on crée un nouveau projet web
sous le nom ‘JavaOnlineClient’ :
Menu >> File >> New >> Dynamic Web Project
Click next >> next >> finish.
On obtient ça:
Maintenant,
on a besoin de quelques bibliothèques nécessaires pour la création des la
couche présentation : JSF et JSTL. Donc on doit importer ces librairies.
Click droite
sur le projet >>
propreties, puis selectionner Java Build Path.
- choisir
l’onglet Libraries
- cliquer Add Library
- Une
nouvelle fenêtre s’ouvre, sélectionner User
Library puis Next
- Cliquer User Libraries puis New, ensuite donner un nom pour votre nouvelle
librairie (JSF)
-
Ensuite valider puis cliquer sur Add JARs
Importer les jar suivants : Jboss-faces.jar - jsf-api.jar - jsf-impl.jar.
Ces jar se trouvent dans JBoss\server\default\deploy\jboss-web.deployer\jsf-libs
Puis
valider.
Avec
la même méthode, on va importer le librairie JSTL ( JSP Standard Taglib).
Jstl.jar
se trouve dans JBoss\server\default\deploy\jboss-web.deployer\
Après avoir importé les bibliothèques
nécessaires, il est recommandé de créer le fichier properties.jndi.
Donc, nous devons créer un dossier nommé config dans le répertoire Java Resources
Ensuite, click droite sur le projet >> properties >> Java Build Path,
choisir l’onglet source.
Click Add
Folder puis sélectionner config puis valider.
Création du fichier jndi.properties :
jndi.properties
# DO NOT EDIT THIS FILE UNLESS YOU KNOW WHAT YOU ARE DOING
#
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=localhost:1099
|
Développement
des contrôleurs
Maintenant, on va créer le contrôleur UserManagedBean.java.
On crée donc la classe UserManagedBean.java
dans le répertoire src sous le
package org.formation.managedBean.
On obtient :
UserManagedBean.java
package
org.formation.managedBean;
import java.util.List;
import
javax.faces.application.FacesMessage;
import
javax.faces.context.FacesContext;
import
javax.naming.Context;
import
javax.naming.InitialContext;
import
org.formation.beans.UserBeanRemote;
import
org.formation.entity.User;
public class UserManagedBean
{
int id;
private String name;
private String reference;
private String country;
private String login;
private String password;
private String confirmPwd;
private List<User> listUser;
private String destination;
public User user;
public String
active()
{
if(user.isState())
{
user.setState(false);
}
else
{
user.setState(true);
}
try
{
Context ctx = new InitialContext();
UserBeanRemote userBean = (UserBeanRemote)
ctx.lookup("UserBean/remote");
userBean.updateUser(user);
return "lista";
}
catch(Exception
e)
{
e.printStackTrace();
return null;
}
}
public String
update()
{
try
{
Context ctx = new InitialContext();
UserBeanRemote userBean = (UserBeanRemote)
ctx.lookup("UserBean/remote");
userBean.updateUser(user);
}
catch(Exception e)
{
e.printStackTrace();
}
return "updated";
}
public String
edit()
{
return destination;
}
public String
add()
{
User user = new User();
user.setCountry(this.country);
user.setName(this.name);
user.setReference(this.reference);
user.setLogin(this.login);
user.setPassword(this.password);
user.setState(false);
if(!password.equals(confirmPwd))
{
FacesContext facesContext = FacesContext.getCurrentInstance();
FacesMessage facesMessage = new
FacesMessage("Confirmation Failed
!!");
facesContext.addMessage(null,facesMessage);
return null;
}
try
{
Context ctx = new InitialContext();
UserBeanRemote userBean = (UserBeanRemote)
ctx.lookup("UserBean/remote");
userBean.addUser(user);
}
catch(Exception
e)
{
e.printStackTrace();
}
return "success";
}
public String
delete()
{
try
{
Context ctx = new InitialContext();
UserBeanRemote userBean =
(UserBeanRemote) ctx.lookup("UserBean/remote");
user = userBean.getById(user.getId());
userBean.deleteUser(user);
return "deleted";
}
catch (Exception
e)
{
e.printStackTrace();
return null;
}
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String
getName() {
return name;
}
public void
setName(String name) {
this.name = name;
}
public String
getReference() {
return reference;
}
public void
setReference(String reference) {
this.reference =
reference;
}
public String
getCountry() {
return country;
}
public void
setCountry(String country) {
this.country = country;
}
public String
getLogin() {
return login;
}
public void
setLogin(String login) {
this.login = login;
}
public String
getPassword() {
return password;
}
public void
setPassword(String password) {
this.password = password;
}
public String
getConfirmPwd() {
return confirmPwd;
}
public void
setConfirmPwd(String confirmPwd) {
this.confirmPwd =
confirmPwd;
}
public
List<User> getListUser() {
try
{
Context ctx = new InitialContext();
UserBeanRemote userBean =
(UserBeanRemote) ctx.lookup("UserBean/remote");
return userBean.getlistUser();
}
catch(Exception
e)
{
e.printStackTrace();
return null;
}
}
public void
setListUser(List<User> listUser) {
this.listUser = listUser;
}
public User
getUser() {
return user;
}
public void
setUser(User user) {
this.user = user;
}
public String
getDestination() {
return destination;
}
public void
setDestination(String destination) {
this.destination = destination;
}
}
|
Dans le répertoire WebContent, nous devons
avoir cette structure :
Si vous remarquez que le fichier faces-config.xml est inexistant, vous devez suivre ces étapes :
-
- Click droite sur le projet >> properties
-
- Sélectionner Project Facets
-
- Cocher JavaServer Faces version 1.2
Faces-config.xml
<?xml version="1.0"
encoding="UTF-8"?>
<faces-config
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd"
version="1.2">
<managed-bean>
<managed-bean-name>userManagedBean</managed-bean-name>
<managed-bean-class>org.formation.managedBean.UserManagedBean</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
</faces-config>
|
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<display-name>JavaOnlineClient</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/faces/*</url-pattern>
</servlet-mapping>
<context-param>
<description>State saving method: 'client' or
'server' (=default). See JSF Specification 2.5.2</description>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>client</param-value>
</context-param>
<context-param>
<param-name>javax.servlet.jsp.jstl.fmt.localizationContext</param-name>
<param-value>resources.application</param-value>
</context-param>
<listener>
<listener-class>com.sun.faces.config.ConfigureListener</listener-class>
</listener>
</web-app>
|
On va faire
un petit test. Créer un fichier index.html dans le répertoire WebContent :
Index.html
<!DOCTYPE html
PUBLIC "-//W3C//DTD
HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type"
content="text/html; charset=ISO-8859-1">
<title>Java Online </title>
</head>
<body>
<h1>My First Application Java Online ...</h1>
</body>
</html>
|
Résultat :
Maintenant
on va importer JavaOnlineEJb à JavaOnlineClient, Click droite
sur le projet >>
properties >>Java
Build Path. Sélectionner
l’onglet Projects >>
Add >> cocher
JavaOnlineEJB puis valider
On crée
maintenant les fichiers suivants dans le répertoire WebContent:
addUser.jsp
<%@taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<%@taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<%@ page language="java" contentType="text/html;
charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<!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>Java Online - Add User</title>
</head>
<body>
<f:view>
<h2>Java Online From Tunisia </h2>
<h3> Add New User </h3>
<br><br>
<h:messages/>
<h:form>
<h:inputHidden value="#{userManagedBean.id}"></h:inputHidden>
<h:panelGrid border="0" columns="2"
cellpadding="5" cellspacing="3">
<h:outputText value="Name"></h:outputText>
<h:inputText value="#{userManagedBean.name}" size="25" maxlength="45"
required="true" requiredMessage="Champs
obligatoire !"
validatorMessage="between 5 and 45 letters">
<f:validateLength maximum="45" minimum="5"></f:validateLength>
</h:inputText>
<h:outputText value="Reference" ></h:outputText>
<h:inputText value="#{userManagedBean.reference}" size="25" maxlength="45"
required="true" requiredMessage="Champs
obligatoire !"
validatorMessage="between 5 and 45 letters">
<f:validateLength maximum="45" minimum="5"></f:validateLength>
</h:inputText>
<h:outputText value="Country"></h:outputText>
<h:inputText value="#{userManagedBean.country}" size="25" maxlength="45"
required="true" requiredMessage="Champs
obligatoire !"
validatorMessage="between 5
and 45 letters">
<f:validateLength maximum="45" minimum="5"></f:validateLength>
</h:inputText>
<h:outputText value="Login"></h:outputText>
<h:inputText value="#{userManagedBean.login}" size="25"
maxlength="15" ></h:inputText>
<h:outputLabel value="Password : " for="pwd" />
<h:inputSecret label="Password" id="pwd" value="#{userManagedBean.password}" size="25"
maxlength="15" required="true"
redisplay="true" />
<h:outputLabel value="Confirm password : " for="confPwd" />
<h:inputSecret label="ConfPassword" id="confPwd" value="#{userManagedBean.confirmPwd}" size="25"
maxlength="15" required="true"
redisplay="true" />
</h:panelGrid>
<h:commandButton action="#{userManagedBean.add}" value="Add"></h:commandButton>
</h:form>
</f:view>
</body>
</html>
|
listUser.jsp
<%@taglib uri="http://java.sun.com/jsf/core"
prefix="f"%><%@taglib
uri="http://java.sun.com/jsf/html"
prefix="h"%><%@
page language="java"
contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!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>Java Online - List User</title>
<STYLE type="text/css">
<!--
.titre {
background-color:#CCCCFF;
color:#FFFFFF;
}
.paire {
background-color:#EFEFEF;
}
.impaire {
background-color:#CECECE;
}
-->
</STYLE>
</head>
<body>
<h2>Java Online From Tunisia </h2>
<h3> list User </h3>
<f:view>
<h:form>
<h:dataTable value="#{userManagedBean.listUser}" var="user"
border="0" rules="rows"
cellpadding="3"
cellspacing="10" rowClasses="paire,impaire"
headerClass="titre" >
<br/><br/>
<f:facet name="header">list ...</f:facet>
<f:facet name="footer">end list</f:facet>
<h:column id="state">
<f:facet name="header">
<h:outputText value="State" />
</f:facet>
<h:commandLink action="#{userManagedBean.active}">
<h:graphicImage value="resources/img/state_#{user.state}.png" style="border:0"></h:graphicImage>
<f:setPropertyActionListener target="#{userManagedBean.user}" value="#{user}"></f:setPropertyActionListener>
</h:commandLink>
</h:column>
<h:column id="Id">
<f:facet name="header" >
<h:outputText value="Id" />
</f:facet>
<h:outputText value="#{user.id}"/>
</h:column>
<h:column id="name">
<f:facet name="header">
<h:outputText value="Name"/>
</f:facet>
<h:outputText value="#{user.name}"/>
</h:column>
<h:column id="ref">
<f:facet name="header">
<h:outputText value="Reference"/>
</f:facet>
<h:outputText value="#{user.reference}"/>
</h:column>
<h:column id="country">
<f:facet name="header">
<h:outputText value="Country"/>
</f:facet>
<h:outputText value="#{user.country}"/>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="Edit"></h:outputText>
</f:facet>
<h:commandLink action="#{userManagedBean.edit}">
<h:graphicImage value="resources/img/edit.png" style="border:0"></h:graphicImage>
<f:setPropertyActionListener target="#{userManagedBean.user}" value="#{user}"></f:setPropertyActionListener>
<f:setPropertyActionListener target="#{userManagedBean.destination}" value="modif"></f:setPropertyActionListener>
</h:commandLink>
</h:column>
<h:column id="Delete">
<f:facet name="header">
<h:outputText value="Edit"/>
</f:facet>
<h:commandLink action="#{userManagedBean.delete}">
<h:graphicImage value="resources/img/delete.png" style="border:0"></h:graphicImage>
<f:setPropertyActionListener target="#{userManagedBean.user}" value="#{user}" />
</h:commandLink>
</h:column>
</h:dataTable>
</h:form>
</f:view>
</body>
</html>
|
editUser.jsp
<%@taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<%@taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<%@ page language="java" contentType="text/html;
charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<!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>Java Online - Add User</title>
</head>
<body>
<f:view>
<h2>Java Online From Tunisia </h2>
<h3> Edit User </h3>
<br><br>
<h:messages/>
<h:form>
<h:inputHidden value="#{userManagedBean.user.id}"></h:inputHidden>
<h:panelGrid border="0" columns="2"
cellpadding="5" cellspacing="3">
<h:outputText value="Name"></h:outputText>
<h:inputText value="#{userManagedBean.user.name}" size="25" maxlength="45"
required="true" requiredMessage="Champs
obligatoire !"
validatorMessage="between 5 and 45 letters">
<f:validateLength maximum="45" minimum="5"></f:validateLength>
</h:inputText>
<h:outputText value="Reference" ></h:outputText>
<h:inputText value="#{userManagedBean.user.reference}" size="25" maxlength="45"
required="true" requiredMessage="Champs
obligatoire !"
validatorMessage="between 5 and 45 letters">
<f:validateLength maximum="45" minimum="5"></f:validateLength>
</h:inputText>
<h:outputText value="Country"></h:outputText>
<h:inputText value="#{userManagedBean.user.country}" size="25" maxlength="45"
required="true" requiredMessage="Champs
obligatoire !"
validatorMessage="between 5
and 45 letters">
<f:validateLength maximum="45" minimum="5"></f:validateLength>
</h:inputText>
</h:panelGrid>
<h:commandButton action="#{userManagedBean.update}" value="Update"></h:commandButton>
</h:form>
</f:view>
</body>
</html>
|
great job men !!!
RépondreSupprimeri haven't try it yet but i think it will b quite useful.
Thanks any way.
je suis un étudiant débutant je avoir le code source merci d'avance
RépondreSupprimer---email: msalahkarzout@gmail.com