
La FAQ Java EEConsultez toutes les FAQ
Nombre d'auteurs : 27, nombre de questions : 83, dernière mise à jour : 26 avril 2013
Sommaire→Servlets→Généralités- Pourquoi n'y a-t-il pas de constructeur dans une servlet ?
- Quelle est la différence entre les méthodes doGet() et doPost() ?
- Comment gérer les caractères spéciaux dans une servlet ?
- Comment connaitre la version de l'API servlet utilisée par un moteur de servlet ?
- Comment accéder à un JavaBean depuis une servlet ?
- Quel est l'objet ServletConfig et quelle est son utilité ?
- Comment modifier le Time Out par défaut de session ?
- Comment modifier le Time Out par de session par programmation ?
- Comment connaître le navigateur utilisé par un utilisateur
- Comment placer et récupérer un paramétre d'initialisation d'une servlet ?
- Comment uploader un fichier depuis une applet vers une servlet ?
- Comment télécharger un fichier depuis une servlet ?
- Comment faire pour gérer des actions à effectuer lors de la création ou suppression de session ?
- Comment faire pour gérer des actions à effectuer lors du démarrage ou de l'arrêt de l'application ?
- Comment récupérer le nom associé au contexte d'une application Web ?
- Comment faire apparaître un fichier (PDF, XLS, CSV, ...) dans mon navigateur ?
- Comment accéder à une ressource dans l'arborescence d'une application web depuis une servlet ?
- Comment donner un type MIME standard compréhensible par tous les navigateurs ?
- Comment obtenir une instance de PageContext dans une Servlet ?
- Qu'est ce que le pattern Transfer Object ?
Une servlet est un peu comme un applet par le fait qu'elle possède une méthode init() qui agit en tant que constructeur. Puisque l'environnement de servlet prend soin d'instancier la servlet, un constructeur explicite n'est pas nécessaire. N'importe quel code d'initialisation que vous devez utiliser devrait être placé dans la méthode init() puisque cette méthode est appelée lorsque le servlet est chargée par le conteneur de servlet.
doGet() est appelée à la suite d'une requête de type HTTP GET. Cela se passe généralement lorsqu'un utilisateur clique sur un lien ou lorsque celui-ci entre une URL dans la barre d'adresse du navigateur.
La méthode doPost() est appelée en réponse d'une requête HTTP POST.
Les 2 méthodes sont appelées à partir de l'implémentation par défaut de la méthode service() se trouvant dans la classe de base HttpServlet
Fondamentalement le navigateur demande toujours des pages par l'intermédiaire de GET et peut envoyer des données sous les 2 formes GET et POST. Les 2 seules différences résident dans le fait que :
- GET est restreint au niveau de la taille des paramètres envoyés au serveur. Cela veut dire qu'il est, la plupart du temps, préférable d'envoyer des données avec la méthode POST.
- En envoyant des données par l'intermédiaire de GET évoque également une question concernant la sécurité puisqu'elles sont ajoutées à la suite de l'URL. Pour cette raison il est plus prudent d'utiliser la méthode POST pour envoyer des données au serveur.
Les caractères spéciaux sont souvent une cause de problème lors de l'utilisation des servlets.
Même si nous déclarons (l'UTF-8 par exemple) dans nos pages servlets et jsps, on peut voir apparaître les caractères spéciaux non gérer.
Pour ce faire, il suffit de faire une vérification comme suit :
String encoding = request.getCharacterEncoding();
if (encoding == null || !encoding.equals("UTF-8")) {
try {
request.setCharacterEncoding("UTF-8");
} catch (UnsupportedEncodingException e) {
System.err.println("HttpMultipartRequest - : " + e);
}
}
Une autre façon de faire est de configurer l'encodage au niveau du fichier web.xml au moyen d'un Filter :
<filter>
<filter-name>Character Encoding</filter-name>
<filter-class>chemin.de.ton.package.CharsetFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>Character Encoding</filter-name>
<servlet-name>action</servlet-name>
</filter-mapping>
Puis d'implémenter un filtre UTF-8 :
/**
* Filtre sur les requetes pour les encoder en UTF-8
*/
public class CharsetFilter implements Filter{
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
request.setCharacterEncoding("UTF-8");
chain.doFilter(request,response);
}
@Override
public void init(FilterConfig arg0) throws ServletException {}
@Override
public void destroy() {}
}
L'interface ServletContext inclut les méthodes getMajorVersion() et getMinorVersion() pour vous indiquer quelle version de l'API Servlet est utilisée.
Un petit exemple :
//Si le moteur de servlet implémente la spec 2.4 de l'API servlet
//majorVersion est égal à 2
int majorVersion = getServletContext().getMajorVersion();
//minorVersion est égal à 4
int minorVersion = getServletContext().getMinorVersion();
Pour pouvoir partager des variables entre vos pages JSP et vos servlets, vous devez savoir comment créer et accéder à ces variables depuis vos servlets.
Les différents exemples qui vont suivre dépendent de la portée, ou si vous préferez, la durée de vie de vos objets.
Pour en savoir plus sur les différentes portées existantes, reportez vous à la section suivante : Quelles sont les différentes portées existantes ?
- page :
Dans cet exemple, le Bean est instancié comme une variable locale est n'est donc pas partageable entre différentes servlets.
com.developpez.beans.MyBean myBean = new com.developpez.beans.MyBean();
- request :
Dans cet exemple, le Bean instancié sera accessible pendant toute la durée de la requête
com.developpez.beans.MyBean myBean = (com.developpez.beans.MyBean) request.getAttribute("myBean");
if (myBean == null) {
myBean = new com.developpez.beans.MyBean();
request.setAttribute("myBean", myBean);
}
- session :
Dans cet exemple, lorsque le Bean est instancié il est placé dans la session actuelle.
HttpSession session = request.getSession(true);
com.developpez.beans.MyBean myBean = (com.developpez.beans.MyBean) session.getAttribute("myBean");
if (myBean == null) {
myBean = new com.developpez.beans.MyBean();
session.setAttribute("myBean", myBean);
}
- application :
Dans ce dernier exemple, lorsque le Bean est instancié il est placé dans le contexte de la servlet.
com.developpez.beans.MyBean myBean = (com.developpez.beans.MyBean) getServletContext().getAttribute("myBean");
if (myBean == null) {
myBean = new com.developpez.beans.MyBean();
getServletContext().setAttribute("counter", counter);
}
L'objet ServletConfig est une interface. Cette interface contient les 4 méthodes suivantes
- getInitParameter(java.lang.String name) : Cette méthode retourne un String contenant le paramètre d'initialisation de la servlet correspondant au paramètre name
- getInitParameterNames() : Cette méthode retourne un objet Enumération contenant les paramètres d'initialisation de la servlet
- getServletContext() : Cette méthode retourne une référence de l'interface ServletContext
C'est la méthode la plus valable car elle permet de partager l'information à travers l'application - getServletName() : Cette méthode retourne un String contenant le nom de l'instance de la servlet
Dans le fichier web.xml situé dans le répertoire WEB-INF de l'application, il suffit d'ajouter les lignes suivantes :
<session-config>
<session-timeout>60</session-timeout>
</session-config>
Il suffit d'accèder à la session voulue et de la modifier comme ceci :
request.getSession().setMaxInactiveInterval(int);
Cette information peut être retrouvée dans le header de la requête:
String browser = request.getHeader("user-agent");
Placer la définition <init-param> dans la description de votre servlet dans le fichier web.xml comme ceci
<servlet>
<servlet-name>maServlet</servlet-name>
<display-name>Ma Servlet</display-name>
<description>Ce que fait ma servlet</description>
<servlet-class>com.servlet.MaServlet</servlet-class>
<init-param>
<param-name>MON_PARAM</param-name>
<param-value>Bonjour</param-value>
</init-param>
</servlet>
Puis dans le code de votre servlet, utilisez ceci pour récupérer la valeur de MON_PARAM
getInitParameter("MON_PARAM");
Si vous désirez mettre plus de paramétres, il suffit d'ajouter des déclarations <init-param> comme ceci
<servlet>
<servlet-name>maServlet</servlet-name>
<display-name>Ma Servlet</display-name>
<description>Ma Servlet</description>
<servlet-class>com.servlet.MaServlet</servlet-class>
<init-param>
<param-name>MON_PARAM</param-name>
<param-value>Bonjour</param-value>
</init-param>
<init-param>
<param-name>MON_PARAM_2</param-name>
<param-value>Bonjour</param-value>
</init-param>
</servlet>
Si vous désirez mettre des paramètres de manière globale afin de pouvoir les récupérer dans toutes les servlets, il suffit d'ajouter <context-param> comme ceci
<webapp>
...
<context-param>
<param-name>Author</param-name>
<param-value>X-plode</param-value>
</context-param>
</webapp>
Puis dans le code de votre servlet, il faut récupérer le contexte de la servlet et appeler la méthode getInitParameter comme la manière précédente pour récupérer la valeur de Author
getServletContext().getInitParameter("MON_PARAM");
Coté applet :
URL urlservlet = new URL("http://localhost:8080/imed/ImageMapServlet");
HttpURLConnection connExtension = (HttpURLConnection)urlservlet.openConnection();
FileInputStream in = new FileInputStream(image);
in.read(tableauImage);
in.close();
HttpURLConnection connImage = (HttpURLConnection)urlservlet.openConnection();
connImage.setDoInput(true);
connImage.setDoOutput(true);
connImage.setUseCaches(false);
connImage.setRequestProperty("Content-Type","application/octet-stream");
DataOutputStream out = new DataOutputStream(connImage.getOutputStream());
out.write(tableauImage, 0, tableauImage.length);
out.flush();
out.close();
Coté servlet
// Récupération du flux entrant
java.io.DataInputStream dis = new java.io.DataInputStream(request.getInputStream());
dis.readFully(temp);
dis.close();
// Ecriture du fichier image sur le serveur
File cibleServeur = new File("/repertoire/nomfichier");
FileOutputStream fos = new FileOutputStream(cibleServeur);
fos.write(temp);
fos.close();
Voici un exemple de code permettant de télécharger un fichier depuis le serveur vers le poste client
response.setContentType("application/download");
response.setHeader("Content-Disposition", "attachment;filename=\"" + filename + "\"");
ServletOutputStream out = response.getOutputStream();
File file = null;
BufferedInputStream from = null;
try {
file = new File(filepath);
response.setContentLength((int) file.length());
int bufferSize = 64 * 1024;
from = new BufferedInputStream(new FileInputStream(file), bufferSize * 2);
byte[] bufferFile = new byte[bufferSize];
for (int i = 0; ; i++) {
int len = from.read(bufferFile);
if (len < 0) {
break;
}
out.write(bufferFile, 0, len);
}
out.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (from != null) {
try {
from.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (out != null) {
try {
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (file != null) {
try {
file.delete();
} catch (Exception e) {
e.printStackTrace();
}
}
}
En implémentant l'interface HttpSessionListener comme ceci
package com.dvp.faq.javaee;
import javax.servlet.http.HttpSessionListener;
import javax.servlet.http.HttpSessionEvent;
public class MyHttpSessionListener implements HttpSessionListener {
/** Cette méthode est appelée lors de la création de session */
public void sessionCreated(HttpSessionEvent hse){
System.out.println("Une session vient d'être créée");
}
/** Cette méthode est appelée lors de la destruction de session*/
public void sessionDestroyed(HttpSessionEvent hse) {
System.out.println("Une session vient d'être détruite");
}
}
Ensuite, il suffit de référencer le listener dans le fichier web.xml (sous la balise racine)
<web-app>
<listener>
<listener-class>
com.dvp.faq.javaee.MyHttpSessionListener
</listener-class
</listener>
</web-app>
En implémentant l'interface ServletContextListener comme ceci
package com.dvp.faq.javaee;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletContextEvent;
public class MyHttpServletContextListener implements ServletContextListener {
/** Cette méthode appelée lors du démarrage de l'application*/
public void contextInitialized(ServletContextEvent sce) {
System.out.println("L'application vient de démarrer");
}
/** Cette méthode appelée lors de l'arret de l'application*/
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("L'application vient de s'arreter");
}
}
Ensuite, il suffit de référencer le listener dans le fichier web.xml (sous la balise racine)
<web-app>
<listener>
<listener-class>
com.dvp.faq.javaee.MyHttpServletContextListener
</listener-class>
</listener>
</web-app>
A l'aide de l'interface HttpServletRequest
String contextPath = request.getContextPath();
De base, le navigateur va tenter d'afficher la page directement selon le flux de données qu'il reçoit. Dans le cas d'un fichier PDF par exemple, les données ne sont pas du tout affichables en l'état par le navigateur. C'est pourquoi, il faut indiquer au navigateur le type de fichier qu'on lui envoie. Pour cela, il faut modifier le content-type de la réponse :
response.setContentType("application/pdf");
Dans ce cas-là, le navigateur comprendra que le fichier retourné est un fichier PDF et agira en conséquence.
Il est également possible de modifier le nom du fichier en ajoutant une entête à la réponse :
response.setHeader("Content-disposition", "filename=monNomDeFichier");
Pour accéder à une ressource depuis une servlet, il faut passer par l'interface ServletContext. Plus exactement la methode : getRealPath(String relativePath).
Cette methode recherche depuis la racine de l'application web le fichier passé en paramètre sous forme d'un chemin relatif.
Voici un exemple d'implementation :
La ressource à laquelle on veut accéder : le fichier de propriété test.properties
clef1=hello World
Emplacement du fichier dans l'application web :
ROOT_WEB_APP
___files
______test.properties
___WEB-INF
Voila le code la servlet :
public class TestServlet extends HttpServlet {
private static final String KEY = "clef1";
private static final String RELATIVE_PATH_FILE= "files/test.properties";
protected void doGet(HttpServletRequest arg0, HttpServletResponse arg1) throws ServletException, IOException {
super.doGet(arg0, arg1);
}
protected void service(HttpServletRequest arg0, HttpServletResponse arg1) throws ServletException, IOException {
InputStream in = null;
ServletContext context = getServletContext();
System.out.println("Affichage du chemin absolue du fichier via la methode getRealPath(String");
System.out.println(context.getRealPath(RELATIVE_PATH_FILE));
String path = context.getRealPath("files/test.properties");
if (path != null){
in = new FileInputStream(path);
}
Properties prop = new Properties();
prop.load(in);
String result = prop.getProperty(KEY);
arg1.setContentType("text/html");
Writer writer = arg1.getWriter();
writer.write("Résultat : " + result);
writer.flush();
}
}
Remarque : Le chemin relatif déterminé par la variable RELATIVE_PATH_FILE doit être relatif à la racine de l'application web
Le résultat à l'affichage sera :
Résultat : hello World
La méthode getResourcePaths() permet de lister tous les fichiers contenu dans l'application web.
Certains types MIME (Content-Type) ne sont pas reconnus par tous les navigateurs, il est possible de passer par un type MIME Standard que tout navigateur comprend :
response.setContentType ("application/octet-stream");
response.setHeader ("Content-Disposition", "attachment; filename=nom_du_fichier");
Le navigateur va donc lancer le téléchargement du fichier.
Il faut utiliser la classe JspFactory et sa méthode getPageContext() pour créer une nouvelle instance de PageContext. Mais attention car tout les PageContext créés de la sorte doivent être libérés par la méthode releasePageContext() :
Voici la structure à utiliser pour utiliser PageContext :
JspFactory jspFactoty = JspFactory.getDefaultFactory();
PageContext pageContext = jspFactoty.getPageContext(
this, // La Servlet
request, // Le request courant
response, // La réponse courante
null, // La page de redirection d'erreur (null si aucune)
true, // Utilise la session
PageContext.NO_BUFFER, // Pas de buffer
false ); // pas d'autoflush
try {
// Utilisation du PageContext
} finally {
// Libération du PageContext
jspFactoty.releasePageContext(pageContext);
}
Le pattern transfer Object précédemment appelé Value Object est une classe implémentant l'interface Serializable.
Ce pattern est essentiellement utilisé pour échanger des données entre une application cliente et des EJB de type Entity (EntityBean).
Pourquoi me direz-vous ?
Tout simplement parce que, comme vous le savez, les EntityBean comme tous les EJB sont des objets distants, ce qui induit, pour chaque accès à celui-ci, un aller-retour à travers le réseau, avec
en plus démarrage/validation de transactions.
Par exemple, pour lire un objet Personne avec 5 attributs, il vous faudra 6 allers-retours pour récupérer vos informations (1 findByPrimaryKey + 5 lectures d'attribut).
C'est pour cette raison que les Transfer Object sont là.
les EntityBean ne sont là que pour être utilisé sur le serveur EJB (dans les EJB 2.0, ils sont maintenant "local", ils ne peuvent pas être accessible de l'exterieur). L'idée est de fournir un
service avec des EJB stateless qui vont vous fournir les service qui vous intéressent (Lecture/création/modification/suppression ... d'un objet). Cet EJB utilise des Entity en interne pour faire
les opérations, et créer des classes de transport (avec uniquement les attributs + get/set), cette classe doit implémenter
Serializable
pour pouvoir passer sur RMI/IIOP. C'est cette classe que l'on appelle Transfer Object
L'avantage de ce modèle, c'est avoir une programmation distante (N tiers) avec le transit de veritables objets que vous allez pouvoir manipuler puis renvoyer au serveur pour modification... .
Voici un petit exemple qui venir étayer la partie théorique.
Entity Bean :
L'interface Local
package com.societe.monserveur;
import javax.ejb.EJBLocalObject;
/**
* Classe d'accès à une entité.
* L'accès est local, cette classe n'est pas accessible depuis l'exterieur.
*/
public interface PersonneEJBCMP extends EJBLocalObject {
public java.lang.Integer getCodePersonne();
public java.lang.String getNom();
public void setNom(java.lang.String nom);
}
L'interface Home
package com.societe.monserveur;
import javax.ejb.CreateException;
import javax.ejb.EJBLocalHome;
import javax.ejb.FinderException;
/**
* Home (Factory) de l' Entité CMP
*/
public interface PersonneEJBCMPHome extends EJBLocalHome {
public PersonneEJBCMP create(java.lang.Integer codePersonne) throws CreateException;
public PersonneEJBCMP create(java.lang.Integer codePersonne, java.lang.String nom) throws CreateException;
public PersonneEJBCMP findByPrimaryKey(java.lang.Integer codePersonne) throws FinderException;
}
Le Bean
package com.societe.monserveur;
import javax.ejb.CreateException;
import javax.ejb.EntityBean;
import javax.ejb.EntityContext;
import javax.ejb.RemoveException;
/**
* Implémentation de l'entité CMP
*/
public abstract class PersonneEJBCMPBean implements EntityBean {
EntityContext entityContext;
public abstract java.lang.Integer getCodePersonne();
public abstract void setCodePersonne(java.lang.Integer codePersonne);
public abstract java.lang.String getNom();
public abstract void setNom(java.lang.String nom);
public java.lang.Integer ejbCreate(java.lang.Integer codePersonne) throws CreateException {
setCodePersonne(codePersonne);
return null;
}
public java.lang.Integer ejbCreate(java.lang.Integer codePersonne, java.lang.String nom) throws CreateException {
setCodePersonne(codePersonne);
setNom(nom);
return null;
}
public void ejbPostCreate(java.lang.Integer codePersonne) throws CreateException { }
public void ejbPostCreate(java.lang.Integer codePersonne, java.lang.String nom,
java.lang.String prenom, java.lang.Integer age, java.lang.Integer codeEntreprise)
throws CreateException { }
public void ejbLoad() { }
public void ejbStore() { }
public void ejbRemove() throws RemoveException { }
public void ejbActivate() { }
public void ejbPassivate() { }
public void setEntityContext(EntityContext entityContext) {
this.entityContext = entityContext;
}
public void unsetEntityContext() {
this.entityContext = null;
}
}
Le SessionBean
L'interface Home
package com.societe.monserveur;
import java.rmi.RemoteException;
import javax.ejb.CreateException;
import javax.ejb.EJBHome;
public interface PersonneEJBFacadeHome extends EJBHome {
public PersonneEJBFacade create() throws RemoteException, CreateException;
}
L'interface Remote
package com.societe.monserveur;
import java.rmi.RemoteException;
import javax.ejb.EJBObject;
public interface PersonneEJBFacade extends EJBObject {
public void insert(Personne obj) throws RemoteException;
public void update(Personne obj) throws RemoteException;
public void delete(Personne obj) throws RemoteException;
public Personne findObject(Integer codePersonne) throws RemoteException;
}
Le Bean
package com.societe.monserveur;
import javax.ejb.EJBException;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class PersonneEJBFacadeBean implements SessionBean {
private SessionContext sessionContext;
public void ejbCreate() { }
public void ejbRemove() { }
public void ejbActivate() { }
public void ejbPassivate() { }
public void setSessionContext(SessionContext sessionContext) {
this.sessionContext = sessionContext;
}
public void insert(Personne obj) {
try {
getCMPHome().create(obj.getCodePersonne(), obj.getNom());
} catch (Exception ex) {
throw new EJBException(ex);
}
}
public void update(Personne obj) {
try {
PersonneEJBCMP personneEJBCMP = getCMPHome().findByPrimaryKey(obj.getCodePersonne());
personneEJBCMP.setNom(obj.getNom());
} catch (Exception ex) {
throw new EJBException(ex);
}
}
public void delete(Personne obj) {
try {
getCMPHome().remove(obj.getCodePersonne());
} catch (Exception ex) {
throw new EJBException(ex);
}
}
public Personne findObject(Integer codePersonne) {
try {
PersonneEJBCMP personneEJBCMP = getCMPHome().findByPrimaryKey( codePersonne);
Personne obj = new Personne(personneEJBCMP.getCodePersonne(), personneEJBCMP.getNom());
return obj;
} catch (Exception ex) {
throw new EJBException(ex);
}
}
public static PersonneEJBCMPHome getCMPHome() throws NamingException {
Context ctx = new InitialContext();
PersonneEJBCMPHome personneEJBCMPHome =
(PersonneEJBCMPHome) ctx.lookup("com/societe/monserveur/PersonneEJBCMP");
return personneEJBCMPHome;
}
}
Le Transfer Object
package com.societe.monserveur;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.rmi.PortableRemoteObject;
/**
* Value Object Personne
*/
public class Personne implements java.io.Serializable {
private Integer codePersonne;
private String nom;
/** Constructeur sans argument */
public Personne() {
super();
}
/**
* Constructeur avec arguments
*/
public Personne(Integer codePersonne, String nom) {
this.codePersonne = codePersonne;
this.nom = nom;
}
/**
* Rechercher un objet à partir de son identifiant
* @return L'objet trouvé
*/
public static Personne findObject(Integer codePersonne) throws Exception {
return getFacade().findObject(codePersonne);
}
/** Insertion de l'objet dans la base */
public void insert() throws Exception {
getFacade().insert(this);
}
/** Modification de l'objet dans la base */
public void update() throws Exception {
getFacade().update(this);
}
/** Suppression de l'objet dans la base */
public void delete() throws Exception {
getFacade().delete(this);
}
/**
* Getter / Setter
*/
public Integer getCodePersonne() {
return codePersonne;
}
public void setCodePersonne(Integer codePersonne) throws Exception {
this.codePersonne = codePersonne;
}
public String getNom() { return nom; }
public void setNom(String nom) throws Exception {
this.nom = nom;
}
/**
* Récupération de l'EJB facade
* @return la facade
*/
private static PersonneEJBFacade getFacade() throws Exception {
Context ctx = new InitialContext();
Object ref = ctx.lookup("com/societe/monserveur/PersonneEJBFacade");
PersonneEJBFacadeHome personneEJBFacadeHome =
(PersonneEJBFacadeHome) PortableRemoteObject.narrow(ref, PersonneEJBFacadeHome.class);
return personneEJBFacadeHome.create();
}
}
Et enfin le Client
package com.societe.monclient;
import com.societe.monserveur.Personne;
public class Test {
public static void main(String[] args) throws Exception {
//Création de toto
Personne toto = new Personne(new Integer(1), "Toto");
toto.insert();
//Modification de toto
toto.setNom("Titi");
toto.update();
//Suppression de toto
toto.delete();
//Récupération d'une autre personne
Personne autre = Personne.findObject(new Integer(99));
}
}
L'avantage avec cette solution (EJB + VO) c'est que l'accès et les régles de gestion sont centralisés sur un seul serveur. Si une autre application (back office) ou un autre serveur web, veut accèder à la même information, il pourra réutiliser tout cela.


















