代码之家  ›  专栏  ›  技术社区  ›  jeff

如何将旧JSP片段重构为某种JSF等效代码?

  •  7
  • jeff  · 技术社区  · 9 年前

    原始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); 
    

    新JSF (工作项.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>
    

    但包含dynamicchecklist facelet代码让我感到困惑,因为我注入各种 Objects 插入此通用属性 :)似乎是错误的。在我最初使用的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的访问权限。使用WorkItem.jsp中的c:set设置的肉

    我正在寻找指导,是的,我应该将所有这些include转换为复合组件,即使我有嵌套的include。或者我应该使用基本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.xml中

    <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动态检查列表。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 回复  |  直到 9 年前
        1
  •  8
  •   Community Egal    7 年前

    一步一个脚印。

    重要的是,在进入下一步之前,一切都要按预期进行。


    继续使用JSTL动态构建视图

    只需继续使用JSTL,并仅使用 <ui:include> 直到你把一切都做好。不要改变太多。首先使其全部工作,然后重构为标记文件或复合文件。

    在最初的JSP方法中,基本上是在JSTL的帮助下动态构建视图。您可以在JSF2.x中继续执行同样的操作,前提是您使用的是更新的JSFimpl版本,以防止视图范围的bean(Mojarra2.1.18+)损坏。你可以继续使用 <c:forEach> , <c:if> <c:set> 在JSF中采用这种方式。您只需要更换 @include <jsp:include> 通过 <ui:包含> 。请注意 <ui:包含> 具有与JSTL相同的生命周期。它也是一个标记处理程序,而不是一个组件。另请参见 JSTL in JSF2 Facelets... makes sense?

    这个 <ui:fragment> 然而,它是一个UI组件。它不会有条件地构建视图。无论其结果如何 rendered 属性,它和它的所有子级仍将在JSF组件树中结束。它们只会在呈现响应阶段有条件地呈现HTML输出。与 <c: 如果> JSF组件树的大小将在每个条件下增长。如果你有4个条件包含,它至少会增长4倍 inc_dynamic_checklist_v 文件只需继续使用JSTL动态构建视图。这是一个非常好的工具。另见a.o。 How to make a grid of JSF composite component? 另一种方法是通过 binding , findComponent() , createComponent() , new SomeComponent() , getChildren().add() 如果没有,这只会导致冗长而脆弱的代码,很难维护。绝对不要那样做。

    这个 <f|o:viewParam> 正如你失败的尝试所显示的,它有不同的目的。他们无法行动 <ui:param> 中的值 <ui:包含> 正如你所料。它们仅对HTTP请求参数起作用。另请参见 What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for? 你可以 <ui:包含> 继续使用 <ui:param> 而不是 <c: 设置> ,但您应该直接访问它们,就像您使用 <c: 设置> 唯一的区别是,这些变量仅在include本身内部可用,而不是在整个请求中可用(即,在include外部也可用)。JSP等价于 <ui:param> 顺便说一下 <jsp:param> ,你实际上应该首先使用它。

    至于支持bean逻辑,只需将预处理Java代码放入 @PostConstruct backing bean和backing bean的操作方法中的后处理Java代码 <h:commandXxx> 组件。这个 <f:viewAction> preRenderView 因为它们在视图构建时间之后运行,因此JSTL无法得到预期的模型。仅用于处理用户提交的HTTP请求参数。

    如果您被旧Mojarra版本中的鸡蛋视图状态错误咬了一口,您绝对无法升级,也无法通过设置禁用部分状态保存 javax.faces.PARTIAL_STATE_SAVING false ,则不能将JSTL标记属性附加到视图范围内的bean属性。如果这里确实有一个视图范围的bean,并且这里不能选择使用请求范围的bean的话,那么您需要删除JSTL并以独占方式使用 <ui:repeat> <ui:片段> 而不是 <c: 对于每个> <c: 如果> 。但是,您可以继续使用 <c: 设置> (如适用)。您还应该保持上述支持bean逻辑的指导原则。


    将包含参数的重复include重构为标记文件

    一旦你完成了所有的工作,那么你就可以开始查看带有参数的重复include(即。 <ui:include><ui:param> 多次使用的块),并通过在 your.taglib.xml 文件这实际上不会改变逻辑和流程,但会使代码更加干净和简洁。另请参见 How to create a custom Facelets tag? 完整的 *.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> .

    基本上,当您在 @后期构造 将服务/DB返回的“外部”模型转换为视图所期望的“内部”模型,和/或当您有相当多的Java代码在操作方法将“内部”模式转换回服务/DB所期望的外部模型时,您可以考虑将其重构为可重用的复合组件。这样,当您想在不同的视图中重用相同的功能时,就不需要将此预处理/后处理任务复制粘贴/重复到不同的后台bean中。最后,您会看到一个视图,它引用的是“外部”模型类型而不是“内部”模型类型,可能由多个属性组成。

    如果没有对所有模型预处理/后处理的完整概述,很难用具体案例的示例来回答这一部分。以下答案包含的示例应能充分了解复合组件的意义和无意义:

    至少,我觉得你的“肉”可能是一个界面。如果有不同的对象/类具有相同的公共行为,那么应该创建一个定义该公共行为的接口,并让这些类实现该接口。这部分并不是严格意义上的JSF相关,而是“基本”Java。


    别忘了:一步一个脚印。

    使用标记文件和组合作为重构工具,以最小化代码重复。您应该已经有了完全可用的代码。