Post on 28-Dec-2015
transcript
EJB3.1/Java EE 6S. Rosmorduc, Conservatoire National des Arts et Métiers
(avec des vrais bouts de transparents de Marc Le Bihan dedans)
���1
Bibliographie et sources
• Oracle Java EE 6 tutorial
• A. Goncalves, Beginning Java EE6
• Cours GLG203 2012-2013 Marc Le Bihan
���2
Plan• Rappels d'architecture
• Définition des EJB
• Types d’EJB
• Interfaces d’EJB
• Cycle de vie
• Utilisation des EJB
• Déploiement
• Concurrence
• Transactions
• Mécanismes sous-jacents
���3
Rappels d'architectureCouche Présentation
(Web, Swing…)
Couche Métier
Couche Accès aux données (DAO)
���4
Rappels d'architecture
Couche Métier
façade1 = service façade2 = service
classe métier
classe métier
classe métier
���5
Rappels d'architecture• Les « services » vont servir de façade pour l’accès
au couche métier
• Ils sont organisés selon les use-case
• Permettent d’isoler la couche métier de son interface : couplage plus faible, meilleure sécurité
• En JEE, ils sont implantés sous forme d’EJB
• Ils peuvent être répartis (remote beans) : leur interface permet de contrôler les opérations possibles.
���6
Définition des EJBs
• Objets Gérés par le serveur applicatif
• créés et partagés par le serveur applicatif
• récupération par appels JNDI ou Injection de dépendance
• le cycle de vie dépend du type de bean
• Vous n’appellerez jamais new pour créer un EJB (sauf éventuellement pour les tests)!!!
• Objets façade pour les couches métier
���7
Caractéristiques des EJBs
• objet décorés fournissant des services supplémentaires
• accès distant
• gestion de transaction
• événements liés au cycle de vie
• injection de dépendances
���8
Contraintes
• ne créent pas de threads
• pas de champ statique
• méthodes exportées non final
• classe non final
• pas de méthode finalize() (anti-pattern, de toutes façons)
���9
Types d'EJB
• Stateless
• fréquemment utilisé comme façade d’accès aux données
• Stateful
• Singleton
• Message-driven Bean (plus tard)
���10
EJB Stateless• Pas d’état : on ne peut
pas garder d’information dans les variables d’instance du bean
• Annotation : @Stateless
• Très souvent utilisé pour l’accès aux données
• Injection d’EntityManager (JPA) par @PersistenceContext
���11
@Stateless public class ForumBean { @PersistenceContext EntityManager em; ! public Message addMessage(Message newMessage) { em.persist(newMessage); return newMessage; } ! public Message getMessage(Long id) { return em.find(Message.class, id); } ! public List<MessageList> getAllMessages() { return em.createQuery( "select m from Message m").getResultList(); } }
L’EJB sans état (Stateless bean)
• Parce qu’il est sans état, le stateless bean ne devrait pas comporter de variables membres,
• sinon en considérant ceci:
• Elles ont des chances de ne plus avoir de contenu à l’appel suivant.
• et il y a un risque qu’elles aient encore le contenu qu’elles avaient à l’appel précédent.
���12
L’EJB sans état peut être initialisé
• Il reste possible de procéder à son initialisation dans une méthode porteuse de l’annotation
@PostConstruct
• Et un équivalent « destructeur » pourra être défini dans une méthode annotée
@PreDestroy
���13
Cycle de vie et annotations
• Le serveur maintient un pool de Stateless beans
• Un nouveau bean est initialisé par son constructeur,
• puis par l’injection de dépendances
• puis par l’appel de la méthode annotée par @PostConstruct (si elle existe)
• quand le bean va être libéré par le serveur, il appelle la méthode annotée par @PreDestroy
• important: si vous voulez initialiser votre bean en accédant à des valeurs de champs fixées par injection, il faut le faire dans la méthode @PostConstruct
���14
n’existe pas
prêt
2. injection de dépendance3. @PostConstruct
3. @PreDestroy
1. création, constructeur
EJB Stateful
• Bean à état, sera généralement stocké en session une fois créé
• Annotation @Stateful
• Doit être Serializable (sinon, pas de passivation possible)
• Exemple typique: panier à provisions
���15
Cycle de vie et annotations
• L’appel d’une méthode annotée par @Remove demande la suppression du bean
���16
n’existe pas
2. injection de dépendance
3. @PostConstruct
1. @Remove
passifprêt
1. création, constructeur
2. @PreDestroy
@PrePassivate
@PostActivate
Exemple
���17
@Stateful public class BasketBean implements Serializable { private HashSet<Product> products= new HashSet<Product>(); public void addProduct(Product p) { // ..... } @Remove public void doOrder() { // Sauve la commande dans la base de données } }
l’appel de cette méthode déclenche la destruction du bean (@Remove)
Singleton
• Bean qui n’existe qu’en un seul exemplaire sur un serveur (application répartie: éventuellement un singleton par serveur)
• Exemple: catalogue chargé en mémoire, conversation entre utilisateurs (non permanente)
• Attention: accès concurrents très probables.
���18
Cycle de vie et annotations
• Le serveur propose toujours la même instance d’un bean singleton.
• L’annotation @Startup demande que le bean soit créé dès le lancement de l’application
• Des annotations permettent de gérer les accès concurrents
���19
n’existe pas
prêt
2. injection de dépendance3. @PostConstruct
3. @PreDestroy
1. création, constructeur
Singleton et accès concurrent
• Les méthodes d’un bean singleton seront sûrement appelées simultanément par plusieurs threads
• Il importe donc de gérer la concurrence
• C’est possible simplement grâce aux annotations Lock
• On distingue l’accès en lecture (parallélisable) et en écriture (bloquant)
���20
/** * Catalogue stocké en mémoire. * pas follement pratique: l'accès en BD est plus * simple. */ @Singleton @ConcurrencyManagement(ConcurrencyManagementType.CONTAINER) public class InMemoryCatalog { ! @EJB ProductService productService; ! public Collection<Product> products; ! @PostConstruct @Lock(LockType.WRITE) public void initCatalog() { products = new HashSet<Product>(productService.getAllProducts()); } ! @Lock(LockType.WRITE) public void rafraichirCatalogue() { initCatalog(); } ! @Lock(LockType.READ) public Collection<Product> getProducts() { return products; } }
Singleton et accès concurrent
���21
optionnel (CONTAINER par défaut)
injection de l’accès aux données
non parallèle
parallèle
Singleton et accès concurrent
• @ConcurrencyManagement(ConcurrencyManagementType.CONTAINER) : gestion automatique par le conteneur
• @ConcurrencyManagement(ConcurrencyManagementType.BEAN) : gestion manuelle
• @Lock(LockType.READ) : méthode de lecture. Parallélisable.
• @Lock(LockType.WRITE): méthode d’écriture, non parallélisable. Valeur par défaut.
• Quand une méthode d’écriture est en cours d’exécution, elle interdit l’appel de toute autre méthode (lecture ou écriture)
• On peut appeler simultanément autant de méthode de lecture qu’on veut.
���22
Interfaces d'accès• Les beans ont été conçus pour pouvoir construire des systèmes
répartis => accès distant
• On peut avoir plusieurs types d’interface pour un bean
• Aucune (équivaut à « local » uniquement)
• Local : interface utilisable au sein de la même application que celle qui héberge le bean
• Remote : interface utilisable à distance
• différences avec RMI
• paramètres des méthodes remote
• LocalBean
���23
Exemple: un bean d’accès aux produits
• Dispose de trois méthodes
• getProducts() : renvoie la liste des produits
• addProduct(Product p) : ajoute un nouveau produit
• removeProduct(Product p) : supprime un produit de la liste
• On veut que le client à distance puisse lister les produits, mais pas les supprimer ou ajouter
���24
Exemple (2)
���25
@Local public interface ProductLocal extends ProductRemote { void addProduct(ProductDTO p); void removeProduct(ProductDTO p); }
!@Remote public interface ProductRemote { public Collection <ProductDTO> getAllProducts(); }
@Stateless public class ProductService implements ProductLocal, ProductRemote { ! @Override public void addProduct(ProductDTO p) { //.... } !
@Local
• interface utilisée pour l’accès interne à l’application
���26
@Remote
• Interface utilisée pour les accès distants
• Les arguments et les valeurs retournées par les méthodes de l’interface Remote doivent être Serializable.
���27
Et si on ne dit rien ?
• Un EJB sans annotation locale ou remote est considéré comme local.
• Note importante: quand on a une interface locale ou remote, seules les méthodes de cette interface sont des méthodes EJB (transactionnelles, entre autres). Les autres méthodes sont « normales »
• Quand on n’a pas d’interface déclarée, l’interface locale correspond à l’ensemble des méthodes publiques.
���28
Utilisation des beans• Nombreuses manières de faire référence à des beans
• En JSF
• injection de dépendance
• Entre beans
• règles
• Depuis une application cliente
• JNDI
• Depuis une Servlet
���29
Accès depuis un Managed Bean JSF
• Dans l’architecture JSF, les clients des EJB sont essentiellement les managed beans
• Très simple: on place l’ejb comme variable d’instance et on utilise l’injection de dépendance.
• Annotation : @EJB (ou @Inject)
���30
Accès depuis un Managed Bean JSF
���31
!@ManagedBean @RequestScoped public class CreatePersonBean { @EJB PersonService personService; private String name; private int age; private Person person; // Or DTO : Data transfer Object public void createPerson() { person= personService.createPerson(name, age); name= ""; age= 0; } public String getName() { return name; }
EJB
Accès depuis un Managed Bean JSF: version « moderne »
���32
!@Named @RequestScoped public class CreatePersonBean { @Inject PersonService personService; private String name; private int age; private Person person; // Or DTO : Data transfer Object public void createPerson() { person= personService.createPerson(name, age); name= ""; age= 0; } public String getName() { return name; }
EJB
Injection et interfaces Remote et Local
• Pour l’injection, le type à utiliser est le nom de l’interface, pas celui de la classe:
@EJB
private ProductLocal productService;
���33
Entre EJB
• On peut utiliser l’injection de dépendance entre EJB
• On utilise aussi @EJB ou @Inject
���34
Accès par une application
• Une application texte ou graphique peut se connecter à un bean
• Le bean doit avoir une « interface distante » (similaire à ce qui se fait pour les RMI) : @Remote
• L’application doit avoir un nombre assez conséquent de bibliothèques du serveur applicatif dans son classPath.
• Il existe une application « lanceur » nommée appclient.
• On peut utiliser l’injection, ou se connecter à JNDI
• ATTENTION : l'application distante doit avoir connaître (avoir dans son classpath) l'interface Remote du bean (pas le bean lui-même)
���35
JNDI Java Naming and Directory Interface
• Fournit un accès unifié à plusieurs services d’annuaires (DNS, LDAP...)
• Annuaire: associe des données (objets) avec un nom
• http://docs.oracle.com/javase/jndi/tutorial/
• L’accès JNDI est fourni par le serveur applicatif
• Derrière l’injection de dépendance, on a quand même JNDI…
���36
Récupérer un Bean avec JNDI
import javax.naming.*; .... .... Context c= new InitialContext(); String beanName= "java:app/MyApp/BasketBean"; BasketBean b= (BasketBean) c.lookup(beanName);
• Si le bean est Stateful, crée un nouveau bean • Si le bean est stateless, peut réutiliser un bean existant • Si le bean est un singleton, renvoie le singleton.
���37
Coordonnées du serveur JNDI
• En local, données fournies par appclient
• Sinon (pour GlassFish) :
���38
Properties properties= new Properties(); properties.setProperty("java.naming.factory.initial", "com.sun.enterprise.naming.SerialInitContextFactory"); properties.setProperty("java.naming.factory.url.pkgs", "com.sun.enterprise.naming"); properties.setProperty("java.naming.factory.state", "com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl"); properties.setProperty("org.omg.CORBA.ORBInitialHost", "localhost"); properties.setProperty("org.omg.CORBA.ORBInitialPort", "3700"); initialContext = new InitialContext(properties);
Noms JNDI des beans (1)• Récemment standardisé…
• Voir trace de glassfish pour les noms des beans
• Pour un bean dans une autre application web, utiliser le nom « global »
• java:global/APP/MODULE/BEAN
• Pour une application construite à partir de plusieurs war, jars: pour accéder à des beans dans d’autres modules d’une même application utiliser le « nom d’application » :
• java:app/MODULE/BEAN
• Pour des beans dans le même module, utiliser le nom de module:
• java:module/BEAN
• APP= nom de l’appli; MODULE = nom du module; Bean= nom du bean (nom de la classe)
���39
Noms JNDI des beans (2)
• Si on veut utiliser une interface particulière, on peut ajouter ‘ !INTERFACE’ après le nom de la classe.
• ex. :
java:app/MyApp/BasketBean!myshop.business.BasketRemoteIF
• Utilise l’interface remote
• nom complet, y compris package.
• Voir http://glassfish.java.net/javaee5/ejb/EJB_FAQ.html#What_is_the_syntax_for_portable_global_ pour plus de détails.
���40
Accès aux EJB depuis une Servlet
• Stateless beans et singletons peuvent être injectés dans la Servlet en utilisant l’annotation @EJB
• Dans les servlets, il faut récupérer les Stateful beans « manuellement » en utilisant JNDI, puis les stocker en session en utilisant session.setAttribute()
���41
accès à un bean session depuis une servlet
• Le bean:@Stateful public class Basket { // Product is serializable ! private List<Product> content=
new ArrayList<Product> (); !
public void add(Product p) { content.add(p); }
....
���42
accès à un bean session depuis une servlet
@WebServlet(name = "AddToBasketServlet", urlPatterns = {"/addToBasket"}) public class AddToBasketServlet extends HttpServlet { ... private Basket lookupBasketBean(HttpServletRequest request) { HttpSession session = request.getSession(); if (session.getAttribute("basket") == null) { try { Context c = new InitialContext(); Basket b = (Basket) c.lookup("java:global/SessionInViewTest/Basket"); session.setAttribute("basket", b); } catch (NamingException ne) { Logger.getLogger(getClass().getName()).log(Level.SEVERE, "exception", ne); throw new RuntimeException(ne); } } return (Basket) session.getAttribute("basket"); } }
Si le bean n’est pas en session, le créer avec
JNDI.
���43
Déploiement
���44
Concurrence
• création manuelle de Threads : INTERDITE
• Timer
• @Startup
• @Schedule
• @Timeout
• Annotation @Asynchronous
���45
L'EJB Timer (1)
• Pour invoquer périodiquement un EJB, il n'existait avant la version EJB 3.1 que des solutions fastidieuses, telles que :
• Création d'une servlet qui démarre avec le serveur d'application,
• puis crée des java.util.Timer,
• et lorsque ces timers arrivent à échéance invoquent la méthode d'EJB voulue…
• Le serveur d'application peut à présent prendre en charge seul ces méthodes à l'exécution programmée dans le temps.
• Le timer est souvent attaché à un Singleton, chargé dès le déploiement (annoté par @Startup)
���46
EJB Timer (2)• Pour programmer une exécution:
• annotation @Schedule placée sur une méthode
• prend une expression « cron » en paramètre pour définir son déclenchement.
• par défaut, hour, minute, second sont à 0.
• dayOfMonth="4", hour="*" : Toutes les heures le 4ème jour de chaque mois.
• minute=*/5 : toutes les cinq minutes.
• dayOfWeek="1, 3,5": lundi, mercredi et vendredi.
• la méthode cible ne doit pas avoir d'arguments.
@Schedule(dayOfMonth="*")!
public void sauvegarde() {…}
���47
EJB Timer
���48
@Singleton @Startup public class MaDemoTimer implements Serializable{ private int compteur= 0; private Logger logger = Logger.getLogger(this.getClass().toString()); @PostConstruct public void myInit() { logger.severe("Init"); } @Schedule(hour = "*", minute = "*", second = "*/5", persistent = true) public void sauverDonnees() { logger.severe("On sauve les données "+ new Date()+ " compteur "+ (compteur++)); } }
souvent singleton. Startup=> créé dès le déploiement du bean
EJB Timer (3)
• @Schedule prend des paramètres constants.
• Lorsque la planification à appliquer n'est connue qu'à l'exécution, il faut utiliser un TimerService.
• C'est une ressource que l'on charge avec des expressions temporelles : cron, ou bien en dates classiques.
���49
Timer programmé
• On crée un timer en utilisant la classe TimerService (qu’on injecte)
• Dans la classe où on crée le timer, on cherche une méthode annotée par @Timeout
• Cette méthode est lancée selon la fréquence indiquée
���50
Timer programmé
���51
@Singleton public class ExempleTimerService { @Resource TimerService timerService; private Logger logger= Logger.getLogger("TimerProgramme"); private Timer timer; // pour annuler le timer si besoin // Installe le timer pour un certain intervalle de temps. public void installerTimer(long intervalle) { cancelTimer(); timer= timerService.createIntervalTimer(1000, intervalle, new TimerConfig()); } public void cancelTimer() { if (timer != null) {timer.cancel();timer= null;} } @Timeout public void sauvegardeProgrammee() { logger.severe("Sauvegarde bis "+ (compteur++) + " a "+ new Date()); } }
Note à propos de Glassfish
• Par défaut, le timer est « persistante » : il se relancera, même en cas d’arrêt du serveur. Il est capable de migrer sur un autre serveur en cas de Load-balancing
• En cas d’erreur de configuration, les timers persistants laissent des fichiers de sauvegarde incorrects dans Glassfish
• Donc, en cas de problème :
• soit désactiver la persistance :
@Schedule(hour = "*", persistent = false)
• soit effacer le fichier incriminé :
glassfish/domains/domain1/generated/ejb/ejb-timer-service-app
���52
Timer programmé
• Quand on crée l'objet timer en appelant
• timerService.createIntervalTimer(10, intervalle, new TimerConfig());
• le timer démarre, et la méthode annotée @TimeOut est lancée (périodiquement ou une fois, selon le timer créé)
• Il est possible de sauver l’objet timer dans un fichier ou une BD en le sérialisant (on sauve la valeur renvoyée par timer.getHandle()).
• par défaut, le timer est persistant quand il est lancé: si on arrête le serveur JEE, le timer se relancera automatiquement.
���53
���54
@Named @RequestScoped public class StartTimerBean { @Min(100) private long intervalle=2000; @EJB private ExempleTimerService timerService; public void demarrerTimer() { timerService.installerTimer(intervalle); } public void arreterTimer() { timerService.cancelTimer(); } public long getIntervalle() { return intervalle; } public void setIntervalle(long intervalle) { this.intervalle = intervalle; } }
<h:form> <p>Intervalle : <h:inputText value="#{startTimerBean.intervalle}"/></p> <h:commandButton value="Démarrer" action="#{startTimerBean.demarrerTimer()}"/> <h:commandButton value="Arrêter" action="#{startTimerBean.arreterTimer()}"/> </h:form>
Exemple de Managed Bean pour le timer précédent
JSF
Gestion de transactions
• rappels
• TransactionManagement
• Annotations disponibles pour @TransactionAttribute
• REQUIRED, REQUIRES_NEW, MANDATORY, SUPPORT, NOT_SUPPORTED, NEVER
���55
Le problème des transactions
• transfert entre deux comptes en banque:
• compte1.retirer(1000)
• compte2.deposer(1000)
• En BD:
• update compte set solde= solde -1000 where id= 1
• update compte set solde= solde + 1000 where id= 2
• Que se passe-t-il si l’opération est interrompue entre les deux étapes ????
• => les deux opérations doivent, ou toutes les deux réussir, ou toutes les deux échouer
���56
Transactions• Définition
• opération informatique cohérente composée de plusieurs tâches unitaires
• implantent les propriétés ACID:
• atomique
• cohérente
• isolée (plus ou moins)
• durable
• mécanisme
• de base dans SQL : commit() rollback() start transaction()
���57
Transaction : le problème
• opération technique au niveau SQL (accès aux données)
• au niveau logique, la délimitation des transaction correspond plutôt à la logique applicative (suite d’opération cohérente) !!
• les EJB permettent de replacer les transactions au « bon » niveau
���58
Transactions et EJB Java Transaction API
• Par défaut, toutes les méthodes qui font partie de l’interface d’une EJB sont transactionnelles
• Quand l’interface utilisateur appelle une méthode EJB, on démarre une transaction; la fin de la méthode correspond au commit().
• S’interface naturellement avec JPA
• Pas besoin d’ouvrir ou fermer une transaction, c’est fait automatiquement par le conteneur
���59
Annotation @TransactionAttribute• @TransactionAttribute(….) devant une
méthode d’un EJB: modifie son comportement transactionnel
• généralement, la question est la suivante:
• une méthode f() transactionnelle appelle une méthode g(), elle aussi transactionnelle
• que va-t-il se passer ? g() va-t-elle s’exécuter dans la transaction démarrée par f() ?
• quel suspense !
���60
Valeurs possibles pour @TransactionAttribute• TransactionAttributeType.REQUIRED: s’il y a une transaction en cours,
exécute la méthode dans cette transaction. Sinon, crée une nouvelle transaction
• TransactionAttributeType.REQUIRES_NEW: crée une nouvelle transaction pour cet appel
• TransactionAttributeType.MANDATORY: exception s’il n’y a pas déjà une transaction en cours
• TransactionAttributeType.SUPPORTS: ne crée pas de transaction, mais s’exécute dans le cadre de celle qui est en cours si elle existe.
• TransactionAttributeType.NEVER: erreur si dans transaction
• TransactionAttributeType.NOT_SUPPORTED: s’exécute en dehors du contexte transactionnel en cours.
���61
Exemple
���62
@Stateful public class PanierService { ! @PersistenceContext EntityManager em; ! private List<ProduitDTO> produits = new ArrayList<ProduitDTO>(); ! @TransactionAttribute(TransactionAttributeType.SUPPORTS) public void addProduit(ProduitDTO dto) { produits.add(dto); } ! // l'annotation ci-dessous est inutile (valeur par défaut) @TransactionAttribute(TransactionAttributeType.REQUIRED) public void sauverCommande() { // ... construit la commande à partir des produit // ... appelle em.persist() Commande c = CommandeHelper.construireCommande(produits); em.persist(c); } }
Exemple (suite)• addProduit : TransactionAttributeType.SUPPORTS
• ne touche pas à la base de données, et peut donc ne pas être transactionnel
• si on l’appelle dans le cadre d’une transaction, utilise celle-ci
• sauverCommande: TransactionAttributeType.REQUIRED
• va forcément s’exécuter dans le cadre d’une transaction.
���63
Transactions• Concrètement, les transactions agissent sur des connections fournies
par les Datasources que le serveur d’application a sous sa garde.
• Agir sur les connections pour débuter une transaction n’est pas nécessaire, le serveur d’application s’en charge.
• Le commit advient de lui-même lorsque le service qui a débuté une transaction s’ est exécuté intégralement et a su composer avec d’autres services
• Sans avoir reçu de notification d’abandon.
• Sans s’être retrouvé dans une situation d’annulation.
• De sorte que dans un service, on ne s’occupe que de notifier les situations de rollback.
���64
Exceptions Systèmes:
• sur initiative du serveur d’application et dans des situations « sévères ».
• Les exceptions issues de RuntimeException, RemoteException, et EJBException.
• Ce sont des exceptions système qu’il n’est pas attendu que nous levions nous-mêmes
���65
Exceptions applicatives• Les exceptions non système
• peuvent être annotées par
@ApplicationException(rollback=true)
• et alors elles provoqueront l’annulation de la transaction en cours si elles sont levées par le service.
• Attention: prendre cette décision pour la classe d’exception elle-même est brutal. C’est peut-être une décision à laisser au service ?
���66
Notification d’abandon• En ajoutant à l’EJB session la variable membre et la
méthode
@Stateless public class MonBean {
@Resource
private SessionContext sessionContext;
….
• Une méthode de service de ce bean pourra annuler une transaction en cours par un:
• sessionContext.setRollbackOnly(true);
���67
Mécanismes sous-jacents
• Quand on appelle une méthode d’EJB, comment le système peut-il décider de commencer/terminer une transaction ?
• On utilise le pattern Décorateur avec un Proxy
• On génère une classe de même interface que le Bean, qui appelle le bean, mais « enrobe » les appels de méthodes dans le code nécessaire au traitement de la transaction
• Pour ça
• classe Proxy : permet d’implanter par programme java une interface quelconque (c’est du java standard). Fonctionne seulement s’il y a une interface Local ou Remote explicite.
• Héritage et synthèse de code : on crée le bytecode d’une nouvelle classe (bibliothèque ASM), qui étend la classe d’origine (d’où l’interdiction de final).
���68
Pour résumer... un exemple de C(RUD) en JSF+EJB (+JPA)
• Base de données de Dvd
• Contrôle : un managed bean CreateDvdBean
• Couche métier : un Stateless Bean DvdService
• Accès aux données : JPA (et le bean DvdService)
���69
���70
on ajoute JSF…
Dvds… la suite
• Noter le découpage en packages
���71
On crée la base de données
Ajout d’une Persistence Unit (pour JPA)
���72
Création du modèle (réduit à une classe ici)
���73
L’EJB d’accès aux Dvd• (on pourrait faire deux EJB: un de bas
niveau (DAO), l'autre orienté façade pour l'interface graphique
���74
Le managed bean pour la création et sa JSF
���75
Note sur la valeur de retour de l'action
• return
"montrerDvd?faces-redirect=true&id=" +id;
• faces-redirect => redirection (on charge une nouvelle page)
• id=… : cette page va afficher le DVD créé
���76
Managed Bean de visualisation
���77
Injection de paramètres GET
@ManagedProperty(value="#{param.id}")
Long id;
• injecte la valeur de param.id dans id
• ne fonctionne que sur un @ManagedBean (pas @Named)
• FacesContext.getCurrentInstance().getExternalContext() permet d’avoir accès aux paramètres comme avec une servlet
• Sinon, on peut injecter les valeurs à partir de la JSF :
���78
<f:metadata> <f:viewParam name="id" value="#{dvd.id}"/> </f:metadata>