4 nov. 2021 16:02:31 Thomas Dumont avatar

XPage

Définition

Une XPage est une page spéciale qui ne fait pas partie de l'arborescence des pages construites avec des portlets. Elle est autonome et s'appelle en utilisant le paramètre page comme suit :

jsp/site/Portal.jsp?page=ma_xpage

Ce composant est typiquement destiné à réaliser des applications fonctionnant au sein du portail.

Implémentation de base

La création d'une XPage nécessite seulement deux actions :

  • la création d'une classe Java qui implémente l'interface XPageApplication
  • la déclaration de la XPage dans le fichier xml du plugin

Dans Exemple de XPage : Le Plugin HelloWorld, plusieurs implémentations sont présentées dans le cadre d'un plugin HelloWorld.

Implémentation de l'interface XPageApplication

L’implémentation de l'interface XPageApplication nécessite de définir la méthode suivante :

XPage getPage( HttpServletRequest request, int nMode, Plugin plugin)

Déclaration dans le fichier XML du plugin

La déclaration doit se faire comme suit :

<!-- Applications -->
<applications>
    ...
    <application>
        <application-id>mypage</application-id>
        <application-class>fr.paris.lutece.plugins.myplugin.web.MyApp </application-class>
    </application>
    ...
</applications>

Présentation générale du framework MVC

Le framework MVC est disponible pour développer des XPages en utilisant le paradigme Model-View-Controller à partir de la version 4.1 de Lutèce.

Lutece 4.1 library-mvc indépendante du core

Lutece 4.2 - 4..4 library-mvc en dépendance du core

Lutece 5.0 framework intégré au core

Ce framework propose :

  • Le dispatching des requêtes par le contrôleur pour traitement des actions et affichage des vues
  • L’identification des actions et des vues par annotations
  • La population et la validation des beans (JSR 303)
  • La gestion des erreurs de validation directement incluse dans le modèle du template (marker « errors »)
  • La gestion des notifications ou messages informatifs incluse dans le modèle du template (marker « infos »)
  • La redirection HTTP des requêtes vers des vues évitant le recours à des JSP

Important ! Le plugin PluginWizard a été réécrit en version 3.1 avec ce framework. Il génère d'une part des plugins utilisant ce framework et constitue d'autre part un exemple avancé de sa mise en oeuvre dans des cas complexes.

Principe de mise en œuvre du modèle MVC

La library MVC propose une implémentation MVCApplication de l'interface XPageApplication offrant des mécanismes permettant de découper les fonctions selon le pattern Modèle-Vue-Controleur dont voici le schéma :

schema MVC

Le point d'entrée de la XPage joue le rôle de contrôleur. C'est la classe MVCApplication qui prend en charge cette fonction en implémentant la méthode getPage de l'interface.

Les actions et les vues sont désignées par des annotations @Action et @View.

Le contrôleur dispatche les traitements sur les méthodes annotées en fonction des paramètres de la request.

L'annotation @Controller à définir sur la classe dérivée de MVCApplication sert à définir des paramètres de la classe.

La page d'accueil de la XPage doit positionner le paramètre defaultView de l'annotation @View à true.

Les vues

Le framework MVC apporte une notion de vues et d'actions.

Les vues servent à afficher un contenu à l'utilisateur. Une vue est une méthode d'un contrôleur ayant l'annotation @View. Cette annotation prend en paramètre la clé unique de la vue qui sera utilisée par le framework pour la définir. Une fois le contenu d'une vue généré, elle doit renvoyer son résultat dans un objet XPage. La vue qui correspond à la page d'accueil de l'application doit comporter le paramètre defaultView de l'annotation @View à true. Lorsqu'une requête est effectuée sur une application, et qu'aucune vue ou action n'est spécifiée, alors la page d'accueil est affichée.

L'URL d'une vue est générée sur le modèle suivant :

jsp/site/Portal.jsp?page=nomdelapplication&view=nomdelavue

où :

  • nomdelapplication est le nom de l'application (défini dans le paramètre de l'annotation @Controller)
  • nomdelavue est le nom de la vue à afficher (définie comme paramètre de l'annotation @View).

Le mot clé view est donc un mot clé réservé et ne doit pas être utilisé comme nom de paramètre HTML pour une autre raison.

Les actions

Les actions servent à effectuer des traitements. Les actions ne doivent pas générer de contenu à afficher à l'utilisateur.

Une action est une méthode d'un contrôleur ayant l'annotation @Action. Cette annotation prend en paramètre la clé unique de l'action qui sera utilisée par le framework pour la définir. Lorsqu'une action termine son traitement, elle doit effectuer une redirection vers une vue grâce aux méthode de redirection de la librairie (cf paragraphe suivant). Une action doit renvoyer un objet de type XPage. Lorsqu'elle effectue une redirection, elle doit renvoyer la XPage créée par la méthode de redirection.

L'URL d'une vue est générée sur le modèle suivant :

jsp/site/Portal.jsp?page=nomdelapplication&action=nomdelaction

où :

  • nomdelapplication est le nom de l'application (défini dans le paramètre de l'annotation @Controller)
  • nomdelaction est le nom de l'action à effectuer (définie comme paramètre de l'annotation @Action).

