Post on 21-Jun-2015
description
PLAY FRAMEWORK « JAVA IS FUN AGAIN » Toulouse JUG – 17 novembre 2011
Le programme
L’histoire de Play! Développer avec Play! Test, déploiement, exploitation L’écosystème autour de Play! Le futur Alors, Play ou pas Play?
A propos…
Sylvain Wallez Architecte expert freelance, web & Java 2008-2010 : CTO de Goojet/Scoop.it 2006-2008 : Backend architect Joost 2000-2008 : cofondateur & CTO
Anyware Technologies 2003 : premier VP français de la fondation
Apache Membre du Tetalab, hacking Kinect & Arduino
sylvain@bluxte.net http://bluxte.net Twitter: @bluxte
C’est quoi, c’est qui, d’où ça vient ?
L’histoire de Play
L’histoire de Play
Framework web Orienté REST (urls matter !)
Framework full stack http, persistance, build, test, déploiement
Haute productivité Très DRY Save / reload, recompilation à la volée
Très inspiré de Rails et Django ! J2EE
L’histoire de Play
Créé par Guillaume Bort (cocorico !) de Zenexity Open source en 2008 Licence Apache Actuellement : version 1.2.3 (Java + Scala) Bientôt : version 2.0 (Scala + Java)
L’histoire de Play
Les frameworks web Java sont créés par des devs Java, et pas des développeurs web
Java a une culture de la complexité, préférant l’empilement des abstractions à la résolution effective des problèmes
Mais l’écosystème Java est incroyablement riche
Hello world… et un peu plus
Développer avec Play!
L’appli finale… wow!
Création du projet
Le contrôleur
package controllers;import play.data.validation.Required;import play.mvc.Controller;public class Application extends Controller { public static void index() { render(); } public static void hello(@Required String who) { if (validation.hasErrors()) { render("@index"); } else { render(who); } }}
Méthode statique
Appel du template
Binding et validation
Modèle pour la vue
Template nommé
Les vues
#{set title:'Bienvenue' /}#{extends 'main.html' /}<form action="@{Application.hello}" method="POST"> <p>Dire bonjour à <input name="who"/> #{error 'who'/} </p> <p> <input type="submit"/> </p></form>
#{set title:'Bonjour' /}#{extends 'main.html' /}<h1>Bonjour ${who} !</h1><p> <a href="@{Application.index}"> Recommencer </a></p>
index.html
hello.html
Variables Héritage de template
Reverse routing
Validation
Modèle
Les vues
<!DOCTYPE html><html> <head> <title>${title}</title> <meta charset="${_response_encoding}"> <link rel="stylesheet" media="screen” href="@{'/public/stylesheets/main.css'}"> #{get 'moreStyles' /} <link rel="shortcut icon" type="image/png” href="@{'/public/images/favicon.png'}"> <script src="@{'/public/javascripts/jquery-1.5.2.min.js'}” type="text/javascript"></script> #{get 'moreScripts' /} </head> <body> #{doLayout /} </body></html>
Inclusion de la vue
CSS spécifiques
à la vue
main.html
Lancement du serveur
Mais comment ça marche ?
L’architecture de Play!
Architecture de Play
Modèle MVC classique…
… mais une implémentation iconoclaste !
HTTP server
Models
Routes
Controllers Views
DB
Architecture : le serveur
Serveur HTTP : ce n’est pas du Servlet ! Serveur NIO très léger et rapide (Netty) Pas de session (stateless, scalabilité horizontale)
Besoin stateful ? API cache avec EHCache & Memcache fournie
HTTP server
Models
Routes
Controllers Views
DB
Architecture : routage des URLs
Routes : dispatching des requêtes sur les contrôleurs Tout le REST est là
HTTP server
Models
Routes
Controllers Views
DB
# Home pageGET / Application.index# Ignore favicon requestsGET /favicon.ico 404# Map static resources from the /app/public folder to the /public pathGET /public/ staticDir:public# Catch all* /{controller}/{action} {controller}.{action}
Méthode HTTP
Contrôleur
Pattern
Architecture : routage des URLs
GET / Application.indexGET /public/ staticDir:publicGET /imgcache/ staticDir:imgcache* /admin module:crudGET /villes/{name} Villes.showByNameGET /boutiques/{name} Boutiques.showByNameGET /categories/{name} Categories.showByNameGET /villes/{id1}/categorie/{id2} Villes.categorieGET /{controller}/{name},{id} {controller}.show2POST /{action} Application.{action}_postGET /{action} Application.{action}GET /{controller}/ {controller}.indexPOST /{controller}/ {controller}.index_postPOST /{controller}/-{id1}/{action}/-{id2} {controller}.{action}_postGET /{controller}/-{id1}/{action}/-{id2} {controller}.{action}GET /{controller}/-{id} {controller}.showPOST /{controller}/-{id}/{action} {controller}.{action}_postGET /{controller}/-{id}/{action} {controller}.{action}POST /{controller}/{action} {controller}.{action}_postGET /{controller}/{action} {controller}.{action}
« mount » d’un module
URLs « SEO friendly »
Patterns génériques
Architecture : contrôleurs
Contrôleurs : méthodes statiques Un contrôleur est sans état Binding et validation automatique des paramètres request/response ? Pas besoin 90% du temps !
HTTP server
Models
Routes
Controllers Views
DB
Architecture : contrôleur
Paramètres de la vue : bytecode analysis pour extraire les variables locales Finis les model.addAttribute("user", user) !
public static void hello(@Required String who) { if (validation.hasErrors()) { render("@index"); } else { render(who); } }
Architecture : modèles
Modèles Attributs publics
Ecriture simplifiée : user.getName() user.name ! Bytecode processing : génération des getter/setter
DAO : méthodes statiques
Fin du « anemic domain model »
HTTP server
Models
Routes
Controllers Views
DB
Architecture : modèles
package models;import ...@Entitypublic class UserGroup extends Model { @Required public String name; @Required public String accessCode; @ManyToOne public User coach; public long getSize() { return find("select count(u) from User u where u.group = ?", this).first(); } // DAO methods public static UserGroup findByAccessCode(String code) { return find("accessCode", code).first(); } public static List<UserGroup> findByCoach(User user) { return find("select g from UserGroup g where g.isActivated = true" + " and g.coach = ?", user).fetch(); }}
Entité JPA
DAO
get/set générés
Architecture : vues
Vues : templates Groovy Héritage de templates Nombreux tags : structures de contrôle, forms, erreurs
de validation, tables, etc. Un tag est un mini template
Escaping HTML par défaut !
Autres moteurs via des modules Scalate, Japid, Cambridge…
HTTP server
Models
Routes
Controllers Views
DB
Architecture : vues
<p> #{if product.ratingCount != 0} <div class="rateit" data-rateit-value="${product.rating}"></div> <a href="#">Notez ce produit</a> #{/if} #{else} <div class="rateit"></div> <a href="#">Soyez le premier à noter ce produit.</a> #{/else}</p> #{list results, as: 'product'} <p class="clear"> <img src="${product.thumbnailUrl}" style="float: left"/> ${product.link}<br/> Boutique ${product.shop.link} à ${product.shop.city.link}. </p>#{/list}<div class="${page.cssClass}"> <h1>${page.title}</h1> ${page.text.textile()}</div>
Fonctions d’extension
Iteration
Ah bon, faut tester ?
Les tests avec Play!
Les tests
Junit, Corbertura et Selenium intégrés Avec des « helpers » spécialisés
public class ApplicationTest extends FunctionalTest { @Test public void testThatIndexPageWorks() { Response response = GET("/"); assertIsOk(response); assertContentType("text/html", response); assertCharset(play.Play.defaultWebEncoding, response); }}
#{selenium} // Open the home page, and check that no error occured open('/') assertNotTitle('Application error')#{/selenium}
Les tests
« play test »
Les tests
Quand le code est fini, c’est là que tout commence !
Déploiement, opérations
Déploiement
The Play! Way Pull du code (taggué) et « play start »
Tout est précompilé au démarrage
The J2EE way « play war » crée un war
Permet de s’intégrer dans un environnement J2EE
Configuration
Fichier de properties centralisé # i18n# ~~~~~# Define locales used by your application.# You can then place localized messages in conf/messages.{locale} files# Date format# ~~~~~# date.format.fr=dd/MM/yyyy# Server configuration# ~~~~~# If you need to change the HTTP port, uncomment this (default is set to 9000)# http.port=9000## By default the server listen for HTTP on the wilcard address.# You can restrict this.# http.address=127.0.0.1# Session configuration# ~~~~~~~~~~~~~~~~~~~~~~# By default, session will be written to the transient PLAY_SESSION cookie.# The cookies are not secured by default, only set it to true# if you're serving your pages through https.# application.session.cookie=PLAY# application.session.maxAge=1h# application.session.secure=false# JVM configuration# ~~~~~# Define which port is used by JPDA when application is in debug mode (default is set to 8000)# jpda.port=8000## Java source level => 1.5, 1.6 or 1.7 (experimental)# java.source=1.5# Log level# ~~~~~# Specify log level for your application.# If you want a very customized log, create a log4j.properties file in the conf directory# application.log=INFO## More logging configuration# application.log.path=/log4j.properties# application.log.system.out=off# application.log.recordCaller=true
Configuration
Modes dev/integration/prod, etc # JPA Configuration (Hibernate)# ~~~~~## Specify the custom JPA dialect to use here (default to guess):# jpa.dialect=org.hibernate.dialect.PostgreSQLDialect## Specify the ddl generation pattern to use. Set to none to disable it # (default to update in DEV mode, and none in PROD mode):# jpa.ddl=update%test.application.mode=dev%test.db.url=jdbc:h2:mem:play;MODE=MYSQL;LOCK_MODE=0%test.jpa.ddl=create%test.mail.smtp=mock%integration.db=mysql://root@localhost/helloworld%integration.jpa.ddl=none
Config de tests
Config d’intégration
Monitoring
« play status »
Monitoring
Disponible en texte et en JSON Intégration très simple avec munin, collectd, etc.
Librairie JaMon pour du monitoring applicatif facile
Monitor monitor = MonitorFactory.start("SuperAlgorithm.findTheAnswer"); // Do complicated stuff// (should be 42 anyway...) monitor.stop();
Monitors:~~~~~~~~SuperAlgorithm.findTheAnswer, ms. -> 1 hits; 1038,0 avg; 1038,0 min; 1038,0 max;
On peut être full-stack et être accueillant !
L’écosystème Play!
L’écosystème
Des modules à foison Système de plugins qui apportent composants, tags,
templates, moteurs de persistance, générateurs de PDF/Excel, interfaces mobiles, etc…
Play a son repository de modules Gestion des dépendances avec Ivy Intégration avec tout repository Maven
L’écosystème : dépendances Ivy
require: - play - play -> fbgraph 0.3 : transitive : false - play -> secure - com.restfb -> restfb 1.6.9 - org.codehaus.jackson -> jackson-core-asl 1.8.0 - org.codehaus.jackson -> jackson-mapper-asl 1.8.0 - org.apache.lucene -> lucene-core 3.3.0 - org.apache.lucene -> lucene-spatial 3.3.0 - com.hazelcast -> hazelcast 1.9.4 : exclude: - org.mockito -> * - local-lib -> json-lib 2.4-jdk15repositories: - local-lib: type: local artifact: "${application.path}/local/lib/[module]-[revision].jar" contains: - local-lib -> *
Dépendances Maven Central
Modules Play
Repository local
Scala en douceur
Le futur de Play!
Le futur de Play
Play 2.0 beta sorti hier (16 nov) Moteur en Scala / Akka API Java pour « masquer » Scala Templates Scala avec typage fort Performances extrèmes
Le futur de Play
TypeSafe s’engage sur Play 2.0 La société du créateur de Scala Play pourrait bien être la « killer app » qui fait
décoller Scala L’API Java permet une évolution en douceur vers Scala
Le futur de Play
Play 1.x is dead ? Non, beaucoup de projets existants Mais entrée en mode maintenance
Play 2.0 est compatible avec Play 1.x ? Les principes sont les mêmes, mais les APIs changent Adaptation importante nécessaire
Alors, on joue ou pas ?
Play ou pas Play ?
The good
Oubliez J2EE, (re)découvrez la simplicité Fin des getters et setters ! Beaucoup moins de code Reload / recompil automatique Des messages d’erreurs parlants Développement high-speed et « in the flow »
The bad
Byte code processing Le debugger n’aime pas (re-attach à chaque recompil)
Mais on en a aussi moins besoin !
Méthodes statiques Empêche l’héritage sur les contrôleurs
Des « contournements » existent dans la lib Play
Bonne doc, mais code source peu commenté
The ugly
(void)
The ugly
Ah si… le temps nécessaire pour
convaincre votre DSI (mais chuuut… « play war » et hop !)
Quand choisir Play ?
Une application web Adhérence sur la couche métier acceptable
Ou se passer de l’intégration Play dans le modèle
Avec des développeurs calés en HTML, mais pas forcément experts en Java
Quand vous êtes pressé Projet court/moyen terme avec Play 1.x
Merci !
Questions ?
Réponses !