diff --git a/cours-03.html b/cours-03.html index 481a700..62b20e3 100644 --- a/cours-03.html +++ b/cours-03.html @@ -9,7 +9,7 @@ - + + + + + + + + + + +
+ +
Please wait, while our marmots are preparing the hot chocolate…
+ +
+ +# @chunk: chunks/title.md + +# Questions ?
Commentaires ? {no-print} + +# @chunk: chunks/objectives.md + +## Pour dès que possible (avant lundi) +- Projets !? {no-print} + - sujet + - description et mini cahier des charges + - quoi en Thymeleaf (génération coté serveur) ? + - quoi en Vue (génération coté client) ? + - groupes + - 3 personnes max + - nom et login github + - rappel + - soutenances : dernier créneau déjà planifié + - commencez tout de suite + +## Pour la prochaine fois +- Classe inversée + - autour du MVC etc + - comprendre ce qu'est une servlet + - avoir une idée de ce qu'est une annotation java + - lire au sujet de « Thymeleaf » + - lire au sujet de « dependency injection » + - ressources + - cours-03 + - cours-05 (à venir) + - wikipedia + - internet +- Dans tous les cas, finir le TP + +# Questions ? + +# TP 1 + + + +## Points Clés {key deck-status-fake-end} + +
+ + +

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

+ + + + + +
+ + + + + + + + + + + diff --git a/cours-05.html b/cours-05.html new file mode 100644 index 0000000..12de044 --- /dev/null +++ b/cours-05.html @@ -0,0 +1,502 @@ + + + + + + + Programmation Web Avancée   Spring MVC, Injection de Dépendances + + + + + + + + + + + + + + + + + +
+ +
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

+ + + + + +
+ + + + + + + + + + + diff --git a/index.html b/index.html index c3f5a58..22aa46a 100644 --- a/index.html +++ b/index.html @@ -13,8 +13,8 @@ body {display: inline-block;} h1 {color: gray; margin-bottom: 2em;} h2 {color: white; background: black; margin:0; margin-top: 120px;} - a {display:inline-block; float: left; width: 165px; padding: 15px;} - a {margin-left: 6px;} + a {display:inline-block; width: 160px; padding: 15px; vertical-align: top; margin-left: 6px; text-align: center;} + body>div {text-align: left;} a:nth-child(4n+1) {margin-left:0;} a {background: rgb(225, 73, 56); color: white; text-decoration: none; font-weight: bold;} a.proj {min-height: 65px;} @@ -33,7 +33,9 @@ Voir les slides? Slides 1
introduction
Slides 2
HTML+CSS
- Slides 3
MVC, Spring+Thymeleaf
+ Slides 3
MVC, Spring+Thymeleaf
+ Slides 4
Projet, TP1
+ Slides 5
Thymeleaf, DI

Code des séances