IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

JSF Java Discussion :

[JSF] Conception backingbean: patterns & architecture


Sujet :

JSF Java

  1. #1
    Membre habitué
    Inscrit en
    Décembre 2002
    Messages
    186
    Détails du profil
    Informations forums :
    Inscription : Décembre 2002
    Messages : 186
    Points : 130
    Points
    130
    Par défaut [JSF] Conception backingbean: patterns & architecture
    salut,

    je cherche à construire des backingbean xxxAction avec la règle 1 par page jsp ET uniquement en portée request.
    Ensuite le bean utilise une classe xxxForm qui contient tous les composants bindés avec la vue, ainsi qu'une classe xxxModel qui contient toutes les données préparée pour être affichées par la vue.

    De plus j'utilise un VariableResolver de Spring pour injecter les services métiers dans le bean. Toutefois, cette opération ne s'effectue qu'une fois le constructeur du bean terminé...

    un petit peu de code...

    le bean managé par jsf sous le nom listeProjetAction :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
     
    public class ListProjetAction {
     
      public ListProjetForm view;
      public ListProjetModel model;
     
      private List<Collaborateur> listCdP;
     
      public ListProjetAction(){
        view = new ListProjetForm();
        model = new ListProjetModel();
      }
     
      //#############################################################################
      //                             BINDING
      //#############################################################################
      public HtmlSelectOneListbox getCpSelected(){
        return view.getCpSelected();
      }
     
      //#############################################################################
      //                            DATA 
      //#############################################################################
      public List<SelectItem> getListChefProjet(){
        model.setListCdP(service.getCdP());
        return model.getListChefProjet();
      }
     
      //#############################################################################
      //                            ACTIONS
      //#############################################################################
      public void action1(){}
      public String action2(){
        return "detail";
      }


    et le xxxModel
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
     
    public class ListProjetModel {
     
      List<Collaborateur> listCdP; // Liste d'objets métiers ou de VO
     
      /**
       * Liste des items à afficher par le composant html
       */
      private List<SelectItem> listChefProjet;
     
     
      public ListProjetModel() {
        listChefProjet = new ArrayList<SelectItem>();
      }
     
      public List<SelectItem> getListChefProjet() {
       // FAUT IL APPELER LE SERVICE ICI ou suppose t'on que c'est DEJA INITIALISE?
        listChefProjet= new ArrayList<SelectItem>();
        if (listChefProjet != null ){
           for ( Collaborateur c : listCdP ){
              listChefProjet.add(new SelectItem(c.getId(), c.getNom());
           }
        }
        return listChefProjet;
      }
     
      public void setListChefProjet(List<SelectItem> listChefProjet) {
        this.listChefProjet = listChefProjet;
      }
     
    }



    Le xxxForm
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
     
    public class ListProjetForm {
     
      /**
       * Binding composant selection du chef de projet.
       */
      private HtmlSelectOneListbox cpSelected;
     
     
      public ListProjetForm(){
        buildComponent();
      }
      private void buildComponent(){
        cpSelected = new HtmlSelectOneListbox();
      }
     
     
      public HtmlSelectOneListbox getCpSelected() {
        return cpSelected;
      }
      public void setCpSelected(HtmlSelectOneListbox cpSelected) {
        this.cpSelected = cpSelected;
      }
     
    }


    et le code de la jsp:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
       <h:selectOneListbox size="1" id="idCP"    binding="#{listProjetAction.cpSelected}" styleClass="textA">
            <f:selectItems value="#{listProjetAction.listChefProjet}"/>
       </h:selectOneListbox>


    * le 1er pb est le suivant: Si je veux initialiser des données en provenance des services, alors :
    - soit je dois le faire en dehors du constructeur
    - soit, pour ceux qui connaissent spring, faire un appel explicite au WebApplicationContext.getBean("monService") ce qui du coup supprime l'interet de l'initialisation par jsf...
    En fait la spécif 1.1 ne propose pas de fonctionalité post/pré-constructeur, donc j'utiise actuelement l'initialisation dans le constructeur.


    *le 2eme soucis, si j'utilise la navigation dynamique, qui consiste à interoger le bean pour connaitre l'outcome, c'est tout le bean xxxAction qui est construit par un appel au constructeur, car on est en portée request... Du coup, juste pour retourner un outcome, je reconstruit tout le bean alors qu'il ne sera peut être jamais affiché! C'est vraiment lourd.


    Alors ma question, comment et a quel moment réaliser la construction des composants contenus xxxForm et l'initialisation des données (dans la classe xxxModel), données qui sont récupérées à partir des services métiers de la classe xxxAction ou d'autres paramètres???!!!

    Ma solution consiste à réaliser les initialisation dans les getters de la classe Action, qui va initialiser le/les champs du Model et le retourner...

    Qu'en pensez vous? Merci de m'éclairer et dite moi en plus sur votre facon de faire, si vous voyez des avantages/inconvénients...

  2. #2
    Membre averti
    Inscrit en
    Août 2005
    Messages
    352
    Détails du profil
    Informations forums :
    Inscription : Août 2005
    Messages : 352
    Points : 427
    Points
    427
    Par défaut
    Bon, j'avoue ne pas avoir une très grande expérience des JSF mais il me semble qu'il manque des informations pour qu'on te comprenne bien comme par exemple ton fichier avec tes managed beans (et les managed property associées) et ton fichier xml pour spring.

    Je ne comprends pas pourquoi tu parles de faire un appel à WebApplicationContext.getBean("monService") ? De plus, pourquoi ton model devrait il faire appel à un service ? Je ne pense pas que ce soit l'endroit idéal pour le faire. Ce serait plutôt à getListChefProjet() de déléguer le traitement au service qui retourne une liste qui constitue le model (ou alors wrapper dans ton objet ListProjetModel). De plus, en mettant ton service dans ta classe xxxAction, il est disponible pour être utilisé dans tes méthodes action1() ou action2()...

  3. #3
    Membre régulier
    Profil pro
    Consultant informatique
    Inscrit en
    Octobre 2002
    Messages
    89
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Consultant informatique

    Informations forums :
    Inscription : Octobre 2002
    Messages : 89
    Points : 111
    Points
    111
    Par défaut
    Je confirme que ton explication est pas très claire:

    le 1er pb est le suivant: Si je veux initialiser des données en provenance des services, alors :
    - soit je dois le faire en dehors du constructeur
    - soit, pour ceux qui connaissent spring, faire un appel explicite au WebApplicationContext.getBean("monService") ce qui du coup supprime l'interet de l'initialisation par jsf...
    En fait la spécif 1.1 ne propose pas de fonctionalité post/pré-constructeur, donc j'utiise actuelement l'initialisation dans le constructeur.
    Tu utilise jsf-spring je suppose. Bon ben tu construit tes bean de service dans ton "aplication-context" de spring
    (genre)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
        <bean id="profileDAO"
              class="com.developpez.model.base.attr.KodoProfileDAO">
            <property name="persistenceManagerFactory" ref="pmf"/>
        </bean>
     
     
    <bean id="testBeanTX" 
           class="com.developpez.ProfilesBeanTX">
            <property name="profileDAO" ref="profileDAO" />
        </bean>
    et dans ton jsf-config, tu fait appel a ces bean pour les injecter

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    <managed-bean>
            <managed-bean-name>TestBean</managed-bean-name>
           <managed-bean-class>com.developpez.backingBean.TestBackingBean</managed-bean-class>
            <managed-bean-scope>request</managed-bean-scope>
            <managed-property>
                <property-name>profileControllerTx</property-name>
                <value>#{testBeanTX}</value>
            </managed-property>
        </managed-bean>
    Sur ton code, il manque des getter sur le model et la view pour jsf


    e 2eme soucis, si j'utilise la navigation dynamique, qui consiste à interoger le bean pour connaitre l'outcome, c'est tout le bean xxxAction qui est construit par un appel au constructeur, car on est en portée request... Du coup, juste pour retourner un outcome, je reconstruit tout le bean alors qu'il ne sera peut être jamais affiché! C'est vraiment lourd.
    Je suppose que le bean est en "pool" car en pratique cela ne pose pas de problème de performance

    Autrement ton approche est valable

  4. #4
    Membre habitué
    Inscrit en
    Décembre 2002
    Messages
    186
    Détails du profil
    Informations forums :
    Inscription : Décembre 2002
    Messages : 186
    Points : 130
    Points
    130
    Par défaut
    Je confirme que ton explication est pas très claire
    exacte!

    1) je n'utilise pas jsf-spring pour l'instant car je le besoin d'assembler les beans depuis spring ne se fait pas encore sentir.
    Par contre j'uilise le variableResolver fournit par défaut dans spring, et effectivement je fais un truc dans le genre
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    <managed-property>
                <property-name>profileControllerTx</property-name>
                <value>#{monService}</value>
            </managed-property>
    Ma remarque était la suivante: si j'ai besoin d'utiliser monService dans le constructeur, le variableResolver ne peut rien pour moi, car l'injection du service ne se fait que apres l'appel au constructeur.
    Je ne comprends pas pourquoi tu parles de faire un appel à WebApplicationContext.getBean("monService") ?
    >Voila pkoi je parle d'utiliser le WebApplicationContext() si on a besoin du service DANS le constructeur.

    Ce serait plutôt à getListChefProjet() de déléguer le traitement au service qui retourne une liste qui constitue le model (ou alors wrapper dans ton objet ListProjetModel). De plus, en mettant ton service dans ta classe xxxAction, il est disponible pour être utilisé dans tes méthodes action1() ou action2()...
    > oui, c'est une erreur que g corrigé!


    2) Vous allez me dire, pourquoi tu as besoin du service dans le constructeur? Parce que jusqu'à maintenant, j'initialisais tous les champs à afficher DANS le constructeur! Mais je cherche une autre méthode...


    3) Pourquoi c'est pas une bonne idée de réaliser les initialisations dans le constructeur?
    Et bien voila un scénario:

    j'ai une page qui contient:
    - un select (remplit dynamiquement par appel à un service, sans paramètres)
    - un tableau (remplit également par appel à un service) dont les valeurs dépendent de la valeur du select décrit + haut

    (a) lors du premier appel à la page, je dois initialiser le select, et le positionner sur une valeur par défaut + initialiser le tableau en appelant le service et lui fournissant la valeur par défaut du select
    REM: je peux tres bien faire tout ca dans le constructeur

    (b) si ensuite je change la valeur du select et fait une requete (methode search() du bean qui retourne null), alors la je dois prendre en compte les valeurs du nouveau champs select et adapter ma requete pour remplir la dataTable en conséquence

    (c) si j'ai une action à appeler qui retourne un outcome vers une autre page, je n'ai pas forcement besoin de reconstruire le model puique je l'affiche pas (je construit uniquement les UIComponent bindés pour récupérer les paramètres...)

    ==> du coup, pas question de construire/initialiser les données dans le constructeur, car dans le cas (b) il va d'abord construire le modele par défaut, puis appeler l'action sur la methode recherche() qui reconstruit le model en prenant en compte les paramètres!

    Dans le cas (c), il va me construire le modele puis retourner vers une autre page, donc ca n'a servit à rien!

    e suppose que le bean est en "pool" car en pratique cela ne pose pas de problème de performance
    > je ne sais pas si il utilise un pool, mais c'est problématique si je réalisais des initialisation dans le constructeur!!!


    ---------------------------------------------------------------------------------------
    La solution sur laquelle je pars:

    - le constructeur du bean ne fait que construire la vue des composants
    - pour reprendre l'exemple précédant, lorsque je fais dans la jsp:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    <f:selectItems value="#{listProjetAction.listChefProjet}"/>
    alors g une méthode dans mon bean qui est appelée:


    Action
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
     
     
    public List<SelectItem> getListChefProjet(){
        if ( ! isInitialized() ) init();
        return model.getListCdPUIData();
      }
     
     
    public String search(){
        initModel();
        return null;
      }
     
    private void init(){
    // initialisation du select
        List<Collaborateur> listCdP = projetFacade.findAllChefDeProjetAgence(idAgenceSelected );
        model.setListCdP(listCdP);
     
    // initialisation du dataTable
        if ( (idAgenceSelected = (Integer) getAgenceSelected().getValue()) == null )
          idAgenceSelected = 1; // par défaut, idAgence de idUser connecté
     
        if ( (idCdPSelected = (Integer) getCpSelected().getValue()) == null )
          idEtatSelected = Etat.EN_COURS; // par défaut, Etat.EN_COURS
     
     
        // Construction du modele métier
        List<InfoProjetVO> listProjet = projetFacade.getListProjet(idCdPSelected, idEtatSelected );
        model.setListProjet(listProjet);
     
        setInitialized(true);
    et dans le Model
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
     
     
    //Modeles métiers initialisés par le service
      private List<Collaborateur> listCdP;
      private List<InfoProjetVO> listProjet;
     
    // retourne le model de la présentation à partir du model métier
    public List<SelectItem> getListCdPUIData() {
        listCdPUIData= new ArrayList<SelectItem>();
        if (getListCdP() != null ){
           for ( Collaborateur c : getListCdP() ){
              listCdPUIData.add(new SelectItem(c.getId(), c.getNom()));
           }
        } 
        return listCdPUIData;
      }
     
    // retourne le model de la présentation à partir du model métier
    public ListDataModel getListProjetUIData() {
        listProjetUIData = new ListDataModel(getListProjet());
        return listProjetUIData;
      }

    et idem pour le tableau, sauf qu'il est initialisé en appelant un service et en fournissant les paramètres fournis ou par défaut



    Bon, je sais c pâs tres clair, mais c pas simple non plus, surotut que les tutoriaux montrent juste de exemple tout simple, ce qui est utile pourdébter mais dans la vrai vie c'est autre chose!

    Je crois que le probleme vient du fait que je viens du monde Struts, où les classes Action ne contenant que des méthodes et transmettaint les paramètres à la vue, alors que avec JSF c'est la page JSP qui instantie dabord le bean PUIS appele plusieurs fois des méthodes dessus!


    Bref, si vous aussi vous avez compris mon pb exposé + haut, j'attend vos remarques...

  5. #5
    Membre régulier
    Profil pro
    Consultant informatique
    Inscrit en
    Octobre 2002
    Messages
    89
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Consultant informatique

    Informations forums :
    Inscription : Octobre 2002
    Messages : 89
    Points : 111
    Points
    111
    Par défaut
    Tu peut faire tes initilialisation juste àprès l'injection

    Pour ce qui est de ma remarque sur getter sur model:

    c'est que a la place de faire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    <f:selectItems value="#{listProjetAction.listChefProjet}"/>
    tu peut faire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    <f:selectItems value="#{listProjetAction.model.listChefProjet}"/>
    => ton backing bean ne devra pas réimplementer tout les getter de ton modèle!! (mais il faut un getModel)

  6. #6
    Membre habitué
    Inscrit en
    Décembre 2002
    Messages
    186
    Détails du profil
    Informations forums :
    Inscription : Décembre 2002
    Messages : 186
    Points : 130
    Points
    130
    Par défaut
    et bien en fit quand je fais getListChefProjet, l'action va transmettre au modele les données (métier). Ensuite l'action appele getListChefDeProjet du modele qui lui va retourner des données de type javax.faces.model ou d'autres données (qui wrape ou décore les données retournées par la couche service), qui seront manipulées par la vue.

    Quand à faire les initialisations apres l'injection, c'est ce que je fais, mais au fur et à mesure que la jsp accede au champs, d'ou la présence de getter pour chaque modele de la vue (en fait g viré la méthode globale init())

    Mais effectivement, si je garde un méthode init globale, il me faudrait un systeme qui oblige à lancer juste apres l'injection: c'est ce que g essayé de faire avec les boolean isInitialized() mais c'est pas tres propre. En+, l'architecture que je cherche à mettre en place doit servir de modele pour tous les autres dvlp, donc fo simplifier au maximum...

    merci! et n'hesitez pas si vous avez des remarques, je suis en pleine phase de recherche...!

Discussions similaires

  1. [Conception] Design Pattern Observer Java
    Par jeb001 dans le forum Général Java
    Réponses: 4
    Dernier message: 02/05/2007, 23h43
  2. [Conception]Design Pattern Factory ?
    Par ®om dans le forum Logging
    Réponses: 8
    Dernier message: 13/09/2006, 10h20
  3. [conception] quel pattern choisir?
    Par r0d dans le forum C++
    Réponses: 4
    Dernier message: 26/04/2006, 18h56

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo