代码之家  ›  专栏  ›  技术社区  ›  Working Title

是否可以以编程方式调用方法签名中定义的方法?

  •  0
  • Working Title  · 技术社区  · 8 年前

    假设我有一个复合组件

    <!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内部以编程方式调用用户附加到侦听器属性的方法,或者我是以错误的方式进行调用?

    1 回复  |  直到 8 年前
        1
  •  3
  •   Community arnoo    4 年前

    是的,它作为 MethodExpression 类型化属性。继承的 UIComponent#getAttributes() 地图另请参见 How to access Composite Component attribute values in the backing UIComponent?

    E、 g.,以获得 #{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 幸运的是,实例变量在这个特定的构造中没有损害,但这是可疑的,您最好在方法局部范围内获取它们。这个 面上下文 仅可由继承 UIComponent#getFacesContext() .

    另请参见: