Structure du backing bean JSF (bonnes pratiques)

118

J'espère que dans cet article, je pourrai avoir l'opinion des gens sur les meilleures pratiques pour l'interface entre les pages JSF et les backing beans.

Une chose sur laquelle je ne pourrai jamais m'arrêter est la structure de mes backing beans. De plus, je n'ai jamais trouvé un bon article sur le sujet.

Quelles propriétés appartiennent à quels backing beans? Quand est-il approprié d'ajouter plus de propriétés à un bean donné plutôt que de créer un nouveau bean et d'y ajouter les propriétés? Pour les applications simples, est-il judicieux de n'avoir qu'un seul bean de support pour toute la page, compte tenu de la complexité de l'injection d'un bean dans un autre? Le bean de support doit-il contenir une logique métier réelle ou doit-il contenir strictement des données?

N'hésitez pas à répondre à ces questions et à toutes autres qui pourraient survenir.


En ce qui concerne la réduction du couplage entre la page JSF et le backing bean, je n'autorise jamais la page JSF à accéder aux propriétés des propriétés du backing bean. Par exemple, je n'autorise jamais quelque chose comme:

<h:outputText value="#{myBean.anObject.anObjectProperty}" />

J'ai toujours besoin de quelque chose comme:

<h:outputText value="#{myBean.theObjectProperty}" />

avec une valeur de backing bean de:

public String getTheObjectProperty()
{
    return anObject.getAnObjectProperty();
}

Lorsque je boucle sur une collection, j'utilise une classe wrapper pour éviter d'explorer un objet dans une table de données, par exemple.

En général, cette approche me semble «juste». Il évite tout couplage entre la vue et les données. Corrigez-moi si j'ai tort, s'il-vous plait.

Zack Marrapese
la source
Pouvez-vous donner un exemple pour: Lorsque je boucle sur une collection, j'utilise une classe wrapper pour éviter de creuser dans un objet dans une table de données, par exemple.
Koray Tugay
2
Pour plus d'informations, voir la réponse de BalusC sur stackoverflow.com/questions/7223055/…
Zack Marrapese

Réponses:

146

Vous voudrez peut-être vérifier ceci: faire des distinctions entre les différents types de beans gérés JSF .

Voici une description des différents types de haricots, tels que définis dans l'article ci-dessus de Neil Griffin:

  • Model Managed-Bean : normalement la portée de la session. Ce type de gestion-bean participe à la préoccupation «Model» du design pattern MVC. Lorsque vous voyez le mot «modèle», pensez aux DONNÉES. Un bean-modèle JSF doit être un POJO qui suit le modèle de conception JavaBean avec des getters / setters encapsulant des propriétés. Le cas d'utilisation le plus courant d'un bean modèle est d'être une entité de base de données ou simplement de représenter un ensemble de lignes à partir du jeu de résultats d'une requête de base de données.
  • Backing Managed-Bean : normalement demander la portée. Ce type de gestion-bean participe à la préoccupation "View" du design pattern MVC. Le but d'un backing-bean est de prendre en charge la logique de l'interface utilisateur et a une relation 1 :: 1 avec une vue JSF ou un formulaire JSF dans une composition Facelet. Bien qu'il ait généralement des propriétés de style JavaBean avec des getters / setters associés, ce sont des propriétés de la vue et non du modèle de données d'application sous-jacent. Les backing-beans JSF peuvent également avoir des méthodes JSF actionListener et valueChangeListener.
  • Controller Managed-Bean : normalement demander la portée. Ce type de gestion-bean participe à la préoccupation «Controller» du design pattern MVC. Le but d'un bean contrôleur est d'exécuter une sorte de logique métier et de renvoyer un résultat de navigation au gestionnaire de navigation JSF. Les beans-contrôleurs JSF ont généralement des méthodes d'action JSF (et non des méthodes actionListener).
  • Support Managed-Bean : normalement la portée de la session ou de l'application. Ce type de bean "prend en charge" une ou plusieurs vues dans la préoccupation "Vue" du modèle de conception MVC. Le cas d'utilisation typique est de fournir une ArrayList à JSF h: selectOneMenu listes déroulantes qui apparaissent dans plusieurs vues JSF. Si les données des listes déroulantes sont propres à l'utilisateur, le bean serait conservé dans la portée de la session. Cependant, si les données s'appliquent à tous les utilisateurs (comme une liste déroulante de provinces), alors le bean serait conservé dans la portée de l'application, de sorte qu'il puisse être mis en cache pour tous les utilisateurs.
  • Utilitaire Managed-Bean : normalement le champ d'application. Ce type de bean fournit un type de fonction "utilitaire" à une ou plusieurs vues JSF. Un bon exemple de cela pourrait être un bean FileUpload qui peut être réutilisé dans plusieurs applications Web.
