Что такое библиотека ресурсов JSF и как ее использовать?

JSF <h:outputStylesheet>, <h:outputScript> и <h:graphicImage> имеют атрибут library. Что это и как это следует использовать? В Интернете есть много примеров, которые используют его как общий тип содержимого/файла css, js и img (или image) в качестве имени библиотеки в зависимости от используемого тега:

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

Как это полезно? Значение library в этих примерах, похоже, просто повторяет то, что уже было представлено именем тега. Для <h:outputStylesheet> он основан на имени тега, уже очевидном, что он представляет собой "библиотеку CSS". Какая разница со следующим, который также работает так же?

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

Кроме того, сгенерированный вывод HTML немного отличается. Учитывая путь контекста отображения /contextname и FacesServlet в шаблоне URL-адреса *.xhtml, первый генерирует следующий HTML-код с именем библиотеки в качестве параметра запроса:

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

Пока последний генерирует следующий HTML-код с именем библиотеки только по пути 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="" />

Последний подход делает задним числом также более ощутимым, чем прежний подход. Как же полезен атрибут library?

Ответ 1

Фактически, все эти примеры в Интернете, где общий тип содержимого/файла типа "js", "css", "img" и т.д. используется как имя библиотеки вводящий в заблуждение.

Примеры реального мира

Для начала рассмотрим, как существующие реализации JSF, такие как Mojarra и MyFaces и библиотеки компонентов JSF, такие как PrimeFaces и OmniFaces использовать его. Ни один из них не использует библиотеки ресурсов таким образом. Они используют его (под обложками @ResourceDependency или UIViewRoot#addComponentResource()) следующим образом:

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

Понятно, что в основном это имя общей библиотеки/модуля/темы, где все эти ресурсы обычно принадлежат.

Легче идентифицировать

Таким образом, гораздо проще указывать и различать, где эти ресурсы принадлежат и/или происходят. Представьте, что у вас есть ресурс primefaces.css в вашем собственном webapp, в котором вы переопределяете/завершаете некоторые CSS CSS по умолчанию; если PrimeFaces не использует имя библиотеки для своего собственного primefaces.css, тогда собственный PrimeFaces не будет загружен, а вместо него будет поставляться с помощью webapp, что сломает look'n'feel.

Кроме того, когда вы используете пользовательский ResourceHandler, вы также можете применять более мелкозернистый контроль над ресурсами, поступающими из определенной библиотеки когда library используется правильно. Если бы все библиотеки компонентов использовали "js" для всех своих JS файлов, как бы ResourceHandler когда-либо отличалось, если бы оно исходило из конкретной библиотеки компонентов? Примерами являются OmniFaces CombinedResourceHandler и GraphicResourceHandler; проверьте метод createResource(), в котором библиотека проверена перед передачей следующему обработчику ресурсов в цепочке. Таким образом, они знают, когда создавать CombinedResource или GraphicResource для этой цели.

Отмечено, что RichFaces сделал это неправильно. Он вообще не использовал никаких library и запустил другой слой обработки ресурсов поверх него, и поэтому невозможно программно идентифицировать ресурсы RichFaces. Именно по этой причине OmniFaces CombinedResourceHander имел ввести хакерство на основе отражения, чтобы заставить его работать в любом случае с ресурсами RichFaces.

Ваш собственный webapp

Ваш собственный webapp не обязательно нуждается в библиотеке ресурсов. Лучше всего просто опустить это.

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

Или, если вам действительно нужно иметь его, вы можете просто дать ему более разумное общее имя, например "default" или какое-то название компании.

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

Или, когда ресурсы специфичны для какого-либо шаблона Masterlets, вы также можете указать ему имя шаблона, чтобы было легче связать друг друга. Другими словами, это больше для самодокументированных целей. Например. в файле шаблона /WEB-INF/templates/layout.xhtml:

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

И файл шаблона /WEB-INF/templates/admin.xhtml:

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

Для примера в реальном мире проверьте исходный код витрины OmniFaces.

Или, если вы хотите разделить одни и те же ресурсы по нескольким веб-папкам и создали для них общий проект, основанный на том же примере, что и в этом ответе, который, в свою очередь, встроен в JAR в webapp /WEB-INF/lib, а затем ссылается на него как на библиотеку (имя по своему выбору, так что такие библиотеки компонентов, как OmniFaces и PrimeFaces):

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

Управление версиями библиотеки

Другим основным преимуществом является то, что вы можете правильно использовать правильную версию библиотеки ресурсов на ресурсах, предоставляемых вашим собственным webapp (это не работает для ресурсов, встроенных в JAR). Вы можете создать прямую дочернюю подпапку в папке библиотеки с именем в шаблоне \d+(_\d+)*, чтобы обозначить версию библиотеки ресурсов.

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

При использовании этой разметки:

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

Это приведет к созданию следующего HTML с версией библиотеки как v:

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

Итак, если вы отредактировали/обновили какой-то ресурс, все, что вам нужно сделать, это скопировать или переименовать папку версии в новое значение. Если у вас несколько папок с версиями, то JSF ResourceHandler будет автоматически обслуживать ресурс с наивысшего номера версии в соответствии с правилами численного заказа.

Итак, при копировании/переименовании resources/default/1_0/* в папку resources/default/1_1/*, как показано ниже:

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

Затем в последнем примере разметки будет создан следующий 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="" />

Это заставит веб-браузер запрашивать ресурс прямо с сервера вместо того, чтобы показывать тот же имя из кеша, когда URL-адрес с измененным параметром был запрошен в первый раз. Таким образом, конечным пользователям не требуется выполнять жесткое обновление (Ctrl + F5 и т.д.), Когда им нужно получить обновленный ресурс CSS/JS.

Обратите внимание, что управление версиями библиотеки невозможно для ресурсов, заключенных в JAR файл. Вам понадобится пользовательский ResourceHandler. См. Также Как использовать управление версиями JSF для ресурсов в банке.

См. также: