websocket中没有环境变量

时间:2017-05-24 08:57:27

标签: java java-ee jetty java-websocket

我想访问一个环境变量,在web.xml中定义,在一个javax WebSocket的实例中,使用jetty9运行。

我可以访问任何servlet中的环境变量,或WebSocket的onOpen方法,但不能访问WebSocket的onMessage方法

web.xml:

<env-entry>
    <env-entry-name>entry</env-entry-name>
    <env-entry-type>java.lang.String</env-entry-type>
    <env-entry-value>env value</env-entry-value>
</env-entry>

WebSocket.java:

package com.example;

import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;

@ServerEndpoint("/ws")
public class WebSocket {

    public String getEntry(Session session) {
        try {
            InitialContext ctx = new InitialContext();
            return (String) ctx.lookup("java:comp/env/entry");
        } catch (NamingException e) {
            e.printStackTrace();
            return null;
        }
    }

    @OnOpen
    public void onOpen(Session session) throws IOException {
        String entry = getEntry(session);
        System.out.println("onOpen: entry = " + (entry != null ? entry : "Not found"));
    }

    @OnMessage
    public void onMessage(String message, Session session) throws IOException {
        String entry = getEntry(session);
        System.out.println("onMessage: entry = " + (entry != null ? entry : "Not found"));
    }

}

pom.xml:

<dependencies>
    <dependency>
        <groupId>javax.websocket</groupId>
        <artifactId>javax.websocket-api</artifactId>
        <version>1.1</version>
        <scope>provided</scope>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-war-plugin</artifactId>
            <version>2.3</version>
            <configuration>
                <webappDirectory>${webAppDirectory}</webappDirectory>
            </configuration>
        </plugin>
    </plugins>
</build>

输出:

onOpen: entry = env value
onMessage: entry = Not found
javax.naming.NameNotFoundException; remaining name 'env/entry'
    at org.eclipse.jetty.jndi.NamingContext.lookup(NamingContext.java:538)
    at org.eclipse.jetty.jndi.NamingContext.lookup(NamingContext.java:569)
    at org.eclipse.jetty.jndi.NamingContext.lookup(NamingContext.java:584)
    at org.eclipse.jetty.jndi.java.javaRootURLContext.lookup(javaRootURLContext.java:108)
    at javax.naming.InitialContext.lookup(InitialContext.java:417)
    at com.example.WebSocket.getEntry(WebSocket.java:17)
    at com.example.WebSocket.onMessage(WebSocket.java:33)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.eclipse.jetty.websocket.common.events.annotated.CallableMethod.call(CallableMethod.java:70)
    at org.eclipse.jetty.websocket.jsr356.annotations.OnMessageTextCallable.call(OnMessageTextCallable.java:60)
    at org.eclipse.jetty.websocket.jsr356.annotations.JsrEvents.callText(JsrEvents.java:189)
    at org.eclipse.jetty.websocket.jsr356.endpoints.JsrAnnotatedEventDriver.onTextMessage(JsrAnnotatedEventDriver.java:377)
    at org.eclipse.jetty.websocket.common.message.SimpleTextMessage.messageComplete(SimpleTextMessage.java:69)
    at org.eclipse.jetty.websocket.common.events.AbstractEventDriver.appendMessage(AbstractEventDriver.java:65)
    at org.eclipse.jetty.websocket.jsr356.endpoints.JsrAnnotatedEventDriver.onTextFrame(JsrAnnotatedEventDriver.java:359)
    at org.eclipse.jetty.websocket.common.events.AbstractEventDriver.incomingFrame(AbstractEventDriver.java:161)
    at org.eclipse.jetty.websocket.common.WebSocketSession.incomingFrame(WebSocketSession.java:309)
    at org.eclipse.jetty.websocket.common.extensions.ExtensionStack.incomingFrame(ExtensionStack.java:214)
    at org.eclipse.jetty.websocket.common.Parser.notifyFrame(Parser.java:220)
    at org.eclipse.jetty.websocket.common.Parser.parse(Parser.java:258)
    at org.eclipse.jetty.websocket.common.io.AbstractWebSocketConnection.readParse(AbstractWebSocketConnection.java:632)
    at org.eclipse.jetty.websocket.common.io.AbstractWebSocketConnection.onFillable(AbstractWebSocketConnection.java:480)
    at org.eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.java:544)
    at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:635)
    at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:555)
    at java.lang.Thread.run(Thread.java:748)

