假设我有一个复合组件
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:composite="http://java.sun.com/jsf/composite"
`enter code here` xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui">
<h:head></h:head>
<h:body>
<composite:interface componentType="editableLabel">
<composite:attribute name="value" required="true" type="java.lang.String"/>
<composite:attribute name="oldValue" type="java.lang.String"/>
<composite:attribute name="editMode" required="false" default="#{false}" type="java.lang.Boolean"/>
<composite:attribute name="updateListener" required="false" method-signature="void actionListener()"/>
<composite:attribute name="cancelListener" required="false" method-signature="void actionListener()"/>
</composite:interface>
<composite:implementation>
<h:panelGroup id="editableLabelComponent">
<h:panelGroup rendered="#{cc.attrs.editMode}">
<p:inputText value="#{cc.attrs.value}"/>
<p:commandButton value="Update" actionListener="#{cc.update}" update="editableLabelComponent"/>
<p:commandButton value="Cancel" actionListener="#{cc.cancel}" update="editableLabelComponent"/>
</h:panelGroup>
<p:commandLink>
<p:outputLabel id="display" value="#{cc.attrs.value}" rendered="#{!cc.attrs.editMode}"/>
<p:ajax event="click" listener="#{cc.toggleEditMode}" update="editableLabelComponent"/>
</p:commandLink>
</h:panelGroup>
</composite:implementation>
</h:body>
</html>
使用FacesComponent
import org.apache.commons.lang3.StringUtils;
import javax.el.ELContext;
import javax.el.ValueExpression;
import javax.faces.component.FacesComponent;
import javax.faces.component.NamingContainer;
import javax.faces.component.UIComponentBase;
import javax.faces.component.UINamingContainer;
import javax.faces.context.FacesContext;
import java.io.Serializable;
/**
* Created by labraham on 1/14/16.
*/
@FacesComponent(value = "editableLabel")
public class EditableLabel extends UIComponentBase implements Serializable, NamingContainer {
private static final long serialVersionUID = 108467781935083432L;
public static final String VALUE_ATTRIBUTE = "#{cc.attrs.value}";
public static final String OLD_VALUE_ATTRIBUTE = "#{cc.attrs.oldValue}";
public static final String EDIT_MODE_ATTRIBUTE = "#{cc.attrs.editMode}";
private FacesContext context;
private ELContext elContext;
@Override
public String getFamily() {
return UINamingContainer.COMPONENT_FAMILY;
}
/**
*
*/
public void update() {
ValueExpression oldValue = getAttr(OLD_VALUE_ATTRIBUTE, String.class);
String value = (String) getAttr(VALUE_ATTRIBUTE, String.class).getValue(getElContext());
oldValue.setValue(getElContext(), value);
toggleEditMode();
}
/**
*
*/
public void cancel() {
ValueExpression value = getAttr(VALUE_ATTRIBUTE, String.class);
String oldValue = (String) getAttr(OLD_VALUE_ATTRIBUTE, String.class).getValue(getElContext());
value.setValue(getElContext(), oldValue);
toggleEditMode();
}
/**
*
*/
public void toggleEditMode() {
if (StringUtils.isEmpty((String) getAttr(OLD_VALUE_ATTRIBUTE, String.class).getValue(getElContext()))) {
getAttr(OLD_VALUE_ATTRIBUTE, String.class).setValue(getElContext(),
getAttr(VALUE_ATTRIBUTE, String.class).getValue(getElContext())
);
}
ValueExpression editmode = getAttr(EDIT_MODE_ATTRIBUTE, Boolean.class);
editmode.setValue(getElContext(), !((Boolean) editmode.getValue(getElContext())));
}
/**Get value expression for a given attr.*/
private ValueExpression getAttr(final String attribute, final Class<?> attributeType) {
return getContext().getApplication().getExpressionFactory()
.createValueExpression(getElContext(), attribute, attributeType);
}
/**Get ElContext.*/
public ELContext getElContext() {
if (this.elContext == null) {
elContext = getContext().getELContext();
}
return elContext;
}
public void setElContext(final ELContext elContext) {
this.elContext = elContext;
}
/**Get faces context*/
public FacesContext getContext() {
if (this.context == null) {
context = FacesContext.getCurrentInstance();
}
return context;
}
public void setContext(final FacesContext context) {
this.context = context;
}
}
现在,此小部件的所有实例都将具有取消和更新的基线功能,如cancel()和update()函数所定义。然而,除了这个基本功能之外,用户可能还需要一些额外的功能(例如,在更新时调用web服务),这些功能将通过updateListener和/或cancelListener属性中的某种辅助bean方法添加。
我的问题是是否可以从FacesComponent内部以编程方式调用用户附加到侦听器属性的方法,或者我是否采用了错误的方法?
答案 0 :(得分:3)
是的,它可用作MethodExpression
类型的属性。继承的UIComponent#getAttributes()
映射以通常的方式提供所有复合属性。另请参阅How to access Composite Component attribute values in the backing UIComponent?
,例如,获取#{cc.attrs.updateListener}
并调用没有参数:
MethodExpression updateListener = (MethodExpression) getAttributes().get("updateListener");
updateListener.invoke(getFacesContext().getELContext(), null);
对具体问题 无关,处理ValueExpression
属性的方式很笨拙。要获得#{cc.attrs.oldvalue}
,请执行以下操作:
String oldvalue = (String) getAttributes().get("oldvalue");
要设置#{cc.attrs.value}
,只需执行以下操作:
getAttributes().put("value", oldvalue);
将FacesContext
和ELContext
作为实例变量在技术上幸运地在这个特定的构造中没有坏处,但这很可疑,你最好在方法局部范围内获得它们。 FacesContext
仅由继承的UIComponent#getFacesContext()
提供。