Cecemel
la source
8
Cet article est super. Je ne l'ai jamais vu auparavant et je suis vraiment heureux que vous l'ayez publié. Celui qui a voté contre cela est fou. Ce n'est pas spécifique à iceFaces.
Zack Marrapese le
2
Le lien vers l'article réel semble avoir disparu.
Bill Rosmus
Une copie peut être trouvée ici
ChrLipp
10
Pourtant, je ne peux pas comprendre que cette réponse est actuellement à 71 votes positifs. Quiconque a implémenté son application JSF selon ces règles doit sans aucun doute par la suite se plaindre du fait que JSF est un cadre terriblement opaque et que ses applications JSF sont un gros désordre de code et qu'ils blâment tous JSF lui-même au lieu de leur propre mauvaise approche basée sur les mauvaises leçons et soi-disant «meilleures pratiques» apprises.
BalusC
la logique de ces beans est-elle exécutée dans le navigateur plutôt que sur le serveur?
eskalera
14

Excellente question. J'ai beaucoup souffert du même dilemme lorsque j'ai rejoint JSF. Cela dépend vraiment de votre application. Je viens du monde Java EE donc je recommanderais d'avoir le moins de logique métier possible dans vos backing beans. Si la logique est purement liée à la présentation de votre page, alors c'est bien de l'avoir dans le backing bean.

Je pense que l'un des (nombreux) atouts de JSF est en fait le fait que vous pouvez exposer des objets de domaine directement sur les beans gérés. Je recommanderais donc fortement l' <:outputText value="#{myBean.anObject.anObjectProperty}" />approche, sinon vous finirez par faire trop de travail pour vous-même en exposant manuellement chaque propriété. De plus, ce serait un peu compliqué lors de l'insertion ou de la mise à jour des données si vous encapsuliez toutes les propriétés. Il existe des situations où un seul objet de domaine peut ne pas être suffisant. Dans ces cas, je prépare un ValueObject avant de l'exposer sur le bean.

EDIT: En fait, si vous allez encapsuler chaque propriété d'objet que vous souhaitez exposer, je vous recommanderais plutôt de lier les composants de l'interface utilisateur au bean de support, puis d'injecter le contenu directement dans la valeur du composant.

En termes de structure de bean, le tournant pour moi a été lorsque j'ai ignoré avec force tout ce que je savais sur la création d'applications Web et que j'ai commencé à le traiter comme une application graphique. JSF imite beaucoup Swing et, par conséquent, les meilleures pratiques pour le développement d'applications Swing s'appliqueraient principalement à la création d'applications JSF.

Allan Lykke Christensen
la source
Merci pour votre perspicacité. Je n'ai jamais vraiment fait grand-chose en matière d'applications swing (à part les projets académiques il y a longtemps). Quels sont les bons principes des applications swing? Aussi, pourquoi est-ce un désordre lors de l'insertion et de la mise à jour des valeurs? me semble-t-il pareil?
Zack Marrapese le
5

Je pense que la chose la plus importante avec vos backing beans est de séparer leurs logiques. Si vous avez une page d'accueil pour un système CMS, je considérerais comme une mauvaise pratique de mettre chaque morceau de code dans un seul bean car:

  1. Le haricot finirait par devenir très gros
  2. Il est plus facile pour d'autres personnes de trouver ce qu'elles recherchent si elles résolvent les problèmes de la page de connexion, si elles peuvent ensuite facilement rechercher le fichier loginBean.java.
  3. Parfois, vous avez de petites fonctionnalités qui sont clairement distinctes du reste de votre code, en séparant cela, j'imagine que vous vous faciliteriez la tâche pour redévelopper / étendre ce code en quelque chose de plus grand, alors que vous avez déjà un bon bean avec du bon structure.
  4. Avoir 1 gros bean, pour tout faire, le rendra plus dépendant de la mémoire si / quand vous devez faire des déclarations comme celle-ci MyBigBean bigBean = new MyBigBean (); au lieu d'utiliser la fonction funksjonality dont vous aviez réellement besoin en faisant LoginBean loginBean = new LoginBean (); (Corrigez-moi si je me trompe ici ???)
  5. À mon avis, séparer vos haricots, c'est comme séparer vos méthodes. Vous ne voulez pas d'une grande méthode qui exécute plus de 100 lignes, mais la divisez plutôt avec de nouvelles méthodes qui gèrent leur tâche spécifique.
  6. N'oubliez pas que quelqu'un d'autre que vous devra probablement travailler sur vos projets JSF.


En ce qui concerne le couplage, je ne vois pas cela comme un problème gênant pour permettre à vos pages JSF d'accéder également aux propriétés des objets de votre backingbean. Il s'agit d'un support intégré à JSF et qui facilite vraiment la lecture et la construction de imo. Vous séparez déjà strictement la logique MVC. En faisant cela, vous économisez des tonnes de lignes avec des getters et des setters dans votre backingbean. Par exemple, j'ai un objet vraiment énorme qui m'est donné par les services Web, où je dois utiliser certaines propriétés dans ma présentation. Si je devais créer un getter / setter pour chaque propriété, mon bean se développerait avec au moins 100 lignes supplémentaires de variables et de méthodes pour obtenir les propriétés. En utilisant la fonctionnalité JSF intégrée, mon temps et mes précieuses lignes de code sont épargnés.

