无法在嵌入式tomcat中使用websocket,因为ServerContainer为空

问题描述 投票:0回答:1

我已经有十多年没有使用 Java 了,并且知道我正在尝试使用嵌入式 tomcat 8.5.95(由于 guacamole-common 而一直使用该版本)以及 websocket 支持。

尝试了各种方法让它工作,但我被困住了,我不知道是什么导致了问题。
问题是

(ServerContainer)ctx.getAttribute("javax.websocket.server.ServerContainer")
始终是
null

我知道这里有很多关于同样问题的问题,但我尝试了很多,但似乎都不起作用。
在我的
main
中或在
ServletContainerInitializer

中调用上面的代码并不重要

主要

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

        Tomcat tomcat = new Tomcat();
    
        tomcat.setPort(8080);
        // tried tomcat.addWebapp and tomcat.addContext
        var ctx = tomcat.addWebapp("", new File(".").getAbsolutePath());
        ctx.addServletContainerInitializer(new Init(), null);
        
       // normal http implementation for guacamole
        Tomcat.addServlet(ctx, "tunnel", new DummyGuacamoleTunnelServlet()); 
        ctx.addServletMappingDecoded("/tunnel", "tunnel");
        
        // tried this first, but according the internet ;) this should go in a 

//      String serverContainerClass = ServerContainer.class.getName();
//        ServerEndpointConfig config =
//                ServerEndpointConfig.Builder.create(DummyGuacamoleWebsocketEndpoint.class, "/websocket-tunnel")
//                       .subprotocols(Arrays.asList(new String[]{"guacamole"}))
//                       .build();
//      String serverContainerClass = ServerContainer.class.getName();
//        ServerEndpointConfig config =
//                ServerEndpointConfig.Builder.create(DummyGuacamoleWebsocketEndpoint.class, "/websocket-tunnel")
//                        .subprotocols(Arrays.asList(new String[]{"guacamole"}))
//                        .build();
//
//        ServerContainer container = (ServerContainer)ctx.getServletContext().getAttribute(serverContainerClass);
//        if (container == null) {
//            return;
//        }
//
//        try {
//
//            // Add configuration to container
//            container.addEndpoint(config);
//
//        }
//        catch (DeploymentException e) {
//            System.out.println("Unable to deploy WebSocket tunnel. " + e);
//        }
        tomcat.start();
        tomcat.getServer().await();
    }

初始化(ServletContainerInitializer)

public class Init implements ServletContainerInitializer {

    @Override
    public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException {
        String serverContainerClass = ServerContainer.class.getName();
                ServerContainer container = (ServerContainer)ctx.getAttribute(serverContainerClass);
        if (container == null) {
            return;
        }
        ServerEndpointConfig config =
                ServerEndpointConfig.Builder.create(DummyGuacamoleWebsocketEndpoint.class, "/websocket-tunnel")
                        .subprotocols(Arrays.asList(new String[]{"guacamole"}))
                        .build();


        try {

            // Add configuration to container
            container.addEndpoint(config);

        }
        catch (DeploymentException e) {
            System.out.println("Unable to deploy WebSocket tunnel. " + e);
        }

    }
}

端点

// GuacamoleWebSocketTunnelEndpoint is from guacamole-common, which I can't change
public class DummyGuacamoleWebsocketEndpoint extends GuacamoleWebSocketTunnelEndpoint {
    @Override
    protected GuacamoleTunnel createTunnel(javax.websocket.Session session, javax.websocket.EndpointConfig config) throws GuacamoleException {
        return null;
    }
}

gradle 依赖项

dependencies {
    implementation("org.apache.guacamole:guacamole-common:1.5.3")
    implementation("org.apache.tomcat.embed:tomcat-embed-core:8.5.95")
    implementation("org.apache.tomcat.embed:tomcat-embed-websocket:8.5.95")
    compileOnly("javax.websocket:javax.websocket-api:1.1")
    compileOnly("javax.websocket:javax.websocket-all:1.1")
}

编辑 我还尝试实现一个

ServletContextListener
,其中我尝试获取
ServerContainer
,但无济于事。

如何获得正确的

ServerContainer

java websocket tomcat8
1个回答
0
投票

好的,经过进一步的搜索和调查,我找到了解决方案:)

我不需要这两个

javax.websocket...
依赖项

添加端点基本上有两种可能性

带注释

  1. 创建这样的上下文(在

    main
    中)

    var ctx = tomcat.addWebapp("", new File(".").getAbsolutePath());
    

    这还将添加对 jsp 的支持(但需要额外的依赖项,例如 jasper)

  2. 添加

    org.apache.tomcat.embed:tomcat-embed-websocket
    提供的ServletContainerInitializer(在
    main
    中)

    ctx.addServletContainerInitializer(new WsSci(), null);
    
  3. @ServerEndpoint("/path")

    注释端点

或者您可以显式地将端点添加到初始值设定项

ctx.addServletContainerInitializer(new WsSci(), new HashSet<>(List.of(GuacamoleWebSocketTunnelEndpoint.class)));

那么你就不需要注释了

无注释

  1. 像这样创建上下文(在 main 中)

    var ctx = tomcat.addContext("", new File(".").getAbsolutePath());
    
    Wrapper defaultServlet = ctx.createWrapper();
    defaultServlet.setName("default");
    defaultServlet.setServletClass("org.apache.catalina.servlets.DefaultServlet");
    defaultServlet.setLoadOnStartup(1);
    ctx.addChild(defaultServlet);
    ctx.addServletMappingDecoded("/", "default");
    

    您必须按照此处
    所述添加默认 servlet 您将无法获得 JSP 支持。

  2. 添加

    org.apache.tomcat.embed:tomcat-embed-websocket
    提供的ServletContainerInitializer(在
    main
    中)

    ctx.addServletContainerInitializer(new WsSci(), null);
    
  3. 添加监听者

    public class Listener implements ServletContextListener {
    
       @Override
       public void contextInitialized(ServletContextEvent event) {
         String serverContainerClass = ServerContainer.class.getName();
         ServerContainer container = (ServerContainer)event.getServletContext().getAttribute(serverContainerClass);
         ServerEndpointConfig config =
                ServerEndpointConfig.Builder.create(DummyGuacamoleWebsocketEndpoint.class, "/websocket-tunnel")
                        .build();
    
          try {
            container.addEndpoint(config);
          } catch (DeploymentException e) {
            throw new RuntimeException(e);
          }
       }
    
       @Override
       public void contextDestroyed(ServletContextEvent event) {
        // Do stuff during server shutdown.
       }
    }
    
  4. main

    中注册监听器

    ctx.addApplicationListener("full.name.to.ListenerClass");

© www.soinside.com 2019 - 2024. All rights reserved.