在 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 会话。
我正在使用 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 会话。