Test de PlayFramework

Tout d'abord, je souhaite exprimer le but de ce post. Ce n'est pas un tutoriel sur ceframework mais plus un ressenti et mon opinion après quelques jours de pratiques

Qu'est ce que play?

Voila la définition sur le site :

The Play framework is a clean alternative to bloated Enterprise Java stacks. It focuses on developer productivity and targets RESTful architectures. Play is a perfect companion to agile software

play_logo_final_big.png

Création d'un projet

Très simple :

$ play new my-cellar
~        _            _
~  _ __ | | __ _ _  _| |
~ | '_ \\| |/ _' | || |_|
~ |  __/|_|\\____|\\__ (_)
~ |_|            |__/
~
~ play! 1.1, http://www.playframework.org
~
~ The new application will be created in /cygdrive/d/java/src/playcellar/my-cellar
~ What is the application name? [my-cellar]
~
~ OK, the application is created.
~ Start it with : play run my-cellar
~ Have fun!

Le framework s'appuie plus sur des conventions que sur du paramétrage. Je trouve l'approche à la fois simple et réaliste. La structure du projet l'est également.

Intégration avec netbeans

Simple et efficace :

play netbeansify

Toutes les actions sont définies. La compilation est désactivée car inutile avec playframework

Pour Google App Engine

La il faut un peu se renseigner. Ce framework fonctionne sous les serveurs JAVAEE, mais une légère configuration s'impose pour GAE. Les extensions existent et fonctionnent bien. Cependant on ne peut utiliser ni JPA ni JDO directement. J'ai "du" me mettre à Objectify. J'ai été agréablement surpris. Après avoir galéré pour intégrer un modèle avec JPA, ce framework facilite l'accès de manière relationnelle au datastore.

Le point négatif de cette intégration est le non support du module CRUD sur la plateforme de google.

Rapidité de développement

La c'est la baffe. Tout est très rapide, on code et, sans compiler/livrer/ on a un environnement disponible pour les tests. Les erreurs de compilation sont directement accessibles dans le browser ( si besoin...), c'est très réactif.

Simplification du code

J'ai déjà abordé l'un des points forts (ou faible selon les cas) . Ce framework est très structurant car il se base énormément sur les conventions de développements (ex.: packages controllers, models, view) et non sur le paramétrage.

Les pojo

Le développement des pojo est largement simplifié : Exit les getters et setters! On arrive a peu près à ce genre de classe :

package models;
 
import com.googlecode.objectify.Key;
import com.googlecode.objectify.Query;
import controllers.Application;
 
import javax.persistence.Id;
import play.data.validation.Required;
import play.modules.objectify.Datastore;
import play.modules.objectify.ObjectifyModel;
 
public class Producer extends ObjectifyModel {
 
    public Producer() {
    }
    @Id
    public Long id;
    @Required
    public String name;
    @Required
    public String address;
    @Required
    public String zip;
    public String city;
    public String country;
    public String phone;
    public String domain;
    public String region;
    public String owner;
 
    public static Producer findById(Long id) {
        return Datastore.find(Producer.class, id, true);
    }
 
    public static Producer findById(Long id, boolean newIfNull) {
        return Datastore.find(Producer.class, id, newIfNull);
    }
 
    public static Query<Producer> findAllByOwner() {
        return Datastore.query(Producer.class).filter("owner", Application.getUserEmail());
    }
 
    public Key<Producer> save() {
        owner = Application.getUserEmail();
        return Datastore.put(this);
    }
 
    public void _save() {
        save();
    }
 
    public static void deleteById(Long id) {
        Datastore.beginTxn();
        Datastore.delete(Producer.class, id);
        Datastore.commit();
    }
 
    public void delete() {
        Datastore.beginTxn();
        Datastore.delete(this);
        Datastore.commit();
    }
 
    public void _delete() {
        delete();
    }
 
}

Une VRAI (?) conception objet

Un des points noirs des développements actuels réside dans le fait que l'on ne fait que des POJO pour stocker les données et des classes services ( résidus de spring) qui centralisent les diverses opérations. En bref, nous arrivons la plupart du temps à un antipattern décrit plus en détail par Martin Fowler. Ici toutes les méthodes liées à un domaine sont centralisées dans la classe en question.

REST

