Preprocess/postprocess 来自 p:remoteCommand 复合内部的 bean 操作方法

Preprocess/postprocess a bean action method from p:remoteCommand inside composite

我有以下场景:

具有复杂 JavaScript 的 JSF 复合组件,我想通过 JavaScript 使用支持 bean 的新值(使用此复合组件的页面的支持 bean,不是支持组件 @FacesComponent)。 我不想进行完整更新,因为它是复杂的 JavaScript 插件,它会严重破坏 UX.

我使用 Primefaces 的 <p:remoteCommand> with callback as described here Best method for passing Data from Java/JSF2 bean to Javascript/jQuery Components

从支持组件 @FacesComponent 获取值

我知道这是对 JSF 的一些滥用,但我想将所有功能封装在一个单元中并且不要弄乱 JAX-RS If you can advice another nice solution how to encapsulate such complex jQuery plugin (for sake of clarity we are talking about FullCalendar,我知道 Primefaces 有它自己的这个组件的实现但是它的功能不足以满足我的要求,所以我需要自己实现),它与 ajax 带参数的回调高度相关,非常欢迎您在这里分享它。

我的问题是如何使用 JavaScript 从支持 bean 更新支持组件 @FacesComponent 中的值?目前我参与了以下一系列事件:

  1. 从 Javascript <p:remoteCommand> 调用参数传递给支持组件 @FacesComponent 稍后在 AjaxBehaviorEvent

    中调度

    JavaScript:

           refreshEvents([
                  {name:'start', value:start.format()}, 
                  {name:'end', value:end.format()}
           ]);
    

    JSF代码:

     <p:remoteCommand name="refreshValues" oncomplete="loadValues()"  action="#{cc.refreshLocal()}" process="@this"/>
    

    我使用

    将传递的参数存储在支持组件中
    getStateHelper().put(...);
    
  2. jQuery 通过以下 JavaScript 代码从复合组件调度的事件:

        var hiddenField = $(document.getElementById(variables.hiddenId));
        hiddenField.trigger("keypress");
    
  3. 在复合组件的覆盖方法 public void queueEvent(FacesEvent event) 中,我在第一步中添加了我之前存储的 AjaxBehaviorEvent 属性 并将其转发。

  4. 在复合组件嵌套的页面中从复合组件 "captured" 调度事件并在此组件上执行 process:

    <p:ajax event="refreshEvent" process="@this"  listener="#{bean.refreshEvents}"/>
    

    #{bean.refreshEvent} 方法中我执行对 @EJB bean 的请求并加载数据。

  5. loadValues()

    再次调用第 1 步的回调时

    <p:remoteCommand name="loadValues" action="#{cc.getLocalData()}" oncomplete="updateValues(xhr, status, args);"/>

  6. 在支持组件的方法中 #{cc.getLocalData()} 我使用以下方法添加回调参数:

    RequestContext.getCurrentInstance().addCallbackParam("param", ...);

  7. 第 5 步中的 updateValues(xhr, status, args) 函数获取 args 此参数的值并执行实际更新。

那么,我的一般问题是可以简化这个过程吗?如何简化?

谢谢。

这确实有点过于复杂了。总共 3 个 ajax 请求仅执行一个操作和一个支持组件通过视图状态来回传递数据。

您的主要目标似乎是能够将 bean 操作方法声明为复合组件属性,然后应该由复合内部的 <p:remoteCommand> 调用,并且 return 所需的模型实体基于传入参数,最好进行一些预处理和 post 处理。

可以在复合接口中使用<cc:attribute method-signature>声明一个方法表达式属性:

<cc:interface componentType="yourComposite">
    <cc:attribute name="eventListener" method-signature="com.example.Entity method(java.lang.String, java.lang.String)" required="true" />
</cc:interface>

可以在模板客户端使用如下:

<my:composite ... eventListener="#{bean.eventListener}" />
public Entity eventListener(String start, String end) {
    // ...
    return entity;
}

复合实现可能如下所示:

<cc:implementation>
    ...
    <p:remoteCommand name="refreshEvents" 
        process="@this" action="#{cc.processEventListener}"
        oncomplete="updateValues(xhr, status, args)" />
    ...
</cc:implementation>

#{cc.processEventListener} 方法可以获得 eventListener 属性作为 MethodExpression 并如下调用它,以及一些预处理和 post 处理:

public void processEventListener() {
    String start = getRequestParameter("start");
    String end = getRequestParameter("end");
    // ...
    MethodExpression method = (MethodExpression) getAttributes().get("eventListener");
    Entity entity = (Entity) eventListener.invoke(getFacesContext().getELContext(), new Object[] { start, end });
    // ...
    addCallbackParam("param", entityAsJSON);
}

现在只有 1 个 ajax 请求 "as usual"。