web-dev-qa-db-ja.com

JSR-356 @ServerEndpointの@OnMessageでServletContextおよびHttpSessionにアクセスする

Spring ServletContextを検索してBeanを検索するには、@ServerEndpoint内からApplicationContextを取得する必要があります。

現時点では、最善の方法は、そのBeanをJNDIネーミングコンテキストにバインドし、Endpointでルックアップすることです。より良い解決策があれば歓迎します。

また、サーブレットのHttpSessionをwebsocketのSessionと同期するための適切な方法も探しています。

27
Sombriks

サーブレットHttpSessionはJSR-356にあります HandshakeRequest#getHttpSession() によって利用可能です @OnOpen の直前にハンドシェイク要求が行われると利用可能になります @ServerEndpointServletContextHttpSession#getServletContext() を介して使用できます。それは一石二鳥です。

ハンドシェイク要求をキャプチャするには、 ServerEndpointConfig.Configurator を実装し、 modifyHandshake() メソッドをオーバーライドします。 HandshakeRequestは、ここでメソッド引数として使用できます。 HttpSessionEndpointConfig#getUserProperties() に入れることができます。 EndpointConfigは、メソッドの引数 @OnOpen として使用できます。

ServerEndpointConfig.Configurator実装のキックオフの例を次に示します。

public class ServletAwareConfig extends ServerEndpointConfig.Configurator {

    @Override
    public void modifyHandshake(ServerEndpointConfig config, HandshakeRequest request, HandshakeResponse response) {
        HttpSession httpSession = (HttpSession) request.getHttpSession();
        config.getUserProperties().put("httpSession", httpSession);
    }

}

これを使用する方法は次のとおりです。@ServerEndpointconfigurator 属性に注意してください。

@ServerEndpoint(value="/your_socket", configurator=ServletAwareConfig.class)
public class YourSocket {

    private EndpointConfig config;

    @OnOpen
    public void onOpen(Session websocketSession, EndpointConfig config) {
        this.config = config;
    }

    @OnMessage
    public void onMessage(String message) {
        HttpSession httpSession = (HttpSession) config.getUserProperties().get("httpSession");
        ServletContext servletContext = httpSession.getServletContext();
        // ...
    }

}

設計のヒントとして、@ServerEndpointをサーブレットAPIの依存関係から完全に解放することをお勧めします。 modifyHandshake()実装では、サーブレットセッションまたはコンテキストから必要な正確なthat情報(通常は変更可能なJavabean)をすぐに抽出し、代わりにユーザープロパティマップに配置します。これを行わない場合は、WebSocketセッションがHTTPセッションよりも長く存続できることに注意してください。したがって、エンドポイントにHttpSessionを持ち歩いている場合、期限切れになっているときにアクセスしようとすると、IllegalStateExceptionに遭遇する可能性があります。

CDI(およびおそらくJSF)を手元に置いている場合、 OmniFaces <o:socket> (リンクはショーケースの一番下にあります)のソースコードからインスピレーションを得ます。

以下も参照してください。

39
BalusC

BalusCの回答のコードを更新しました。onOpenメソッドは@OnOpenで装飾する必要があります。その後、Endpointクラスを拡張する必要はもうありません。

@ServerEndpoint(value="/your_socket", configurator=ServletAwareConfig.class)
public class YourSocket {

    private EndpointConfig config;

    @OnOpen
    public void onOpen(Session websocketSession, EndpointConfig config) {
        this.config = config;
    }

    @OnMessage
    public void onMessage(String message) {
        HttpSession httpSession = (HttpSession) config.getUserProperties().get("httpSession");
        ServletContext servletContext = httpSession.getServletContext();
        // ...
    }

}
5
hfmanson

BalusCの上記sessionではServletAwareConfigを取得できない場合があります。これは、セッションがまだ作成されていないためです。セッションではなくservletContextを探すので、Tomcatでは次のようにできます。

public static class ServletAwareConfig extends ServerEndpointConfig.Configurator {

    @Override
    public void modifyHandshake(ServerEndpointConfig config, HandshakeRequest request, HandshakeResponse response) {
        try {
            Field reqfld = request.getClass().getDeclaredField("request");
            reqfld.setAccessible(true);
            HttpServletRequest req = (HttpServletRequest) reqfld.get(request);
            ServletContext ctxt = req.getServletContext();
            Map<String, Object> up = config.getUserProperties();
            up.put("servletContext", ctxt);
        } catch (NoSuchFieldException e) {
        } catch (SecurityException e) {
        } catch (IllegalArgumentException e) {
        } catch (IllegalAccessException e) {
        }
    }

}

すぐに初期化セッションが必要な場合は、request.getSession()を呼び出すことができます。

参照: Websocket-httpSessionはnullを返します

0
Inshua

Tomcat(バージョン7.0.56および8.0.14)でBalusCの回答を試しました。両方のコンテナで、modifyHandshakeのリクエストパラメータにはHttpSessionが含まれていません(したがって、servletContextは含まれていません)。 「グローバル」変数(Webアプリケーショングローバル)にアクセスするためだけにサーブレットコンテキストが必要だったので、これらの変数をホルダークラスの通常の静的フィールドに格納しました。これはエレガントではありませんが、うまくいきました。

これは、この特定のTomcatバージョンのバグのように見えます-これを見た人はいますか?

0