Un GROS plus de ce framework est d'avoir une architecture entièrement REST. Toutes les actions sont spécifiées par des chemins REST:

# Home page
GET     /                                       Application.index

# producers

GET     /producers                                                            Producers.index
GET     /producers/create                                                     Producers.create
GET     /producers/{<[0-9]+>id}                                               Producers.edit
POST    /producers/create                                                     Producers.save
POST    /producers/{<[0-9]+>id}                                               Producers.save
DELETE  /producers/{<[0-9]+>id}                                               Producers.delete


GET     /login                                  Application.login
GET     /logout                                 Application.logout    

# Map static resources from the /app/public folder to the /public path
GET     /public/                                staticDir:public

# Catch all
*       /{controller}/{action}                  {controller}.{action}

Je pense que ceci peut faciliter le développement d'applications multi-canaux.

GUIS

La on oublie les specs JSF 2.0 , tout est basé sur des templates. Après quelques heures de pratique on trouve rapidement ses marques . Les domaines ( voir les pojo) sont regroupés dans des répertoires et il y a une page pour l'édition, l'affichage, etc...

views/Producers/:
edit.html  index.html

L'affichage d'une liste d'éléments :


#{extends 'main.html' /}
#{set title:'All producers' /}

<table class="data">
    <tr>
        <th width="50">&{'producer.id'}</th>
        <th>&{'producer.name'}</th>
        <th width="100">&{'producer.address'}</th>
        <th width="110">&{'producer.zip'}</th>
        <th width="80">&{'producer.city'}</th>
        <th width="80">&{'producer.country'}</th>
        <th width="80">&{'producer.phone'}</th>
        <th width="80">&{'producer.domain'}</th>
        <th width="80">&{'producer.region'}</th>
        <th>&nbsp;</th>
        <th>&nbsp;</th>
        <th>&nbsp;</th>
    </tr>
    #{list producers, as:'producer'}
    <tr>
        <td>${producer.id}</td>
        <td>${producer.name}</td>
        <td>${producer.address}</td>
        <td>${producer.zip}</td>
        <td>${producer.city}</td>
        <td>${producer.country}</td>
        <td>${producer.phone}</td>
        <td>${producer.domain}</td>
        <td>${producer.region}</td>
        <td class="edit"><a href="@{edit(producer.id)}">&{'edit'}</a></td>
        <td class="delete">
            #{delete @delete(producer.id), id:'delete_'+producer.id}Delete#{/delete}</td>
    </tr> 
    #{/list}
</table>

<br/>
<a href="@{create()}">Add</a>

Pour l'édition/insertion on a un écran qui contient ce genre d'éléments :

<form method="post">
#{authenticityToken /}
<input type="hidden" name="producer.id" value="${producer.id}"/>
<div class="fields">
    <table>
        #{field 'producer.name'}
        <tr class="field ${field.errorClass}">
            <td class="label"><label for="name">Nom:</label></td>
            <td class="field"><input id="name" type="text" name="${field.name}" value="${producer.name}" class="large"/></td>
            <td>#{ifError field.name}<span class="error">${field.error}</span>#{/ifError}</td>
        </tr>
        #{/field}
 

On déjà peut voir que ce framework offre par défaut coté front-office:

  1. La gestion de l'identification et facilite cette intégration dans les pages par la fonction #{authenticityToken /}
  2. La gestion des erreurs est elle aussi fournie par le framework par introspection dans le champ (variable field)
  3. Une gestion de templates intéressante ( réutilisation des modèles crées). Pas besoin de connaître le cycle de vie des managed beans JSF par exemple.

Les liens create, delete sont référencés dans le fichier routes décrit ci-dessus.

Pérennité / Fiabilité

La grosse inconnue.Qui sont les boites qui utilisent ca au quotidien, qui réalisent des applications avec beaucoup d'utilisateurs... Ce framework est réalisé par une société française Zenexity sous licence Apache2. On n'a pas la vue sur les gros projets en production. Il existe une plateforme d’exécution playapps.net qui héberge des applications PLAY sur le cloud. On paye par rapport à l'utilisation, ça permet d'ouvrir l'ouverture de services basés sur la plateforme JAVA au plus grand nombre.

Vus : 1026
Publié par Littlewing : 368