3 个答案:

答案 0 :(得分:0)

首先,我们需要添加一个自定义的ServletContextListener:

public class Config implements ServletContextListener {
    private static final String ATTRIBUTE_NAME = "config";
    private String entry;

    @Override
    public void contextInitialized(ServletContextEvent event) {
        ServletContext servletContext = event.getServletContext();
        String entryName = servletContext.getInitParameter("entry");
        try {
            entry = new InitialContext().lookup("java:comp/env/entry");
        } catch (NamingException e) {
            throw new RuntimeException("Config failed: entry not found", e);
        }
        servletContext.setAttribute(ATTRIBUTE_NAME, this);
    }

    @Override
    public void contextDestroyed(ServletContextEvent event) {
    }

    public String getEntry() {
        return entry;
    }

    public static Config getInstance(ServletContext servletContext) {
        return (Config) servletContext.getAttribute(ATTRIBUTE_NAME);
    }
}

在连接接受时,方法onOpen写一个新的上下文,你可以通过将ServletContext添加到当前上下文的EndpointConfig映射中来简单地传递它

public class ServletSavingContext extends ServerEndpointConfig.Configurator {

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

}

现在上一堂课:

package com.example;

import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.EndpointConfig;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;

@ServerEndpoint(value = "/ws", configurator = ServletSavingContext.class)
public class WebSocket {

  private EndpointConfig config;

  @OnOpen
  public void onOpen(Session session, EndpointConfig config) throws IOException {
    this.config = config;
    String entry = Config.getInstance(config.getUserProperties("context")).getEntry();
    System.out.println("onOpen: entry = " + (entry != null ? entry : "Not found"));
  }

  @OnMessage
  public void onMessage(String message, Session session) throws IOException {
    String entry = Config.getInstance(config.getUserProperties("context")).getEntry();
    System.out.println("onMessage: entry = " + (entry != null ? entry : "Not found"));
  }
}

一些文档:http://docs.oracle.com/javaee/7/api/javax/websocket/EndpointConfig.html#getUserProperties%28%29

答案 1 :(得分:0)

注意:以下内容可能不是“最佳实践”,可能不能保证在所有容器上都可以使用,但在Tomcat上对我有用,并且可能对其他用户有用吗?

您可以将上下文分配给onOpen中的实例变量,然后在onMessage中使用相同的实例变量。

@ServerEndpoint("/ws")
public class WebSocket {

    private Context envContext;

    public String getEntry(Session session) {
        try {
            return this.envContext.lookup("entry");
        } catch (NamingException e) {
            e.printStackTrace();
            return null;
        }
    }

    @OnOpen
    public void onOpen(Session session) throws IOException {
        try {
            InitialContext ctx = new InitialContext();
            this.envContext = ctx.lookup("java:comp/env");
        } catch (NamingException e) {
            e.printStackTrace();
            return null;
        }

        String entry = getEntry(session);
        System.out.println("onOpen: entry = " + (entry != null ? entry : "Not found"));
    }

    @OnMessage
    public void onMessage(String message, Session session) throws IOException {
        String entry = getEntry(session);
        System.out.println("onMessage: entry = " + (entry != null ? entry : "Not found"));
    }

}

答案 2 :(得分:-2)

这是一种解决方法。我只是用前面存储的变量填充上下文:

@OnMessage
public void onMessage(String message, Session session) throws IOException, NamingException {
    // Somewhere after onOpen, populate the context
    InitialContext ctx = new InitialContext();
    ctx.createSubcontext("java:comp/env");
    ctx.bind("java:comp/env/entry", STORED_ENTRY);  // Store the variable as an attribute of the WebSocket

    String entry = getEntry(session);
    System.out.println("onMessage: entry = " + (entry != null ? entry : "Not found")); 
}