<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(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
我所追求的是一种更优雅的方式将模型(我称之为肉)注入每个动作的视图中.在工作项(单页面视图)下,有多个操作.作为清单的动作可以是各种类型(是/否/ na,数量主要/次要,是/否/ na /已解决等).
复合组件done_button是直截了当的,因为我只访问基本动作模型而没有肉.例如,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 facelet代码的包含让我感到困惑,因为我将各种Object注入这个通用属性meat :)的方法似乎是错误的.在我最初的JSP中,我使用了< c:set var =“checklist”value =“${actionItem.meat}”scope =“request”/>然后inc_dynamic_checklist_v.jsp的原始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,它是使用WorkItem.jsp中的c:set设置的
我正在寻找指导,是的,我应该将所有这些包括转换为复合组件,即使我有嵌套包含.或者我应该使用基本的ui:includes?我知道我可以使用include或cc发送param但是我仍然在我的模型中使用通用字段私有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>
UPDATE
工作项支持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一步一步来.
重要的是,在进入下一步之前,所有事情都要保持良好的工作状态.
继续使用JSTL动态构建视图
继续使用JSTL,只用< ui:include>替换JSP包含直到你完成所有工作.不要改变太多.首先让它全部工作,然后重构为标签文件或复合材料.
在最初的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 in JSF2 Facelets… makes sense?
然而,< ui:fragment>是UI组件.它不会有条件地构建视图.无论其呈现属性的结果如何,它及其所有子代仍将最终出现在JSF组件树中.它们只会在渲染响应阶段有条件地呈现HTML输出.与< c:if>相比的收益是因为每种条件的JSF组件树大小都会增长.考虑到你在inc_dynamic_checklist_v文件中有4个条件包含,它会增长至少4倍.只需继续使用JSTL动态构建视图.这是一个非常好的工具.另见a.o. How to make a grid of JSF composite component?另一种方法是通过绑定,findComponent(),createComponent(),new SomeComponent(),getChildren().add()以及什么不是手动创建支持bean中的组件,这只会以详细和脆弱的代码结束难以维持.绝对不要那样做.
< f | o:viewParam>如你失败的尝试所示,有不同的目的.他们无法对< ui:param>采取行动正如您所期望的那样,来自< ui:include>的值.它们仅对HTTP请求参数起作用.另请参阅What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?您可以为您的< ui:include>继续使用< ui:param>而不是< c:set>,但您应该直接访问它们,就像使用< c:set>一样.唯一的区别是这些变量仅在包含本身内而不是在整个请求中可用(即因此也在包含之外).与JSP相当的< ui:param>顺便说一句< jsp:param>,你实际应该在第一时间使用它.
至于支持bean逻辑,只需将预处理Java代码放在支持bean的@PostConstruct中,并将后处理Java代码放在支持bean的操作方法中,绑定到< 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> (如适用).您还应该遵循上面描述的支持bean逻辑的准则.
重构重复包括params与params文件
一旦你完成所有工作,那么你可以开始查看重复的include-with-params(即< ui:include>< ui:param>块,这些块不止一次使用)并通过简单注册将它们重构为tagfiles它们位于your.taglib.xml文件中.这实际上不会改变逻辑和流程的任何内容,但会使代码更加简洁明了.有关完整的* .taglib.xml示例以及web.xml中的注册,另请参阅How to create a custom Facelets tag?.
这个虚构的例子包括“是/否/ na清单”
<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>
(你没有展示你的模型,所以我只是指定了一个过于通用的类型)
重构模型前/后处理复合模型
一旦你再次使用它,你就可以开始查看重复的模型前/后处理,并将它们重构为具有“后备组件”的复合材料,以及内部< cc:implementation>中的相关XHTML.
基本上,当你在@PostConstruct中有相当多的Java代码将服务/数据库返回的“外部”模型转换为视图所期望的“内部”模型时,和/或当你有相当多的Java代码时action方法将“内部”模型转换回服务/ DB期望的“外部”模型,然后您可以考虑将其重构为可重用的复合组件.这样,当您想要在不同视图中重用相同的功能时,您不需要将此前/后处理任务复制/重复到不同的支持bean中.并且,您最终得到的视图完全引用“外部”模型类型而不是“内部”模型类型,可能由多个属性组成.
如果没有对所有模型前/后处理的完整概述,那么这个部分很难用您的具体案例作为例子.以下答案包含的示例应该能够充分了解复合组件的含义和无意义:
> Split java.util.Date over two h:inputText fields representing hour and minute with f:convertDateTime
> Initialize a composite component based on the provided attributes
> #{cc.clientId} evalutated in wrong composite after upgrading to JSF 2.2
至少,我的印象是你的“肉”可能是一个界面.如果您有不同的具有相同公共行为的对象/类,那么您应该创建一个定义该公共行为的接口,并让这些类实现该接口.这部分反过来并不是严格的JSF相关,而只是“基本的”Java.
别忘了:一次一步.
使用标记文件和合成作为重构工具来最小化代码重复.您应该已经拥有完整的代码.