¿Cuándo usar <ui: include>, archivos de etiquetas, componentes compuestos y / o componentes personalizados?

102

Comencé a usar JSF 2.0 con Facelets recientemente y me desconcertaron los nuevos componentes compuestos al conocer las <ui:include>técnicas de plantillas existentes y otras que ofrece Facelets 1.x.

¿Cuál es la diferencia entre esos enfoques? Funcionalmente, parecen ofrecer casi lo mismo: <ui:param>vs <cc:attribute>, <ui:insert>+ <ui:define>vs archivos de etiquetas, reutilización de las plantillas existentes. ¿Hay algo además de la sintaxis y la especificación clara de la interfaz en el caso de componentes compuestos? ¿Podría diferir el rendimiento?

mrembisz
fuente

Respuestas:

176

¿Cuál es la diferencia entre esos enfoques?

Plantillas de facelet

Utilice las plantillas de Facelet (como en <ui:composition>, <ui:include>y <ui:decorate>) si desea dividir los fragmentos de diseño de la página principal en plantillas reutilizables. Por ejemplo, encabezado, menú, contenido, pie de página, etc.

Ejemplos:

Archivos de etiquetas de facelet

Utilice los archivos de etiquetas Facelet si desea tener un grupo de componentes reutilizables para evitar / minimizar la duplicación de códigos. Por ejemplo, un grupo de componentes etiqueta + entrada + mensaje. La principal diferencia con los componentes compuestos es que la salida de un archivo de etiqueta Facelet no representa uno solo UIComponenty, en algunas circunstancias, puede ser la única solución cuando un componente compuesto no es suficiente. Generalmente, tener un <ui:include>con uno o más <ui:param>que pase una propiedad de bean administrado (y por lo tanto no un valor codificado) es una señal de que el archivo de inclusión puede ser mejor un archivo de etiqueta.

Ejemplos:

Componentes compuestos

Utilice componentes compuestos si desea crear una personalizada única y reutilizable UIComponentcon una sola responsabilidad utilizando XML puro. Dicho componente compuesto generalmente consta de un grupo de componentes existentes y / o HTML y se representa físicamente como un solo componente y se supone que está vinculado a una sola propiedad de bean. Por ejemplo, un componente que representa una java.util.Datepropiedad única por 3 <h:selectOneMenu>componentes dependientes , o un componente que se combina <p:fileUpload>y <p:imageCropper>en una única <my:uploadAndCropImage>referencia a una única com.example.Imageentidad personalizada como propiedad.

Ejemplos:

Componentes personalizados

Utilice un componente personalizado siempre que la funcionalidad no se pueda lograr con archivos de etiquetas Facelet o componentes compuestos, debido a la falta de compatibilidad en el conjunto de componentes estándar / disponible. Se pueden encontrar ejemplos en todo lugar en el código fuente de bibliotecas de componentes de código abierto como PrimeFaces y OmniFaces .

Controladores de etiquetas

Cuando desee controlar la construcción del árbol de componentes JSF en lugar de la representación de la salida HTML, debe usar un controlador de etiquetas en lugar de un componente.

Ejemplos:

Proyectos de ejemplo

Aquí hay algunos proyectos de ejemplo que utilizan todas las técnicas mencionadas anteriormente.


¿Podría diferir el rendimiento?

Técnicamente, la preocupación por el rendimiento es insignificante. La elección debe basarse en los requisitos funcionales concretos y el grado final de abstracción, reutilización y mantenibilidad de la implementación. Cada enfoque tiene sus propios objetivos y limitaciones bien definidos.

Sin embargo, los componentes compuestos tienen una sobrecarga significativa durante la construcción / restauración de la vista (específicamente: al guardar / restaurar el estado de la vista). Y, en versiones anteriores de Mojarra, los componentes compuestos tenían problemas de rendimiento con la asignación de valores predeterminados, esto ya está arreglado desde 2.1.13. Además, Mojarra tuvo una pérdida de memoria cuando <cc:attribute method-signature>se usa a para expresiones de método, básicamente se vuelve a hacer referencia a todo el árbol de componentes en la sesión HTTP, esto se corrigió desde 2.1.29 / 2.2.8. La pérdida de memoria se puede omitir en versiones anteriores 2.1 como se muestra a continuación:

