我正在使用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 应该在请求之间保持状态。谁能解释这种行为?提前谢谢!
答案 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会话中的关联数据。