Как создать модульное приложение JSF 2.0? - PullRequest
25 голосов
/ 01 июня 2011

У меня есть приложение с четко определенным интерфейсом. Он использует CDI для разрешения модулей (в частности, он использует точки внедрения Instance <> на интерфейсах API для разрешения модулей) и передает различные данные обратно и четвертым через интерфейсы без проблем. Я намеренно держал API и реализацию отдельно, а модули наследуются только от API, чтобы избежать тесной связи, а приложение знает о модулях только через зависимости времени выполнения и передачу данных через API. Приложение работает нормально без модулей, которые можно добавить, просто поместив jar в папку WEB-INF / lib и перезапустив сервер приложений.

Проблема, с которой я сталкиваюсь, заключается в том, что я хочу, чтобы модули создавали часть представления, и поэтому я хочу вызывать переносимым способом либо компонент JSF, либо делать включение из модуля по порядку. чтобы он сделал свое мнение. Я уже решил, какой модуль я хочу вызвать, и у меня есть ссылки на интерфейс модуля. Первоначально я думал, что это нужно сделать, это сделать пользовательский интерфейс: include, который просит модуль указать, где находится шаблон представления, но я понятия не имею, как ответить на этот запрос осмысленно, поскольку разрешение представления выполняется из приложения. корень, а не корень библиотеки.

Резюме заключается в том, что я понятия не имею, как перейти от приложения к библиотеке с помощью JSF для файлов .xhtml (шаблон / компонент).

Было бы неплохо использовать CC, но как мне указать, что я хочу, чтобы конкретный экземпляр CC во время выполнения вместо того, чтобы жестко кодироваться на странице?

Я, конечно, могу напрямую вызывать код приложения и запрашивать его для разметки, но это кажется грубой силой, и когда у меня есть разметка, я не совсем уверен, как сказать JSF, чтобы она оценивалась. Тем не менее, я могу представить компонент, который будет брать путь к ресурсу, захватывать разметку и оценивать ее, возвращая завершенную разметку, я просто не знаю, как это реализовать.

Я бы предпочел избегать принуждения разработчиков модулей к использованию сверхмощного подхода UIComponent, если это возможно, что означает либо динамический способ выполнения пользовательского интерфейса: включение (или некоторый эквивалент), либо динамический способ вызова CC. (Я не против кодировать UIComponent подход ОДИН РАЗ в приложении, если это то, что нужно, чтобы облегчить жизнь разработчикам модулей)

Любые предложения о том, где я должен искать, чтобы выяснить это? (Я опубликую ответ здесь, если найду его первым)

Ответы [ 3 ]

33 голосов
/ 01 июня 2011

Я понимаю, что ваш вопрос в основном сводится к Как я могу включить представления Facelets в JAR?

Вы можете сделать это, поместив пользовательский ResourceResolver в JAR.

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;
    }

}

Настройте это в 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.

См. Также:

5 голосов
/ 25 марта 2012

Я искал информацию по той же теме и наткнулся на эту ссылку: Практическое руководство. Модульные приложения Java EE с CDI и PrettyFaces , которые мне очень помогли.

2 голосов
/ 07 июня 2013

Между прочим .. вы можете избежать реализации своего собственного распознавателя ресурсов, когда используете припой для шва (в настоящее время интегрируемый в 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;
}

, теперь вы можете изменить представление, отображаемое на панели, с помощью кнопкив меню, которое дает вам навигацию без перезагрузки страницы.

Несколько советов (или «что я выучил»):

  1. Вы можете захотетьвыберите большую область действия для метода getTopMenuItems
  2. Не вкладывайте тег ui: include.К сожалению, это невозможно (например, ваш view1.xhtml не может включать другую композицию).Мне бы очень хотелось, чтобы что-то подобное было возможным, поскольку вы можете создавать действительно модульные представления jsf с помощью этого, вроде только портлетов без портлетов.,
  3. обычно не рекомендуется смешивать JSTL (c: forEach) и JSF.Тем не менее я обнаружил, что это единственный способ работать с пользовательским интерфейсом: повтор оценивается слишком поздно например, ваш включенный контент не отображается.
...