Aucun titre de diapositive

Transcription

Aucun titre de diapositive
MVC ET STRUTS
2
MVC

Origine :


Objectif initial :


Smalltalk [1979-1983]
aider à la conception d'applications très interactives.
Solution : découpage en trois couches :
Modèle (model) : données et traitement sur les données.
 Vue (view) : affichage des données.
 Contrôleur (control) : interface entre modèle et vue.

3
MVC

Les différentes couches sont séparées dans le code :




Possibilité d'avoir :



L'accès aux données.
Les vues/affichages.
Les contrôles.
Plusieurs vues simultanées.
Plusieurs contrôles possibles (clavier, souris, …)
On doit pouvoir changer une couche sans toucher aux autres

Par exemple changer de BD sans modifier des fichiers jsp.
Vue = interface utilisateur

Objectifs :


Présentation des données.
Moyens d'interaction pour l'utilisateur (clic, menu, …)

La vue n'effectue aucun traitement, affichage uniquement !

On peut avoir plusieurs vues

Exemple : choix de produits sur un site web :




Deux cases prix minimum / prix maximum souhaité
Un slider permettant de sélectionner les deux prix extrêmes
…
Le changement de vue ne doit pas avoir de conséquence sur le
stockage des données
Modèle = données + traitements

Objectifs :


Disposer de méthodes pour récupérer ou mettre à jour les données
(insertion, suppression, modification).
Autoriser éventuellement des vues partielles.


Gestion des données de l'application, garantie de leur intégrité.


Exemple : concurrence en cas d'accès simultanés sur une BD ou des fichiers.
Les résultats renvoyés ne sont pas mis en forme :


Exemple : méthodes faisant des select sur une base de données.
Retour XML, Json, objet Java, etc.
Cas typique : base de données + méthodes SQL + classes Java

Exemple : classe panier sur un site de vente en ligne et stockage du
panier en BD.
Modèle, version complexe

Data Access Layer (DAL) :

Couche d’abstraction avec méthodes génériques = driver.


Data Access Object (DAO) :

Conversion entre la sortie DAL et des objets (Java ou autre).


