Как реорганизовать фрагмент старого JSP в какой-нибудь эквивалент JSF?

ОРИГИНАЛЬНАЯ JSP (WorkItem.jsp)

<c:forEach var="actionItem" items="${workItem.work_action_list}">
    <c:if test="${actionItem.workActionClass.work_action_type_id == '1'}" >
       <%@ include file="inc_done_button.jsp" %>
    </c:if>
    <c:if test="${actionItem.workActionClass.work_action_type_id == '2'}" >
         <c:set var="actionItem" value="${actionItem}" scope="request" />
         <c:set var="checklist" value="${actionItem.meat}" scope="request" />
        <jsp:include page="inc_dynamic_checklist_v.jsp" flush="true" />
    </c:if>
    etc...
</c:forEach>

ОРИГИНАЛЬНАЯ ЯВА

for (ListIterator<WorkflowInstanceWorkItemAction> actionIter = wfiwi.getWork_action_list().listIterator(); actionIter.hasNext();) {
    if ("2".equals(work_action_type_id)) {
        ChecklistInstanceForm ciForm = new ChecklistInstanceForm(this, authenticatedUser);
         ChecklistInstance ci = null; 
        ci = (ChecklistInstance) ciForm.getChkLstInstanceByWfiWiaOwner(wfiWorkItemAction, authenticatedUser);
    // Get the meat details for this action and inject it into the object
        wfiWorkItemAction.setMeat(ci);
    }
}

request.setAttribute("workItem", wfiwi);
request.setAttribute("workFlowInstance", wfi); 

NEW JSF (WorkItem.xhtml)

 <f:metadata>
    <o:viewParam name="wfi_wid" value="#{workItemController.wfiwi}" converter="#{workItemConverter}"
    <f:event type="preRenderView" listener="#{workItemController.preRender}" />
 </f:metadata>
<ui:repeat var="actionItem" value="#{workItemController.wfiwi.work_action_list}">
    <ui:fragment rendered="#{actionItem.workActionClass.workActionType.action_type_id == '1'}">
        <stk:done_button actionItem="#{actionItem}" /> <!-- Here I chose custom c -->
    </ui:fragment>
    <ui:fragment rendered="#{actionItem.workActionClass.workActionType.action_type_id == '2'}">
                <ui:include src="inc_dynamic_checklist.xhtml">
                    <ui:param name="checklist" value="#{actionItem.meat}" />
                </ui:include>
    </ui:fragment>

Создания моего нового боба

public class WorkItemController implements Serializable {
    private static final long serialVersionUID = 1L;
    private WorkflowInstanceWorkItem wfiwi;

