A quoi sert la bibliothèque de ressources JSF et comment doit-elle être utilisée?

228

Le JSF <h:outputStylesheet>, <h:outputScript>et les <h:graphicImage>composants ont un libraryattribut. Qu'est-ce que c'est et comment devrait-il être utilisé? Il y a beaucoup d'exemples sur le web qui l' utilisent comme suit avec le contenu commun / type de fichier css, jset img(ou image) comme nom de la bibliothèque en fonction de l'étiquette utilisée:

<h:outputStylesheet library="css" name="style.css" />
<h:outputScript library="js" name="script.js" />
<h:graphicImage library="img" name="logo.png" />

Comment est-ce utile? La libraryvaleur dans ces exemples semble simplement répéter tout ce qui est déjà représenté par le nom de la balise. Pour un <h:outputStylesheet>c'est basé sur le nom de balise déjà évident qu'il représente une "bibliothèque CSS". Quelle est la différence avec ce qui suit, qui fonctionne également de la même manière?

<h:outputStylesheet name="css/style.css" />
<h:outputScript name="js/script.js" />
<h:graphicImage name="img/logo.png" />

De plus, la sortie HTML générée est un peu différente. Étant donné un chemin de contexte /contextnameet un FacesServletmappage sur un modèle d'URL de *.xhtml, le premier génère le code HTML suivant avec le nom de la bibliothèque comme paramètre de demande:

<link rel="stylesheet" type="text/css" href="/contextname/javax.faces.resource/style.css.xhtml?ln=css" />
<script type="text/javascript" src="/contextname/javax.faces.resource/script.js.xhtml?ln=js"></script>
<img src="/contextname/javax.faces.resource/logo.png.xhtml?ln=img" alt="" />

Alors que ce dernier génère le code HTML suivant avec le nom de la bibliothèque juste dans le chemin de l'URI:

<link rel="stylesheet" type="text/css" href="/contextname/javax.faces.resource/css/style.css.xhtml" />
<script type="text/javascript" src="/contextname/javax.faces.resource/js/script.js.xhtml"></script>
<img src="/contextname/javax.faces.resource/img/logo.png.xhtml" alt="" />

Avec le recul, cette dernière approche est également plus sensée que la première. Dans quelle mesure l' libraryattribut est-il alors utile?

BalusC
la source

Réponses:

256

En fait, tous ces exemples sur le Web dans lesquels le type de contenu / fichier commun comme "js", "css", "img", etc. est utilisé comme nom de bibliothèque sont trompeurs .

Exemples du monde réel

