I have joined Anti-IF Campaign

play! , jqGrid et Jelastic


Voici un petit tutorial pour montrer la puissance de play! utilisé avec le plugin jqGrid le tout hébergé dans le cloud avec Jelastic.



La version de Play utilisée est la 1.2.4, jqGrid : 4.3.0 et le module jelastic 0.1 (Play install jelastic).

On ouvre une fenêtre de ligne de commande Windows
On se place dans le workspace eclipse et on lance la création d'un nouveau projet Play 1.2.4 :
Play new mytest --with=jelastic

On se place dans le répertoire du projet crée (mytest)
On lance la création des fichiers eclipse pour le projet :
Play eclipsify

On importe le projet dans eclipse.
L'application est dès à présent opérationnelle.
Il est possible de la lancer en utilisant le launcher eclipse situé dans le projet :
/mytest/eclipse/mytest.launch

Nous allons maintenant éditer le fichier de configuration du projet Play :
/mytest/conf/application.conf

Nous allons y déclarer deux environnements cibles : local (defaut) et cloud.

1ere étape, mise en place d'une base hsqldb de type fichier pour conserver les données.
Pour se faire, on ajoute les déclarations suivantes :

db=fs

# Jelastic Account configuration
jelastic.api.login=????@????
jelastic.api.password=????
jelastic.api.context=root
jelastic.api.environment=playframework
jelastic.api.apihoster=api.jelastic.com

# Configuration cloud par defaut
%jelastic.db.url=jdbc:mysql://mysql-playframework.jelastic.com/mytest
%jelastic.db.driver=com.mysql.jdbc.Driver
%jelastic.db.user=root
%jelastic.db.pass=??????
%jelastic.db.pool.timeout=15000


2ème étape, on va mettre en oeuvre un module additionnel de Play : CRUD
Ce module est présent dans l'installation par défaut de Play.
Pour l'activer, on ajoute dans le fichier de configuration la ligne suivante :
module.crud=${play.path}/modules/crud


3eme étape, on va activer le cache hibernate pour optimiser les performances :

hibernate.cache.use_second_level_cache=true
hibernate.cache.provider_class=net.sf.ehcache.hibernate.EhCacheProvider

Le module crud est maintenant utilisable mais il nous faut préciser les routes pour le rendre accessible depuis notre application.
Ajoutons la ligne suivante en fin du fichier conf/routes
* /crud module:crud

Enfin on ajoute quelques librairies dans /mytest/lib pour les étapes suivantes :
jackson-core-asl-1.9.4.jar
jackson-mapper-asl-1.9.4.jar

Pour que ce nouveau module soit pris en compte par eclipse, vous devrez relancer la commande suivante depuis la ligne de commande :
Play eclipsify

Lancons maintenant l'application :
mytest.launch

Lancer l'url suivante dans un navigateur pour valider que l'application fonctionne :

http://localhost:9000/


Mise en place du modèle.

Dans le répertoire : /mytest/app/models nous allons créer un bean simple qui va nous permettre de gérer nos données.
package models;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
@Entity
@Table(name="TABLE_CHAMP")
@Cache(usage=CacheConcurrencyStrategy.READ_WRITE)
public class Champ extends play.db.jpa.GenericModel implements Serializable {
public static final long serialVersionUID = 1L;
@Id
@SequenceGenerator(name = "seq_champ", sequenceName = "SEQ_CHAMP")
@GeneratedValue(generator = "seq_champ")
@Column(name="CL_ID", unique=true, nullable=false, precision=22)
public long id;
@Column(name="CL_CODE", nullable=false, length=100)
public String code;
@Column(name="CL_LIBELLE", length=100)
public String libelle;
@Column(name="CL_TYPE", length=100)
public String type;
@Column(name="CL_COMMENTAIRE", length=500)
public String commentaire;
public Champ() { }
public String toString() {
return this.code;
}
}


Il nous faut ensuite déclarer un contrôleur dédié au module CRUD pour ce bean.
Dans le répertoire /mytest/app/controllers créons ainsi la classe controllers.ChampCtrl avec le code suivant :

package controllers;
import models.Champ;
@CRUD.For(Champ.class)
public class ChampCtrl extends CRUD {
}


Compliqué n'est-ce pas ???

Une fois fait, ouvrons le module crud pour observer ce qu'il propose :
http://localhost:9000/crud/

Vous avez remarqué que nous n'avons pas relancé le serveur.


Nous allons maintenant mettre en place un accès aux données dans le format json.
Créons la classe util.ListData avec le code suivant qui nous permettra de gérer une liste de Champ :

package util;
import java.util.List;
public class ListData {
public final int total;
public final int page;
public final int records;
public final List rows;
public ListData(int total, int page, int records, List rows) {
super();
this.total = total;
this.page = page;
this.records = records;
this.rows = rows;
}
}


Améliorons notre contrôleur général pour permettre l'accès aux éléments Champs.