Juste mes 2 cents à ce sujet même avec la question déjà marquée comme réponse.

Chris Dale
la source
1
cependant, si vous avez un objet énorme qui est assis dans votre bean, et que vous avez - disons - 15 fonctions EL creusant dans cet objet à partir de la page JSF, vous êtes maintenant lié non seulement au bean, mais à cet objet. Par conséquent, il sera difficile de supprimer cet objet sans casser l'interface utilisateur.
Zack Marrapese
1
Mais votre haricot de soutien ne sera-t-il pas lié à cet objet également? Et votre interface utilisateur est liée au backing bean? Lorsque vous devrez ensuite le modifier, vous devrez changer tous vos getters / setters dans l'interface utilisateur et le bean.
Chris Dale
4

Je ne répondrai peut-être pas à chacune de vos questions, car peu d'entre elles semblent dépendre d'un cas à l'autre.

  • C'est bien d'avoir une logique métier dans votre backing bean. Cela dépend d'où tu viens. Si vous pratiquez la conception pilotée par domaine, vous serez tenté d'inclure la logique métier dans le backing bean ou peut-être aussi la logique de persistance. Ils soutiennent que pourquoi objet si stupide. L'objet doit porter non seulement l'état mais aussi le comportement. D'un autre côté, si vous considérez la manière traditionnelle de faire les choses de Java EE, vous pourriez avoir envie d'avoir des données dans votre bean de sauvegarde, qui peut également être votre bean entité, et d'autres logiques commerciales et de persistance dans un bean session ou quelque chose. C'est bien aussi.

  • C'est parfaitement bien d'avoir un seul bean de support pour toute la page. Je ne vois aucun problème avec cela seul. Cela peut ne pas sembler correct, mais cela dépend du cas.

  • Votre autre question dépend beaucoup plus du cas que vous avez en main. Je préférerais utiliser le domaine ici, il pourrait être approprié d'ajouter des propriétés à l'existant ou de créer un nouveau bean pour cela. Ce qui convient toujours mieux. Je ne pense pas qu'il y ait de solution miracle pour cela.

  • Quelles propriétés appartiennent à quel backing bean. Eh bien, cela ne dépend pas de l'objet de domaine? Ou peut-être que la question n'est pas si claire.

De plus, dans votre exemple de code donné, je ne vois aucun avantage énorme.

Adeel Ansari
la source
si, par exemple, nous devions passer de l'utilisation de POJO faits maison créés avec des requêtes JDBC à des entités Hibernate qui avaient des noms de champ légèrement différents, nous n'aurions pas seulement à changer le bean de support. Il faudrait également changer la page JSF. Ce n'est pas le cas avec mon exemple de code. Changez simplement le haricot.
Zack Marrapese le
Dans ce cas, vous pouvez créer vos backing beans, des entités. il vous suffit alors de changer les pages JSF. Ou cela dépend pourquoi changeriez-vous le nom des propriétés de toute façon? cela n'a de sens que lorsque vous renommez le champ pour qu'il corresponde au nom de la colonne de votre base de données. Mais c’est un cas complètement différent.
Adeel Ansari
4

Je n'aurais pas besoin de garder un seul backing bean par page. Cela dépend de la fonctionnalité, mais la plupart du temps, j'avais un bean par page, car la plupart du temps, une page gérait une fonctionnalité. Par exemple, sur une page, j'ai un lien d'inscription (je vais créer un lien avec RegisterBean) et un lien vers le panier (ShoopingBasketBean).

J'utilise ce <: outputText value = "# {myBean.anObject.anObjectProperty}" /> car je continue normalement à sauvegarder des beans comme des beans d'action qui contiennent des objets de données. Je ne veux pas écrire de wrapper dans mon bean de sauvegarde pour accéder aux propriétés de mes objets de données.

Bhushan Bhangale
la source
0

J'aime tester le code métier sans View, donc je considère BackingBeans comme des interfaces du code View au Model. Je n'ai jamais mis de règle ou de processus dans un BackingBean. Ce code entre dans les Services ou Helpers, permettant la réutilisation.

Si vous utilisez des validateurs, retirez-les de votre BackingBean et référencez-les à partir de votre méthode de validation.

Si vous accédez aux DAO pour remplir Selects, Radios, Checkboxes, faites-le toujours à partir d'un BackingBean.

Crois moi!. Vous pouvez injecter un JavaBean dans un BackingBean, mais essayez d'injecter un BackingBean dans un autre. Vous serez bientôt dans une phase de maintenance et de compréhension du code.

jjruiz
la source