<context-param>
    <param-name>com.sun.faces.serializeServerState</param-name>
    <param-value>true</param-value>
</context-param>

O en versiones 2.2 anteriores como se muestra a continuación:

<context-param>
    <param-name>javax.faces.SERIALIZE_SERVER_STATE</param-name>
    <param-value>true</param-value>
</context-param>

Aún así, cuando tiene relativamente "muchos" componentes compuestos, y lo ha javax.faces.STATE_SAVING_METHODconfigurado client, entonces el rendimiento será un fastidio. No abuse de los componentes compuestos si simplemente desea la funcionalidad básica que ya es posible con un simple archivo de inclusión o etiqueta. No use la facilidad de configuración (léase: no se *.taglib.xmlnecesita archivo) como excusa para preferir componentes compuestos a archivos de etiquetas.

Cuando utilice Mojarra 2.2.10 o una versión anterior, no olvide deshabilitar el período de actualización de Facelets relativamente corto para el modo de producción:

<context-param>
    <param-name>javax.faces.FACELETS_REFRESH_PERIOD</param-name>
    <param-value>-1</param-value>
</context-param>

No use esta configuración para el desarrollo, de lo contrario, debe reiniciar todo el servidor para que los cambios en los archivos Facelets se reflejen. Mojarra 2.2.11 y versiones posteriores, y MyFaces ya tiene el valor predeterminado -1cuando javax.faces.PROJECT_STAGEno está configurado en Development.

BalusC
fuente
¿Por qué querría renderizar 1 componente (componente compuesto) en lugar de, digamos, 3 (archivo de etiqueta facelet)? Quiero decir, bueno, en un día soleado tal vez te sientas como 1 en lugar de 3 ... pero supongo que hay algo más detrás. En su ejemplo, está extendiendo UINamingContainer ... ¿podría ser esa una de las razones para optar por un cc (para poder sobrescribir algunas funciones específicas de implementación de jsf)?
Toskan
2
Un archivo de etiqueta debe verse como una especie de inclusión. Un componente compuesto debe verse como un componente real. Es necesario implementar un componente compuesto NamingContainer; de lo contrario, terminará con problemas de identificación duplicada cuando el mismo componente se reutilice varias veces.
BalusC
@BalusC Digamos que tengo un montón de HTML y JSF que crean un 'bloque' que me permite agregar o eliminar Direcciones (y todos sus atributos: calle, número, ciudad, etc.). Necesito usar ese mismo bloque en 2 o 3 páginas. ¿Se incluye eso en su descripción de un componente compuesto?
RinaldoPJr
1
@Rinaldo: Creo que usaría un archivo de etiqueta para eso con ID de componentes llenados dinámicamente como se muestra en stackoverflow.com/questions/5713718/… . En mi opinión, si se puede hacer con un archivo de etiqueta, úselo. Si no se puede hacer con un archivo de etiqueta, utilice un compuesto. Si necesita varios componentes para manipular una sola propiedad (no la dirección, pero p. Ej. Streetname + housenumber que debería ir en una sola propiedad), entonces un componente compuesto sería la única solución.
BalusC
2
@Tarik: los compuestos tienen mucha sobrecarga en comparación con los archivos de etiquetas. En otras palabras: bajo rendimiento. Úselo solo si necesita crear un único componente de IU personalizado basado en un conjunto de componentes existentes estrechamente relacionados. Esto no se puede hacer con un archivo de etiquetas. ZEEF.com, por ejemplo, tiene solo un compuesto: la imagen de carga / descarga / recorte todo en uno que se usa en una imagen de página, imagen de perfil, encabezado de bloque de enlace, bloques de imagen, etc. Está vinculado solo a una Imagepropiedad en frijol.
BalusC