Pour commencer, regardons comment les implémentations JSF existantes comme Mojarra et MyFaces et les bibliothèques de composants JSF comme PrimeFaces et OmniFaces l' utilisent. Aucun d'entre eux n'utilise les bibliothèques de ressources de cette façon. Ils l'utilisent (sous les couvertures, par @ResourceDependencyou UIViewRoot#addComponentResource()) de la manière suivante:

<h:outputScript library="javax.faces" name="jsf.js" />
<h:outputScript library="primefaces" name="jquery/jquery.js" />
<h:outputScript library="omnifaces" name="omnifaces.js" />
<h:outputScript library="omnifaces" name="fixviewstate.js" />
<h:outputScript library="omnifaces.combined" name="[dynamicname].js" />
<h:outputStylesheet library="primefaces" name="primefaces.css" />
<h:outputStylesheet library="primefaces-aristo" name="theme.css" />
<h:outputStylesheet library="primefaces-vader" name="theme.css" />

Il devrait devenir clair qu'il représente essentiellement le nom de bibliothèque / module / thème commun auquel toutes ces ressources appartiennent généralement.

Identification plus facile

De cette façon, il est beaucoup plus facile de spécifier et de distinguer la provenance et / ou la provenance de ces ressources. Imaginez que vous ayez une primefaces.cssressource dans votre propre application Web dans laquelle vous remplacez / affinez certains CSS par défaut de PrimeFaces; si PrimeFaces n'utilisait pas de nom de bibliothèque pour lui-même primefaces.css, alors celui de PrimeFaces ne serait pas chargé, mais à la place celui fourni par l'application Web, ce qui romprait l'apparence.

De plus, lorsque vous utilisez une personnalisation ResourceHandler, vous pouvez également appliquer un contrôle plus fin sur les ressources provenant d'une bibliothèque spécifique lorsqu'elles librarysont utilisées correctement. Si toutes les bibliothèques de composants avaient utilisé "js" pour tous leurs fichiers JS, comment ResourceHandlerdistinguerait-il s'il provient d'une bibliothèque de composants spécifique? Les exemples sont OmniFaces CombinedResourceHandleret GraphicResourceHandler; vérifiez la createResource()méthode dans laquelle la bibliothèque est vérifiée avant de déléguer au gestionnaire de ressources suivant dans la chaîne. De cette façon, ils savent quand créer CombinedResourceou GraphicResourcedans quel but.

Il convient de noter que RichFaces a mal agi. Il n'en a pas utilisé librarydu tout et a créé une autre couche de gestion des ressources par-dessus et il est donc impossible d'identifier par programme les ressources RichFaces. C'est exactement la raison pour laquelle OmniFaces CombinedResourceHander a dû introduire un hack basé sur la réflexion afin de le faire fonctionner de toute façon avec les ressources RichFaces.

Votre propre webapp

Votre propre application Web n'a pas nécessairement besoin d'une bibliothèque de ressources. Vous feriez mieux de l'omettre.

<h:outputStylesheet name="css/style.css" />
<h:outputScript name="js/script.js" />
<h:graphicImage name="img/logo.png" />

Ou, si vous en avez vraiment besoin, vous pouvez simplement lui donner un nom commun plus sensé, comme "par défaut" ou un nom de société.

<h:outputStylesheet library="default" name="css/style.css" />
<h:outputScript library="default" name="js/script.js" />
<h:graphicImage library="default" name="img/logo.png" />

Ou, lorsque les ressources sont spécifiques à un modèle de Facelets maître, vous pouvez également lui donner le nom du modèle, afin qu'il soit plus facile de se relier. En d'autres termes, c'est plus à des fins d'auto-documentaire. Par exemple, dans un /WEB-INF/templates/layout.xhtmlfichier modèle:

<h:outputStylesheet library="layout" name="css/style.css" />
<h:outputScript library="layout" name="js/script.js" />

Et un /WEB-INF/templates/admin.xhtmlfichier modèle:

<h:outputStylesheet library="admin" name="css/style.css" />
<h:outputScript library="admin" name="js/script.js" />

Pour un exemple concret , consultez le code source de la vitrine OmniFaces .

Ou, lorsque vous souhaitez partager les mêmes ressources sur plusieurs webapps et avez créé un projet "commun" pour celui-ci basé sur le même exemple que dans cette réponse qui est à son tour incorporé en tant que JAR dans les webapps /WEB-INF/lib, puis référencez-le également en tant que bibliothèque (le nom est libre de votre choix; les bibliothèques de composants comme OmniFaces et PrimeFaces fonctionnent également de cette façon):

<h:outputStylesheet library="common" name="css/style.css" />
<h:outputScript library="common" name="js/script.js" />
<h:graphicImage library="common" name="img/logo.png" />

Versionnage de bibliothèque

Un autre avantage principal est que vous pouvez appliquer le bon contrôle de version de la bibliothèque de ressources sur les ressources fournies par votre propre application Web (cela ne fonctionne pas pour les ressources intégrées dans un JAR). Vous pouvez créer un sous-dossier enfant direct dans le dossier de la bibliothèque avec un nom dans le \d+(_\d+)*modèle pour indiquer la version de la bibliothèque de ressources.

WebContent
 |-- resources
 |    `-- default
 |         `-- 1_0
 |              |-- css
 |              |    `-- style.css
 |              |-- img
 |              |    `-- logo.png
 |              `-- js
 |                   `-- script.js
 :

Lorsque vous utilisez ce balisage:

<h:outputStylesheet library="default" name="css/style.css" />
<h:outputScript library="default" name="js/script.js" />
<h:graphicImage library="default" name="img/logo.png" />

Cela générera le code HTML suivant avec la version de la bibliothèque comme vparamètre:

<link rel="stylesheet" type="text/css" href="/contextname/javax.faces.resource/css/style.css.xhtml?ln=default&amp;v=1_0" />
<script type="text/javascript" src="/contextname/javax.faces.resource/js/script.js.xhtml?ln=default&amp;v=1_0"></script>
<img src="/contextname/javax.faces.resource/img/logo.png.xhtml?ln=default&amp;v=1_0" alt="" />

Donc, si vous avez édité / mis à jour une ressource, il vous suffit de copier ou renommer le dossier de version dans une nouvelle valeur. Si vous avez plusieurs dossiers de versions, le JSF ResourceHandlerservira automatiquement la ressource à partir du numéro de version le plus élevé, selon les règles de classement numérique.

Ainsi, lorsque vous copiez / renommez un resources/default/1_0/*dossier resources/default/1_1/*comme suit:

WebContent
 |-- resources
 |    `-- default
 |         |-- 1_0
 |         |    :
 |         |
 |         `-- 1_1
 |              |-- css
 |              |    `-- style.css
 |              |-- img
 |              |    `-- logo.png
 |              `-- js
 |                   `-- script.js
 :

Le dernier exemple de balisage générerait alors le code HTML suivant:

<link rel="stylesheet" type="text/css" href="/contextname/javax.faces.resource/css/style.css.xhtml?ln=default&amp;v=1_1" />
<script type="text/javascript" src="/contextname/javax.faces.resource/js/script.js.xhtml?ln=default&amp;v=1_1"></script>
<img src="/contextname/javax.faces.resource/img/logo.png.xhtml?ln=default&amp;v=1_1" alt="" />

Cela obligera le navigateur Web à demander la ressource directement au serveur au lieu d'afficher celle du même nom dans le cache, lorsque l'URL avec le paramètre modifié est demandée pour la première fois. De cette façon, les utilisateurs finaux ne sont pas tenus d'effectuer une actualisation matérielle (Ctrl + F5 et ainsi de suite) lorsqu'ils ont besoin de récupérer la ressource CSS / JS mise à jour.

Veuillez noter que le versionnage de la bibliothèque n'est pas possible pour les ressources contenues dans un fichier JAR. Vous auriez besoin d'une coutume ResourceHandler. Voir aussi Comment utiliser le versioning JSF pour les ressources en jar .

Voir également:

BalusC
la source
2
Est-il possible d'utiliser EL pour la bibliothèque? Donc, si je voulais avoir un resources / default et un resources / feelingFroggyToday, je pourrais faire quelque chose comme library = "# {someLibraryHere}" mapper someLibraryHere à ma bibliothèque choisie et ne pas avoir à compter à chaque fois en renommant le répertoire resources en une version supérieure. Je voulais les changer.
gebuh
Lorsque vous dites bibliothèque = admin ou libray = layout, ces dossiers (admin et layout) sont-ils dans le dossier des ressources?
Koray Tugay
Umm. Balus très intéressant. Je rencontre un problème dans une application Web où le fichier theme.css apparaît vide lors du chargement. Cela ne se produit qu'après plusieurs redéploiements (dans JBOSS EAP). L'URL css est comme ceci: /javax.faces.resource/css/theme.css.xhtml?ln=default&v=3_3_0_130416 et elle est déclarée de cette façon: <h: outputStylesheet library = "default" name = "css / theme. css "target =" head "/>. Peut-être que ce problème est lié à des problèmes de version?
Ricardo Vila
2
Les caractères autorisés pour la valeur de libraryou quelque chose qui y est lié ont-ils changé entre mojarra 2.2.5 (2.2.5-jbossorg-3, wildfly 8.0) et 2.2.11 (2.2.11-jbossorg-1)? Je n'arrive pas à trouver quoi que ce soit dans les notes de version. Voir stackoverflow.com/questions/35719808/…
Kukeltje
3
Merci @BalusC. Malheureusement, même le tutoriel Java EE 7 d'Oracle donne le mauvais exemple en utilisant un nom de bibliothèque cssdans le chapitre 8.6 Ressources Web et en le faisant mal avec css et les images dans l' exemple d'application guessnumber-jsf .
Jesper