¿Para qué sirve la biblioteca de recursos JSF y cómo debe usarse?

228

El JSF <h:outputStylesheet>, <h:outputScript>y <h:graphicImage>los componentes tienen un libraryatributo. ¿Qué es esto y cómo debe usarse? Hay muchos ejemplos en la web que lo usan de la siguiente manera con el tipo de contenido / archivo común css, jsy img(o image) como nombre de la biblioteca dependiendo de la etiqueta utilizada:

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

¿Cómo es útil? El libraryvalor en esos ejemplos parece estar simplemente repitiendo lo que ya ha sido representado por el nombre de la etiqueta. Para un <h:outputStylesheet>se basa en el nombre de la etiqueta ya obvio que representa una "biblioteca CSS". ¿Cuál es la diferencia con lo siguiente que también funciona de la misma manera?

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

Además, la salida HTML generada es un poco diferente. Dada una ruta de contexto /contextnamey una FacesServletasignación en un patrón de URL de *.xhtml, el primero genera el siguiente HTML con el nombre de la biblioteca como parámetro de solicitud:

<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="" />

Mientras que este último genera el siguiente HTML con el nombre de la biblioteca solo en la ruta del 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="" />

El último enfoque tiene, en retrospectiva, también más sentido que el enfoque anterior. ¿Cómo es exactamente el libraryatributo útil?

BalusC
fuente

Respuestas:

256

En realidad, todos esos ejemplos en la web en los que se usa el tipo de contenido / archivo común como "js", "css", "img", etc. como nombre de biblioteca son engañosos .

Ejemplos del mundo real

