null

Переиспользуемые компоненты в JSF

В ходе разработки JSF приложений зачастую возникают участки xhtml-разметки, используемые в нескольких местах. Нет необходимости объяснять, какие неудобства при модификации это вызывает. Потому у любого разрабочика возникает естественное желание выделить такие участки в какой-то отдельный компонент, и далее использовать его. Но при этом написание полноценного JSF-компонента является трудоемкой задачей. Хорошо, что есть стандартные (и куда более простые) способы решения этой задачи.

ui:include

Первый способ - вынести часть разметки в отдельный файл, и затем воспользоваться Facelsts тегом ui:include. У данного тега есть единственный атрибут src, значением которого будет путь к странице.

about.xhtml

<html class="promo-bg">
    <f:view xmlns="http://www.w3c.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core"
            xmlns:h="http://java.sun.com/jsf/html" xmlns:p="http://primefaces.org/ui"
            xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
        <h:head>
            <title>Title here</title>
        </h:head>

        <style>
            ...
        </style>

        <h:body style="height: 100vh">
            <h:outputText value="Before include" styleClass="text-block first"/>
            <br/>
            <ui:include src="/include.xhtml"/>
            <br/>
            <h:outputText value="After include" styleClass="text-block second"/>
        </h:body>
    </f:view>
</html>

include.xhtml

<f:view xmlns="http://www.w3c.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core"
        xmlns:h="http://java.sun.com/jsf/html" xmlns:p="http://primefaces.org/ui"
        xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
    <h:outputText value="Include body" styleClass="text-block include"/>
</f:view>
Результат (about.xhtml)
Это уже обеспечит некоторую степень переиспользования кода, но разметка будет статичной. Для параметризации можно использовать тег ui:param - у него есть атрибуты name (имя параметра) и value (его значение). Тогда во включаемой странице в EL-контексте будет доступна переменная с данным именем, и ее можно будет использовать в EL-выражениях.
 
about.xhtml
<html class="promo-bg">
    <f:view xmlns="http://www.w3c.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core"
            xmlns:h="http://java.sun.com/jsf/html" xmlns:p="http://primefaces.org/ui"
            xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
        <h:head>
            <title>Title here</title>
        </h:head>

        <style>
            ...
        </style>

        <h:body style="height: 100vh">
            <h:outputText value="Before include" styleClass="text-block first"/>
            <br/>
            <ui:include src="/include.xhtml">
                <ui:param name="text" value="Lorem ipsum dolor sit amet, consectetur adipiscing elit. In at elit vel nulla maximus vestibulum. Suspendisse sit amet libero metus. Curabitur congue risus at libero sodales, id tempus eros tempus."/>
            </ui:include>
            <br/>
            <h:outputText value="After include" styleClass="text-block second"/>
        </h:body>
    </f:view>
</html>

include.xhtml

<f:view xmlns="http://www.w3c.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core"
        xmlns:h="http://java.sun.com/jsf/html" xmlns:p="http://primefaces.org/ui"
        xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
    <h:outputText value="${text}" styleClass="text-block include"/>
</f:view>

composite

Другой способ заключается в создании сущностей, интерфейс использования которых будет очень похож на обычные компоненты JSF, но при этом для их создание не требуется написание Java-кода — только XHTML-разметка. Это так называемые композитные компоненты.

Для их создания необходимо:

  1. Создать каталог resources в каталоге webapp вашего проекта.
  2. В нем создать каталог для файлов композитных компонентов. Имя каталога важно — в дальнейшем оно будет необходимо импорта xmlns с вашими компонентами.

В этом каталоге уже можно создавать файлы с XHTML разметкой. Имя файла будет соответствовать имени компонента. Библиотека тегов, необходимая для создания композитных элементов, определяется по URI http://java.sun.com/jsf/composite; как правило, для нее используют префикс composite.

xmlns:composite="http://java.sun.com/jsf/composite"

Создание компонента разделяется на определение интерфейса и реализации. Для этого используются теги composite:interface и composite:implementation соответственно. В первом определяются, например, атрибуты компонента, во втором — его разметка.

Рассмотрим на примере.

Создадим каталог resources/custom в каталоге webapp, в нем создадим файл orderedList.xhtml со следующим содержимым:

<f:view xmlns="http://www.w3c.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core"
        xmlns:h="http://java.sun.com/jsf/html"
        xmlns:ui="http://xmlns.jcp.org/jsf/facelets" xmlns:composite="http://java.sun.com/jsf/composite"
>
    <composite:interface>
        <composite:attribute name="items" required="true" type="java.util.Collection"/>
        <composite:attribute name="emptyMessage" type="java.lang.String" default="List is empty"/>
    </composite:interface>
    <composite:implementation>
        <div>
            <h:panelGroup rendered="#{not empty cc.attrs.items}">
                <ol>
                    <ui:repeat value="#{cc.attrs.items}" var="item">
                        <li>#{item}</li>
                    </ui:repeat>
                </ol>
            </h:panelGroup>
            <h:outputText value="#{cc.attrs.emptyMessage}" rendered="#{empty cc.attrs.items}"/>
        </div>
    </composite:implementation>
</f:view>

В блоке composite:interface с помощью тегов composite:attribute обозначены атрибуты, которые можно будет использовать у этого компонента. В примере обозначены основные возможности тега composite:attribute: возможность указания имени, типа, значения по умолчанию и указать обязательность использования атрибута.

В блоке composite:implementation содержится реализация компонента, доступ к атрибутам из интерфейса происходит через EL-выражения (#{cc.attrs.ИМЯ_АТРИБУТА}).

Для использования созданного компонента необходимо подключить простанство имен xmlns:custom="http://java.sun.com/jsf/composite/ИМЯ_ПРОСТРАНСТВА_ИМЕН", где имя пространства имен совпадает с каталогом, в котором был создан компонент (в рассмотренном примере custom); имена компонентов будут совпадать с именами файлов.

Ниже приведен пример использования созданного компонента.

<html>
    <f:view xmlns="http://www.w3c.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core"
            xmlns:h="http://java.sun.com/jsf/html" xmlns:p="http://primefaces.org/ui"
            xmlns:ui="http://xmlns.jcp.org/jsf/facelets" xmlns:custom="http://java.sun.com/jsf/composite/custom">
        <h:head>
            <title>Title here</title>
        </h:head>

        <style>...
        </style>

        <h:body style="height: 100vh">
            <div class="block-1">
                <custom:orderedList items="#{['One', 'Two', 'Three', 'Four']}"/>
            </div>
            <div class="block-2">
                <custom:orderedList items="#{[]}"/>
            </div>
            <div class="block-3">
                <custom:orderedList items="#{[]}" emptyMessage="There are no items"/>
            </div>
        </h:body>
    </f:view>
</html>

Засим откланиваюсь, прощайте.