【问题标题】:Omnifaces socket + commandScript combinationsOmnifaces 套接字 + commandScript 组合
【发布时间】:2017-03-19 23:17:07
【问题描述】:

我想用the <o:commandScript> option as documented here 实现 OmniFaces 。

我的 JSF 页面如下所示:

<h:form id="myForm">
    <!-- the socket is by default disconnected. It will
         connect when the user selects a subChannel. 
         Setting the subChannel to "null" must disconnect
         the socket -->
    <o:socket channel="myChannel" scope="session"
              connected="#{myManager.subChannel ne null}"
              user="#{myManager.subChannel}"
              onmessage="someTestScript" onopen="onOpen" onclose="onClose"/>

    <o:commandScript name="someTestScript"
                     actionListener="#{myManager.testPush}"
                     render=":testValue" />

    <!-- dummy rendering to check if everything is working -->
    <h:panelGroup id="testValue"
                  rendered="#{myManager.subChannel ne null}" >
        <h:outputText value="#{myManager.bbb} #{myManager.aaa}" />
    </h:panelGroup>

    <!-- To simplify: I have several buttons which allows
         the user to select the socket "user". The buttons
         are only displayed when no "user" is selected 
         (thus, socket is not connected yet as well) -->
    <p:dataGrid value=#{...a list...} var="sth" 
                rendered="#{myManager.subChannel eq null">

        <p:ajax event="click"
                update="myForm"
                listener="#{myManager.setSubChannel(sth.id)}" />

        <p:panel>
            <h:outputText value=#{sth.text} />
        </p:panel> 

    </p:dataGrid>

    <!-- Resetting -->
    <p:commandButton value="Reset"
                     actionListener="#{myManager.setSubChannel(null)"
                     update="myForm" />
</h:form>

我的后盾:

@Named(value = "myManager")
@SessionScoped
public class MyStuffManager implements Serializable{

    private Long subChannel = null;
    private Long aaa;
    private String bbb;

    public void testPush(Long aaa, String bbb){
       System.out.println("Text received: " + bbb + ", Number received: " + aaa);
       this.aaa = aaa;    
       this.bbb = bbb;
    }

    // getter & setter

}

我的套接字推送点:

@Named 
@ApplicationScoped
public Class mySocket implements Serializable{
    @Inject
    @Push(channel = "myChannel")
    private PushContext socket;

    // Basically, all methods are triggered by CDI events. So
    // far, I just want to send an int and a String to see how
    // I send parameters.
    public void test(@Observes @MyEventQualifier AnEvent event) {
        Map<String, Object> input = new HashMap<>();
        input.put("aaa", 123456789);
        input.put("bbb", "a text");
        socket.send(input);
    }
}

目前,我的情况是:

  1. 单击面板和“重置”按钮时,套接字正确连接和断开连接。
  2. 仍然根据链接文档, 选项可以正常工作,但我无法发送参数。

但是,我的观点是:

  1. 有一个“null”用户属性。无论我使用“connect”属性触发连接还是
    oncomplete="OmniFaces.Push.open('myChannel')"
    ,subChannel 仍然被解析为 null。奇怪的是,如果我执行其他 JSF 内容(例如更新 字段),子通道会正确更新和检索。 当连接不是自动时,我应该如何根据 EL 获得动态“用户”属性?
  2. 我错过了 OmniFaces 文档中的一些内容,因为从未调用过 myManager.testPush。我错过了什么? 相反,我的 Firefox 控制台上有一个 ReferenceError: someTestScript is not defined。我试图在 JavaScript 文件中添加一个空的 someTestScript,但看起来只调用了空的,而不是 o:commandScript。

我们正在使用文档中所述的 OmniFaces 2.6。

显然欢迎任何提示/建议。谢谢。

【问题讨论】:

  • 对于那些与我有同样问题的人 2),我误解了 commandScript documentation 关于如何传递变量。 JavaScript 代码需要调用 commandScript 函数名称(完全独立于套接字 onmessage 名称)并通过 ({param: value, ...}) 语法添加参数。但是,我仍然不知道 1),我的用户还没有更新。谁有想法,请指教。

标签: jsf websocket omnifaces


【解决方案1】:

我终于修好了!对于那些对解决感兴趣的人,以后自己注意:

1)如何动态改变子频道

选项 1:将 o:socket 范围更改为 view,使 HTTP 会话范围比套接字范围更宽。

<o:socket channel="myChannel" scope="view"
          connected="#{myManager.subChannel ne null}"
          user="#{myManager.subChannel}"
          onmessage="someTestScript" onopen="onOpen" onclose="onClose"/>

退出套接字时,套接字将正确关闭并使用正确的 subChannel 值重新打开。由于某些原因,似乎将“subChannel”作为 String 比 Long 效果更好。

选项 2:使用“子频道地图”。实际上,我没有在我的问题中说明多个用户可以连接到同一个子频道。另一种选择是让所有用户通过他们的 userId &lt;o:socket channel="myChannel" user="#{user.id}" session="scope" /*default value anyway*/ {...}/&gt; 进行连接

然后,我不是发送到子频道,而是发送到用户 ID 的集合:

Map<String, Set<String>> subChannelUserMap = new HashMap<>();
// ...
public void onUserConnect(User user, String subChannel){
    subChannelUserMap.get(subChannel).add(user.getId());
}
// ....
public void sendMessage(Map<K, V> input, String subChannel){
    socket.send(input, subChannelUserMap.get(subChannel));
}

2) 从 JavaScript 调用支持 bean 方法

正如我在自我评论中所说,我误解了&lt;o:commandScript&gt; 的用法。让我们考虑支持 bean 方法:

// ...
public class BackingBean{
    public void test(){
        String aaa = Faces.getRequestParameter("aaa", String.class);
        String bbb = Faces.getRequestParameter("aSillyName", String.class);
        LOGGER.debug("aaa={}, bbb={}", aaa, bbb);
    }    
}

将套接字写为&lt;o:socket /*...*/ onmessage=onMessage /&gt;,我将拥有:

JSF 页面:

 <o:commandScript name="aSillyFunctionName" render="..." 
                  actionListener="#{backingBean.test}" ... />

JavaScript 文件:

 function onMessage(message, channel, event){
     aSillyFunctionName({aaa: message.aaa, aSillyName: bbb});
 }

我已经完成了。

【讨论】:

    猜你喜欢
    • 2018-06-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-20
    • 1970-01-01
    • 2016-07-17
    • 1970-01-01
    • 2012-12-31
    相关资源
    最近更新 更多