当自定义复合组件中的某些其他JSF元素与提交h:form的h:commandButton存在于同一页面中时,我在调用托管bean的操作时遇到问题。我可以将导致问题的页面元素缩小到那些执行以下无害(对我来说)渲染测试的人:
<h:panelGroup rendered="#{not empty cc.attrs.element}">
或:
<h:panelGroup rendered="#{empty cc.attrs.element}">
其中'element'是必需属性,由id从JPA实体加载。关于“空cc.attrs.element”或“非空cc.attrs.element”测试的内容会阻止正确的表单提交,并阻止在其出现的任何h:表单中调用操作。
表单提交页面debug.xhtml是:
<f:view>
<f:metadata>
<f:viewParam name="id" value="#{elementController.id}"/>
</f:metadata>
</f:view>
<h:head>
<title>DEBUG</title>
</h:head>
<h:body>
<h:form>
<util:view_link element="#{elementController.selected}"/>
<h:commandButton value="Apply" action="#{elementController.reflect}" />
</h:form>
</h:body>
注意视图参数'id',通过ElementController.setId将强制通过JPA中的id加载'selected'或'current'元素实体,此处未显示。然后应该通过动作reflect():
移动到test.xhtml@JSFaction
public Object reflect() {
String $i = "reflect";
log_debug($i);
if (current==null) {
log_warn($i, "can't generate reflect outcome for null current element");
return null;
}
//return "reflect?faces-redirect=true&includeViewParams=true&id="+current.getId();
//return "test?faces-redirect=true&includeViewParams=true&id="+current.getId();
//return "reflect?id="+current.getId();
return "/test?faces-redirect=true&id="+current.getId();
}
你可以看到上面我已经尝试过不同的结果URL,但事实证明问题与此无关,只是根本没有调用该行为(当{not empty cc.attrs.element时) } test在另一个页面元素中执行。
导致问题的复合组件是我的util:view_link ::
<composite:interface>
<composite:attribute name="element" required="true" type="com.greensoft.objectdb.test.entity.Element"/>
<composite:attribute name="name" required="false"/>
<composite:attribute name="showOwnerAsText" required="false" default="false"/>
<composite:attribute name="showModelClass" required="false" default="false"/>
<composite:attribute name="showEntityClass" required="false" default="false"/>
<composite:attribute name="showId" default="false"/>
<!--composite:attribute name="showHelp" required="false" default="false"/-->
<!--composite:attribute name="title" required="false"/-->
</composite:interface>
<composite:implementation>
<h:panelGroup rendered="#{empty cc.attrs.element}">
<span class="warn">NULL</span>
</h:panelGroup>
<h:panelGroup rendered="#{not empty cc.attrs.element}">
<h:panelGroup rendered="#{cc.attrs.showOwnerAsText}">
<h:outputText style="font-weight:bold" value="#{cc.attrs.element.owner.name}."/>
</h:panelGroup>
<h:panelGroup rendered="#{cc.attrs.showId}">
<h:link outcome="/view" value="<#{cc.attrs.element.id}>">
<f:param name="id" value="#{cc.attrs.element.id}"/>
</h:link>
</h:panelGroup>
<h:link outcome="/view"
value="#{empty cc.attrs.name ? cc.attrs.element.name: cc.attrs.name}"
>
<f:param name="id" value="#{cc.attrs.element.id}"/>
</h:link>
</h:panelGroup>
</composite:implementation>
您可以看到这只是创建每个元素链接的可重用方法,数据库ID作为参数传递。如果没有元素,则显示“NULL”。
通过一次注释掉比特(包围)我可以证明问题与render =“#{empty cc.attrs.element}和render =”#{not empty cc.attrs.element} test有关这两个都阻止了表单提交和操作啊:commandButton在同一个组合页面中调用(参见上面的debug.xhtml)。例如,如果我只使用普通的h:panelGroup元素而没有'rendered =“#{empty cc.attrs.element}'和'rendered =”#{not empty cc.attrs.element}'test,那么一切都很好,并且h:commandButton按预期工作,操作被称为ok,导航工作正常!
问:为什么测试'rendered =“#{empty cc.attrs.element}'或'rendered =”#{not empty cc.attrs.element}'阻止正确的表单提交并停止调用该操作?
感谢创意,Webel
编辑:问题只发生在我对elementController.selected进行测试时,其中.selected是一个@Entity元素。我尝试使用一个带有String name属性的简单Duummy类和一个@RequestScoped DebugController,它运行正常(该动作被调用)。
<h:panelGroup rendered="#{not empty debugController.dummy}">
<h:outputText value="#{debugController.dummy.name}"/>
</h:panelGroup>
<h:commandButton value="Apply" action="#{elementController.reflect}" />
答案 0 :(得分:0)
我现在可以部分回答这个问题了。我现在可以看到正在发生的事情并对其进行描述,但我仍然无法完全理解 - 就JSF阶段和请求范围而言 - 为什么会发生这种情况。这是一个微妙而棘手的问题。
为了解释它,我重写了测试用例以使其更简单。带有id查询参数的view.xhtml测试页面是:
<f:view>
<f:metadata>
<f:viewParam name="id" value="#{elementController.id}"/>
</f:metadata>
</f:view>
<h:body>
<h:form>
<h:panelGroup rendered="#{empty elementController.selected}">
<div style="color:orange;">
No Element found for id(#{elementController.id}) or page called without id query param.
</div>
</h:panelGroup>
<h:panelGroup rendered="#{not empty elementController.selected}">
[<h:outputText value="#{elementController.selected.id}"/>]
<h:outputText value="#{elementController.selected.name}"/>
</h:panelGroup>
<br/><br/>
<h:commandButton value="Apply" action="#{elementController.action}" />
</h:form>
</h:body>
ElementController扩展RequestController。在加载view.xhtml时,id查询参数使用setId设置为viewParam,后者通过id(来自数据库)加载匹配的Element实体,并将其设置为'current'(又名“selected”)元素,可用作getSelected( ),它还对零电流进行了测试,这就是导致问题的原因:
public void setId(Long id) {
log_debug("setId","id",id);
if (id != null) {
this.id = id;
T found = (T) getAbstractFacade().find(id);
if (found == null) {
String $error = "No object with id(" + id + ") found for class " + getManagedClass().getSimpleName();
log_error($error);
}
setCurrent(found);
}
}
public T getSelected() {
log_debug("getSelected","current",current);
if (current == null) {
//current = newElement(); //THIS WAS CAUSING PROBLEMS
log_warn("getSelected","null current Element");
}
return current;
}
问题在于,在提交表单时,为每个测试实例'#{not empty elementController.selected}'或'#{empty elementController.selected}'调用了两次getSelected()该行动被称为和,字段为'current'null 。
在@RequestScoped @ManagedBean ElementController中,getSelected()方法测试当前(也就是选定的)Element是否为null,并且正在采取导致错误的操作,这是对操作调用的短路当调用'not empty elementController.selected'时,在commandButton上:
(我看到的问题与“选定的”元素是否经过'非空'或'空'测试是否是@Entity无关,我误导相信因为问题是处理Element实体的ElementController,当然这个结论听起来并不正确。)
如果我摆脱导致错误的newElement()的赋值,并且在没有id参数的情况下调用视图页面时触发了这种情况(触发了id加载'current'实体)而是记录一个警告,我可以看到,对于'not empty elementController.selected'或'empty elementController.selected'测试的每个实例,在表单提交时调用commandButton的操作之前,会记录两次该警告。 / p>
不知怎的 - 这是我不完全理解的部分 - 在@RequestScoped下,分配给变量'current'(又名“selected”)的Element丢失了,'not empty elementController.selected'test in使用current = null(带副作用)调用视图页面(以及getSelected())两次。
如果我将ElementController的范围更改为@SessionScoped,问题就会消失;保持当前的Element状态,并且永远不会使用'current'null调用getSelected()。
我将非常感谢任何回复评论,这些评论根据JSF阶段和请求范围解释为什么我的'当前'变量突然为空以及为什么'#{not empty elementController.selected}'执行两次之前该动作被调用。我已经检查过中间没有调用setId(仅在初始视图页面加载时),其他东西正在将当前重置为null,或者在表单提交和调用操作之间重新创建请求范围bean。