Casse le lien entre les objets et la BD utilisée (permet d'en changer).
Object / Relation Mapping (ORM) :

Transfère les contraintes du niveau BD au niveau objet :


Principe CRUD (Create Read Update Delete).
Par exemple la gestion des clés étrangères.
Couche métier :


Le reste du modèle. Plus aucun problème lié à la BD, on n'utilise que des objets.
Exemple : panier dans un objet Java, synchronisé avec le panier BD.
Contrôleur

Objectifs :


Gérer la synchronisation entre vues et modèle.
Recevoir les événements de l'utilisateur et faire les actions correspondantes :




demande la modification des données au modèle qui demandera à la vue de se
mettre à jour.
Si l'événement concerne la vue, le contrôleur lui demande de se modifier.
Le contrôleur n'effectue aucun traitement, ne modifie aucune donnée, ne fait
aucun affichage.
Exemple : ajout d'un produit dans un panier par un utilisateur :


Le contrôleur "ajoute" le produit au modèle et demande à la vue de se mettre à
jour.
Si l'utilisateur veut visualiser son panier, pas de modification du modèle, juste
une mise à jour de la vue.
Contrôleur

Selon les cas on peut avoir plusieurs contrôleurs
(MVC1) ou un seul (MVC2) :
 MVC
fait à la main : plusieurs contrôleurs
 Plus simple
 MVC
de faire un contrôleur par type d'action.
fait avec un framework : un seul contrôleur
 C'est le
code de plusieurs contrôleurs mis bout à bout dans
un switch. Pas propre fait à la main mais facile à générer
automatiquement.
 Ou de manière équivalent un contrôleur qui fait le tri et
sous-traite à d'autres contrôleurs spécialisés.
MVC - fonctionnement
1.
2.
3.
4.
5.
Le client agit sur la vue.
Le contrôleur intercepte l'action.
Le contrôleur traite la demande en utilisant le
modèle.
Le contrôleur reçoit une réponse du modèle et
effectue les actions associées.
Le contrôleur sélectionne une vue pour présenter
les résultats (mise à jour si besoin).
MVC sur le web

Contrôleur :
 Scripts

gérant les demandes de l'utilisateur.
Vue :
 Affichage

via le navigateur web.
Modèle :
 Méthodes d'accès
à la base de données et traitements.
 Source de données : BD, fichiers texte, json ou xml, etc.
Complexité de MVC

Sur de petits projets (quelques pages web), on se
contente de ne rien faire ou de faire un pseudo MVC :


Éviter les requêtes SQL dans les fichiers JSP par exemple.
Sur de gros projets, pas simple à mettre en œuvre,
surtout dans la version modèle complexe + MVC2 :

Utilise pour de gros projets à long terme :
Changement de BD probable.
 Changement de vue probable.
 Etc.


D'où l'utilisation de frameworks web.
Framework web

Un framework est une application "vide" offrant déjà de
nombreuses fonctionnalités :







Un contrôleur par défaut.
La conversion des paramètres de formulaires dans les bons types.
Le remplissage des objets Java avec le contenu des formulaires.
La validation de formulaires.
Les redirections, etc.
Librairies de tags permettant de faire des actions non triviales.
Impose un certain style de programmation plus standard :


Peut cacher des choses complexes au programmeur.
Kernighan Law : "Debugging is twice as hard as writing the code in the
first place. Therefore, if you write the code as cleverly as possible, you
are, by definition, not smart enough to debug it."
Framework web

La mise en place d'un framework n'est pas triviale :
 Programmation plus
contrainte.
 Beaucoup de choses à apprendre.
 S'assurer que le framework est viable sur le long terme.

Valable seulement pour de grosses applications !
STRUTS (VERSION 2)
Problèmes liés aux servlets/JSP

servlets uniquement : génération de HTML peu lisible et lourd
(out.println).

JSP uniquement : ok pour des application simples. Pour des
applications plus complexe, on met du Java lourd dans les jsp, moins
lisible et mélange fort entre présentation et code.

JSP+beans : ok mais problème si on souhaite avoir plusieurs vues,
chacune doit jouer avec les beans.

JSP+Servlets+Beans :


Requête faite à la servlet (contrôleur) qui utilise un objet Java (modèle)
et permet à la JSP d'accéder au résultat pour l'affichage (vue).
C'est du MVC (quand c'est bien fait).
Struts et MVC

Struts est un framework MVC :
 Fourni
le contrôleur et la vue.
 S'intègre avec d'autres technologies pour le modèle.
 Fait le pont entre la vue web et le modèle applicatif.
Principe

A chaque requête (appel d'une url) :
 Le
contrôleur struts filtre les urls et applique des
opérations/intercepteurs (validation, conversion, etc.)
puis appelle une classe action.
 La classe action utilise ou modifie le modèle ou une
interface représentant le modèle (cf modèle complexe).
 Le transfert de données entre le modèle et la vue se
fait généralement via des variables de la classe action
(ou des Beans).
Principe

Pour simplifier la présentation, struts propose des
librairies de tags :
 Utile
pour créer/valider des formulaires.
 Pour les problèmes d'internationalisation (i18n).
 La librairie de tags peut être utilisée avec différents
outils (notamment JSP dans ce cours).
 D'autres librairies de tags peuvent aussi être utilisées
(JSTL, …)
CRÉATION D'UNE
APPLICATION STRUTS 2
Dans la suite

Un exemple HelloWorld complet pour :
 Comprendre le
fonctionnement de struts.
 Voir les fichiers nécessaires.

Des exemples plus complexes pour d'autres taches :
 Validation de
formulaire et validateurs.
 Upload de fichier et intercepteurs.
Premiers pas

Fichiers nécessaires
 Un
fichier struts.xml :
 Définition des différentes classes
associées aux actions de
l'utilisateur.
 Un
fichier web.xml :
 Uniquement pour associer toutes
 Des
fichiers jsp pour le(s) vue(s) :
 Utilisation de
 Des
les urls à struts.
tags struts possible.
classes java pour les actions et le modèle.
Fichier struts.xml

Définition des différentes action à exécuter en fonctions des choix
de l'utilisateur.

Si l'url est hello.action :


Appel à la méthode execute de la classe HelloWorldAction.
Si execute() retourne success alors transfert vers HelloWorld.jsp, sinon
transfert vers error.jsp.
<action name="hello"
class="action.HelloWorldAction"
method="execute">
<result name="success">/HelloWorld.jsp</result>
<result name="error">/error.jsp</result>
</action>
Fichier struts.xml

En l'absence de classe dans l'action :
traité comme un succès.
 index, index.jsp et index.action correspondent à la même
page.


En l'absence de name dans result :

success par défaut.
<action name="index">
<result>/index.jsp</result>
</action>
<action name="hello" class="action.HelloWorldAction" method="execute">
<result name="success">/HelloWorld.jsp</result>
</action>
Fichier struts.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name="struts.devMode" value="true" />
<package name="basicstruts2" extends="struts-default">
<action name="index">
<result>/index.jsp</result>
</action>
<action name="hello" class="action.HelloWorldAction" method="execute">
<result name="success">/HelloWorld.jsp</result>
<result name="error" type="redirect">error</result>
</action>
<action name="error">
<result>/error.jsp</result>
</action>
</package>
</struts>
Fichier struts.xml

Valeurs de retour (result) possibles :


La classe action peut retourner n'importe quelle string.
Si on étend une classe telle que ActionSupport alors des valeurs de retour sont
prédéfinies :





Le résultat peut rediriger vers :


SUCCESS, ERROR.
NONE : ok mais rien à afficher.
INPUT : informations manquantes (exemple : formulaire mal rempli).
LOGIN : il faut être connecté, action impossible.
Une page, un fichier ou une autre action.
Remarque : il existe des plugins pour ne pas utiliser de fichier struts.xml
mais plutôt des conventions de nommage avec des règles par défaut.
Fichier index.jsp

Utilisation de tags spécifiques struts :
 url
: création d'une url vers hello.action
 Voir plus loin pour d'autres tags.

C'est une page qui n'utilise pas le modèle.
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<body>
<a href="<s:url action='hello'/>">Hello World</a>
</body>
</html>
Fichier index.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<body>
<a href="<s:url action='hello'/>">Hello World</a>
</body>
</html>
<html>
<body>
<a href="/Struts/hello.action">Hello World</a>
</body>
</html>
Fichier HelloWorld.jsp

C'est une vue, accès aux objets de l'action :
On appelle le getter (getmessageStore) de la classe
correspondante.
 Similaire à un bean (cf cours jsp)
 Message par défaut si l'objet n'existe pas (au lieu de null)

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<body>
<s:property value="messageStore.message" default="objet inexistant"/>
</body>
</html>
Fichier HelloWorld.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<body>
<s:property value="messageStore.message" default="objet inexistant"/>
</body>
</html>
<html>
<body>
Hello Struts User
</body>
</html>
Fichier web.xml

Très similaire à un fichier web.xml classique :
On utilise des filtres de servlet au lieu de servlets.
 Toutes les urls sont associées à struts.

<filter>
<filter-name>struts2</filter-name>
<filter-class>
org.apache.struts.action2.dispatcher.FilterDispatcher
</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Classe Action

Une méthode execute() :



Utilise le modèle.
Retourne un résultat.
Possibilité de définir une méthode validate appelée avant l'exécution.
public class HelloWorldAction extends ActionSupport {
private MessageStore messageStore;
public String execute() throws Exception {
messageStore = new MessageStore() ;
return SUCCESS;
}
/* getters/setters */
}
Le modèle

On utilise ici un modèle trivial sans BD.
public class MessageStore {
private String message;
public MessageStore() {
setMessage("Hello Struts User");
}
/* getters/setters */
}
TAGS STRUTS
Tags struts

Il existe de nombreux tags struts pour générer du html.


http://struts.apache.org/2.0.14/docs/tag-reference.html
Objectifs :
Générer du html propre standard.
 Permettre la validation de manière simple (tout est du struts)
 Eviter d'avoir du Java pur dans les vues (jsp) :

Tags if/then/else
 Iterateurs sur des objets, …

Tags de contrôle

Un exemple simple :
 if,
elseif, else
<s:if test="%{false}">
<div>Cas 1</div>
</s:if>
<s:elseif test="%{true}">
<div>Cas 2</div>
</s:elseif>
<s:else>
<div>Cas 3</div>
</s:else>
Création de formulaires

On dispose aussi de nombreux tags pour créer des
formulaires :
Checkbox, file, hidden, password, radio, reset, select,
submit, textfield, …
 Certains sont associés à du Javascript

<s:form>
<s:textfield key="user" />
<s:password label="pass" name="pass" size="10"
maxlength="15" />
</s:form>
Création de formulaires
<s:form>
<s:textfield key="user" />
<s:password label="pass" name="pass" size="10" maxlength="15" />
</s:form>
<form id="index" name="index" action="/Struts/index.jsp" method="post">
<table class="wwFormTable">
<tr>
<td class="tdLabel"><label for="index_user" class="label">user:</label></td>
<td ><input type="text" name="user" value="" id="index_user"/></td>
</tr>
<tr>
<td class="tdLabel"><label for="index_pass" class="label">pass:</label></td>
<td ><input type="password" name="pass" size="10" maxlength="15"
id="index_pass"/></td>
</tr>
</table>
</form>
VALIDATION DE
FORMULAIRE
Validation avec validators

Création d'un fichier xml de validation :
Indiquer pour chaque champ s'il est obligatoire, son type,
les valeurs qu'il peut contenir, etc.
 Doit avoir le même nom que la classe action associée au
formulaire.

Exemple : classe login.java = fichier login-validation.xml
 A mettre dans le même répertoire que la classe.


Autre solution :
Utiliser la méthode validate() via la classe Action.
 Moins trivial.

Validation avec validators


Création d'un fichier de validation associé à la
classe action.
Pour chaque champ du formulaire on peut :
 Dire
s'il est obligatoire ou pas.
 Spécifier son type.
 Selon le type on peut mettre des contraintes
supplémentaires :
 Entier compris entre
x et y.
 Date après le xx/xx/xxxx
 regexp
Login.jsp
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<body>
<s:form action="doLogin" method="POST">
<s:actionerror /> <!-- erreurs dans l'action -->
<s:fielderror /> <!-- erreurs sur les champs -->
<s:textfield name="username" label="Login"/>
<s:textfield name="age" label="Age"/>
<s:password name="password" label="Password"/>
<s:submit value="Login" align="center"/>
</s:form>
</body>
</html>
Login-validation.xml
<validators>
<field name="username">
<field-validator type="requiredstring">
<param name="trim">true</param>
<message>login obligatoire</message></field-validator></field>
<field name="password">
<field-validator type="requiredstring">
<param name="trim">true</param>
<message>mot de passe obligatoire</message></field-validator></field>
<field name="age">
<field-validator type="required">
<message>age obligatoire</message></field-validator>
<field-validator type="int">
<param name="min">18</param>
<message>pour adultes uniquement</message></field-validator></field>
</validators>
Classe Action

Une fois la validation du formulaire, on valide
l'identifiant et le mot de passe :

Ici on le fait de manière simpliste.
package action;
import com.opensymphony.xwork2.ActionSupport;
public class Login extends ActionSupport {
public String execute() throws Exception {
System.out.println("Validating login");
if(!getUsername().equals("Admin") ||
!getPassword().equals("Admin")){
addActionError("Identifiants erronés");
return ERROR;
}else{
return SUCCESS;
}
}
// variables + getters/setters
}
OGML : OBJECT GRAPH
NAVIGATIONAL
LANGUAGE
Objets disponibles
Quatre types d'objets
1.
Objets temporaires, créés durant l'exécution
(exemple via un tag d'itération)
2.
Objets du modèle
3.
Objets de l'action en cours d'exécution
4.
Objets généraux, notamment #application,
#session, #request, #attr et #parameters qui
correspondent aux portées d'une servlet.
Accéder aux variables

Il suffit de connaitre le nom d'un objet pour y accéder :
Pas besoin de savoir à quel niveau se trouve l'objet, les 4
niveaux sont traités dans l'ordre jusqu'à ce que l'objet soit
trouvé.
 On utilise les getters disponibles dans les classes Java.
 Attention si plusieurs objets ont le même nom, seul le premier
sera retourné (éviter les noms du genre id).


Permet de faire des choses plus complexes :
<s:property value="messageStore.message"
 Équivalent à un getmessageStore().getMessage()

OGNL

On dispose de :
Propriétés (via getters/setters)
 Appel de méthodes
 Gestion d'indices de tableaux


name.toCharArray()[0].numericValue
Propriété name de l'objet courant.
 Appel de la méthode toCharArray().
 Extraction du premier caractère.
 Convertion en valeur numérique.

INTERCEPTEURS – EXEMPLE
VIA UPLOAD DE FICHIER
Upload de fichier

Objectif :
 Création d'un
formulaire d'upload de fichier simple
 Validation du type et de la taille du fichier
<s:form action="fileUpload"
method="post"
enctype="multipart/form-data" >
<s:file name="userImage" label="User Image" />
<s:submit />
</s:form>
Fichier FileUploadAction

Classe action pour l'upload :
Stocke le fichier, son type et son nom dans un objet.
 Validation du type et de la taille :

Soit dans la fonction execute ou validate
 Soit directement dans le fichier struts.xml avec des intercepteurs.

package action;
import java.io.File;
import com.opensymphony.xwork2.ActionSupport;
public class FileUploadAction extends ActionSupport {
private File userImage;
private String userImageContentType;
private String userImageFileName;
public String execute() {return SUCCESS;}
/* getters/setters */
}
Intercepteurs

Un intercepteur :



Agit avant et après les actions.
Permet de préparer les données avant les actions ou de formater
les résultats des actions.
De nombreux intercepteurs sont déjà définis et utilisables,
de même que des enchainements d'intercepteurs :






Validation de formulaires.
Internationalisation.
Gestion des exceptions.
Upload de fichier.
Gestion de session.
…
Fichier struts.xml

On défini un nouvel agrégat d'intercepteurs :


Ajout d'une validation de taille et de type
Pour créer un nouvel intercepteur :
<interceptor name="myInter" class="myPackage.myInter"/>
<!–- définition d'un intercepteur taille + type -->
<interceptor-stack name="fileUploadStack">
<interceptor-ref name="basicStack"/>
<interceptor-ref name="fileUpload">
<param name="maximumSize">10240</param>
<param name="allowedTypes">image/jpeg,image/gif,image/png</param>
</interceptor-ref>
<interceptor-ref name="validation"/>
<interceptor-ref name="workflow"/>
</interceptor-stack>
Fichier struts.xml
<package name="fileUploadPackage" extends="struts-default">
<interceptors>
<interceptor-stack name="fileUploadStack">
<interceptor-ref name="basicStack"/>
<interceptor-ref name="fileUpload">
<param name="maximumSize">10240</param>
<param name="allowedTypes">image/jpeg,image/gif,image/png</param>
</interceptor-ref>
<interceptor-ref name="validation"/>
<interceptor-ref name="workflow"/>
</interceptor-stack>
</interceptors>
<action name="fileUpload" class="action.FileUploadAction">
<interceptor-ref name="fileUploadStack" />
<result name="input">/upload.jsp</result>
<result name="success">/upload-success.jsp</result>
</action>
</package>
CONCLUSION
Conclusion


Présentation de base de struts.
De nombreuses autres fonctionnalités sont
disponibles :
 Validation niveau
 Tags
client (javascript).
AJAX.
…

D'autres frameworks Java existent, le plus gros
concurrent est JSF (Java Server Faces)