O que é a biblioteca de recursos JSF e como deve ser usada?

228

O JSF <h:outputStylesheet>, <h:outputScript>e <h:graphicImage>componentes têm um libraryatributo. O que é isso e como isso deve ser usado? Há uma série de exemplos na web que o utilizam como segue com o tipo de conteúdo comum / arquivo css, jse img(ou image) como nome da biblioteca, dependendo da tag usada:

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

Como isso é útil? O libraryvalor nesses exemplos parece estar apenas repetindo o que já foi representado pelo nome da tag. Para <h:outputStylesheet>isso, é baseado no nome da tag já óbvio que representa uma "biblioteca CSS". Qual é a diferença com o seguinte, que também funciona da mesma maneira?

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

Além disso, a saída HTML gerada é um pouco diferente. Dado um caminho de contexto /contextnamee o FacesServletmapeamento em um padrão de URL *.xhtml, o primeiro gera o seguinte HTML com o nome da biblioteca como parâmetro de solicitação:

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

Enquanto o último gera o seguinte HTML com o nome da biblioteca apenas no caminho do 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="" />

A última abordagem faz, em retrospectiva, também mais sentido do que a anterior. Como exatamente o libraryatributo é útil?

BalusC
fonte

Respostas:

256

Na verdade, todos esses exemplos na Web em que o conteúdo / tipo de arquivo comum, como "js", "css", "img" etc., são usados, são enganosos .

Exemplos do mundo real

