Как создать модульное приложение JSF 2.0?
У меня есть приложение с четко определенным интерфейсом. Он использует CDI для разрешения модулей, (в частности, он использует экземпляры инстанции для интерфейсов API для решения модулей) и без проблем передает различные данные назад и четвертый через интерфейсы. Я намеренно сохранил API и реализацию отдельно, и модули только наследуют от API, чтобы избежать жесткой связи, и приложение знает только о модулях через ожидания выполнения, а передача данных выполняется через API. Приложение отлично работает без модулей, которые можно добавить просто, отбросив банку в папку WEB-INF/lib и перезапустив сервер приложений.
В тех случаях, когда я сталкиваюсь с проблемами, я хочу, чтобы модули создавали часть представления, и поэтому я хочу вызывать переносимым образом как компонент JSF, так и сделать его из модуля в порядке чтобы он сделал свое мнение. Я уже решил, какой модуль я хочу вызывать, и имею ссылки на интерфейс модуля. То, как я изначально думал, чтобы сделать это, было сделать ui: include, который просит модуль предоставить, где он просматривает шаблон, но я понятия не имею, как ответить на этот запрос значимым образом, поскольку разрешение представления выполняется из приложения root, а не корень библиотеки.
Резюме состоит в том, что я не знаю, как перераспределить пробел от приложения к библиотеке, используя JSF для файлов .xhtml(template/component).
Использование CC было бы неплохо, но как я могу указать, что я хочу, чтобы конкретный экземпляр CC во время выполнения вместо того, чтобы иметь жесткую кодировку на странице?
Я могу, конечно, вызвать код приложения напрямую и запросить его для разметки, но это кажется действительно грубой силой, и как только у меня есть разметка, я не уверен точно, как рассказать JSF о ее оценке. Тем не менее, я могу представить себе компонент, который будет использовать путь к ресурсам, захватить разметку и оценить ее, возвращая завершенную разметку, я просто не знаю, как ее реализовать.
Я бы предпочел избегать принуждения разработчиков модулей к возможности использования UIComponent с большой нагрузкой, если это возможно, что означает либо динамический способ выполнения ui: include (или некоторый эквивалент), либо динамический способ вызова CC. (Я не против кодирования UIComponent подхода ONCE в приложении, если это то, что требуется, чтобы сделать жизнь разработчиков модулей проще)
Любые предложения о том, где я должен посмотреть, чтобы понять это? (Я отправлю ответ здесь, если найду его первым)
Ответы
Ответ 1
Я понимаю, что ваш вопрос в основном сводится к тому, как включить отображение Facelets в JAR?
Вы можете сделать это, разместив в JAR пользовательский ResourceResolver
.
public class FaceletsResourceResolver extends ResourceResolver {
private ResourceResolver parent;
private String basePath;
public FaceletsResourceResolver(ResourceResolver parent) {
this.parent = parent;
this.basePath = "/META-INF/resources"; // TODO: Make configureable?
}
@Override
public URL resolveUrl(String path) {
URL url = parent.resolveUrl(path); // Resolves from WAR.
if (url == null) {
url = getClass().getResource(basePath + path); // Resolves from JAR.
}
return url;
}
}
Настройте это в webapp web.xml
следующим образом:
<context-param>
<param-name>javax.faces.FACELETS_RESOURCE_RESOLVER</param-name>
<param-value>com.example.FaceletsResourceResolver</param-value>
</context-param>
Представьте, что у вас есть /META-INF/resources/foo/bar.xhtml
в random.jar
, тогда вы можете просто включить его обычным способом
<ui:include src="/foo/bar.xhtml" />
или даже динамически
<ui:include src="#{bean.path}" />
Примечание. Начиная с версии Servlet 3.0 и более поздних версий JBoss/JSF 2.0, весь метод ResourceResolver
не требуется, если вы храните файлы в папке /META-INF/resources
. Вышеприведенный ResourceResolver
является обязательным только для версий Servlet 2.5 или старше JBoss/JSF, поскольку они имеют ошибки в разрешении ресурсов META-INF
.
См. также:
Ответ 2
Я искал информацию по той же теме и наткнулся на эту ссылку: How-to: Модульные приложения Java EE с CDI и PrettyFaces, которые отлично работали для меня.
Ответ 3
Кстати, вы можете избежать реализации собственного распознавателя ресурсов, когда используете припой для пайки (в настоящее время интегрированный в apache deltaspike), который является действительно полезной библиотекой, дополняющей CDI (ваша типичная модель Java EE 6)
Я тоже экспериментировал с модулями в приложениях jsf. В основном я построил интерфейс шаблона с панелью инструментов, которая заполняется кнопками, предоставляемыми каждым модулем. Как правило, вы сделаете это, предоставив список строк в качестве именованного объекта:
@Produces
@SomethingScoped
@Named("topMenuItems")
public List<String> getTopMenuItems(){
return Arrays.asList("/button1.xhtml", "/button2.xhtml", "/button3.xhtml");
}
Обратите внимание, как каждая из кнопок может поступать из другого модуля приложения jsf.
Интерфейс шаблона содержит панель, в которой
вы можете использовать его в своей разметке следующим образом (на свой страх и риск;)):
....
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
....
<xy:toolbar>
<xy:toolbarGroup>
<c:forEach items="#{topMenuItems}" var="link">
<ui:include src="#{link}" />
</c:forEach>
</xy:toolbarGroup>
</xy:toolbar>
<xy:panel>
<ui:include src="#{contentPath}"/>
</xy:panel>
Это была панель инструментов и панель содержимого.
простая кнопка или определение представления может выглядеть так:
<ui:composition ...>
<xy:commandButton actionListener="#{topMenuController.switchContent()}"
value="Test" id="testbutton" />
</ui:composition>
позволяет назвать этот артефакт view1.xhtml
Когда эта кнопка нажата (которая не вызывает обратную передачу с помощью actionListener, мы хотим перезагрузить контент с помощью ajax), switchContentMethod в вашем контроллере может изменить строку, возвращаемую getContentPath:
public void switchContent(){
contentPath = "/view1.xhtml";
}
@Produces
@SomethingScoped
@Named("contentPath")
public String getContentPath(){
return contentPath;
}
теперь вы можете изменить представление, отображаемое на панели, с помощью кнопки в строке меню, которая дает вам навигацию без перезагрузки страницы.
Некоторые советы (или "что я узнал" ):
- Вы можете выбрать большую область для метода getTopMenuItems.
- Не вставляйте тег ui: include. К сожалению, это невозможно (например, ваш view1.xhtml не может содержать другую композицию). я действительно
хотелось бы, чтобы подобное было возможно, поскольку вы можете
модульные представления jsf с этим, вроде портлетов только без
портлеты.. = D
- Выполнение ui: включение в компоненты контейнера, такие как tabviews, также оказывается проблематичным.
- Обычно не рекомендуется смешивать JSTL (c: forEach) и JSF. Тем не менее, я нашел, что это единственный способ работать как ui: repeat получает
оценивается слишком поздно, например. ваш включенный контент не отображается.