package controllers;
import java.io.IOException;
import java.io.StringWriter;
import java.util.List;
import models.Champ;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import play.exceptions.UnexpectedException;
import play.mvc.Controller;
import util.ListData;
public class Application extends Controller {
public static void index() {
render();
}
public static void load() throws JsonGenerationException, JsonMappingException, IOException {
final List listeParamBasic = Champ.findAll();
final ListData listData = new ListData(1, 1, listeParamBasic.size(), listeParamBasic);

ObjectMapper mapper = new ObjectMapper();
StringWriter stringWriter = new StringWriter();
mapper.writeValue(stringWriter, listData);

renderJSON(stringWriter.toString());
}
}


Appelons le contrôleur :
http://localhost:9000/Application/load

Déployons maintenant l'application dans le cloud :
play jelastic:deploy

Ouvrons ensuite jelastic : https://app.jelastic.com/ et déployons l'application sur notre tomcat.


Développons maintenant l'affichage en utilisant jquery et le plugin jqGrid.
Pour cela nous allons d'abord ajouter quelques ressources à notre projet.

dans public/javascripts :
jquery-ui-1.7.1.custom.css
reset-min.css
ui.jqgrid.css

dans public/stylesheets :
grid.locale-fr.js
jquery-ui-1.7.1.custom.min.js
jquery.jqGrid.min.js
ainsi que quelques images

Modifions la page mytest/app/views/Application/index.html :

#{extends 'main.html' /}
#{set title:'Demo play - jqgrid - jelastic' /}

#{set 'moreStyles'}
<link rel="stylesheet" type="text/css" media="screen" href="@{'/public/stylesheets/reset-min.css'}">
<link rel="stylesheet" type="text/css" media="screen" href="@{'/public/stylesheets/main.css'}">
<link rel="stylesheet" type="text/css" media="screen" href="@{'/public/stylesheets/jquery-ui-1.7.1.custom.css'}">
<link rel="stylesheet" type="text/css" media="screen" href="@{'/public/stylesheets/ui.jqgrid.css'}">
#{/set}

#{set 'moreScripts'}
<script src="@{'/public/javascripts/jquery-ui-1.7.1.custom.min.js'}" type="text/javascript" charset="utf-8"></script>
<script src="@{'/public/javascripts/grid.locale-fr.js'}" type="text/javascript" charset="utf-8"></script>
<script src="@{'/public/javascripts/jquery.jqGrid.min.js'}" type="text/javascript" charset="utf-8"></script>
<script src="@{'/public/javascripts/prop.js'}" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
var listLoadJsonUrl = "@{ Application.load() }";
$(document).ready(function() {
launch(listLoadJsonUrl);
});
</script>
#{/set}

Demo play - jqgrid - jelastic
<br />

<div id="container1">
<table id="grilleChamp"></table>
<div id="pagerChamp"></div>
</div>


Créons un fichier js pour mettre en place le fonctionnement de jqGrid : /mytest/public/javascripts/prop.js

$.ajaxSetup({
cache: false
});
function launch(jsonUrl) {
var fieldTypes = ":;A:Alpha;N:Nombre;D:JJ/MM/AAAA;DT:JJ/MM/AAAA HH:MM;S:Liste déroulante;BR:OUI/NON;I:Identifiant Incident";
$("#grilleChamp").jqGrid({
datatype: "json",
url: jsonUrl,
colNames:['Id','Code', 'Libellé','Type','Commentaire'],
colModel:[
{name:'id',index:'id',key:true, width:80,editable:false, hidden: true},
{name:'code',index:'code', width:70,editable:true,editoptions:{size:10}},
{name:'libelle',index:'libelle', width:180,editable:true,editoptions:{size:50}},
{name:'type',index:'type',width:135,align:'left',editable:true,formatter: "select", edittype:"select",editoptions:{value:fieldTypes}},
{name:'commentaire',index:'commentaire',width:150,sortable:false,editable: true, edittype:"textarea", editoptions:{rows:"2",cols:"20"}}
],
rowNum:500,
pager : '#pagerChamp',
headertitles: true,
sortname: 'code',
viewrecords: true,
sortorder: "desc",
caption:"Declaration champ",
height: 'auto',
jsonReader : {
root: "rows",
page: "page",
total: "total",
records: "records",
repeatitems: false,
id: "0"
}
});
}

Rafraichissons la page d'accueil de l'application et observons le comportement du tableau.


Mettons en oeuvre la fonction de tri coté serveur.
Pour cela ajoutons une méthode dans le contrôleur /mytest/app/controllers/Application.java.
Elle permet de parser les paramètres de la request exécutée lors du clic du le petit symbole de tri sur notre tableau.

private static String processOrder() {
String orderby = "";
final String sidx = params.get("sidx");
if (StringUtils.isNotBlank(sidx)) {
orderby += " order by " + sidx + " ";
final String sord = params.get("sord");
if (StringUtils.equalsIgnoreCase(sord, "desc")) {
orderby += " desc ";
}
}
return orderby;
}


Branchons cette méthode dans la méthode load.

public static void load() throws JsonGenerationException, JsonMappingException, IOException {

final String orderby = processOrder();

final List listeParamBasic = Champ.find("from Champ " + orderby).fetch();
final ListData listData = new ListData(1, 1, listeParamBasic.size(), listeParamBasic);

ObjectMapper mapper = new ObjectMapper();
StringWriter stringWriter = new StringWriter();
mapper.writeValue(stringWriter, listData);

renderJSON(stringWriter.toString());
}