    public void preRender() {
    if (wfiwi.getWork_action_list() != null) {
            //loop through and add real model to meat attribute

То, что мне нужно, - это более элегантный способ ввести модель (то, что я называю мясом) в мое представление для каждого действия. Под рабочим элементом (просмотр одной страницы) есть несколько действий. Действия, которые являются контрольными списками, могут быть различных типов (да / нет / нет, количество большое / незначительное, да / нет / нет / разрешено и т. Д.).

Композитный компонент done_button был прямо вперед, потому что я только доступ к базе action модель и нет meat, Например, фрагмент done_button.xhtml составной компонент

<ui:fragment rendered="#{cc.attrs.actionItem.is_active != '1'}">
     Action is not active for you until the following has been completed:
     <h:outputText value="#{cc.attrs.actionItem.prerequisite_work_action_list}" escapeXml="false" />
</ui:fragment>

но включение кода facelet dynamic_checklist меня озадачило, потому что мой подход к внедрению различных Objects в этот общий атрибут meat:) кажется не так. В моей оригинальной JSP я использовал <c:set var="checklist" value="${actionItem.meat}" scope="request" /> а затем оригинальная JSP для inc_dynamic_checklist_v.jsp выглядело примерно так

inc_dynamic_checklist_v.jsp

<form method="post" >

<c:out value="${actionItem.workActionClass.name}" /> 

<c:if test="${checklist.checkListClass.type == '1'}" >
  <%@ include file="inc_yes_no_na_resolved_checklist.jsp" %>
</c:if>

<c:if test="${checklist.checkListClass.type == '2'}" >
  <%@ include file="inc_major_minor_checklist.jsp" %>
</c:if>

<c:if test="${checklist.checkListClass.type == '3'}" >
  <%@ include file="inc_quantity_checklist.jsp" %>
</c:if>

<c:if test="${checklist.checkListClass.type == '4'}" >
  <%@ include file="inc_yes_no_na_checklist.jsp" %>
</c:if>

в том числе также необходим доступ к actionItem.meat, который был установлен с помощью c: set в WorkItem.jsp

Я ищу рекомендации относительно того, что да, я должен преобразовать все эти включения в составные компоненты, даже если у меня есть вложенные включения. Или я должен использовать базовый интерфейс: включает? Я знаю, что могу отправить param либо с помощью include или cc, но я все еще использую общее поле private Object meat в моей модели или есть лучший способ получить эти отдельные модели действий.

возможно это но это не сработало

<ui:include src="inc_dynamic_checklist.xhtml" >
    <ui:param name="wfi_id" value="#{actionItem.workflowInstance.workflow_instance_id}" />
    <ui:param name="wfi_aid" value="#{actionItem.wfi_work_item_action_id}" />
</ui:include>

а затем в inc_dynamic_checklist.xhtml

<f:metadata>
    <o:viewParam name="wfi_id" value="#{checklistInstanceView.ci}" converter="#{checklistInstanceConverter}">
        <f:attribute name="wfi_id" value="#{param.wfi_id}" />
        <f:attribute name="wfi_aid" value="#{param.wfi_aid}" />
    </o:viewParam>
</f:metadata>

ОБНОВИТЬ

Работа элемента поддержки бобов. Рабочий элемент содержит массив действий. Действия могут быть выполнены кнопками (тип действия id=1), контрольными списками (тип действия id=2) и другими вещами, не реализованными / не показанными. То, что у меня сейчас работает, но верно ли это?

public void preRender() {
if (wfiwi.getWork_action_list() != null) {

    for (ListIterator<WorkflowInstanceWorkItemAction> actionIter = wfiwi.getWork_action_list().listIterator(); actionIter.hasNext();) {

        WorkflowInstanceWorkItemAction wfiWorkItemAction = new WorkflowInstanceWorkItemAction();
        wfiWorkItemAction = actionIter.next();

        Long work_action_type_id = wfiWorkItemAction.getWorkActionClass().getWorkActionType().getAction_type_id();

        updatePrerequisites(wfiWorkItemAction, wfiwi.getWorkflowInstance(), wfiwi);

        if (work_action_type_id == 2) {
            System.out.println("Action Type 2 is Dynamic Checklist Type");
            ci = ciRepository.retrieveLatestByWfiWiai(wfiwi.getWorkflowInstance().getWorkflow_instance_id(), wfiWorkItemAction.getWfi_work_item_action_id());

            if (ci != null) {
                if ("1".equals(ci.getCheckListClass().getType())) {
                    List<YesNoNaResolvedAnswer> answer_attribute_list = yesNoNaResolvedDao.retrieveByCiWfi(ci.getChecklist_instance_id(), ci.getWorkflowInstance().getWorkflow_instance_id());
                    ci.setAnswer_attribute_list(answer_attribute_list);
                }

                if ("2".equals(ci.getCheckListClass().getType())) {
                    List<MajorMinorAnswer> answer_attribute_list = majorMinorAnsDao.retrieveByCiWfi(ci.getChecklist_instance_id(), ci.getWorkflowInstance().getWorkflow_instance_id());
                    ci.setAnswer_attribute_list(answer_attribute_list);
                }

                if ("3".equals(ci.getCheckListClass().getType())) {
                    List<QuantityAnswer> answer_attribute_list = quantityAnsDao.retrieveByCiWfi(ci.getChecklist_instance_id(), ci.getWorkflowInstance().getWorkflow_instance_id());
                    ci.setAnswer_attribute_list(answer_attribute_list);
                }
                if ("4".equals(ci.getCheckListClass().getType())) {
                    List<YesNoNaAnswer> answer_attribute_list = yesNoNaAnsDao.retrieveByCiWfi(ci.getChecklist_instance_id(), ci.getWorkflowInstance().getWorkflow_instance_id());
                    ci.setAnswer_attribute_list(answer_attribute_list);
                }

                wfiWorkItemAction.setMeat(ci);
            } else {
                Messages.addFlashErrorMessage("Could not find checklist Instance");
            }

            // wfi_action_list.add(ci);
        } else {
            wfiWorkItemAction.setMeat("meat pie");
        }
    }
}

}

inc_dynamic_checklist.xhtml (см. выше WorkItem.xhtm, как это включено) Это отображает "мясо"

    <ui:fragment rendered="#{checklist.checkListClass.type == '1'}">
        <ui:include src="inc_yes_no_na_resolved_checklist.xhtml" />
    </ui:fragment>

    <ui:fragment rendered="#{checklist.checkListClass.type == '2'}">
        <ui:include src="inc_major_minor_checklist.xhtml" />
    </ui:fragment>

    <ui:fragment rendered="${checklist.checkListClass.type == '3'}">
        <ui:include src="inc_quantity_checklist.xhtml" />
    </ui:fragment>

    <ui:fragment rendered="${checklist.checkListClass.type == '4'}">
        <ui:include src="inc_yes_no_na_checklist.xhtml" />
    </ui:fragment>

модель

@Entity
public class WorkflowInstanceWorkItemAction implements Serializable {
private static final long serialVersionUID = 1L;
private String status;
private String is_active;

@Transient
private Object meat; 
and various mappings

1 ответ

Решение

Один шаг за раз.

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


Продолжайте использовать JSTL для динамического построения представления

Просто продолжайте использовать JSTL и заменяйте только включенные JSP на <ui:include> пока вы не получите все это на работу. Пока не меняйся слишком сильно. Сначала заставьте все это работать, а затем рефакторинг в тег-файлы или композиты.

В вашем первоначальном подходе к JSP вы в основном динамически строите представление с помощью JSTL. Вы можете просто продолжить делать то же самое в JSF 2.x, при условии, что вы используете более свежую версию JSF impl для предотвращения неправильных представлений bean-объектов (Mojarra 2.1.18+). Вы можете продолжать использовать <c:forEach>, <c:if> а также <c:set> таким образом в JSF. Вам нужно только заменить @include а также <jsp:include> от <ui:include>, Обратите внимание, что <ui:include> имеет тот же жизненный цикл, что и JSTL. Это также обработчик тегов, а не компонент. Смотрите также JSTL в JSF2 Facelets... имеет смысл?

<ui:fragment>тем не менее, является компонентом пользовательского интерфейса. Условно не строит представление. Независимо от результата его rendered атрибут, он и все его дочерние элементы все равно окажутся в дереве компонентов JSF. Они будут только условно отображать свои выходные данные HTML во время фазы ответа визуализации. Выплата по сравнению с <c:if> является то, что размер дерева компонентов JSF будет расти для каждого условия. Это увеличится как минимум в 4 раза, учитывая, что вы inc_dynamic_checklist_v файл. Просто продолжайте использовать JSTL для динамического построения представления. Это идеальный инструмент для этого. Смотрите также ao Как сделать сетку из составного компонента JSF? Альтернативой может быть ручное создание компонентов в компоненте поддержки через binding, findComponent(), createComponent(), new SomeComponent(), getChildren().add() а что нет, и это будет в конечном итоге только в подробном и хрупком коде, который трудно поддерживать. Абсолютно не делай этого.

<f|o:viewParam> как показано в вашей неудачной попытке служит другой цели. Они не могут действовать на <ui:param> значения из <ui:include>как ты и ожидал. Они действуют только на параметры HTTP-запроса. См. Также Для чего могут использоваться , и ? Вы можете для вашего <ui:include> продолжайте использовать <ui:param> вместо <c:set>, но вы должны просто получить к ним доступ напрямую, как и в случае с <c:set>, Единственное отличие состоит в том, что эти переменные доступны только внутри самого включения, а не во всем запросе (т. Е. Также и вне включения). JSP эквивалент <ui:param> кстати <jsp:param>, который вы на самом деле должны были использовать в первую очередь.

Что касается поддержки логики бина, просто поместите Java-код предварительной обработки в @PostConstruct вспомогательного компонента и Java-кода постобработки в методах действия вспомогательного компонента, привязанного к <h:commandXxx> компоненты. <f:viewAction> а также preRenderView они не подходят, потому что они запускаются далеко после времени построения представления и, следовательно, JSTL не получит ожидаемую модель. Используйте их только для обработки отправленных пользователем параметров HTTP-запроса.

Если вас укусила ошибка состояния просмотра куриного яйца в старой версии Mojarra, и вы абсолютно не можете обновить ее, а также не можете отключить частичное сохранение состояния, установив javax.faces.PARTIAL_STATE_SAVING в false, тогда вы не можете прикрепить атрибуты тега JSTL для просмотра свойств bean-объекта. Если вы действительно просматриваете bean-объект с областью видимости и не можете использовать здесь bean-объект с областью запроса, вам нужно удалить JSTL и использовать исключительно <ui:repeat> а также <ui:fragment> вместо <c:forEach> а также <c:if>, Однако вы можете продолжать использовать <c:set> (где применимо). Вы также должны придерживаться принципов поддержки логики бинов, как описано выше.


Рефакторинг повторяет include-with-params для файлов тегов

Как только вы заставите все это работать, вы можете начать смотреть на повторяющиеся включения с параметрами (т.е. <ui:include><ui:param> фрагменты, которые используются более одного раза) и перегруппировать их в файлы тегов, просто зарегистрировав их в your.taglib.xml файл. Это на самом деле ничего не меняет в отношении логики и потока, но делает код более чистым и лаконичным. Смотрите также Как создать пользовательский тег Facelets? для завершения *.taglib.xml пример и регистрация в web.xml,

Этот вымышленный пример включает "контрольный список да / нет / нет"

<ui:include src="/WEB-INF/includes/tristateChecklist.xhtml">
    <ui:param name="value" value="#{actionItem}" />
</ui:include>

... можно использовать как показано ниже

<my:tristateChecklist value="#{actionItem}" />

... после перемещения физического файла в /WEB-INF/tags/tristateChecklist.xhtml и зарегистрировать его в /WEB-INF/your.taglib.xml как показано ниже со всеми включаемыми параметрами в качестве атрибутов тега.

<tag>
    <tag-name>tristateChecklist</tag-name>
    <source>tags/tristateChecklist.xhtml</source>
    <attribute>
        <name>value</name>
        <type>java.lang.Object</type><!-- TODO: fix type -->
    </attribute>
</tag>

(вы не показывали свою модель, поэтому я просто указал слишком общий тип)


Рефакторинг повторной модели до / постобработки на композиты

После того, как вы снова все заработаете, вы можете начать просмотр повторной предварительной / постобработки модели и преобразовать их в композиты с "компонентом поддержки" вместе со связанным XHTML внутри. <cc:implementation>,

В основном, когда у вас есть достаточно Java-кода в @PostConstruct преобразовать "внешнюю" модель, возвращаемую службой / базой данных, во "внутреннюю" модель, как того ожидает представление, и / или когда у вас есть достаточно кода Java в действии, чтобы преобразовать "внутреннюю" модель обратно в "внешняя" модель, как ожидает служба / БД, тогда вы можете рассмотреть возможность ее преобразования в составной компонент многократного использования. Таким образом, вам не нужно копировать, вставлять / повторять эту задачу до / пост-обработки в другой компонент EJB, если вы хотите повторно использовать те же функции в другом представлении. И в итоге вы получаете представление, которое ссылается именно на "внешний" тип модели, а не на "внутренний", возможно, состоящий из нескольких свойств.

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

По крайней мере, у меня сложилось впечатление, что ваше "мясо" может стать интерфейсом. Если у вас разные объекты / классы с одинаковым общим поведением, вам следует создать интерфейс, определяющий это общее поведение, и эти классы должны реализовывать этот интерфейс. Эта часть, в свою очередь, не только связана с JSF, но и является "базовой" Java.


Не забывайте: один шаг за раз.

Используйте файлы тегов и композиты в качестве инструмента рефакторинга, чтобы минимизировать дублирование кода. У вас уже должен быть полностью рабочий код.

Другие вопросы по тегам