Commit 9ac948f81dca4ee6fc9764405fa67f9e3a81fa9a

Authored by Rémi Emonet
1 parent ef52bdc52f
Exists in master

post tp1

Showing 4 changed files with 640 additions and 4 deletions

cours-03.html View file @ 9ac948f
... ... @@ -9,7 +9,7 @@
9 9  
10 10 <meta name="author" content="Rémi Emonet">
11 11 <meta name="venue" content="PWA M1 DSC">
12   - <meta name="date" content="2016">
  12 + <meta name="date" content="2017">
13 13 <meta name="affiliation" content="Université Jean Monnet − Laboratoire Hubert Curien">
14 14  
15 15 <style type="text/css">
cours-04.html View file @ 9ac948f
  1 +<!DOCTYPE html>
  2 +<html>
  3 + <head>
  4 + <meta charset="utf-8">
  5 + <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
  6 +
  7 + <title>Programmation Web Avancée   TP Basics Front</title>
  8 + <meta name="cours-n" content="3">
  9 +
  10 + <meta name="author" content="Rémi Emonet">
  11 + <meta name="venue" content="PWA M1 DSC">
  12 + <meta name="date" content="2017">
  13 + <meta name="affiliation" content="Université Jean Monnet − Laboratoire Hubert Curien">
  14 +
  15 + <style type="text/css">
  16 + li blockquote {
  17 + padding: 5px;
  18 + font-size: 20px;
  19 + }
  20 + blockquote {
  21 + border: 1px solid darkgrey;
  22 + border-radius: 5px;
  23 + padding: 0;
  24 + font-size: 30px;
  25 + font-style: italic;
  26 + }
  27 + blockquote p {
  28 + margin: 0;
  29 + padding: 30px;
  30 + }
  31 + blockquote p cite {
  32 + font-size: 20px;
  33 + }
  34 + </style>
  35 +
  36 + <!--
  37 + <script src="deck.js/extensions/includedeck/load.js"></script>
  38 + <script src="extensions/slides-dev.js"></script>
  39 + -->
  40 + <script src="extensions/deck-packed.js"></script>
  41 + <script src="extensions/slides.js"></script>
  42 + <script>go()</script>
  43 + </head>
  44 +
  45 +<body>
  46 +
  47 +<div class="deck-container">
  48 +
  49 + <div class="deck-loading-splash" style="background: black; color: chartreuse;"><span class="vcenter" style="font-size: 30px; font-family: Arial; ">Please wait, while our marmots are preparing the hot chocolate…</span></div>
  50 +
  51 +<section class="smart">
  52 +
  53 +# @chunk: chunks/title.md
  54 +
  55 +# Questions ? <br/> Commentaires ? {no-print}
  56 +
  57 +# @chunk: chunks/objectives.md
  58 +
  59 +## Pour dès que possible (avant lundi)
  60 +- Projets !? {no-print}
  61 + - sujet
  62 + - description et mini cahier des charges
  63 + - quoi en Thymeleaf (génération coté serveur) ?
  64 + - quoi en Vue (génération coté client) ?
  65 + - groupes
  66 + - 3 personnes max
  67 + - nom et login github
  68 + - rappel
  69 + - soutenances : dernier créneau déjà planifié
  70 + - commencez tout de suite
  71 +
  72 +## Pour la prochaine fois
  73 +- Classe inversée
  74 + - autour du MVC etc
  75 + - comprendre ce qu'est une servlet
  76 + - avoir une idée de ce qu'est une annotation java
  77 + - lire au sujet de « Thymeleaf »
  78 + - lire au sujet de « dependency injection »
  79 + - ressources
  80 + - cours-03
  81 + - cours-05 (à venir)
  82 + - wikipedia
  83 + - internet
  84 +- Dans tous les cas, finir le TP
  85 +
  86 +# Questions ?
  87 +
  88 +# TP 1
  89 +
  90 +<!-- key points -->
  91 +
  92 +## Points Clés {key deck-status-fake-end}
  93 +
  94 +</section>
  95 +
  96 + <!-- deck.status snippet -->
  97 + <p class="deck-status deck-progress-10"> <span class="deck-status-current"></span> / <span class="deck-status-total"></span> − <span class="var-author">will be replaced by the author</span> − <span class="var-title">will be replaced by the title</span></p>
  98 +
  99 + <a data-progress-size=": spe.top(15, 555); height: 45*designRatio; left: slide.right - 90*designRatio; width: 90*designRatio" class="ccby" href="http://en.wikipedia.org/wiki/Creative_Commons_license" title="This work is under CC-BY licence." target="_blank"></a>
  100 +
  101 + <a class="ujm" data-progress-size=": spe.top(15, 525); height: 65*designRatio; left: slide.left; width: 130*designRatio" target="_blank"></a>
  102 +
  103 +</div>
  104 +<!-- clicky Cla -->
  105 +<script type="text/javascript">
  106 +var clicky_site_ids = clicky_site_ids || [];
  107 +clicky_site_ids.push(100779706);
  108 +(function() {
  109 + var s = document.createElement('script');
  110 + s.type = 'text/javascript';
  111 + s.async = true;
  112 + s.src = '//static.getclicky.com/js';
  113 + ( document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0] ).appendChild( s );
  114 +})();
  115 +</script>
  116 +<noscript><p><img alt="Clicky" width="1" height="1" src="//in.getclicky.com/100779706ns.gif" /></p></noscript>
  117 +
  118 +
  119 +<!-- Histats.com START (aync)-->
  120 +<script type="text/javascript">var _Hasync= _Hasync|| [];
  121 +_Hasync.push(['Histats.start', '1,2767123,4,0,0,0,00010000']);
  122 +_Hasync.push(['Histats.fasi', '1']);
  123 +_Hasync.push(['Histats.track_hits', '']);
  124 +(function() {
  125 +var hs = document.createElement('script'); hs.type = 'text/javascript'; hs.async = true;
  126 +hs.src = ('http://s10.histats.com/js15_as.js');
  127 +(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(hs);
  128 +})();</script>
  129 +<noscript><a href="http://www.histats.com" target="_blank"><img src="http://sstatic1.histats.com/0.gif?2767123&101" alt="javascript hit counter" border="0"></a></noscript>
  130 +<!-- Histats.com END -->
  131 +</body>
  132 +</html>
cours-05.html View file @ 9ac948f
  1 +<!DOCTYPE html>
  2 +<html>
  3 + <head>
  4 + <meta charset="utf-8">
  5 + <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
  6 +
  7 + <title>Programmation Web Avancée   Spring MVC, Injection de Dépendances</title>
  8 + <meta name="cours-n" content="5">
  9 +
  10 + <meta name="author" content="Rémi Emonet">
  11 + <meta name="venue" content="PWA M1 DSC">
  12 + <meta name="date" content="2017">
  13 + <meta name="affiliation" content="Université Jean Monnet − Laboratoire Hubert Curien">
  14 +
  15 + <style type="text/css">
  16 + .slide.densish>ul {font-size: 70%;}
  17 + </style>
  18 +
  19 + <!--
  20 + <script src="deck.js/extensions/includedeck/load.js"></script>
  21 + <script src="extensions/slides-dev.js"></script>
  22 + -->
  23 + <script src="extensions/deck-packed.js"></script>
  24 + <script src="extensions/slides.js"></script>
  25 + <script>go()</script>
  26 + </head>
  27 +
  28 +<body>
  29 +
  30 +<div class="deck-container">
  31 +
  32 + <div class="deck-loading-splash" style="background: black; color: chartreuse;"><span class="vcenter" style="font-size: 30px; font-family: Arial; ">Please wait, while our marmots are preparing the hot chocolate…</span></div>
  33 +
  34 +<section class="smart">
  35 +
  36 +# @chunk: chunks/title.md
  37 +
  38 +# Questions ? <br/> Commentaires ? {no-print}
  39 +
  40 +# @chunk: chunks/objectives.md
  41 +
  42 +## Programmation Web Avancée <span>{var-cours-n}</span> : Plan {#plan overview}
  43 +- MVC Web et Spring MVC {mvcweb}
  44 +- MVC Web en Pratique {mvcdemo}
  45 +- Injection de Dépendances {di}
  46 +- Introduction à la persistance en Java {persi}
  47 +- Java Persistence API (JPA) {jpa}
  48 +# @copy:#plan
  49 +
  50 +
  51 +
  52 +
  53 +<!-- MVC Web Spring (et un peu Java EE) -->
  54 +# @copy:#plan: %+class:inred: .mvcweb
  55 +
  56 +## MVC avec Spring dans ce cours {libyli}
  57 +- Modèle
  58 + - JavaBeans (objets Java)
  59 + - persistance avec JPA et Repositories de Spring Data
  60 +- Contrôleur
  61 + - description de route : annotations Java
  62 + - méthodes Java, avec injection de paramètres
  63 + - classe `Model` pour le ViewModel
  64 +- Vue
  65 + - templates Thymeleaf
  66 + - accès automatique au ViewModel
  67 +
  68 +
  69 +## Interaction Client Serveur et MVC
  70 +<p> </p>
  71 +
  72 +@svg: media/client-server-mvc/server-mvc.svg 700px 400px
  73 +
  74 +- @anim: #user, #client |#server |#r0 |#a0 |#s0,#router |#s1,#controller |#s2,#service |#s3,#db |#s4 |#s5,#view |#s6 |#s7 |#legend
  75 +
  76 +
  77 +<!-- ################################### -->
  78 +# @copy:#plan: %+class:inred: .mvcdemo
  79 +
  80 +## Quelques Éléments en Vrac (+ astuces) {libyli densish}
  81 +- Pour tester on peut faire un modèle en mémoire
  82 + - sous forme d'objets Java
  83 + - stockés dans une liste dans une variable « globale »
  84 +- Un/des contrôleur(s) {libyli}
  85 + - annotation de classe `@Controller`
  86 + - annotation de méthode `@RequestMapping(.....)`
  87 + - paramètre « magique » `Model m`, qui sera passé à la vue
  88 + - `m.addAttribute("letruc", valeur)` pour remplir le « modèle de vue »
  89 + - paramètre et annotation `@RequestParameter` pour les formulaires {unseen}
  90 + - capture de pattern dans l'url avec `@PathVariable` {unseen}
  91 +- Une/des vue(s) {libyli}
  92 + - fichiers Thymeleaf = XHTML + `th:....` (templates dite naturelles)
  93 + - remplacer le contenu d'une balise, attribut `... th:text="${letruc}"`
  94 + - ...
  95 + - accès à une propriété d'un objet `${letruc.machin}{}` équivalent à `letruc.getMachin()` en Java
  96 + - répéter la balise donnée, attribut `... th:each="e : ${letruc}"`
  97 + - mélanger texte et variables dans une balise
  98 + - la balise doit avoir `th:inline="text"` (ou il faut utiliser Thymeleaf 3)
  99 + - dans la balise, utiliser des doubles crochets, e.g., `Bonjour [[${nom}]] !` {unseen}
  100 + - gérer les formulaires (cf TP) avec `th:action`, `th:object`, `th:field` {unseen}
  101 +- Convention maven (système de build) + Spring
  102 + - fichiers Java dans `src/main/java/.....`
  103 + - fichiers templates dans `src/main/resources/templates/`
  104 + - fichiers statiques dans `src/main/resources/static/` (pour les .css, .js, images etc)
  105 +
  106 +# Start Démo
  107 +
  108 +# modèle simple et affichage de la liste
  109 +
  110 +# ajout "id" aux classe du modèle (pour la suppresison)
  111 +
  112 +# `th:inline="text"`, lien détails (`th:href="@{....}"`)
  113 +
  114 +# suppression, `@RequestParam`, `return "redirect:/....";`
  115 +
  116 +# page de détails `@PathVariable`
  117 +
  118 +# formulaire d'ajout avec `th:action` (et `th:object`, `th:field`, et constructeur vide)
  119 +
  120 +# End Démo
  121 +
  122 +<!-- ################################### -->
  123 +# @copy:#plan: %+class:inred: .di
  124 +
  125 +## Injection de dépendance (DI) {libyli}
  126 +- Cas sans injection de dépendance
  127 + - il nous faut une instance (par ex, une connection DB)
  128 + - on la crée (ou on utilise une « Factory »)
  129 +- Patron « injection de dépendance »
  130 + - Dependency Injection (DI) Inversion of Control (IoC)
  131 + - quelqu'un fourni l'instance (e.g. avec `@Component`), qui est injectée dans notre programme
  132 + - injection par constructeur ou par “setter”
  133 +```java
  134 +class UserObject {
  135 + @Inject Connection connection;
  136 + @Inject BlablaService blabla;
  137 +}
  138 +{slide denser}
  139 +```
  140 +- Ce que fait à peu près le framework d'injection : il cherche des implémentations de Connection et BlablaService, puis
  141 +```java
  142 +Connection cDB = new SQLDataConnection();
  143 +BlablaService s = new BlaBlaServiceImpl();
  144 +UserObject obj = new UserObject();
  145 +obj.setConnection(cDB);
  146 +obj.setService(s);
  147 +{slide denser}
  148 +```
  149 +
  150 +# Injectons avec `@Inject` et `@Component` (+ ajout de dépendance maven à javax.inject)
  151 +
  152 +
  153 +
  154 +
  155 +<!-- ###################### -->
  156 +# @copy:#plan: %+class:inred: .persi
  157 +
  158 +## Persistence: motivation {libyli}
  159 +- When we close/restart an application
  160 + - memory is freed
  161 + - all objects are lost
  162 +- Persistence
  163 + - saving objects state
  164 + - ... on a permanent storage (non-volatile), e.g., database, file, etc
  165 + - allows for reloading objects later
  166 +
  167 +## Persistence Options in Java {libyli}
  168 +- Simple JDBC with or without DAOs (DataAccessObjects)
  169 + - direct access to the SQL database
  170 + - DAO: object that encapsulates/hides SQL requests
  171 +- ORM Concept: Object-Relational Mapping
  172 + - systematic mapping between Java objects and database relations/tables
  173 +- Persistence Frameworks with ORM
  174 + - JPA (Java Persistence API) // most recent
  175 + - JDO (Java Data Objects) // most complete (more than JPA)
  176 + - EJB 3 (Entreprise JavaBeans) // higher level
  177 + - Hibernate (Spring), via JPA // just a JPA backend now
  178 +
  179 +
  180 +## Simple JDBC Example
  181 +```
  182 +import java.sql.*;
  183 +…
  184 +// JDBC driver name and database URL
  185 +static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
  186 +static final String DB_URL = "jdbc:mysql://localhost/EMP";
  187 +// Database credentials
  188 +static final String USER = "username";
  189 +static final String PASS = "password";
  190 +
  191 +public static void main(String[] args) throws ... {
  192 +
  193 + Class.forName(JDBC_DRIVER);
  194 +
  195 + Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
  196 +
  197 + Statement stmt = conn.createStatement();
  198 +
  199 + ResultSet rs = stmt.executeQuery("SELECT id, prenom, nom, age FROM Employes");
  200 +
  201 + while(rs.next()){
  202 +
  203 + int id = rs.getInt("id");
  204 + int age = rs.getInt("age");
  205 + String first = rs.getString("prenom");
  206 + String last = rs.getString("nom");
  207 +
  208 + System.out.print(id + " : " + first + " " + last + " agé de " + age);
  209 + }
  210 +
  211 + rs.close(); // hum....
  212 + stmt.close(); // hum....
  213 + conn.close(); // hum....
  214 +}
  215 +…
  216 +{denser}
  217 +```
  218 +<div class="slide anim-show" data-dur="400" data-what="code>span:nth-of-type(-n+10)"></div>
  219 +<div class="slide anim-show" data-dur="400" data-what="code>span:nth-of-type(n+10):nth-of-type(-n+18)"></div>
  220 +<div class="slide anim-show" data-dur="400" data-what="code>span:nth-of-type(n+18):nth-of-type(-n+28)"></div>
  221 +<div class="slide anim-show" data-dur="400" data-what="code>span:nth-of-type(n+28):nth-of-type(-n+34)"></div>
  222 +
  223 +## Simple JDBC example, Java 7+
  224 +```java
  225 +import java.sql.*;
  226 +…
  227 +// JDBC driver name and database URL
  228 +static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
  229 +static final String DB_URL = "jdbc:mysql://localhost/EMP";
  230 +// Database credentials
  231 +static final String USER = "username";
  232 +static final String PASS = "password";
  233
  234 +public static void main(String[] args) throws ... {
  235 +  
  236 + Class.forName(JDBC_DRIVER);
  237 +  
  238 + try (
  239 + Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
  240 + Statement stmt = conn.createStatement();
  241 + ResultSet rs = stmt.executeQuery("SELECT id, prenom, nom, age FROM Employes");
  242 + ) {
  243 +  
  244 + while(rs.next()){
  245 +  
  246 + int id = rs.getInt("id");
  247 + int age = rs.getInt("age");
  248 + String first = rs.getString("prenom");
  249 + String last = rs.getString("nom");
  250 +  
  251 + System.out.print(id + " : " + first + " " + last + " agé de " + age);
  252 + }
  253 + }
  254 +}
  255 +{denser}
  256 +```
  257 +
  258 +# JDBC simple : avantages/inconvénients ?
  259 +
  260 +
  261 +## Objet-Relational Mapping: concept
  262 +
  263 +- @anim: #objs |#rel |#car |#table |#arr0 |#arr1 |#arr2 |#arr3 |#arr4
  264 +- @anim: #optionClass |#optionTable |#arr678 |#optColumn |#arr5
  265 +
  266 +@SVG: media/orm.svg 800 420
  267 +
  268 +
  269 +
  270 +## Object-Relational Mapping {libyli}
  271 +- Questions?
  272 + - what class corresponds to what table
  273 + - what attribute corresponds to what column
  274 + - what attribute corresponds to what foreign key
  275 + - what are the multiplicities
  276 +- In practice{libyli}
  277 + - using JDBC, manually… tedious
  278 + - source code very long (most of the app) // 30%
  279 + - very repetitive code
  280 + - dangerous code (error-prone)
  281 + - difficult to evolve
  282 + - using a persistence framework
  283 + - JPA, JDO, Hibernate
  284 + - writing metadata on Java classes and attributes
  285 +
  286 +
  287 +<!-- ###################### -->
  288 +# @copy:#plan: %+class:inred: .jpa
  289 +
  290 +## JPA: Java Persistance API {libyli}
  291 +- Why the JPA standard? {libyli}
  292 + - Pure JDBC: tedious
  293 + - Data Access Objects: abstraction, but too much code
  294 + - need a Object/Relational Mapping (ORM) description
  295 + - XML description too verbose and not DRY (Don't Repeat Yourself)
  296 + - proliferation of frameworks (hibernate, toplink, ...)
  297 + - need a usable standard
  298 +- What is JPA?
  299 + - a set of annotations and conventions // default values etc
  300 + - description of object/relational mappings
  301 + - originally, a part EJB 3 (Entreprise Java Beans)
  302 + - an `EntityManager` to manage data (transparent in Spring)
  303 + - to save, `em.persist()`
  304 + - to delete, `em.remove()`
  305 + - to read, `em.find()`, …
  306 +
  307 +## JPA Annotations: simple example
  308 +```java
  309 +import javax.persistence.Column;
  310 +import javax.persistence.Entity;
  311 +import javax.persistence.Id;
  312 +import javax.persistence.GeneratedValue;
  313 +
  314 +
  315 +
  316 +@Entity
  317 +public class Car {
  318 +
  319 +
  320 + @Id
  321 + @GeneratedValue(strategy = GenerationType.AUTO)
  322 + private long id;
  323 +
  324 +
  325 + private String company;
  326 +
  327 +
  328 + private String model;
  329 +
  330 +
  331 + private long price;
  332 +
  333 + ...constr/get/set... Important!
  334 +}
  335 +
  336 +...
  337 +
  338 +EntityManager em;
  339 +...
  340 +em.persist(myCar);
  341 +{}
  342 +```
  343 +
  344 +## JPA Annotations: simple example
  345 +```java
  346 +import javax.persistence.Column;
  347 +import javax.persistence.Entity;
  348 +import javax.persistence.Id;
  349 +import javax.persistence.GeneratedValue;
  350 +import javax.persistence.Table;
  351 +
  352 +@Entity
  353 +@Table(name = "Vehicle")
  354 +public class Car {
  355 +
  356 + @Id
  357 + @Column(name = "id")
  358 + @GeneratedValue(strategy = GenerationType.AUTO)
  359 + private long id;
  360 +
  361 + @Column(name = "company")
  362 + private String company;
  363 +
  364 + @Column(name = "model")
  365 + private String model;
  366 +
  367 + @Column(name = "price")
  368 + private long price;
  369 +
  370 + ...constr/get/set... Important!
  371 +}
  372 +
  373 +...
  374 +
  375 +EntityManager em;
  376 +...
  377 +em.persist(myCar);
  378 +{}
  379 +```
  380 +
  381 +
  382 +## JPA Annotations // make them write something
  383 +- Others {right autre}
  384 + - @PersistenceContext // expliquer qu'il faut sauver les EJB
  385 + - …
  386 +- Class-level
  387 + - @Entity
  388 + - @Table
  389 + - (EJB @Stateless)
  390 + - (EJB @Stateful)
  391 + - …
  392 +- Attribute-level, JavaBean relations {right relations}
  393 + - @OneToOne
  394 + - @ManyToOne
  395 + - @OneToMany
  396 + - @ManyToMany
  397 + - @MapKey
  398 + - @OrderBy
  399 + - …
  400 +- Attribute-level, JavaBean {attr}
  401 + - @Column
  402 + - @Id
  403 + - @GeneratedValue
  404 + - @Temporal, @Lob, @Basic
  405 + - @Version
  406 + - @Transient
  407 + - …
  408 + - @anim: .attr | .relations | .autre
  409 +
  410 +## Manipulating JPA Entities {libyli}
  411 +- (Using an `EntityManager`)
  412 + - to read, `em.find()`, …
  413 + - to save, `em.persist()`
  414 + - to delete, `em.remove()`
  415 +- Using `Repositories`
  416 + - abstraction to list and filter objects
  417 + - need to define an interface
  418 + - implemented automatically, e.g., by Spring Data
  419 + - interfaces: Repository, CrudRepository, PagingAndSortingRepository
  420 + - implementation is obtained via dependency injection
  421 +
  422 +# JPA (`@Entity`, `@Id`, `@OneToMany`, ...), Spring Data (`CrudRepository` x2 + `.save`), `/TEST`
  423 +
  424 +## What Did We Just Do? {libyli}
  425 +- Update the model
  426 + - add an `@Entity` on the class
  427 + - add a `long id` field, <br/> with `@Id @GeneratedValue(strategy=GenerationType.AUTO) {dense}`
  428 +- Create a new repository
  429 + - an (empty) interface (not a class)
  430 + - extending *CrudRepository&lt;MyEntity, Long>{smartcode}*
  431 +- Used the new repository interface
  432 + - injected it
  433 + - used `findAll` and `save`
  434 + - the implementation being provided by spring data
  435 +- According to project configuration (and defaults)
  436 + - spring automatically uses an H2 database
  437 + - the database is in memory (by default)
  438 + - the database schema is automatically created
  439 + - the database is dropped at startup
  440 +
  441 +# Keeping Our Data! <br/> Tuning `application.properties{dense}`
  442 +
  443 +## What Did We Just Do? {libyli}
  444 +- Changing project configuration
  445 + - to override default configuration
  446 + - adding key=value properties in `application.properties`
  447 +- Using a file database (instead of solely in-memory)
  448 + - `spring.datasource.url=jdbc:h2:/tmp/mytestdb`
  449 +- Stopped dropping (and recreating) the database everytime
  450 + - `spring.jpa.hibernate.ddl-auto=none`
  451 +- NB about previous point
  452 + - in case one need to re-create the databse (schema update)
  453 + - the line can be remove
  454 + - or, use `spring.jpa.hibernate.ddl-auto=create-drop`
  455 +- Some properties
  456 + - `spring.datasource.password`, `spring.datasource.username`
  457 + - `server.port`
  458 + - and <a href="http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html" target="_blank">WAY more</a>
  459 +
  460 +
  461 +# ORM : avantages/inconvénients ?
  462 +
  463 +
  464 +</section>
  465 +
  466 + <!-- deck.status snippet -->
  467 + <p class="deck-status deck-progress-10"> <span class="deck-status-current"></span> / <span class="deck-status-total"></span> − <span class="var-author">will be replaced by the author</span> − <span class="var-title">will be replaced by the title</span></p>
  468 +
  469 + <a data-progress-size=": spe.top(15, 555); height: 45*designRatio; left: slide.right - 90*designRatio; width: 90*designRatio" class="ccby" href="http://en.wikipedia.org/wiki/Creative_Commons_license" title="This work is under CC-BY licence." target="_blank"></a>
  470 +
  471 + <a class="ujm" data-progress-size=": spe.top(15, 525); height: 65*designRatio; left: slide.left; width: 130*designRatio" target="_blank"></a>
  472 +
  473 +</div>
  474 +<!-- clicky Cla -->
  475 +<script type="text/javascript">
  476 +var clicky_site_ids = clicky_site_ids || [];
  477 +clicky_site_ids.push(100779706);
  478 +(function() {
  479 + var s = document.createElement('script');
  480 + s.type = 'text/javascript';
  481 + s.async = true;
  482 + s.src = '//static.getclicky.com/js';
  483 + ( document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0] ).appendChild( s );
  484 +})();
  485 +</script>
  486 +<noscript><p><img alt="Clicky" width="1" height="1" src="//in.getclicky.com/100779706ns.gif" /></p></noscript>
  487 +
  488 +
  489 +<!-- Histats.com START (aync)-->
  490 +<script type="text/javascript">var _Hasync= _Hasync|| [];
  491 +_Hasync.push(['Histats.start', '1,2767123,4,0,0,0,00010000']);
  492 +_Hasync.push(['Histats.fasi', '1']);
  493 +_Hasync.push(['Histats.track_hits', '']);
  494 +(function() {
  495 +var hs = document.createElement('script'); hs.type = 'text/javascript'; hs.async = true;
  496 +hs.src = ('http://s10.histats.com/js15_as.js');
  497 +(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(hs);
  498 +})();</script>
  499 +<noscript><a href="http://www.histats.com" target="_blank"><img src="http://sstatic1.histats.com/0.gif?2767123&101" alt="javascript hit counter" border="0"></a></noscript>
  500 +<!-- Histats.com END -->
  501 +</body>
  502 +</html>
... ... @@ -13,8 +13,8 @@
13 13 body {display: inline-block;}
14 14 h1 {color: gray; margin-bottom: 2em;}
15 15 h2 {color: white; background: black; margin:0; margin-top: 120px;}
16   - a {display:inline-block; float: left; width: 165px; padding: 15px;}
17   - a {margin-left: 6px;}
  16 + a {display:inline-block; width: 160px; padding: 15px; vertical-align: top; margin-left: 6px; text-align: center;}
  17 + body>div {text-align: left;}
18 18 a:nth-child(4n+1) {margin-left:0;}
19 19 a {background: rgb(225, 73, 56); color: white; text-decoration: none; font-weight: bold;}
20 20 a.proj {min-height: 65px;}
... ... @@ -33,7 +33,9 @@
33 33 <a class="outlined" href="more-aide-transparents.html">Voir les slides?</a>
34 34 <a href="cours-01.html">Slides 1 <br/> introduction</a>
35 35 <a href="cours-02.html">Slides 2 <br/> HTML+CSS</a>
36   - <a href="cours-03.html" style="font-size:90%;">Slides 3 <br/> MVC, Spring+Thymeleaf</a>
  36 + <a href="cours-03.html" style="font-size:80%;">Slides 3 <br/> MVC, Spring+Thymeleaf</a>
  37 + <a href="cours-04.html">Slides 4 <br/> Projet, TP1</a>
  38 + <a href="cours-05.html">Slides 5 <br/> Thymeleaf, DI</a>
37 39  
38 40 <h2>Code des séances</h2>
39 41 <a data-code-date="09-13"></a>