Rafraichissons la page d'accueil de l'application et observons le comportement du tableau.


Ajoutons maintenant une fonction de recherche

Dans le fichier prop.js, modifions la fin avec l'appel à la fonction navGrid :

...
jsonReader : {
root: "rows",
page: "page",
total: "total",
records: "records",
repeatitems: false,
id: "0"
}
}).navGrid(&apos;#pagerChamp&apos;,{del:false, add:false, edit:false, view:false, search:true}, {});
}


Mettons en oeuvre la fonction de filtre coté serveur.
Pour cela ajoutons une méthode dans le contrôleur /mytest/app/controllers/Application.java.

private static String processFilter() {
String where = "";
final String searchField = params.get("searchField");
final String searchString = params.get("searchString");
final String searchOper = params.get("searchOper");
if (StringUtils.isNotBlank(searchField) &amp;&amp; StringUtils.isNotBlank(searchString) &amp;&amp; StringUtils.isNotBlank(searchOper)) {
if ("eq".equals(searchOper)) {
where = "where " + searchField + " = '" + searchString + "' ";
}
}
return where;
}


Branchons cette méthode dans la méthode load.

public static void load() throws JsonGenerationException, JsonMappingException, IOException {

final String where = processFilter();
final String orderby = processOrder();

final List listeParamBasic = Champ.find("from Champ " + where + orderby).fetch();
final ListData listData = new ListData(1, 1, listeParamBasic.size(), listeParamBasic);

ObjectMapper mapper = new ObjectMapper();
StringWriter stringWriter = new StringWriter();
mapper.writeValue(stringWriter, listData);

renderJSON(stringWriter.toString());
}


Rafraichissons la page d'accueil de l'application et observons le comportement du tableau.

Finissons par la mise en place d'une méthode d'ajout, modification et de suppression sur notre tableau.
Modifions la page pour préciser l'url à utiliser pour ces actions :

...
<script type="text/javascript">
var listLoadJsonUrl = "@{ Application.load() }";
var listSaveJsonUrl = "@{ Application.createEditDelete() }";
$(document).ready(function() {
launch(listLoadJsonUrl, listSaveJsonUrl);
});
</script>
...


Dans le fichier prop.js, modifions le script à plusieurs endroits :

$.ajaxSetup({
cache: false
});
function launch(myjsonUrl, myeditUrl) {
var fieldTypes = ":;A:Alpha;N:Nombre;D:JJ/MM/AAAA;DT:JJ/MM/AAAA HH:MM;S:Liste déroulante;BR:OUI/NON;I:Identifiant Incident";

$("#grilleChamp").jqGrid({ datatype: "json",
url: myjsonUrl,
editurl: myeditUrl,
colNames:['Id','Code', 'Libellé','Type','Commentaire'],
colModel:[
{name:'id',index:'id',key:true, width:80,editable:false, hidden: true},
{name:'code',index:'code', width:70,editable:true,editoptions:{size:10}},
{name:'libelle',index:'libelle', width:180,editable:true,editoptions:{size:50}},
{name:'type',index:'type',width:135,align:'left',editable:true,formatter: "select", edittype:"select",editoptions:{value:fieldTypes}},
{name:'commentaire',index:'commentaire',width:150,sortable:false,editable: true, edittype:"textarea", editoptions:{rows:"2",cols:"20"}}
],
rowNum:500,
pager : '#pagerChamp',
headertitles: true,
sortname: 'code',
viewrecords: true,
sortorder: "desc",
caption:"Declaration champ",
height: 'auto',
jsonReader : {
root: "rows",
page: "page",
total: "total",
records: "records",
repeatitems: false,
id: "0"
}
}).navGrid('#pagerChamp',{del:true, add:true, edit:true, view:false, search:true}, {});
}


Modifions enfin notre contrôleur en ajoutant une nouvelle méthode :

public static void createEditDelete(String oper, String code, long id, String libelle, String type, String commentaire) {

if (StringUtils.equalsIgnoreCase(oper, "del")) {
Champ champ = Champ.findById(id);
champ.delete();
} else if (StringUtils.equalsIgnoreCase(oper, "edit")) {
Champ champ = Champ.findById(id);
champ.code = code;
champ.commentaire = commentaire;
champ.libelle = libelle;
champ.type = type;
champ.save();
} else if (StringUtils.equalsIgnoreCase(oper, "add")) {
Champ champ = new Champ();
champ.code = code;
champ.commentaire = commentaire;
champ.libelle = libelle;
champ.type = type;
champ.save();
} else {

}
}


Rafraichissons la page d'accueil de l'application et observons le comportement du tableau.

Finissons ce tutorial en déployant le tout dans le cloud.
play jelastic:deploy
Et zou …


Liens utiles :
jqGrid : http://www.trirand.com/blog/
Play Framework : http://www.playframework.org/
Jelastic : http://jelastic.com/

Aucun commentaire:

Enregistrer un commentaire