JSF 2 – 如何向复合组件接口添加Ajax侦听器方法?

我有一个JSF 2复合组件,它采用了一些Ajax行为。 我想在复合组件中的标记中添加一个listener方法,但是listener方法应该在作为提供。

我的复合组件中的标签当前被硬编码为这样的监听器:

  

bean上的listener方法有这个签名:

 public void genericAjaxEventLogger(AjaxBehaviorEvent event) throws AbortProcessingException { // implementation code... } 

我希望复合组件是这样的,所以页面可以提供自己的事件方法,但我无法弄清楚接口的正确语法。

  

我怎样才能做到这一点?

更新解决方案:

我采用了BalusC建议的方法,效果很好。 相关的片段是:

复合组件中的接口声明

   ...  

我的复合组件中使用的Ajax标记

  

我在页面中使用复合组件的位置

    

和我的支持bean上的方法

 public void updatedEventListenerXYZ() { // do something here... } 

如果你可以摆脱AjaxBehaviorEvent参数,

 public void genericAjaxEventLogger() { // ... } 

那你可以用

  

如果参数是必需的(对于日志记录?),则需要重新指定属性,如下所示

  

但是,这不会像预期的那样起作用

  

在GF 3.1 + Mojarra 2.1.1上:

 SEVERE: javax.faces.FacesException: wrong number of arguments at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:89) at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101) at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118) at javax.faces.webapp.FacesServlet.service(FacesServlet.java:409) at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1534) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:281) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175) at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655) at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595) at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:98) at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:91) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:162) at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:326) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:227) at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:170) at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:822) at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:719) at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1013) at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:225) at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137) at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104) at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90) at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79) at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54) at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59) at com.sun.grizzly.ContextTask.run(ContextTask.java:71) at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532) at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513) at java.lang.Thread.run(Unknown Source) Caused by: java.lang.IllegalArgumentException: wrong number of arguments at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at com.sun.el.parser.AstValue.invoke(AstValue.java:234) at com.sun.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:297) at com.sun.faces.facelets.el.ContextualCompositeMethodExpression.invoke(ContextualCompositeMethodExpression.java:177) at com.sun.faces.facelets.tag.TagAttributeImpl$AttributeLookupMethodExpression.invoke(TagAttributeImpl.java:450) at com.sun.faces.facelets.tag.jsf.core.AjaxBehaviorListenerImpl.processAjaxBehavior(AjaxHandler.java:447) at javax.faces.event.AjaxBehaviorEvent.processListener(AjaxBehaviorEvent.java:113) at javax.faces.component.behavior.BehaviorBase.broadcast(BehaviorBase.java:102) at javax.faces.component.UIComponentBase.broadcast(UIComponentBase.java:760) at javax.faces.component.UICommand.broadcast(UICommand.java:300) at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:794) at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1259) at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:81) ... 28 more 

我不确定这是不是一个bug。 为此,我需要投入更多时间来naildown它。 但是,它可以通过创建一个支持组件来解决,该组件从属性获取MethodExpression并使用正确数量的参数进行调用。 这是一个完整的启动示例:

           

 package com.example; import javax.el.MethodExpression; import javax.faces.component.FacesComponent; import javax.faces.component.UINamingContainer; import javax.faces.context.FacesContext; import javax.faces.event.AjaxBehaviorEvent; @FacesComponent(value="testCC") public class TestCC extends UINamingContainer { public void ajaxEventListener(AjaxBehaviorEvent event) { FacesContext context = FacesContext.getCurrentInstance(); MethodExpression ajaxEventListener = (MethodExpression) getAttributes().get("ajaxEventListener"); ajaxEventListener.invoke(context.getELContext(), new Object[] { event }); } } 

无论如何,我相信支持组件为新的方法打开了大门,以实现您想到的function要求;)

以下是如何使用接口设置属性并在实现中引用它的示例。 您必须定义将被调用的方法的方法签名。 这通知复合组件处理程序##cc.attrs.ajaxEventListener}表达式中包含方法值而不是值表达式。

     . . .