Le mot clé action est donc un mot clé réservé et ne doit pas être utilisé comme nom de paramètre HTML pour une autre raison.

Les redirections

Lorsqu'une vue ou une action souhaite effectuer une redirection vers une autre vue ou une URL définie, elle doit appeler une des méthodes redirect( ) de la classe MVCApplication.

Ces méthodes permettent d'effectuer des redirections vers des vues de l'application en spécifiant uniquement le nom de la vue à afficher, ou vers une URL complète définie manuellement. Lorsque la redirection se fait vers une vue de l'application, des paramètres peuvent être spécifiés en les ajoutant dans une Map.

Une fois le traitement de la méthode de redirection terminé, la réponse HTTP est envoyé. Il n'est donc pas possible d'afficher un contenu HTML ou de faire une autre redirection pour ignorer la première.

Les méthodes de redirection renvoient des objets de type XPage. Ces objets doivent être renvoyés par les vues ou actions ayant appelé la méthode de redirection.

Exemple de code

Voici le code d'une XPage proposant 2 vues :

  • la page d'accueil affichant une liste de contacts
  • la page de création d'un contact

ainsi que 2 actions :

  • créer un contact
  • supprimer un contact
// MVCDemoApp.java

@Controller( xpageName = "mvcdemo" , pageTitle = "mvcdemo.pageTitle" , pagePath = "mvcdemo.pagePathLabel" )
public class MVCDemoApp extends MVCApplication
{
    private static final String TEMPLATE_HOME = "/skin/plugins/mvcdemo/home.html";
    private static final String TEMPLATE_FORM = "/skin/plugins/mvcdemo/form.html";
    private static final String VIEW_HOME = "home";
    private static final String VIEW_ADD_CONTACT = "addContact";
    private static final String ACTION_ADD_CONTACT = "addContact";
    private static final String ACTION_REMOVE_CONTACT = "removeContact";
    private static final String MARK_CONTACTS_LIST = "contacts_list";
    private static final String PARAMETER_ID = "id";


    @View( value = VIEW_HOME , defaultView = true )
    public XPage viewHome(HttpServletRequest request)
    {
        Map<String,Object> model = getModel();
        model.put( MARK_CONTACTS_LIST , ContactService.getContacts() );
        return getXPage( TEMPLATE_HOME, request.getLocale(  ) , model );
    }

    @View( VIEW_ADD_CONTACT )
    public XPage viewAddContact(HttpServletRequest request)
    {
        return getXPage( TEMPLATE_FORM, request.getLocale(  ) );
    }

    @Action( ACTION_ADD_CONTACT )
    public XPage addContact(HttpServletRequest request)
    {
        Contact contact = new Contact();
        populate(contact, request);

        if ( !validateBean(contact))
        {
            return redirectView( request , VIEW_ADD_CONTACT );
        }
        ContactService.addContact(contact);
        return redirectView( request , VIEW_HOME );
    }

    @Action( ACTION_REMOVE_CONTACT )
    public XPage removeContact(HttpServletRequest request)
    {
        String strContact = request.getParameter( PARAMETER_ID );
        ContactService.removeContact( strContact );
        return redirectView( request , VIEW_HOME );
    }

Fonctions avancées

Formulaires multi-actions

Exemple de formulaire mono action :

<form action="jsp/site/Portal.jsp" >
    <input type="hidden" name="page" value="myplugin" />
    <input type="hidden" name="action" value="action1" />
    ...
    <button type="submit" value="Action 1" />
</form>

Exemple de formulaire multi-actions :

<form action="jsp/site/Portal.jsp" >
    <input type="hidden" name="page" value="myplugin" />
    ...
    <button type="submit" name=action_action1 value="Action 1" />
    <button type="submit" name=action_action2 value="Action 2" />
    <button type="submit" name=view_view1 value="Action 3" />
</form>

Les prefix action_ et view_ dans les noms des boutons sont interprétés comme des appels d'actions ou de vues. L'autre partie du nom est interprétée comme la valeur de l'action ou de la vue.

Renvoie de flux JSON ou XML par la XPage

A partir de Lutece 5.0

Cette fonctionnalité peut être utile pour réaliser certaine partie de la page en Ajax tout en gardant le code de la partie serveur dans la même classe.

Pour cela deux méthodes ont été ajoutées au framework dans la classe MVCApplication :

  • XPage responseJSON( HttpServletRequest request )
  • XPage responseXML( HttpServletRequest request )

Voici un exemple qui renvoie une liste d'images au format JSON :

@View( VIEW_LIST_IMAGES )
public XPage viewListImages( HttpServletRequest request )
{
    String strTopicId = request.getParameter( Constants.PARAMETER_TOPIC_ID );
    JSONArray array = new JSONArray();

    if( strTopicId != null )
    {
        int nTopicId = Integer.parseInt(strTopicId);
        List<Image> list = ImageHome.findByTopic( nTopicId , _plugin );
        for( Image image : list )
        {
            JSONObject jsonImage = new JSONObject();
            jsonImage.accumulate( "id", image.getId() );
            jsonImage.accumulate( "name", image.getName() );
            array.add( jsonImage );
        }
    }

    return responseJSON( array.toString() ); 
}