Quando usar <ui: include>, arquivos de tag, componentes compostos e / ou componentes personalizados?

102

Comecei a usar JSF 2.0 com Facelets recentemente e fiquei intrigado com os novos componentes compostos, sabendo das <ui:include>técnicas existentes e de outras técnicas de modelagem oferecidas pelo Facelets 1.x.

Qual é a diferença entre essas abordagens? Funcionalmente, eles parecem oferecer quase o mesmo: arquivos de tag <ui:param>vs <cc:attribute>, <ui:insert>+ <ui:define>vs, reutilização dos modelos existentes. Existe algo além de sintaxe e especificação de interface clara no caso de componentes compostos? O desempenho pode ser diferente?

Mrembisz
fonte

Respostas:

176

Qual é a diferença entre essas abordagens?

Modelos de facelet

Use Facelet templates (como em <ui:composition>, <ui:include>e <ui:decorate>) se você quer dividir principais fragmentos de layout de página em modelos reutilizáveis. Por exemplo, cabeçalho, menu, conteúdo, rodapé, etc.

Exemplos:

Arquivos de tag Facelet

Use os arquivos de tag do Facelet se desejar ter um grupo reutilizável de componentes para prevenir / minimizar a duplicação de código. Por exemplo, um grupo de componentes de etiqueta + entrada + mensagem. A principal diferença com os componentes compostos é que a saída de um arquivo de tag Facelet não representa um único UIComponente pode, em algumas circunstâncias, ser a única solução quando um componente composto não é suficiente. Geralmente, ter um <ui:include>com um ou mais <ui:param>que passa uma propriedade de bean gerenciado (e, portanto, não um valor codificado permanentemente) é um sinal de que o arquivo de inclusão pode ser melhor um arquivo de tag.

Exemplos:

Componentes compostos

Use componentes compostos se desejar criar um personalizado único e reutilizável UIComponentcom uma única responsabilidade usando XML puro. Esse componente composto geralmente consiste em um monte de componentes existentes e / ou HTML e é renderizado fisicamente como um único componente e deve ser vinculado a uma única propriedade de bean. Por exemplo, um componente que representa uma única java.util.Datepropriedade por 3 <h:selectOneMenu>componentes dependentes , ou um componente que combina <p:fileUpload>e <p:imageCropper>em um único <my:uploadAndCropImage>referindo uma única com.example.Imageentidade personalizada como propriedade.

Exemplos:

Componentes personalizados

Use um componente personalizado sempre que a funcionalidade não puder ser alcançada com arquivos de tag do Facelet ou componentes compostos, devido à falta de suporte no conjunto de componentes padrão / disponível. Os exemplos podem ser encontrados em todos os lugares no código-fonte de bibliotecas de componentes de software livre , como PrimeFaces e OmniFaces .

Manipuladores de tags

Quando você deseja controlar a construção da árvore de componentes JSF em vez de renderizar a saída HTML, deve usar um manipulador de tags em vez de um componente.

Exemplos:

Projetos de exemplo

Aqui estão alguns exemplos de projetos que utilizam todas as técnicas mencionadas acima.


O desempenho pode ser diferente?

Tecnicamente, a preocupação com o desempenho é insignificante. A escolha deve ser feita com base nos requisitos funcionais concretos e no grau final de abstração, reutilização e manutenção da implementação. Cada abordagem tem seu próprio propósito e limitações bem definidas.

Os componentes compostos, entretanto, têm uma sobrecarga significativa durante a construção / restauração da vista (especificamente: durante o salvamento / restauração do estado da vista). E, nas versões mais antigas do Mojarra, os componentes compostos tinham problemas de desempenho com a atribuição de valores padrão, isso já foi corrigido desde 2.1.13. Além disso, Mojarra teve um vazamento de memória quando um <cc:attribute method-signature>é usado para expressões de método, basicamente toda a árvore de componentes é referenciada novamente na sessão HTTP, isso foi corrigido desde 2.1.29 / 2.2.8. O vazamento de memória pode ser contornado em versões 2.1 mais antigas, conforme abaixo:

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

Ou em versões 2.2 mais antigas, conforme abaixo:

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

Ainda assim, quando você tem relativamente "muitos" componentes compostos e os javax.faces.STATE_SAVING_METHODdefiniu client, o desempenho será péssimo. Não abuse dos componentes compostos se desejar apenas a funcionalidade básica que já é possível com um arquivo de inclusão simples ou arquivo de marca. Não use a facilidade de configuração (leia: nenhum *.taglib.xmlarquivo necessário) como uma desculpa para preferir componentes compostos a arquivos de tag.

Ao usar o Mojarra 2.2.10 ou mais antigo, não se esqueça de desativar o período de atualização do Facelets relativamente curto para o modo de produção:

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

Não use esta configuração para desenvolvimento, caso contrário, você terá que reiniciar todo o servidor para que as alterações nos arquivos Facelets sejam refletidas! Mojarra 2.2.11 e mais recente, e MyFaces já assume o padrão -1quando javax.faces.PROJECT_STAGEnão está definido como Development.

BalusC
fonte
por que você quer renderizar 1 componente (componente composto) em vez de, digamos, 3 (arquivo de tag facelet)? Bem, em um dia ensolarado você pode se sentir como 1 em vez de 3 ... mas acho que há algo mais por trás disso. Em seu exemplo, você está estendendo UINamingContainer ... poderia ser esse um dos motivos para ir para um cc (para poder sobrescrever algumas funções específicas de implementação jsf)?
Toskan
2
Um arquivo de tag deve ser visto como uma espécie de inclusão. Um componente composto deve ser visto como um componente real. Um componente composto precisa ser implementado NamingContainer, caso contrário, você acabará com problemas de ID duplicado quando o mesmo componente for reutilizado várias vezes.
BalusC de
@BalusC Digamos que eu tenha um monte de HTML e JSF que criam um 'bloco' que me permite adicionar ou remover Endereços (e todos os seus atributos: rua, número, cidade, etc). Preciso usar esse mesmo bloco em 2 ou 3 páginas. Isso se encaixa na sua descrição de um componente composto?
RinaldoPJr
1
@Rinaldo: Acho que usaria um arquivo de tag para isso com IDs de componentes populados dinamicamente, como demonstrado em stackoverflow.com/questions/5713718/… . IMO, se isso pode ser feito com um arquivo de tag, use-o. Se não puder ser feito com um arquivo de tag, use um composto. Se você precisar de vários componentes para manipular uma única propriedade (não o endereço, mas, por exemplo, streetname + housenumber que deve estar em uma única propriedade), então um componente composto seria a única solução.
BalusC de
2
@Tarik: os compostos têm uma grande sobrecarga em comparação com os tagfiles. Em outras palavras: desempenho ruim. Use-o apenas se precisar criar um único componente de UI customizado com base em um conjunto de componentes existentes intimamente relacionados. Isso não pode ser feito com um tagfile. ZEEF.com, por exemplo, tem apenas um composto: o upload / download / recortar imagem tudo-em-um que é usado em uma imagem de página, imagem de perfil, cabeçalho de bloco de link, blocos de imagem, etc. Está vinculado a apenas uma Imagepropriedade no feijão.
BalusC