Para começar, vamos ver como as implementações JSF existentes, como Mojarra e MyFaces e as bibliotecas de componentes JSF, como PrimeFaces e OmniFaces, a utilizam. Ninguém deles usa bibliotecas de recursos dessa maneira. Eles o usam (sob as cobertas, por @ResourceDependencyou UIViewRoot#addComponentResource()) da seguinte maneira:

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

Deve ficar claro que basicamente representa o nome comum da biblioteca / módulo / tema ao qual todos esses recursos geralmente pertencem.

Identificação mais fácil

Dessa forma, é muito mais fácil especificar e distinguir de onde esses recursos pertencem e / ou são provenientes. Imagine que você possui um primefaces.cssrecurso em seu próprio aplicativo da web no qual está substituindo / ajustando algum CSS padrão do PrimeFaces; se o PrimeFaces não usasse o nome de uma biblioteca primefaces.css, o próprio PrimeFaces não seria carregado, mas o fornecido pelo aplicativo da Web, que quebraria a aparência.

Além disso, ao usar um costume ResourceHandler, você também pode aplicar um controle mais refinado sobre os recursos provenientes de uma biblioteca específica quando libraryusado da maneira correta. Se todas as bibliotecas de componentes usassem "js" para todos os seus arquivos JS, como ResourceHandlerdistinguiriam se vier de uma biblioteca de componentes específica? Exemplos são OmniFaces CombinedResourceHandlere GraphicResourceHandler; verifique o createResource()método em que a biblioteca é verificada antes de delegar para o próximo manipulador de recursos na cadeia. Dessa forma, eles sabem quando criar CombinedResourceou GraphicResourcepara o objetivo.

Deve-se notar que o RichFaces fez errado. Ele não usou nenhum librarye montou outra camada de manipulação de recursos em homebrew e, portanto, é impossível identificar programaticamente os recursos do RichFaces. Essa é exatamente a razão pela qual o OmniFaces CombinedResourceHander teve que introduzir um hack baseado em reflexão para fazê-lo funcionar de qualquer maneira com os recursos RichFaces.

Seu próprio webapp

Seu próprio aplicativo da web não precisa necessariamente de uma biblioteca de recursos. É melhor você simplesmente omiti-lo.

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

Ou, se você realmente precisar de um, basta atribuir um nome comum mais sensato, como "padrão" ou algum nome de empresa.

<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, quando os recursos são específicos para algum modelo mestre do Facelets, você também pode fornecer o nome do modelo, para que seja mais fácil se relacionar. Em outras palavras, é mais para fins de auto-documentação. Por exemplo, em um /WEB-INF/templates/layout.xhtmlarquivo de modelo:

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

E um /WEB-INF/templates/admin.xhtmlarquivo de modelo:

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

Para um exemplo do mundo real, verifique o código-fonte da exibição do OmniFaces .

Ou, quando você quiser compartilhar os mesmos recursos em vários aplicativos da web e criar um projeto "comum" para o mesmo, com base no mesmo exemplo da resposta, que por sua vez é incorporado como JAR nos aplicativos da web /WEB-INF/lib, faça referência a ele como biblioteca (o nome é livre para sua escolha; as bibliotecas de componentes como OmniFaces e PrimeFaces também funcionam dessa maneira):

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

Controle de versão da biblioteca

Outra vantagem principal é que você pode aplicar o controle de versão da biblioteca de recursos da maneira correta nos recursos fornecidos por seu próprio aplicativo da web (isso não funciona para recursos incorporados em um JAR). Você pode criar uma subpasta filha direta na pasta da biblioteca com um nome no \d+(_\d+)*padrão para indicar a versão da biblioteca de recursos.

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

Ao usar esta marcação:

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

Isso irá gerar o seguinte HTML com a versão da 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="" />

Portanto, se você editou / atualizou algum recurso, tudo o que você precisa fazer é copiar ou renomear a pasta da versão para um novo valor. Se você tiver várias pastas de versão, o JSF ResourceHandlerservirá automaticamente o recurso a partir do número de versão mais alto, de acordo com as regras de pedido numérico.

Portanto, ao copiar / renomear a resources/default/1_0/*pasta para o resources/default/1_1/*seguinte:

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

Em seguida, o último exemplo de marcação geraria o seguinte 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="" />

Isso forçará o navegador da web a solicitar o recurso diretamente do servidor, em vez de mostrar aquele com o mesmo nome do cache, quando a URL com o parâmetro alterado for solicitada pela primeira vez. Dessa forma, os usuários finais não precisam fazer uma atualização definitiva (Ctrl + F5 e assim por diante) quando precisam recuperar o recurso CSS / JS atualizado.

Observe que o controle de versão da biblioteca não é possível para recursos incluídos em um arquivo JAR. Você precisaria de um costume ResourceHandler. Consulte também Como usar a versão JSF para recursos no jar .

Veja também:

BalusC
fonte
2
É possível usar o EL para a biblioteca? Portanto, se eu quisesse ter um resources / default e um resources / feelingFroggyToday, eu poderia fazer algo como library = "# {someLibraryHere}" mapear someLibraryHere à minha biblioteca escolhida e não precisar renomear o diretório de recursos para uma versão superior sempre Eu queria mudá-los.
gebuh
Quando você diz library = admin ou libray = layout, essas pastas (admin e layout) estão na pasta de recursos?
Koray Tugay
Umm. Balus muito interessante. Estou enfrentando um problema em um aplicativo Web em que o arquivo theme.css aparece vazio ao carregar. Isso acontece apenas após várias reimplantações (no JBOSS EAP). A URL do CSS é assim: /javax.faces.resource/css/theme.css.xhtml?ln=default&v=3_3_0_130416 e é declarada desta maneira: <h: outputStylesheet library = "default" name = "css / theme. css "target =" head "/>. Talvez esse problema esteja relacionado a problemas de versão?
Ricardo Vila
2
Os caracteres permitidos para o valor libraryou algo relacionado a ele mudaram entre mojarra 2.2.5 (2.2.5-jbossorg-3, wildfly 8.0) e 2.2.11 (2.2.11-jbossorg-1)? Parece que não consigo encontrar nada nas notas liberadas. Veja stackoverflow.com/questions/35719808/…
Kukeltje
3
Obrigado @BalusC. Infelizmente, mesmo o próprio Java EE 7 Tutorial da Oracle fornece o exemplo errado, usando um nome de biblioteca cssno capítulo 8.6 Recursos da Web e fazendo errado com css e imagens no aplicativo de exemplo guessnumber-jsf .
Jesper