JEE / Spring - Une introduction - NSY102 - 2019 Stéphane Bruyère - Cnam
←
→
Transcription du contenu de la page
Si votre navigateur ne rend pas la page correctement, lisez s'il vous plaît le contenu de la page ci-dessous
JEE - Les outils Pour JEE Pour le serveur Tomcat https://www.eclipse.org/downloads/packages/ https://tomcat.apache.org/download-90.cgi 2
JEE - Introduction Java EE ou JEE (maintenant Jakarta EE) est une est une spécification pour la plate-forme Java destinée aux applications d'entreprise. L'objectif majeur de JEE est de faciliter le développement d'applications web robustes et distribuées, déployées et exécutées sur un serveur d'applications. JEE étend donc Java SE en fournissant un ensemble de concepts et d’API pour le développement d’applications web. JEE est défini à l’aide d’un ensemble de standards (JSR - java specification request) spécifiques. 4
JEE - Introduction Un serveur d'applications est l’infrastructure logicielle qui permet d’héberger les applications developpées selon le standard JEE. Il en existe plusieurs implémentations, dont une de référence (Oracle Glassfish). Parmi les implémentations complètes open source, on citera notamment Wildly (RedHat) et Payara (dérivé de Glassfish), et Apache Tomcat ou encore Jetty pour les conteneurs web légers. 5
JEE - Introduction Les serveurs d’applications implémentant JEE doivent être certifiés pour une version donnée de JEE. Un outils existe : le TCK (test compatibility kit) est un ensemble de tests (environ 20,000) qui accompagne les spécifications Java EE et permet de verifier qu’un serveur d’applications donné répond bien aux standards JEE. 6
JEE - principes Java Enterprise Edition, comme son nom l'indique, a été créé pour le développement d'applications d'entreprises. Ses spécifications ont été pensées dans cette optique, afin de permettre le développement le plus rapide possible d’applications d’entreprise qualitatives, sûres, sécurisées, portables, performantes, disponibles, maintenables, extensibles ... 7
JEE - notions générales - client / serveur client / serveur requête / réponse html, css, javascript php, python, C#, javascript ... interprétés par le navigateur du client ... et java 8
JEE - notions générales - architecture 3 tiers modèle systématique d’organisation des applications JEE : Présentation : JSP, Servlet ... métier : code métier, EJB Données : JDBC, JPA, frameworks ORM ... Chaque couche est associée à des technologies JEE. Decouplage fort entre les couches 11
JEE - quelques exemples d’API ● Servlets, JSP(Java Server Pages), JSF (Java Server Faces) : pages web dynamiques ● EJB (Entreprise Java Beans) : objets métiers ● JDBC : API d'accès à des SGBD ● JNDI (Java Naming an Directory Interface) : API pour nommage des objets ● JPA (Java Persistence API) : gestion de la persistence et du mapping objet-relationnel (correspondances entre les schémas de la base de données et les classes du programme applicatif) ● JTA (Java Transaction API) ; API pour gestion des transactions 12
JEE - Enterprise Java Bean ou EJB Ce sont des composants distribués (càd déployés sur des serveurs distants) hébergés au sein d'un serveur applicatif permettant de représenter des données (EJB dit « entity bean »), de proposer des services avec ou sans conservation d'état entre les appels (EJB dit « session bean »), ou encore d'accomplir des tâches de manière asynchrone (EJB dit « message-driven bean »). Tous les EJB peuvent évoluer dans un contexte transactionnel. Depuis la version 3.0, le modèle EJB utilise le principe d'annotation java (vs fichier de config xml) pour spécifier la configuration et les propriétés transactionnelles de l'objet. 13 source wikipedia
JEE - Enterprise Java Bean ou EJB Les EJB « session » fournissent des services sous forme de méthodes écrites par le développeur. Il sont créés, gérés et partagés par le serveur applicatif. Ils sont récupérés par appels JNDI ou Injection de dépendance. Ils ne sont donc jamais appelés par new ! Les Session beans sont des objets façade pour les couches métier. Ils peuvent être « stateless » s’ils ne conservent pas leur état entre deux appels, ou « stateful » dans le cas contraire. 14 source S. Rosmorduc GLG203
JEE - Enterprise Java Bean ou EJB Les EJB « entity » sont des beans ayant majoritairement pour vocation d'être persistants, c'est-à-dire pouvant être stockés sur un support physique entre deux sessions. Depuis la version 3.0 de la spécification EJB, il sont directement liés à la base de données via un mapping objet-relationnel géré par des annotations (via JPA). Les EJB «message-driven» permettent de déclencher un processus côté serveur applicatif lors de la publication d'un message asynchrone. Le client ne s'adresse pas directement aux composants mais publie un message sur un réceptacle JMS (queue ou topic) configuré sur le serveur applicatif qui va alors déclencher l'activation par ce serveur d'une instance de l'EJB concerné pour pouvoir traiter ce message. 15 source wikipedia
JEE - architecture 16
JEE - Patrons de conception Nouveau patrons de conception mis en jeu : ● Data Access Object (DAO) ● Data Transfer Object (DTO) ● Facade ● MVC 17
JEE - MVC JEE permet une utilisation assez naturelle du patron MVC Dans une application Java EE : Modèle = objets Java Vue = pages JSP Contrôle = servlets (aiguillage les requêtes entrantes vers les traitements et vues correspondants). 18
JEE - Servlets 2 packages : ● javax.servlet : support de servlets génériques indépendants du protocole ● javax.servlet.http : fonctionnalités spécifiques au protocole HTPP Pour écrire une servlet, il faut : ● écrire une classe héritant de javax.servlet.http.HttpServlet ● redéfinir les méthodes nécessaires 19
JEE - Servlets Le cycle de vie d’une servlet est géré par le serveur (web container) ● Initialisation : ● Chargement de la classe (au démarrage ou sur requête). ● Instanciation d’un objet. ● Appel de la méthode init() (de la classe javax.servlet.GenericServlet dont hérite HttpServlet. « Called by the servlet container to indicate to a servlet that the servlet is being placed into service ») 20
JEE - Servlets ● Utilisation : ● Appel de la méthode service() (« Receives standard HTTP requests from the public service method and dispatches them to the doXXX methods defined in this class ... There's no need to override this method. ») ● Dans le cas d’une HttpServlet : appel vers doGet(), doPost(). ● Destruction : ● Peut être provoquée pour optimiser la mémoire ● appel de la méthode destroy() (de la classe GenericServlet. « Called by the servlet container to indicate to a servlet that the servlet is being taken out of service. ») 21
JEE - invoquer une Servlet La Servlet est invoquée par une URL dans un navigateur http://localhost:8080/MyApp/HelloWorld protocole serveur port contexte de la Servlet nom de l’appli sur le serveur url pattern pour la Servlet 22
JEE - HttpServletRequest et HttpServletResponse Ces objet sont notamment passés en paramètre des méthodes service() et doXXX(). Ils sont instanciés par le conteneur de servlets, qui les transmet à la méthode service, qui les transmet au méthodes doXXX. 23
JEE - HttpServletRequest extends ServletRequest HttpServletRequest contient les informations relatives à la requête. Elle possède notamment les méthodes : ● getAttribute(String name) : Returns the value of the named attribute as an Object, or null if no attribute of the given name exists. ● setAttribute(String name, Object o) : Stores an attribute in this request. ● getParameter(String name) : Returns the value of a request parameter as a String, or null if the parameter does not exist. ● getMethod() : Returns the name of the HTTP method with which this request was made, for example, GET, POST, or PUT. ● getSession(boolean create) : Returns the current HttpSession associated with this request or, if there is no current session and create is true, returns a new session. 24
JEE - HttpServletResponse extends ServletResponse HttpServletResponse permet de construire et renvoyer une réponse au client. Elle possède notamment les méthodes : ● setContentType(String type) : Sets the content type of the response being sent to the client (ex : text/html;charset=UTF-8). ● getWriter() : Returns a PrintWriter object that can send character text to the client. ● sendRedirect(String location) : Sends a temporary redirect response to the client using the specified redirect location URL and clears the buffer. 25
JEE - HttpServlet ->forward Transmettre une demande d'un servlet à une autre ressource (servlet, fichier JSP ou fichier HTML) sur le serveur : getServletContext().getRequestDispatcher(String path). forward(ServletRequest request, ServletResponse response) ● ServletContext : Defines a set of methods that a servlet uses to communicate with its servlet container ● RequestDispatcher : Defines an object that receives requests from the client and sends them to any resource on the server. 26
JEE - Execution des Servlets Une Servlet est un Singleton (1 seule instance par classe). Les servlets sont donc multithread. Si le conteneur reçoit plusieurs reqûetes pour une servlet , la méthode service () de ce servlet sera exécutée simultanément dans plusieurs threads. Conséquence : les variables (de classe et d’instance) d’une Servlet sont des ressources partagées. Seules les variables locales sont toujours thread safe. Il faut donc protéger les ressources des accès concurrents ou plus généralement privilégier les Servlets Stateless 27
JEE - notre 1ère Servlet http://localhost:8080/NSY102/bonjour?param=Bill @WebServlet(urlPatterns={"/bonjour"}) public class HelloBill extends HttpServlet { public void doGet(final HttpServletRequest request, final HttpServletResponse response) throws IOException, ServletException { response.setContentType("text/html"); final PrintWriter out = response.getWriter(); String param = request.getParameter("param"); out.println( "" ); out.println(""); out.println("Hello " + param + ""); out.println(LocalDateTime.now().toLocalDate()); out.println( "" ); out.close(); } } 28
JEE - notre 1ère Servlet ... avec doPost() http://localhost:8080/NSY102/MyForm.html public void doPost(final HttpServletRequest request, final HttpServletResponse response) throws IOException, ServletException { response.setContentType("text/html"); Mon Formulaire final PrintWriter out = response.getWriter(); String nom = request.getParameter( "nom" ); String prenom = request.getParameter( "prenom" ); out.println( "" ); out.println( "Retour de l'envoi du Formulaire" ); Nom out.println( "Bonjour " + prenom + " " + nom ); Prénom out.println( "" ); out.close(); } post 29
JEE - Conclusion sur les Servlets programme Java s'exécutant côté serveur (Servlet container) • que l'on peut invoquer à l'aide d'une URL • adapté à l'écriture de traitements complexes (contenant donc principalement du code java) • peu adapté à l’écriture de code html complexe 30
JEE - Java Server Page (JSP) Une JSP est une page HTML avec du code Java s'exécutant côté serveur. La technologie JSP permet de créer des pages web dynamiques exécutées par un moteur de JSP. Une JSP accessible par son chemin. Les JSP sont plus adaptées que les servlets pour l’affichage, mais pas pour les traitements. Lorsque la JSP est appelée pour la 1ère fois, le serveur crée une Servlet correspondant à cette JSP. 31
JEE - Java Server Page (JSP) Dans une JSP, le code java est introduit par Ce code sera recopié dans la méthode _jspService de la Servlet créée. Il ne peut donc contenir que des instructions. Variables disponibles dans la JSP : ● request et response, la requête et la réponse ● out , le flux de sortie pour écrire ● session session courante du client ● application pour accéder à l’espace de données partagée (ServletContext) ● page désigne la JSP courante ● config pour accéder à l’objet ServletConfig 32
JEE - Java Server Page (JSP) Les imports : La balise permet d’écrire des directives qui concernent la classe engendrée L’inclusion de JSP : ● : recopie directement le code de toto.jsp dans la servlet courante (risque de conflits avec les noms de variables) ● inclut le résultat de l’exécution de la jsp toto.jsp dans la sortie de la jsp courante. La page incluse est déterminée à l’exécution (pas de conflit de nom) 33 source S. Rosmorduc GLG203
JEE - Collaboration JSP/Servlet La servlet reçoit une requête puis la traite. Elle utilise ensuite un requestDispatcher pour déléguer la fin du traitement à une jsp (elle appelle la méthode _jspService de la jsp). Elle doit dire à la jsp quoi afficher. ● problème : passer des information de la servlet à la jsp ● solution : les passer en bean request (request.setAttribute() côté Servlet et request.getAttribute côté JSP) La JSP peut être masquée (non accessible directement mais uniquement via la Servlet) en étant placée dans un sous-répertoire de WEB-INF 34 source S. Rosmorduc GLG203
JEE - notre 1ère JSP Factorielles Table des factorielles 35
JEE - notre 2ème JSP Mon Formulaire Bonjour salutations Nom 36
JEE - une petite dernière package cnam.fr; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; Signin Template @WebServlet(urlPatterns = { "/signin" }) public class SigninServlet extends HttpServlet { Login public void doGet(final HttpServletRequest request, final HttpServletResponse response) throws IOException, ServletException { request.getRequestDispatcher("/WEB-INF/jsp/login.jsp"). ${message} forward(request, response); Please sign in } Email address final HttpServletResponse response) Password String email = request.getParameter("email"); Sign String mdp = request.getParameter("mdp"); in if (email == null || mdp == null || "".equals(email) || "".equals(mdp)) { request.setAttribute("message", "Tous les champs doivent être remplis"); } else { request.setAttribute("email", email); url = "/WEB-INF/jsp/loggedin.jsp"; } request.getRequestDispatcher(url). forward(request, response); } } 37
JEE - une petite dernière package cnam.fr; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet(urlPatterns = { "/signin" }) public class SigninServlet extends HttpServlet { public void doGet(final HttpServletRequest request, final HttpServletResponse response) throws IOException, ServletException { request.getRequestDispatcher("/WEB-INF/jsp/login.jsp"). forward(request, response); } public void doPost(final HttpServletRequest request, final HttpServletResponse response) throws IOException, ServletException { String url = "/WEB-INF/jsp/login.jsp"; String email = request.getParameter("email"); String mdp = request.getParameter("mdp"); if (email == null || mdp == null || "".equals(email) || "".equals(mdp)) { request.setAttribute("message", Signin Template "Tous les champs doivent être remplis"); } else { request.setAttribute("email", email); Login url = "/WEB-INF/jsp/loggedin.jsp"; } request.getRequestDispatcher(url). forward(request, response); Vous êtes authentifié avec l'adresse e-mail ${email} } } 38
JEE - Les sessions ● Http étant un protocole sans état, une session permettra de suivre l’activité d’un internaute. ● Objet prédéfini de type HttpSession en java (methode HttpSession getSession(boolean) sur HttpServletRequest pour le récupérer) ● Garantie d’isolation des sessions les unes des autres sur une même application. ● Opérations sur la session : ● void setAttribute( String name, Object value ) ● Object getAttribute( String name ) 39
JEE - Les sessions ... vite, un exemple ! La Servlet 1/2 @WebServlet(urlPatterns = { "/checkSession" }) public class SessionServlet extends HttpServlet { public void doGet(final HttpServletRequest request, final HttpServletResponse response) throws IOException, ServletException { // Calcule le temps de persistence de la session http long created = System.currentTimeMillis(); long current = request.getSession().getCreationTime(); int totalSeconds = (int) (created - current) / 1000; // String refresh = request.getParameter("refresh"); // Si on clique sur le bouton rafraichir avec une session active if (refresh != null && request.getSession().getAttribute("sessionUser") !=null) request.setAttribute("message", "La valeur " + request.getSession(). getAttribute("sessionUser") est stockée en session depuis " + totalSeconds + " secondes! "); request.getRequestDispatcher("/WEB-INF/jsp/essaiSession.jsp").forward(request, response); } ... 40
JEE - Les sessions ... vite, un exemple ! ... La Servlet 2/2 public void doPost(final HttpServletRequest request, final HttpServletResponse response) throws IOException, ServletException { HttpSession session = request.getSession(); String sessionUser = (String) session.getAttribute("sessionUser"); // Calcule le temps de persistence de la session http long created = System.currentTimeMillis(); long current = session.getCreationTime(); int totalSeconds = (int) (created - current) / 1000; // String user = request.getParameter("user"); String invalidate = request.getParameter("invalidate"); // Si la session est nouvelle if (sessionUser == null || sessionUser.length() < 0) { // Si le nom de l'utilisateur est saisi if (user != null && user.length() > 0) { request.setAttribute("message", "La valeur " + user + " est stockée en session"); session.setAttribute("sessionUser", user); } // Si on clique sur le bouton invalider session } else if (invalidate != null && invalidate.length() > 0) { session.invalidate(); // La session existe, on affiche sa durée } else { request.setAttribute("message", "Session en cours pour " + sessionUser + " depuis " + totalSeconds + " secondes !Veuillez invalider pour changer d'utilisateur"); } request.getRequestDispatcher("/WEB-INF/jsp/essaiSession.jsp").forward(request, response); } } 41
JEE - Les sessions ... vite, un exemple ! La JSP 1/1 Signin Template Login ${message} Utilisateur: Rafraichir 42
JEE - JDBC Package Java pour l'accès aux SGDBR : java.sql driver 100% java Mise en oeuvre : 1. Enregistrer le driver JDBC 2. Ouvrir une connexion sur la base 3. Créer la requête (un Statement) 4. Exécuter la requête 5. Traiter le résultat retourné (un ResultSet) 6. Fermer les objets ● JDBC permet d' accéder à un SGBDR ● Une application basée sur JDBC est indépendante du SGBDR utilisé ● JDBC permet un accès SQL mais n’automatise pas la gestion de la persistance des objets java 43 source P. Graffion GLG203
JDBC - DAO Séparation des préoccupations : accès aux données / mise en oeuvre ● bas niveau : requête SQL JDBC ● haut niveau : interface java pour l’accès aux données : ● interface PersonneDAO { List findAll( ); } ● 3 éléments : ● interface (suffxée DAO) ● une classe d’implémentation (suffixée DAOImpl) ● une classe contenant les données 44
JDBC - DAO CRUD, acronyme pour Create, Read, Update, Delete interface PersonneDAO { void add( Personne p ); // Create Personne find( int id ); // Read List findAll(); // Read void update( Personne p ); // Update void delete( int id ); } // Delete ● Sépare la logique métier des détails de mise en oeuvre ● Permet de se concentrer sur les opération de haut niveau ● ... et facilite l’optimisation des requêtes de bas niveau 45
JEE - JPA Java Persistence API ● interface de programmation pour la gestion des données relationnelles ● plusieurs implémentations : Hibernate, EclipseLink, TopLink ... ● Mapping objet-relationnel (ORM ou Object Relation Mapping) ● Opérations SQL courantes ● haut niveau ● transfert automatique des données 46
JEE - JPA Principes de correspondance : classe java table SQL attribut d’une classe colonne de table SQL références en classes relations entre tables SQL objet java enregistrement dans une table SQL Les modifications apportées à l’objet en mémoire sont répercutées dans la base. constructeur, getters / setters obligatoires 47
JEE - annotations JPA @Entity : à déclarer sur une classe dont les données doivent être prises en charge par JPA. @Id : clé primaire (obligatoire) @GeneratedValue : génération automatique de la clé @Table : correspondance classe / table @Column : correspondance attribut / colonne @OneToMany : cardinalité 1-n @ManyToOne : cardinalité n-1 @OneToOne : cardinalité 1-1 @ManyToMany : cardinalité n-n 48
JEE - JPA @Entity public class Eleve implements Serializable { @id @Entity @Column(name= « ELEVE_ID ») public class Eleve implements Serializable{ private Long Id ... private String nom; @ManyToMany @ManyToOne @JoinTable(name="ELEVE_COURS", @JoinColumn(name= « ECOLE_ID ») joinColumns=@JoinColumn(name="EC_ELEVE_ID"), private Ecole ecole; inverseJoinColumns=@JoinColumn(name="EC_COURS_ID")) // constructeur private Collection cours; // getters/setters ... } } la classe java qui gère la relation correspond à la table qui contient la clé étrangère 49
JEE - L’Entity Manager de JPA L’EntityManager assure la liaison entre java et le SGBD. Il fournit les méthodes courantes d’accès aux données. EntityManagerFactory emf = Persistence.createEntityManagerFactory("myApp"); EntityManager em = emf.createEntityManager(); Personne bill = new Personne("Bill", 37); em.persist(bill); Personne p123 = em.find(Personne.class, 123); // recherche de la personne d’id 123 bill.setAge(38); em.merge(bill); em.remove(bill); 50
JEE - JPA et JTA (Java Transaction API) Les transactions sont un élément fondamental de la persistance. Une transaction de base de données consiste en un ensemble d'opérations SQL validées ou non, mais de façon indivisible. Une transaction au niveau objet est une opération dans laquelle un ensemble de modifications apportées à un ensemble d'objets est validé dans la base de données comme un groupe indivisible. Objectif : permettre la concurrence des traitements tout en garantissant la cohérence des données. Les transactions dans JPA se font toujours au niveau objet. Cela signifie que toutes les modifications apportées à tous les objets intégrés au contexte de persistance font partie de la transaction. 51
JEE - JPA et JTA Par défaut, les méthodes des EJB sont transactionnelles. Dans un EJB, l’appel d’une méthode démarre une transaction JTA si aucune n'est en cours. On injecte l’EntityManager en utilisant l’annotation @PersistenceContext. Ensuite, les méthodes sont transactionnelles par défault. @Stateless public class MaClasseService { @PersistenceContext(unitName = "annuairePU") EntityManager em; public void enregistrer(List personnes) { for (Personne p: personnes) { em.persist(p); } } 52
JEE - JPA et JTA Gestion des erreurs : Quand la fonction se termine correctement : ● commit automatique Quand elle échoue sur une exception : ● RuntimeException -> rollback ● Exceptions déclarées -> commit 53
JEE - JPA et JTA Initier une transaction dehors du mode géré par le container. EntityManagerFactory emf = Persistence.createEntityManagerFactory(persistenceUnitName) EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); Compte bill = em.find( Compte.class, "Bill" ); Compte martin = em.find( Compte.class, "Martin" ); tx.begin(); try { bill.setSolde( bill.getSolde() - 100 ); martin.setSolde( martin.getSolde() + 100); em.persist(bill); em.persist(martin); tx.commit(); } catch( Exception e ) { tx.rollback(); } em.close(); emf.close(); 54
JEE - JPA Persitence Unit La configuration de l’accès à la bd est est paramétrée dans le fichier META-INF/persistence.xml. org.hibernate.jpa.HibernatePersistenceProvider 55
JEE - exemple d’implémentation JPA 3 classes « métier » : Ecole, Matière, Elève @Entity @Entity public class Ecole { public class Matiere { @Id @Id @GeneratedValue @GeneratedValue private int id; private int id; private String nom; private String nom; public Ecole() {} public Matiere() {} public int getId() { public int getId() { return id; return id; } } public void setId(int id) { public void setId(int id) { this.id = id; this.id = id; } } public String getNom() { public String getNom() { return nom; return nom; } } public void setNom(String nom) { public void setNom(String nom) { this.nom = nom; this.nom = nom; } } } } 56
JEE - exemple d’implémentation JPA @Entity public class Eleve { ... public String getNom() { @Id return nom; @GeneratedValue } private int id; public void setNom(String nom) { private String nom; this.nom = nom; } @ManyToOne @JoinColumn(name="ECOLE_ID") public Ecole getEcole() { private Ecole ecole; return ecole; } @ManyToMany @JoinTable(name="ELEVE_COURS", public void setEcole(Ecole ecole) { joinColumns=@JoinColumn(name="EC_ELEVE_ID"), this.ecole = ecole; inverseJoinColumns=@JoinColumn(name="EC_COURS_ID")) } private Collection matieres; public Collection public Eleve() { getMatieres() { matieres = new HashSet(); return matieres; } } public int getId() { public void return id; setMatieres(Collection matieres) { } this.matieres = matieres; } public void setId(int id) { } this.id = id; } ... ● 1 élève est dans 1 école (une école a plusieurs élèves) ● 1 élève suit plusieurs cours (un cours comprend également plusieurs élèves) 57
JEE - exemple d’implémentation JPA public class App { public static void main(String[] args) { EntityManagerFactory emf = Persistence.createEntityManagerFactory("PU"); EntityManager em = emf.createEntityManager(); Ecole cnam = new Ecole(); cnam.setNom("CNAM"); Matiere NFP121 = new Matiere(); NFP121.setNom("NFP121"); Matiere NSY102 = new Matiere(); NSY102.setNom("NSY102"); Matiere GLG203 = new Matiere(); GLG203.setNom("GLG203"); Matiere SMB116 = new Matiere(); EntityTransaction tx = em.getTransaction(); SMB116.setNom("SMB116"); tx.begin(); Eleve jean = new Eleve(); try { jean.setNom("Jean"); em.persist(cnam); jean.setEcole(cnam); em.persist(NFP121); jean.getMatieres().add(NFP121); em.persist(NSY102); jean.getMatieres().add(NSY102); em.persist(GLG203); Eleve paul = new Eleve(); em.persist(SMB116); paul.setNom("paul"); em.persist(jean); paul.setEcole(cnam); em.persist(paul); paul.getMatieres().add(GLG203); tx.commit(); paul.getMatieres().add(SMB116); } catch (Exception e) { paul.getMatieres().add(NSY102); tx.rollback(); } em.close(); emf.close(); } } 58
JEE - implementation JPA ... dans une servlet @WebServlet(urlPatterns = {"/show"}) public class AffichageServlet extends HttpServlet{ @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { EntityManagerFactory emf = Persistence.createEntityManagerFactory("PU"); EntityManager em = emf.createEntityManager(); DisplayService service = new DisplayService(em); List ecoles = service.findAllSchools(); List matieres = service.findAllCourses(); List eleves = service.findAllStudents(); em.close(); il faut construire emf.close(); req.setAttribute("eleves", eleves); notre Service ! req.setAttribute("matieres", matieres); req.setAttribute("ecoles", ecoles); req.getRequestDispatcher("/WEB-INF/jsp/affichage.jsp").forward(req, resp); } } 59
JEE - implementation JPA ... le DAO public class DisplayService { private EntityManager em; public DisplayService(EntityManager em) { this.em = em; } public List findAllSchools() { Query query = em.createQuery("SELECT e FROM Ecole e"); return (List) query.getResultList(); } public List findAllStudents() { Query query = em.createQuery("SELECT e FROM Eleve e"); return (List) query.getResultList(); } public List findAllCourses() { Query query = em.createQuery("SELECT e FROM Matiere e"); return (List) query.getResultList(); } } 60
JEE - implementation JPA ... la JSP 1/2 SHOW Template Login ----- ECOLES ----- ID-- NAME--- ${ecole.id}${ecole.nom} ----- MATIERES ----- ID-- NAME--- ${matiere.id}${matiere.nom} 61
JEE - implementation JPA ... la JSP 2/2 ----- ELEVES ----- ID-- NAME--- ECOLE--- MATIERE 1- MATIERE 2- MATIERE 3- ${eleve.id} ${eleve.nom} ${eleve.ecole.nom} ${elevMat.nom}
JEE - la JSTL ou Java Standard Tags Library ● jeu de tags pour remplacer la plupart des constructions java dans les JSP ● exemple pour une boucle foreach, vu dans les pages précédentes : ● ● ${ecole.id}${ecole.nom} ● ● travaille de très près avec l’expression language ● il faut insérer la ligne suivante en début du fichier ● jsp : ● insérer la bibliothèque JSTL dans le classpath 63
Utiliser MAVEN pour la création d’un projet Spring Maven est un outil de gestion de dépendances et de build spécifiquement créé pour java. Un projet Maven est structuré et normé. Un fichier Pom.xml définit les propriétés et les dépendances (librairies) dont a besoin le projet pour compiler ou s’exécuter. Arborescence d’un projet Maven /src /main /java /resources /webapp /test /java /resources /target // fichiers compilés 64
Utiliser MAVEN pour la création d’un projet Spring Ensemble de tâches pour compiler ou préparer une librairie : ● compile ● clean ● test ● package Les dépendances sont distribué à travers les repositories. Repository central : https://mvnrepository.com/ Repository local : là où l’ensemble des dépendances sont téléchargées lorsqu’on utilise un projet maven : C:\Users\xxx\.m2\repository 65
Spring - introduction Spring est un framework open source pour le développement d’applications java, qui n'est pas standardisé par le JCP (java community process qui émet les JSR) ... ... mais est un standard de facto du fait de sa large utilisation. Il permet d’intégrer les framework open source (Hibernate ...) et les principales API java (Servlet, JMS ...) Spring peut s’utiliser dans un simple conteneur web (Tomcat) ... ... car il utilise de simples POJO pour développer des applications plutôt que d'utiliser des EJB dans un conteneur. 66
Spring - introduction Le noyau de Spring est basé sur une fabrique générique de composants informatiques (beans) et un conteneur capable de stocker ces beans. De plus, le noyau de Spring permet de forcer le contrôle de ces composants de leur extérieur, par l’inversion de contrôle. Le principal avantage est de composer les beans de façon plus déclarative plutôt que de façon impérative dans le programme 67 source wikipedia
Spring - l’inversion de contrôle Spring s’appuie donc sur l’inversion de contrôle, assurée de deux façons différentes : la recherche de dépendances et l'injection de dépendances. Pour mémoire (NFP121), l’inversion de contrôle fournit un moyen cohérent de configuration et de gestion des objets Java à l'aide de l’introspection. 68
Spring - l’inversion de contrôle ● La recherche de dépendance consiste à interroger le conteneur, afin d’obtenir un objet avec un nom spécifique ou d'un type spécifique. C’est un cas de fonctionnement similaire aux EJBs. ● L’injection de dépendances - cette injection peut être effectuée de trois manières possibles : ● L’injection de dépendance via le constructeur. ● L’injection de dépendance via les modificateurs (setters). ● L’injection de dépendance via une interface. Les deux premières sont les plus utilisées par Spring. 69 source wikipedia
Spring - l’inversion de contrôle Avec Spring, on ne crée pas directement d'objet, mais on décrit comment un objet doit être créé. Le framework se charge de la création. De même, les services et les composants ne sont pas appelés directement. Les services et les composants devant être appelés sont définit dans un fichier de configuration . L’inversion de contrôle est destinée à augmenter la facilité de maintenance et de test. 70
Spring - l’inversion de contrôle Les annotations de Spring permettent de marquer des classes comme beans, afin qu’ils soit reconnus comme tels par le container et puissent être « injectés ». Avec les annotations @Component, @Repository, @Service et @Controller et l'analyse automatique des composants activée, Spring importera automatiquement les beans dans le conteneur et les « injectera » quand nécessaire. L’annotation @Autowired gère le câblage. Elle est à placer au- dessus de l’attribut à récupérer par injection dans une classe. Cet objet devra avoir été annoté par l’une des annotations vues précédemment. 71
Spring - l’inversion de contrôle L'annotation @Component marque une classe java comme un bean afin que le mécanisme d'analyse des composants de Spring puisse la repérer et l'intégrer au contexte de l'application. Les autres annotations sont des spécialisations de celle-ci pour les DAO (@Repository), les services -« Business Service Facade »- (@Service) et les contrôleurs (@Controller). Elles permettent de préciser l’intention, et peuvent amener des fonctionnalités supplémentaires, comme la gestion des exceptions par DataAccessException pour @Repository, ou la possibilité d’utiliser l’annotation additionnelle @RequestMapping pour @Controller. 72
Spring - programmation orientée aspect Ce type de programmation (AOP) permet de prendre en compte les fonctionnalités transverses. Par exemple, une couche logicielle dédiée à gérer la logique métier applicative (par exemple un système bancaire), va se retrouver dépendante de modules gérant les aspects transactionnels, de journalisation, etc. ; la croissance de ces dépendances conduit à une complexification du code, de son développement et de sa maintenance. La programmation par aspect va permettre d'extraire les dépendances entre modules concernant des aspects techniques entrecroisés et de les gérer depuis l'extérieur de ces modules en les spécifiant dans des composants du système à développer nommés « aspects » ; ils sont développés à un autre niveau d'abstraction (source wikipedia). Spring va utiliser les concepts de la programmation par aspects via les notions d’intercepteur et de coupe, notamment pour la mise en oeuvre des transactions. 73
Spring - la couche d’abstraction La couche d’abstraction de Spring permet d’intégrer d’autres frameworks et bibliothèques avec une plus grande facilité. Grâce à cette couche, Spring ne concurrence pas d’autres frameworks dans une couche spécifique d’un modèle architectural MVC mais s’avère être un framework multi-couches pouvant s’insérer au niveau de toutes les couches ; modèle, vue et contrôleur. Ainsi il permet d’intégrer Hibernate pour la couche de persistance ou encore JavaServer Faces (JSF)pour la couche présentation. 74 source wikipedia
Spring - modules Spring fournit un ecosystème particulièrement riche avec plus de 50 sous-projets : Spring Boot : Spring Boot makes it easy to create stand-alone, production-grade Spring based Applications that you can "just run". Spring Data : Spring Data’s mission is to provide a familiar and consistent, Spring-based programming model for data access while still retaining the special traits of the underlying data store. Spring MVC : Spring Web MVC is the original web framework built on the Servlet API and has been included in the Spring Framework from the very beginning. Spring Security, Spring Websocket, Spring AMPQ, Spring Web Services, Spring Kafka, Spring Cloud, Spring Mobile ... 75
Spring - Spring Boot La configuration de Spring est particulièrement compliquée. Spring Boot a donc été créé dans le but de faciliter la configuration d’un projet Spring et de réduire le temps alloué à son démarrage. Pour cela Spring Boot propose : ● Un site web (https://start.spring.io/) permettant de générer rapidement la structure d’un projet en y incluant toutes les dépendances Maven nécessaires. ● des « Starters » pour gérer les dépendances. Les dépendances Maven sont regroupées dans des « méga dépendances » afin de faciliter leur gestion. ● L’auto-configuration, qui applique une configuration par défaut au démarrage de l’application pour toutes dépendances présentes . Cette configuration s’active à partir du moment où l’application est annotée avec « @SpringBootApplication » (cette configuration peut-être surchargée). L’auto-configuration simplifie la configuration sans pour autant vous restreindre dans les fonctionnalités de Spring. ● possibilité d’intégrer directement un serveur Tomcat dans l’exécutable. Un Tomcat embarqué sera démarré au lancemenbt afin de faire tourner l’application. 76
Spring - architecture modèle web Front controller 77
Spring - Le POM Spring Boot 4.0.0 org.springframework.boot spring-boot-starter-parent 2.1.4.RELEASE fr.cnam NSY102 0.0.1-SNAPSHOT généré via https://start.spring.io/ jar NSY102 ou via Eclipse Demo project for Spring Boot pour les éléments pricipaux 1.8 (web, jpa, json, Thymeleaf) org.springframework.boot spring-boot-starter-data-jpa org.springframework.boot spring-boot-starter-jdbc org.springframework.boot spring-boot-starter-thymeleaf 78
Spring - Le POM Spring Boot nz.net.ultraq.thymeleaf thymeleaf-layout-dialect org.springframework.boot spring-boot-starter-web com.h2database h2 runtime com.fasterxml.jackson.dataformat jackson-dataformat-csv org.webjars bootstrap 4.3.1 org.webjars jquery 3.4.0 org.springframework.boot spring-boot-starter-test test org.springframework.boot spring-boot-maven-plugin 79
Spring - arborescence Spring Boot Fichier de config application.properties # =============================== # DATABASE # =============================== spring.datasource.driver-class-name=org.h2.Driver spring.datasource.url=jdbc:h2:./db spring.datasource.username=user spring.datasource.password=user # =============================== # JPA / HIBERNATE # =============================== spring.jpa.show-sql=true spring.jpa.hibernate.ddl-auto=update spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect 80
Spring - le fichier de lancement de Spring Boot Généré par Spring boot regroupe les annotations : ● @EnableAutoConfiguration : package fr.cnam.nsy102; permet le mécanisme d’auto- import org.springframework.boot.SpringApplication; configuration import org.springframework.boot.autoconfigure.SpringBootApplication; ● @ComponentScan : indique à @SpringBootApplication Spring dans quels packages public class Nsy102Application { rechercher les beans (classes public static void main(String[] args) { SpringApplication.run(Nsy102Application.class, args); annotées) } } ● @Configuration : Les classes où elle est apposée se substituent aux traditionnels fichiers de configuration XML. On y trouve la déclaration de beans Spring, l’import de fichiers ou de classes de configuration. 81
Spring - un 1er exemple un première appli web « Hello World ! » annotation @Controller, le contrôleur MVC servlet en JEE @Controller public class SimpleController { annotation @RequestMapping, @RequestMapping("/simple") donne l’URL par laquelle on @ResponseBody public String simple() { pourra invoquer l’action return "Hello World !"; } } annotation @ResponseBody signifie que le résultat s’affichera dans le corps de la page html 82
Spring - un 2ème exemple url paramétrée avec @PathVariable ● pattern matching possible annotation @RequestMapping possible au niveau de la classe @Controller @RequestMapping("/hello") public class SimpleController { ... avec une spécialisation @RequestMapping("/simple") @ResponseBody au niveau des méthodes name est ici une variable public String simple() { ( ./hello/simple ) return "Hello World !"; } @RequestMapping("/details/{name}") l’annotation @PathVariable signifie @ResponseBody public String details(@PathVariable String name) { que la variable de l’url est injectée return "Hello "+name; dans le paramètre de la méthode } et sera donc utilisable dans celle-ci } 83
Spring - Femto Application Nous allons construire une application très basique, qui comprend une seule classe métier, « article ». Nous devrons pouvoir créer des articles, les afficher, les supprimer, les mettre dans notre panier (dans le cadre d’une session). Classement de nos classes dans l’arborescence selon leur typologie (métier, contrôleur, service, dao) 84
Spring - Application : classe métier @Entity prise en charge par JPA public class Article { clé primaire @Id private String id; private String name; private double price; Compte tenu de notre configuration public String getId() { return id; (spring.jpa.hibernate.ddl-auto=update), } Spring créera la db si elle n’existe pas au public void setId(String id) { this.id = id; lancement du programme. } 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; } } 85
Spring - Application : classe métier public class Panier { private List articles; public Panier() { articles = new ArrayList(); } public List getArticles() { return this.articles; } public void setArticles(List articles) { this.articles = articles; } } Le panier, que nous ne persisterons pas 86
Spring - Application : DAO Interfaces Spring xxxRepository, spécifiques pour l’accès aux données via JPA. Les repositories génériques fournis par Spring permettent de réaliser les opérations courantes d’accès aux données. On trouve notamment les Interfaces Repository, CrudRepository ... Il suffit de créer une interface héritant d’un de ces repositories pour utiliser ses méthodes, et en définir de plus spécifiques si nécessaire (en respectant les conventions de nommage, par ex findByAttribut). 2 paramètres génériques : le type de l’entité et le type de sa clé primaire. Le code sera généré par Spring Data à partir de notre interface, sans que nous ayons à fournir nous mêmes l’implémentation ! public interface ArticleRepository extends JpaRepository {} 87
Spring - application : business service facade @Service composant / bean de type service. public class ArticleService { L’annotation permettra au bean d’être importé @Autowired dans le conteneur et injectable à la demande private ArticleRepository articleRepository; @Transactional public Article enregistrer(Article article) { injection du bean DAO return articleRepository.save(article); } @Transactional méthode transactionnelle (cf slide suivante) public void supprimer(String id) { articleRepository.deleteById(id); } ) public List lister() { return articleRepository.findAll(); } public Optional trouver(String id) { return articleRepository.findById(id); } } 88
Spring - Les transactions avec Spring Boot La gestion des transactions est configurée par défaut avec Spring Boot, pour autant qu’une dépendance de type « spring-data-* » soit dans le classpath. L’annotation @Transactional au niveau d’une classe ou d’une méthode (forcément public) suffira à la rendre transactionnelle. L'annotation prend également en charge les configurations suivantes (entre autres) : ● le type de propagation de la transaction (la propagation décrit ce qui se passe si une transaction doit être ouverte dans le cadre d'une transaction déjà existante). ● le niveau d'isolement de la transaction (l'isolement détermine entre autres si une transaction peut voir des écritures non validées d'une autre transaction) ● un indicateur readOnly (indicateur pour le fournisseur de persistance que la transaction doit être en lecture seule) ● les règles de roll-back pour la transaction 89
Spring - Application : un contrôleur 1/2 @Controller public class ManageArticlesController { - composant / bean de type contrôleur. @Autowired - injection du bean Service ArticleService articleService; - annotation possible dans un bean de type Controller @GetMapping("/show") public String viewTemplate(Model model) { (= @RequestMapping + méthode HTTP GET) List catalog = articleService.lister(); model.addAttribute("catalog", catalog); - appelle ShowCatalog.html return "showCatalog"; } - Model = objet permettant de transmettre des @GetMapping("/new") public String createArticle(Model model) { paramètres à la vue model.addAttribute("article", new Article()); return "createArticle"; } - paramètre de l’URL transmis à la méthode @GetMapping("/delete/{id}") public String deleteArticle(@PathVariable String id) { articleService.supprimer(id); - ModelAttribute = indique que l'argument doit être return "redirect:/show"; } extrait du modèle. Ici, article est rempli avec les @PostMapping("/new") données du formulaire transmis public String newArticle(@ModelAttribute Article article, Model model) { if (article.getId() != "" && article.getId() != null && article.getName() != "" && article.getName() != null && article.getPrice() != 0.0) { articleService.enregistrer(article); } else { model.addAttribute("error", true); return "createArticle"; } return "redirect:/show"; - redirige vers l’URL /show, càd appelle la méthode } ViewTemplate de ce contrôleur 90
Spring - Application : un contrôleur 2/2 @GetMapping("/addToBasket/{id}") public String addToBasket(HttpSession session, @PathVariable String id) { Double totalPrice = 0.0; Panier monPanier = (Panier) session.getAttribute("panier"); if (monPanier == null) { monPanier = new Panier(); session.setAttribute("panier", monPanier); injection de l’objet session ... } Article art = articleService.trouver(id).get(); monPanier.getArticles().add(art); for (Article a : monPanier.getArticles()) { ... auquel on ajoute des totalPrice += a.getPrice(); } attributs qui survivront tout au session.setAttribute("totalPrice", totalPrice); session.removeAttribute("emptyBasket"); long du cycle de vie de l’objet return "redirect:/show"; } @GetMapping("/removeFromBasket/{index}") public String removeFromBasket(HttpSession session, @PathVariable int index) { Double totalPrice = 0.0; ((Panier) session.getAttribute("panier")).getArticles().remove(index); Panier monPanier = (Panier) session.getAttribute("panier"); for (Article a : monPanier.getArticles()) { totalPrice += a.getPrice(); } session.setAttribute("totalPrice", totalPrice); if (totalPrice == 0) session.setAttribute("emptyBasket", "yes"); else session.removeAttribute("emptyBasket"); return "redirect:/show"; } } 91
Spring - Application : un contrôleur REST annotation qui combine @Controller et @ResponseBody, et nous évite ainsi de devoir annoter chaque méthode de la @RestController classe avec l’annotation @ResponseBody public class ArticlesRestController { @Autowired ArticleService articleService; @GetMapping(path="/showJson", produces = MediaType.APPLICATION_JSON_UTF8_VALUE ) public List viewJson(Model model) { List catalog=articleService.lister(); return catalog; } @GetMapping(path="/showJson/{id}", produces = MediaType.APPLICATION_JSON_UTF8_VALUE ) public Article viewSingleJson(@PathVariable String id) { Article article = articleService.trouver(id).get(); return article; } } « produces » donne le type du contenu produit par la méthode (type JSON ici) 92
Spring - Application : default.html NSY102 NSY102 Cnam 2019 93
Spring - Application : CreateArticle.html fichier messages.properties article.id= ID de l'article article.name= Nom de l'article article.price= Prix de l'article article.error=Tous les champs doivent être complétés basket.empty=Votre panier est vide Article id Article name Article price SEND 94
Spring - Application : showCatalog.html table { font-family: arial, sans-serif; border-collapse: collapse; width: 100%; } td, th { border: 1px solid #dddddd; text-align: left; padding: 8px; } tr:nth-child(even) { background-color: #dddddd; } ----- CATALOGUE ----- ID NAME PRICE REMOVE BASKET + 59.9 Supprimer ajouter au panier 95
Spring - Application : showCatalog.html ----- PANIER ----- ARTICLE BASKET - retirer du panier Prix total € H.T. 96
JEE - SPRING THE END 97
Vous pouvez aussi lire