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

Share data between JSF @ViewScoped and WebSocket @ServerEndpoint

我正在使用 JSR356 网络套接字并想向我的服务器端点添加一些函数和值 class 而不是创建另一个 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注释的方法时18=] 那么 language 为空。我认为 viewsocoped 应该在请求之间保持状态。谁能解释这种行为?提前致谢!

您基本上得到了 class 的 2 个独立创建的实例。一个通过 @Named 作为 CDI 管理的 bean,另一个通过 @ServerEndpoint 作为 JSR356 websocket 端点。它并没有像您预期的那样以单个共享实例结束。他们两个互不了解,也不会分享任何东西。

然后是第二个问题:@ServerEndpoint 对当前的 JSF 视图状态没有任何概念。此信息在 WS 请求中无处可用。您可以获得的最接近的是 HTTP 会话。如何在 @ServerEndpoint 中获取 HttpSession 在这个答案中有详细阐述:.

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