В ходе разработки 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-разметка. Это так называемые композитные компоненты.
Для их создания необходимо:
- Создать каталог resources в каталоге webapp вашего проекта.
- В нем создать каталог для файлов композитных компонентов. Имя каталога важно — в дальнейшем оно будет необходимо импорта 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>

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