我有一个复杂验证的应用程序,我只能根据模型层次结构执行,所以我不能使用JSF的验证阶段。
我的问题是我需要将验证错误链接回gui(直观地显示需要注意的文本字段)。所以我需要在某处将UI组件与域模型项链接起来。
我希望使用PreRenderComponentEventListener来实现这一点:
起初这似乎有效: 我在xhtml页面中有以下内容:
<ui:composition template="/templates/mainTemplate.xhtml">
<ui:define name="content">
<ui:repeat value="#{contactController.contactManager.contactList}" var="contact">
<h:inputText value="#{contact.name}"/>
<h:inputText value="#{contact.firstName}"/>
<br/>
</ui:repeat>
</ui:define>
</ui:composition>
现在假设我有一个firstName失败的联系人列表。
ValueExpression的expressionstring给了我“#{contact.firstName}”:我从这个构建一个新的ValueExpression来检索父“#{contact}”,并且可以检查失败的firstname是否是正确的联系人之一列表。
所以我在Listener中做了类似的事情:
private Object extractParent(UIInput input) {
FaceletContext faceletElContext = (FaceletContext) FacesContext.getCurrentInstance().getAttributes().get(FaceletContext.FACELET_CONTEXT_KEY);
ValueExpression orig = input.getValueExpression("value");
String parent = getParent(orig.getExpressionString());
ValueExpression valueExpression = FacesContext.getCurrentInstance().getApplication().getExpressionFactory().createValueExpression(faceletElContext,"#{"+parent+"}", Object.class);
return valueExpression.getValue(faceletElContext);
}
现在这仅在重复位于顶部facelet时才有效。
一旦我的复杂应用程序使用包含文件,或者由于两个原因,这开始失败:
所以我完全陷入困境!有人可以给我一个替代方案吗?
评估@BalusC 的回复后更新:
我尝试使用ELContext
但没有成功。我进一步调查了一下,核心问题是ELContext
和FaceletContext
都不允许我访问包含文件中定义的变量:
ELContext
没有它们FaceletContext
似乎是最后一个包含文件中的一个,因此不是正确的文件。我有一个小的测试用例证明了这一点:当渲染“contactinner”输入文本时,ELContext没有这个变量,而faceletcontext有错误的xhtml层次结构。
非常感谢所有人的帮助。
test.xhtml:
<ui:composition>
<h:form id="myform">
<c:set var="itemContact" value="#{contactController.contact}"/>
<c:set var="itemPerson" value="#{contactController.person}"/>
<ui:include src="contact.xhtml"/>
<ui:include src="person.xhtml"/>
<h:commandButton action="#{contactController.process}"/>
</h:form>
</ui:composition>
contact.xhtml:
<ui:composition>
<c:set var="contactinner" value="#{itemContact}"/>
<h:inputText value="#{contactinner}"/>
</ui:composition>
person.xhtml:
<ui:composition>
<c:set var="personinner" value="#{itemPerson}"/>
<h:inputText value="#{personinner}"/>
</ui:composition>
faces-config.xml(extract):
<system-event-listener>
<system-event-listener-class>TestSystemEventListener</system-event-listener-class>
<system-event-class>javax.faces.event.PreRenderComponentEvent</system-event-class>
</system-event-listener>
TestSystemEventListener(extract):
public class TestSystemEventListener implements SystemEventListener {
@Override
public void processEvent(SystemEvent event) throws AbortProcessingException {
UIInput input = (UIInput) event.getSource();
FaceletContext faceletElContext = (FaceletContext) FacesContext.getCurrentInstance().getAttributes().get(FaceletContext.FACELET_CONTEXT_KEY);
FacesContext context = FacesContext.getCurrentInstance();
ValueExpression orig = input.getValueExpression("value");
}
运行这个,当在第一个xhtml #{contactInner}
中为inputext启动evenlistener时,我得到了监听器中的数据:
orig = {com.sun.faces.facelets.el.TagValueExpression@24201}"/xhtml/contact.xhtml @6,43 value=\"#{contactinner}\""
orig = {com.sun.el.ValueExpressionImpl@24220}"ValueExpression[#{contactinner}]"
expr = {java.lang.String@24270}"#{contactinner}"
varMapper = {com.sun.el.lang.VariableMapperImpl@24271}
vars = {java.util.HashMap@24275} size = 1
[0] = {java.util.HashMap$Entry@24278}"contactinner" -> "/xhtml/contact.xhtml @5,54 value=\"#{itemContact}\""
context = {com.sun.faces.context.FacesContextImpl@24200}
elContext = {com.sun.faces.el.ELContextImpl@24205}
functionMapper = {com.sun.faces.facelets.compiler.NamespaceHandler@24284}
variableMapper = {com.sun.faces.el.ELContextImpl$VariableMapperImpl@24221}
variables = {java.util.HashMap@24289} size = 2
[0] = {java.util.HashMap$Entry@24292}"itemContact" -> "/xhtml/test.xhtml @9,68 value=\"#{contactController.contact}\""
[1] = {java.util.HashMap$Entry@24295}"itemPerson" -> "/xhtml/test.xhtml @10,66 value=\"#{contactController.person}\""
faceletElContext = {com.sun.faces.facelets.impl.DefaultFaceletContext@24199}
faces = {com.sun.faces.context.FacesContextImpl@24200}
ctx = {com.sun.faces.el.ELContextImpl@24205}
facelet = {com.sun.faces.facelets.impl.DefaultFacelet@24151}"/xhtml/person.xhtml"
faceletHierarchy = {java.util.ArrayList@24206} size = 2
[0] = {com.sun.faces.facelets.impl.DefaultFacelet@23792}"/xhtml/test.xhtml"
[1] = {com.sun.faces.facelets.impl.DefaultFacelet@24151}"/xhtml/person.xhtml"
varMapper = {com.sun.faces.facelets.el.VariableMapperWrapper@24207}
target = {com.sun.faces.el.ELContextImpl$VariableMapperImpl@24221}
vars = {java.util.HashMap@24222} size = 1
[0] = {java.util.HashMap$Entry@24225}"personinner" -> "/xhtml/person.xhtml @5,52 value=\"#{itemPerson}\""
答案 0 :(得分:0)
您应该使用FacesContext#getELContext()
获得的ELContext
实例,而不是FaceletContext
。
private Object extractParent(UIInput input) {
ELContext elContext = FacesContext.getCurrentInstance().getELContext();
ValueExpression orig = input.getValueExpression("value");
String parent = getParent(orig.getExpressionString());
ValueExpression valueExpression = FacesContext.getCurrentInstance().getApplication().getExpressionFactory().createValueExpression(elContext, "#{" + parent + "}", Object.class);
return valueExpression.getValue(elContext);
}
顺便提一下Application#evaluateExpressionGet()
。
private Object extractParent(UIInput input) {
FacesContext context = FacesContext.getCurrentInstance();
ValueExpression orig = input.getValueExpression("value");
String parent = getParent(orig.getExpressionString());
return context.getApplication().evaluateExpressionGet(context, "#{" + parent + "}", Object.class);
}