原始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 (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复合组件的片段
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 facelet代码的包含使我感到困惑,因为我将各种Objects注入此通用属性的方法meat似乎是错误的。我在原来的JSP我使用<c:set var="checklist" value="${actionItem.meat}" scope="request" />,然后原来的JSP用于inc_dynamic_checklist_v.jsp看起来是这样
Objects
<c:set var="checklist" value="${actionItem.meat}" scope="request" />
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>
这些还包括需要访问在WorkItem.jsp中使用c:set设置的actionItem.meat
我正在寻找有关是的指导,即使我已嵌套包含,我也应将所有这些包含转换为复合组件。还是我应该使用基本的ui:includes?我知道我可以param使用include或cc 发送,但我仍在private Object meat模型中使用通用字段,还是有更好的方法来检索这些单独的动作模型。
param
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
一步一步来。
在进行下一步之前,一切都必须按预期进行,这一点很重要。
只需继续使用JSTL,并仅替换JSP包含项,<ui:include>直到一切正常即可。不要改变太多。首先使其全部正常工作,然后将其重构为标记文件或复合文件。
<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相同的生命周期。它也是标记处理程序,而不是组件。另请参见JSF2 Facelets中的JSTL …有意义吗?
<c:forEach>
<c:if>
<c:set>
@include
<jsp:include>
的<ui:fragment>,但是,是一个UI组件。它不会有条件地构建视图。无论其rendered属性的结果如何,它及其所有子代仍将最终出现在JSF组件树中。他们只会在渲染响应阶段有条件地渲染HTML输出。与之相比的收益<c:if>是,对于每种条件,JSF组件树的大小都会增加。假设您在该inc_dynamic_checklist_v文件中有4个条件包含,那么它的大小至少会增长4倍。只需继续使用JSTL即可动态构建视图。这是一个非常好的工具。另请参见ao 如何制作JSF复合组件的网格?另一种方法是通过手动创建在背衬bean组件binding,findComponent(),createComponent(),new SomeComponent(),getChildren().add()否则,这只会导致冗长而脆弱的代码,而这些代码很难维护。绝对不要那样做。
<ui:fragment>
rendered
inc_dynamic_checklist_v
binding
findComponent()
createComponent()
new SomeComponent()
getChildren().add()
在<f|o:viewParam>你失败的尝试如用于不同的用途。正如您所期望的那样,它们无法对中的<ui:param>值采取行动<ui:include>。它们仅对HTTP请求参数起作用。另请参见,和有什么用途?您可以<ui:include>继续使用<ui:param>来代替<c:set>,但是您应该像直接使用一样直接访问它们<c:set>。唯一的区别是,这些变量仅在包含本身内部可用,而不是在整个请求中可用(即,因此也可以在包含外部使用)。<ui:param>顺便说一句<jsp:param>,您实际上应该首先使用JSP的等效项。
<f|o:viewParam>
<ui:param>
<jsp:param>
对于支持bean逻辑,只需将支持Java的预处理Java代码放入@PostConstruct支持bean 中,将支持Java的后处理Java代码放入与<h:commandXxx>组件绑定的支持bean的操作方法中即可。在<f:viewAction>和preRenderView因为他们认为建造时间后跑多远,因此JSTL不会得到它期望的模型是insuitable。仅使用这些参数来处理用户提交的HTTP请求参数。
@PostConstruct
<h:commandXxx>
<f:viewAction>
preRenderView
如果您在较旧的Mojarra版本中被Chicken- egg视图状态错误所咬伤,并且您绝对不能升级,也不能通过将设置javax.faces.PARTIAL_STATE_SAVING为来禁用部分状态保存false,那么您就不能将JSTL标记属性附加到查看作用域的bean中属性。如果您确实在这里有一个范围内的视图bean,并且不是在这里使用请求范围内的bean的选项,则需要删除JSTL并专门使用<ui:repeat>and <ui:fragment>代替<c:forEach>and <c:if>。但是,您可以继续使用<c:set>(如果适用)。您还应该保留上述支持bean逻辑的准则。
javax.faces.PARTIAL_STATE_SAVING
false
<ui:repeat>
一旦一切<ui:include><ui:param>就绪,您就可以开始查看重复的包含参数(即,多次使用的块),并通过简单地将它们注册到your.taglib.xml文件中将它们重构为标记文件。实际上,这不会改变逻辑和流程,但会使代码更简洁明了。另请参阅如何创建自定义Facelets标签?有关完整的*.taglib.xml示例和在中的注册web.xml。
<ui:include><ui:param>
your.taglib.xml
*.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如下所示进行注册后,所有包含参数均作为标记属性。
/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>。
<cc:implementation>
基本上,当您有很多Java代码@PostConstruct可以将服务/数据库返回的“外部”模型转换为视图所期望的“内部”模型时,和/或当您有很多Java代码在使用方法时按照服务/数据库的期望将“内部”模型转换回“外部”模型,那么您可以考虑将其重构为可重用的复合组件。这样,当您想在不同的视图中重用相同的功能时,就无需将该粘贴/重复此预处理/后处理任务复制/粘贴到其他支持bean中。并且,您最终得到一个视图,该视图精确地引用了“外部”模型类型而不是“内部”模型类型,该模型类型可能包含多个属性。
如果没有全面了解所有模型的前/后处理,则很难用特定案例的示例来回答这一部分。以下答案包含一些示例,这些示例应该可以对复合组件的意义和废话提供足够的了解:
至少,我的印象是您的“肉”可能是一个界面。如果您具有相同行为的不同对象/类,则应创建一个定义该行为的接口,并让这些类实现该接口。反过来,这部分与JSF并不严格相关,而只是“基本” Java。
别忘了:一次一步。
使用标记文件和组合作为重构工具,以最大程度地减少代码重复。您应该已经有完整的工作代码。