【问题标题】:Accessing HttpSession inside an annotated @WebSocket class on Embedded Jetty 9在 Embedded Jetty 9 上的带注释的 @WebSocket 类中访问 HttpSession
【发布时间】:2015-02-24 14:15:34
【问题描述】:

如何在 Jetty 9 中访问带注释的 @WebSocket 类中的 HttpSession 对象?

我找到了使用@ServerEndpoint 注释的方法,例如:HttpSession from @ServerEndpoint

使用@WebSocket注解,就像在下面的类中,我该怎么做?

@WebSocket
public class AuctionWebSocket {

    // NEED TO ACCESS HttpSession OBJECT INSIDE THESE METHODS:

    @OnWebSocketConnect
    public void onConnect(Session session) {
        System.out.println("onConnect...");        
    }

    @OnWebSocketMessage
    public void onMessage(String message) {        
        System.out.println("Message: " + message);
    }    

    @OnWebSocketClose
    public void onClose(int statusCode, String reason) {
        System.out.println("onClose...");        
    }

    @OnWebSocketError
    public void onError(Throwable t) {
        System.out.println("onError...");        
    }    
}

在方法onConnect(Session session) 中,我尝试调用session.getUpgradeRequest().getSession(),它总是返回null

为了提供信息,以下是我启动嵌入式 Jetty 9 的方法:

public class Main {

    public static void main(String[] args) throws Exception {

        String webPort = System.getenv("PORT");
        if (webPort == null || webPort.isEmpty()) {
            webPort = "8080";
        }

        Server server = new Server(Integer.parseInt(webPort));

        ClassList classlist = org.eclipse.jetty.webapp.Configuration.ClassList.setServerDefault(server);
        classlist.addBefore("org.eclipse.jetty.webapp.JettyWebXmlConfiguration",
                "org.eclipse.jetty.annotations.AnnotationConfiguration");

        WebAppContext wac = new WebAppContext();
        String webappDirLocation = "./src/main/webapp/";

        wac.setAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern", ".*/classes/.*");
        wac.setDescriptor(webappDirLocation + "/WEB-INF/web.xml");
        wac.setBaseResource(new ResourceCollection(new String[]{webappDirLocation, "./target"}));
        wac.setResourceAlias("/WEB-INF/classes/", "/classes/");
        wac.setContextPath("/");
        wac.setParentLoaderPriority(true);

        /*
         * WebSocket handler.
         */
        WebSocketHandler wsh = new WebSocketHandler() {

            @Override
            public void configure(WebSocketServletFactory wssf) {
                wssf.register(AuctionWebSocket.class);
            }
        };

        ContextHandler wsc = new ContextHandler();
        wsc.setContextPath("/auction-notifications");
        wsc.setHandler(wsh);

        ContextHandlerCollection chc = new ContextHandlerCollection();
        chc.setHandlers(new Handler[]{wac, wsc});

        server.setHandler(chc);

        server.start();
        server.join();
    }

}

如果您需要更多信息,请告诉我。

任何帮助将不胜感激。

提前致谢。

【问题讨论】:

    标签: websocket embedded-jetty jetty-9


    【解决方案1】:

    您需要使用 WebSocketCreator 概念。

    首先,您在WebSocketServletFactory 中设置您选择的WebSocketCreator,您在WebSocketServlet 中配置了该WebSocketServlet

    public class MySessionSocketServlet extends WebSocketServlet
    {
        @Override
        public void configure(WebSocketServletFactory factory)
        {
            factory.getPolicy().setIdleTimeout(30000);
            factory.setCreator(new MySessionSocketCreator());
        }
    }
    

    接下来,您需要在升级期间获取 HttpSession 并将其传递给您正在创建的 WebSocket 对象。

    public class MySessionSocketCreator implements WebSocketCreator
    {
        @Override
        public Object createWebSocket(ServletUpgradeRequest req, ServletUpgradeResponse resp)
        {
            HttpSession httpSession = req.getSession();
            return new MySessionSocket(httpSession);
        }
    }
    

    最后,只需在您自己的 WebSocket 中跟踪 HttpSession

    @WebSocket
    public class MySessionSocket
    {
        private HttpSession httpSession;
        private Session wsSession;
    
        public MySessionSocket(HttpSession httpSession)
        {
            this.httpSession = httpSession;
        }
    
        @OnWebSocketConnect
        public void onOpen(Session wsSession)
        {
            this.wsSession = wsSession;
        }
    }
    

    注意:HttpSession 可以在 WebSocket 处于活动状态时过期并被清除和清理。此外,此时的HttpSession 内容不能保证与其他 Web 操作的更改保持同步(这主要取决于您在服务器端使用的 Session 存储/缓存技术)

    还有一点需要注意:不要在 Socket 实例中存储/跟踪 ServletUpgradeRequest 对象,因为该对象会被 Jetty 适当地回收和清理。

    【讨论】:

    • 我只想访问HttpSession 中的已登录用户,以维护用户地图及其各自的 websocket 会话,以便进一步通信。作为一种解决方法,在onopen javascript 回调中,我使用用户ID 向websocket 发送一条消息,例如ws.onopen = function () { ws.send("onopen:" + sessionId_); };,然后,我在服务器上的用户和websocket 会话之间建立关联。您认为这种方法比通过WebSocketCreator 概念访问HttpSession 更好吗?
    • 我有一些类似的要求,(我的要求是,如果同一个用户在多个选项卡中打开应用程序,则创建多个 websocket 会话,所以如果用户在一个选项卡中注销,我想注销用户所有标签),您能帮忙解决一下问题吗?
    • @Jayesh 请为新主题打开一个新问题
    • HttpSession httpSession = req.getSession(); 向我返回 null,我认为是因为请求已经升级。我用HttpSession httpSession = req.getHttpServletRequest().getSession();解决了。
    猜你喜欢
    • 2014-10-29
    • 2013-03-16
    • 2014-05-12
    • 1970-01-01
    • 1970-01-01
    • 2012-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多