在JSF @ViewScoped和WebSocket @ServerEndpoint之间共享数据

时间:2015-03-17 15:34:02

标签: java-ee jsf-2 websocket view-scope

我正在使用JSR356 Web套接字,并希望将一些函数和值添加到我的Server End Point类,而不是创建另一个ManagedBean。

此外,我想在请求之间保留bean属性,因此我使用注释@ViewScoped注释了我的服务器端点。现在它看起来像这样:

@Named
@ViewScoped
@ServerEndpoint(value = "/session", encoders = ChatMessageEncoder.class, decoders = ChatMessageDecoder.class)
public class ChatEndpoint implements Serializable {

    @EJB
    private LanguageHelper languageHelper;
    private String language;

    public void filterByLanguage() {
        if (language == null)
            language = "US";
    }

    @OnOpen
    public void open(final Session session) throws IOException, EncodeException {
        // ...
    }

    @OnMessage
    public void onMessage(final Session session, final ChatMessage chatMessage) {
        // ...
    }

    @OnClose
    public void onClose(Session session) throws IOException {
        // ...
    }

    // getters & setters
}

在我的view xhtml我正在尝试使用ajax更新属性language

 <h:form>
    <h:outputLabel value="Select languages you want to practice" for="languages"/>
    <h:selectOneMenu value="#{chatEndpoint.language}">
        <f:selectItems value="#{chatEndpoint.languageHelper.languages}" var="l"
                       itemLabel="#{l.language}" itemValue="#{l.code}"/>
        <f:ajax event="change" listener="#{chatEndpoint.filterByLanguage}" render="@form" execute="@this"/>
    </h:selectOneMenu>
</h:form>

首先,当ajax调用方法filterByLanguage时,将值设置为字段language,但之后,当我调用使用@OnOpen注释的方法通过javascript然后{{ 1}}为空。我认为 viewsocoped 应该在请求之间保持状态。谁能解释这种行为?提前谢谢!

1 个答案:

答案 0 :(得分:2)

你基本上最终得到了2个独立创建的类实例。一个作为CDI托管bean通过@Named,另一个作为JSR356 websocket端点通过@ServerEndpoint。它并没有像您期望的那样最终成为单个共享实例。这两个人对彼此一无所知,也不会分享任何东西。

然后还有第二个问题:@ServerEndpoint对当前的JSF视图状态没有任何概念。 WS请求中没有此信息。最接近的是HTTP会话。如何在HttpSession中获取@ServerEndpoint详细说明在此答案中:Accessing ServletContext and HttpSession in @OnMessage of a JSR-356 @ServerEndpoint

您可能已经知道可以通过HttpSession访问JSF端ExternalContext#getSessionMap()的属性。如果您通过例如JSF方面生成一些唯一令牌UUID.randomUUID().toString()并将其用作会话属性键,然后通过JSF视图传递给websocket作为URL路径或查询参数,然后websocket可以利用它来查找共享HTTP会话中的关联数据。