Para comenzar, veamos cómo las implementaciones JSF existentes como Mojarra y MyFaces y las bibliotecas de componentes JSF como PrimeFaces y OmniFaces lo usan. Nadie usa bibliotecas de recursos de esta manera. Lo usan (debajo de las cubiertas, por @ResourceDependencyo UIViewRoot#addComponentResource()) de la siguiente manera:

<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" />

Debe quedar claro que básicamente representa el nombre común de biblioteca / módulo / tema al que pertenecen comúnmente todos esos recursos.

Identificación más fácil

De esta manera es mucho más fácil especificar y distinguir de dónde provienen y / o de dónde provienen esos recursos. Imagine que tiene un primefaces.cssrecurso en su propia aplicación web en la que anula / ajusta algunos CSS predeterminados de PrimeFaces; si PrimeFaces no usara un nombre de biblioteca propio primefaces.css, entonces el propio PrimeFaces no se cargaría, sino el suministrado por la aplicación web, lo que rompería el look'n'feel.

Además, cuando usa una costumbre ResourceHandler, también puede aplicar un control más fino sobre los recursos que provienen de una biblioteca específica cuando libraryse usa de la manera correcta. Si todas las bibliotecas de componentes hubieran utilizado "js" para todos sus archivos JS, ¿cómo podría ResourceHandlerdistinguir si proviene de una biblioteca de componentes específica? Ejemplos son OmniFaces CombinedResourceHandlery GraphicResourceHandler; verifique el createResource()método en el que se verifica la biblioteca antes de delegar al siguiente manejador de recursos en cadena. De esta manera, saben cuándo crear CombinedResourceo GraphicResourcecon el propósito.

Cabe señalar que RichFaces lo hizo mal. No usó ninguno libraryy creó otra capa de manejo de recursos sobre él y, por lo tanto, es imposible identificar los recursos de RichFaces mediante programación. Esa es exactamente la razón por la cual OmniFaces CombinedResourceHander tuvo que introducir un truco basado en la reflexión para que funcione de todos modos con los recursos de RichFaces.

Tu propia aplicación web

Su propia aplicación web no necesita necesariamente una biblioteca de recursos. Será mejor que lo omitas.

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

O, si realmente necesita tener uno, simplemente puede darle un nombre común más sensible, como "predeterminado" o algún nombre de compañía.

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

O bien, cuando los recursos son específicos de alguna plantilla maestra de Facelets, también puede darle el nombre de la plantilla, para que sea más fácil relacionarse entre sí. En otras palabras, es más para fines de autodocumentación. Por ejemplo, en un /WEB-INF/templates/layout.xhtmlarchivo de plantilla:

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

Y un /WEB-INF/templates/admin.xhtmlarchivo de plantilla:

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

Para ver un ejemplo del mundo real, consulte el código fuente del escaparate de OmniFaces .

O bien, cuando desee compartir los mismos recursos en varias aplicaciones web y haya creado un proyecto "común" para eso basado en el mismo ejemplo que en esta respuesta, que a su vez está incrustado como JAR en las aplicaciones web /WEB-INF/lib, también haga referencia a él como biblioteca (el nombre es libre para su elección; las bibliotecas de componentes como OmniFaces y PrimeFaces también funcionan de esa manera):

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

Versiones de biblioteca

Otra ventaja principal es que puede aplicar versiones de biblioteca de recursos de la manera correcta en los recursos proporcionados por su propia aplicación web (esto no funciona para los recursos integrados en un JAR). Puede crear una subcarpeta secundaria directa en la carpeta de la biblioteca con un nombre en el \d+(_\d+)*patrón para indicar la versión de la biblioteca de recursos.

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

Al usar este marcado:

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

Esto generará el siguiente HTML con la versión de la biblioteca como vparámetro:

<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="" />

Entonces, si ha editado / actualizado algún recurso, todo lo que necesita hacer es copiar o cambiar el nombre de la carpeta de la versión a un nuevo valor. Si tiene varias carpetas de versión, el JSF ResourceHandlerservirá automáticamente el recurso desde el número de versión más alto, de acuerdo con las reglas de orden numérico.

Entonces, al copiar / cambiar el nombre de la resources/default/1_0/*carpeta en la resources/default/1_1/*siguiente forma:

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

Entonces, el último ejemplo de marcado generaría el siguiente HTML:

<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="" />

Esto obligará al navegador web a solicitar el recurso directamente desde el servidor en lugar de mostrar el que tiene el mismo nombre de la memoria caché, cuando se solicita por primera vez la URL con el parámetro modificado. De esta manera, no se requiere que los usuarios finales realicen una actualización completa (Ctrl + F5, etc.) cuando necesitan recuperar el recurso CSS / JS actualizado.

Tenga en cuenta que el control de versiones de la biblioteca no es posible para los recursos incluidos en un archivo JAR. Necesitarías una costumbre ResourceHandler. Consulte también Cómo usar el control de versiones JSF para recursos en jar .

Ver también:

BalusC
fuente
2
¿Es posible usar EL para la biblioteca? Entonces, si quisiera tener un recurso / predeterminado y un recurso / feelingFroggyToday, podría hacer algo como library = "# {someLibraryHere}" mapear someLibraryHere a mi biblioteca elegida y no tener que confiar en cambiar el nombre del directorio de recursos a una versión superior cada vez Quería cambiarlos.
Gebuh
Cuando dice library = admin o libray = layout, ¿están esas carpetas (admin y layout) en la carpeta de recursos?
Koray Tugay
Umm Muy interesante Balus. Estoy enfrentando un problema en una aplicación web donde el archivo theme.css aparece vacío al cargar. Esto solo ocurre después de varias redespliegues (en JBOSS EAP). La url css es así: /javax.faces.resource/css/theme.css.xhtml?ln=default&v=3_3_0_130416 y se declara de esta manera: <h: outputStylesheet library = "default" name = "css / theme. css "target =" head "/>. ¿Quizás este problema está relacionado con problemas de versiones?
Ricardo Vila
2
¿ libraryCambiaron los caracteres permitidos para el valor de algo relacionado con él entre mojarra 2.2.5 (2.2.5-jbossorg-3, wildfly 8.0) y 2.2.11 (2.2.11-jbossorg-1)? Parece que no puedo encontrar nada en las notas de liberación. Ver stackoverflow.com/questions/35719808/…
Kukeltje
3
Gracias @ BalusC. Desafortunadamente, incluso el Tutorial Java EE 7 de Oracle da un ejemplo incorrecto al usar un nombre de biblioteca cssen el capítulo 8.6 Recursos web y hacerlo mal con css e imágenes en la aplicación de ejemplo guessnumber-jsf .
Jesper