Please wait, while our marmots are preparing the hot chocolate…
# @chunk: chunks/title.md # Questions ?
Commentaires ? {no-print} # @chunk: chunks/objectives.md ## Programmation Web Avancée {var-cours-n} : Plan {#plan overview} - MVC Web et Spring MVC {mvcweb} - MVC Web en Pratique {mvcdemo} - Injection de Dépendances {di} - Introduction à la persistance en Java {persi} - Java Persistence API (JPA) {jpa} # @copy:#plan # @copy:#plan: %+class:inred: .mvcweb ## MVC avec Spring dans ce cours {libyli} - Modèle - JavaBeans (objets Java) - persistance avec JPA et Repositories de Spring Data - Contrôleur - description de route : annotations Java - méthodes Java, avec injection de paramètres - classe `Model` pour le ViewModel - Vue - templates Thymeleaf - accès automatique au ViewModel ## Interaction Client Serveur et MVC

 

@svg: media/client-server-mvc/server-mvc.svg 700px 400px - @anim: #user, #client |#server |#r0 |#a0 |#s0,#router |#s1,#controller |#s2,#service |#s3,#db |#s4 |#s5,#view |#s6 |#s7 |#legend # @copy:#plan: %+class:inred: .mvcdemo ## Quelques Éléments en Vrac (+ astuces) {libyli densish} - Pour tester on peut faire un modèle en mémoire - sous forme d'objets Java - stockés dans une liste dans une variable « globale » - Un/des contrôleur(s) {libyli} - annotation de classe `@Controller` - annotation de méthode `@RequestMapping(.....)` - paramètre « magique » `Model m`, qui sera passé à la vue - `m.addAttribute("letruc", valeur)` pour remplir le « modèle de vue » - paramètre et annotation `@RequestParameter` pour les formulaires {unseen} - capture de pattern dans l'url avec `@PathVariable` {unseen} - Une/des vue(s) {libyli} - fichiers Thymeleaf = XHTML + `th:....` (templates dite naturelles) - remplacer le contenu d'une balise, attribut `... th:text="${letruc}"` - ... - accès à une propriété d'un objet `${letruc.machin}{}` équivalent à `letruc.getMachin()` en Java - répéter la balise donnée, attribut `... th:each="e : ${letruc}"` - mélanger texte et variables dans une balise - la balise doit avoir `th:inline="text"` (ou il faut utiliser Thymeleaf 3) - dans la balise, utiliser des doubles crochets, e.g., `Bonjour [[${nom}]] !` {unseen} - gérer les formulaires (cf TP) avec `th:action`, `th:object`, `th:field` {unseen} - Convention maven (système de build) + Spring - fichiers Java dans `src/main/java/.....` - fichiers templates dans `src/main/resources/templates/` - fichiers statiques dans `src/main/resources/static/` (pour les .css, .js, images etc) # Start Démo # modèle simple et affichage de la liste # ajout "id" aux classe du modèle (pour la suppresison) # `th:inline="text"`, lien détails (`th:href="@{....}"`) # suppression, `@RequestParam`, `return "redirect:/....";` # page de détails `@PathVariable` # formulaire d'ajout avec `th:action` (et `th:object`, `th:field`, et constructeur vide) # End Démo # @copy:#plan: %+class:inred: .di ## Injection de dépendance (DI) {libyli} - Cas sans injection de dépendance - il nous faut une instance (par ex, une connection DB) - on la crée (ou on utilise une « Factory ») - Patron « injection de dépendance » - Dependency Injection (DI) Inversion of Control (IoC) - quelqu'un fourni l'instance (e.g. avec `@Component`), qui est injectée dans notre programme - injection par constructeur ou par “setter” ```java class UserObject { @Inject Connection connection; @Inject BlablaService blabla; } {slide denser} ``` - Ce que fait à peu près le framework d'injection : il cherche des implémentations de Connection et BlablaService, puis ```java Connection cDB = new SQLDataConnection(); BlablaService s = new BlaBlaServiceImpl(); UserObject obj = new UserObject(); obj.setConnection(cDB); obj.setService(s); {slide denser} ``` # Injectons avec `@Inject` et `@Component` (+ ajout de dépendance maven à javax.inject) # @copy:#plan: %+class:inred: .persi ## Persistence: motivation {libyli} - When we close/restart an application - memory is freed - all objects are lost - Persistence - saving objects state - ... on a permanent storage (non-volatile), e.g., database, file, etc - allows for reloading objects later ## Persistence Options in Java {libyli} - Simple JDBC with or without DAOs (DataAccessObjects) - direct access to the SQL database - DAO: object that encapsulates/hides SQL requests - ORM Concept: Object-Relational Mapping - systematic mapping between Java objects and database relations/tables - Persistence Frameworks with ORM - JPA (Java Persistence API) // most recent - JDO (Java Data Objects) // most complete (more than JPA) - EJB 3 (Entreprise JavaBeans) // higher level - Hibernate (Spring), via JPA // just a JPA backend now ## Simple JDBC Example ``` import java.sql.*; … // JDBC driver name and database URL static final String JDBC_DRIVER = "com.mysql.jdbc.Driver"; static final String DB_URL = "jdbc:mysql://localhost/EMP"; // Database credentials static final String USER = "username"; static final String PASS = "password"; public static void main(String[] args) throws ... { Class.forName(JDBC_DRIVER); Connection conn = DriverManager.getConnection(DB_URL, USER, PASS); Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery("SELECT id, prenom, nom, age FROM Employes"); while(rs.next()){ int id = rs.getInt("id"); int age = rs.getInt("age"); String first = rs.getString("prenom"); String last = rs.getString("nom"); System.out.print(id + " : " + first + " " + last + " agé de " + age); } rs.close(); // hum.... stmt.close(); // hum.... conn.close(); // hum.... } … {denser} ```
## Simple JDBC example, Java 7+ ```java import java.sql.*; … // JDBC driver name and database URL static final String JDBC_DRIVER = "com.mysql.jdbc.Driver"; static final String DB_URL = "jdbc:mysql://localhost/EMP"; // Database credentials static final String USER = "username"; static final String PASS = "password";   public static void main(String[] args) throws ... {   Class.forName(JDBC_DRIVER);   try ( Connection conn = DriverManager.getConnection(DB_URL, USER, PASS); Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery("SELECT id, prenom, nom, age FROM Employes"); ) {   while(rs.next()){   int id = rs.getInt("id"); int age = rs.getInt("age"); String first = rs.getString("prenom"); String last = rs.getString("nom");   System.out.print(id + " : " + first + " " + last + " agé de " + age); } } } {denser} ``` # JDBC simple : avantages/inconvénients ? ## Objet-Relational Mapping: concept - @anim: #objs |#rel |#car |#table |#arr0 |#arr1 |#arr2 |#arr3 |#arr4 - @anim: #optionClass |#optionTable |#arr678 |#optColumn |#arr5 @SVG: media/orm.svg 800 420 ## Object-Relational Mapping {libyli} - Questions? - what class corresponds to what table - what attribute corresponds to what column - what attribute corresponds to what foreign key - what are the multiplicities - In practice{libyli} - using JDBC, manually… tedious - source code very long (most of the app) // 30% - very repetitive code - dangerous code (error-prone) - difficult to evolve - using a persistence framework - JPA, JDO, Hibernate - writing metadata on Java classes and attributes # @copy:#plan: %+class:inred: .jpa ## JPA: Java Persistance API {libyli} - Why the JPA standard? {libyli} - Pure JDBC: tedious - Data Access Objects: abstraction, but too much code - need a Object/Relational Mapping (ORM) description - XML description too verbose and not DRY (Don't Repeat Yourself) - proliferation of frameworks (hibernate, toplink, ...) - need a usable standard - What is JPA? - a set of annotations and conventions // default values etc - description of object/relational mappings - originally, a part EJB 3 (Entreprise Java Beans) - an `EntityManager` to manage data (transparent in Spring) - to save, `em.persist()` - to delete, `em.remove()` - to read, `em.find()`, … ## JPA Annotations: simple example ```java import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.GeneratedValue; @Entity public class Car { @Id @GeneratedValue(strategy = GenerationType.AUTO) private long id; private String company; private String model; private long price; ...constr/get/set... Important! } ... EntityManager em; ... em.persist(myCar); {} ``` ## JPA Annotations: simple example ```java import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.GeneratedValue; import javax.persistence.Table; @Entity @Table(name = "Vehicle") public class Car { @Id @Column(name = "id") @GeneratedValue(strategy = GenerationType.AUTO) private long id; @Column(name = "company") private String company; @Column(name = "model") private String model; @Column(name = "price") private long price; ...constr/get/set... Important! } ... EntityManager em; ... em.persist(myCar); {} ``` ## JPA Annotations // make them write something - Others {right autre} - @PersistenceContext // expliquer qu'il faut sauver les EJB - … - Class-level - @Entity - @Table - (EJB @Stateless) - (EJB @Stateful) - … - Attribute-level, JavaBean relations {right relations} - @OneToOne - @ManyToOne - @OneToMany - @ManyToMany - @MapKey - @OrderBy - … - Attribute-level, JavaBean {attr} - @Column - @Id - @GeneratedValue - @Temporal, @Lob, @Basic - @Version - @Transient - … - @anim: .attr | .relations | .autre ## Manipulating JPA Entities {libyli} - (Using an `EntityManager`) - to read, `em.find()`, … - to save, `em.persist()` - to delete, `em.remove()` - Using `Repositories` - abstraction to list and filter objects - need to define an interface - implemented automatically, e.g., by Spring Data - interfaces: Repository, CrudRepository, PagingAndSortingRepository - implementation is obtained via dependency injection # JPA (`@Entity`, `@Id`, `@OneToMany`, ...), Spring Data (`CrudRepository` x2 + `.save`), `/TEST` ## What Did We Just Do? {libyli} - Update the model - add an `@Entity` on the class - add a `long id` field,
with `@Id @GeneratedValue(strategy=GenerationType.AUTO) {dense}` - Create a new repository - an (empty) interface (not a class) - extending *CrudRepository<MyEntity, Long>{smartcode}* - Used the new repository interface - injected it - used `findAll` and `save` - the implementation being provided by spring data - According to project configuration (and defaults) - spring automatically uses an H2 database - the database is in memory (by default) - the database schema is automatically created - the database is dropped at startup # Keeping Our Data!
Tuning `application.properties{dense}` ## What Did We Just Do? {libyli} - Changing project configuration - to override default configuration - adding key=value properties in `application.properties` - Using a file database (instead of solely in-memory) - `spring.datasource.url=jdbc:h2:/tmp/mytestdb` - Stopped dropping (and recreating) the database everytime - `spring.jpa.hibernate.ddl-auto=none` - NB about previous point - in case one need to re-create the databse (schema update) - the line can be remove - or, use `spring.jpa.hibernate.ddl-auto=create-drop` - Some properties - `spring.datasource.password`, `spring.datasource.username` - `server.port` - and WAY more # ORM : avantages/inconvénients ?

/ will be replaced by the authorwill be replaced by the title