Как создать модульное приложение JSF 2.0?

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

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

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

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

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

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

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

3 ответа

Решение

Я понимаю, что ваш вопрос в основном сводится к тому, как я могу включить представления Facelets в 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;
    }

}

Настройте это в веб-приложении 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 разрешение ресурсов.

Смотрите также:

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

Кстати... вы можете избежать реализации своего собственного средства распознавания ресурсов, когда используете припой для шва (в настоящее время интегрируемый в 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 с этим, вроде как портлетов только без портлетов.. =D
  3. Выполнение пользовательского интерфейса: включение в компоненты контейнера, такие как tabviews, также проблематично.
  4. как правило, не рекомендуется смешивать JSTL (c:forEach) и JSF. Тем не менее я обнаружил, что это единственный способ работать с пользовательским интерфейсом: повтор оценивается слишком поздно, например, ваш включенный контент не отображается.
Другие вопросы по тегам