Как отредактировать фрагмент старого 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>

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

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>

Задачи моей новой поддержки bean

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>

но включение в личный код 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

Я ищу рекомендации относительно того, что я должен преобразовать все это в составные компоненты, даже если я вложен. Или я должен использовать базовые ui: includes? Я знаю, что могу отправить 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>

ОБНОВЛЕНИЕ

Поддержка рабочего элемента bean. Рабочий элемент содержит массив действий. Действия могут выполняться кнопками (тип действия 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, чтобы предотвратить поврежденный вид с областью видимости beans (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 файле есть 4 условных выражения. Просто продолжайте использовать JSTL для динамического создания представления. Это отличный инструмент для этого. См. Также a.o. Как создать сетку композитного компонента JSF? Альтернативой было бы вручную создавать компоненты при поддержке bean через binding, findComponent(), createComponent(), new SomeComponent(), getChildren().add(), а что нет, и это только закончится сложным и хрупким кодом, который трудно поддерживать. Абсолютно не делайте этого.

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

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

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


Повторный набор refactor include-with-params для tagfiles

Как только вы заработаете все, чтобы начать работать, вы можете начать просмотр повторяющихся include-with-params (т.е. <ui:include><ui:param> фрагментов, которые используются более одного раза) и реорганизовать их в tagfiles, просто зарегистрировав их в файле 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, как показано ниже, со всеми параметрами include в качестве атрибутов тега.

<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-код в методе действий для преобразования "внутренней" модели обратно во "внешнюю" модель, которую ожидает служба/БД, тогда вы можете рассмотреть возможность реорганизации ее в составной компонент многократного использования. Таким образом, вам не нужно копировать/повторять эту задачу до/после обработки в другую резервную копию bean, если вы хотите повторно использовать одну и ту же функциональность в другом представлении. И вы получите представление, которое в точности относится к "внешнему" типу модели вместо "внутреннего", возможно, состоящему из нескольких свойств.

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

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


Не забывайте: шаг за шагом.

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