Tomcat7中实现WebSocket 使用HttpSession?

刘学炜 发布于 2014/06/22 19:28
阅读 17K+
收藏 2
Tomcat7中实现WebSocket 中 Endpoint的Session跟httpSession不是同一个东西,如何在WebSocket中访问HttpSocket呢?这样可以获取HttpSocket中的对象,例如getAttribute()
加载中
0
刘学炜
刘学炜
解决了:
首先要继承 ServerEndpointConfig,并实现 modifyHandshake方法,该方法有个

HandshakeRequest参数,代码如下:

import javax.servlet.http.HttpSession;
import javax.websocket.HandshakeResponse;
import javax.websocket.server.HandshakeRequest;
import javax.websocket.server.ServerEndpointConfig;

public class GetHttpSessionConfigurator extends ServerEndpointConfig.Configurator
{
    @Override
    public void modifyHandshake(ServerEndpointConfig config, 
                                HandshakeRequest request, 
                                HandshakeResponse response)
    {
        HttpSession httpSession = (HttpSession)request.getHttpSession();
        config.getUserProperties().put(HttpSession.class.getName(),httpSession);
    }
}
这时可以在实现ServerEndPoint的类中作为configurator参数
package action;

import java.io.IOException;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;

import javax.servlet.http.HttpSession;
import javax.websocket.EndpointConfig;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import org.apache.log4j.Logger;

import common.GetHttpSessionConfigurator;
import common.HTMLFilter;

@ServerEndpoint(value = "/action/websocket/chat",configurator=GetHttpSessionConfigurator.class)
public class ChatAction{
private final static Logger log = Logger.getLogger(ChatAction.class);
    private static final Set<ChatAction> onlineUsers =
            new CopyOnWriteArraySet<ChatAction>();
    private String nickname;
    private Session session;
    private HttpSession httpSession;
  
    @OnOpen
    public void start(Session session, EndpointConfig config) {
        this.session = session;
        this.httpSession = (HttpSession) config.getUserProperties()
                .get(HttpSession.class.getName());
        this.nickname=(String) httpSession.getAttribute("loginOperatorId");
        onlineUsers.add(this);
        String message = String.format("* %s %s", nickname, " from websocket 上线了...");
        broadcast(message);
    }

    @OnClose
    public void end(Session session) {
        onlineUsers.remove(this);
        String message = String.format("* %s %s",
                nickname, " from websocket 已经离开...");
        broadcast(message);
    }

    @OnMessage
    public void incoming(String message, EndpointConfig config) {
        // Never trust the client
        String filteredMessage = String.format("%s: %s",
                nickname, HTMLFilter.filter(message.toString()));
        broadcast(filteredMessage);
    }

    @OnError
    public void onError(Throwable t) throws Throwable {
        log.error("错误: " + t.toString(), t);
    }

    private static void broadcast(String msg) {
        for (ChatAction client : onlineUsers) {
            try {
                synchronized (client) {
                    client.session.getBasicRemote().sendText(msg);
                }
            } catch (IOException e) {
                log.debug("错误: 消息发送失败!", e);
                onlineUsers.remove(client);
                try {
                    client.session.close();
                } catch (IOException e1) {
                    // Ignore
                }
                String message = String.format("* %s %s",
                        client.nickname, " from websocket 已经离开...");
                broadcast(message);
            }
        }
    }
}

刘学炜
刘学炜
@osc4alex 跟你说的意思差不多 要在第一阶段获取httpsession才可以
1
小杨阿哥哥
小杨阿哥哥

引用来自“osc4alex”的评论

Websocket的连接分为两个阶段,第一阶段使用http协议进行握手,此时,可以通过httprequest获取当前用户的session,在第二阶段建立socket连接的时候创建websocket的session ,可以通过介入握手过程,保存两个session之间的关联。

具体实现可以参考spring中的HttpSessionHandshakeInterceptor的实现

<websocket:handlers>
        <websocket:mapping path="/demo" handler="demoWebSocketHandler"/>
        <websocket:handshake-interceptors>
            <ref bean="demoHandshakeInterceptor" ></ref>
        </websocket:handshake-interceptors>
        <websocket:sockjs>

        </websocket:sockjs>
    </websocket:handlers>
    <bean class="com.wsapi.demo.springwebsocket.DemoHandshakeInterceptor" id="demoHandshakeInterceptor"/>
    <bean class="com.wsapi.demo.springwebsocket.DemoWebSocketHandler" id="demoWebSocketHandler"></bean>



0
osc4alex
osc4alex

Websocket的连接分为两个阶段,第一阶段使用http协议进行握手,此时,可以通过httprequest获取当前用户的session,在第二阶段建立socket连接的时候创建websocket的session ,可以通过介入握手过程,保存两个session之间的关联。

具体实现可以参考spring中的HttpSessionHandshakeInterceptor的实现

osc4alex
osc4alex
回复 @小杨阿哥哥 : 1. 检查拦截器配置的是否正确 2. 客户端js在进行连接时的地址是否正确,127.0.0.1和localhost可能有不同的效果
小杨阿哥哥
小杨阿哥哥
回复 @小杨阿哥哥 : 但是无法进入拦截器。。
小杨阿哥哥
小杨阿哥哥
哥,我这里配置了interceptor但是在握手时没有进入这个拦击器。
0
红薯
红薯
用 tomcat 8 吧,巨简单!
红薯
红薯
不要依赖开发环境
刘学炜
刘学炜
eclipse 还不支持tomcat8啊,还得装个IntelliJ
0
离合不骚

引用来自“刘学炜”的评论

解决了:
首先要继承 ServerEndpointConfig,并实现 modifyHandshake方法,该方法有个

HandshakeRequest参数,代码如下:

import javax.servlet.http.HttpSession;
import javax.websocket.HandshakeResponse;
import javax.websocket.server.HandshakeRequest;
import javax.websocket.server.ServerEndpointConfig;

public class GetHttpSessionConfigurator extends ServerEndpointConfig.Configurator
{
    @Override
    public void modifyHandshake(ServerEndpointConfig config, 
                                HandshakeRequest request, 
                                HandshakeResponse response)
    {
        HttpSession httpSession = (HttpSession)request.getHttpSession();
        config.getUserProperties().put(HttpSession.class.getName(),httpSession);
    }
}
这时可以在实现ServerEndPoint的类中作为configurator参数
package action;

import java.io.IOException;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;

import javax.servlet.http.HttpSession;
import javax.websocket.EndpointConfig;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import org.apache.log4j.Logger;

import common.GetHttpSessionConfigurator;
import common.HTMLFilter;

@ServerEndpoint(value = "/action/websocket/chat",configurator=GetHttpSessionConfigurator.class)
public class ChatAction{
private final static Logger log = Logger.getLogger(ChatAction.class);
    private static final Set<ChatAction> onlineUsers =
            new CopyOnWriteArraySet<ChatAction>();
    private String nickname;
    private Session session;
    private HttpSession httpSession;
  
    @OnOpen
    public void start(Session session, EndpointConfig config) {
        this.session = session;
        this.httpSession = (HttpSession) config.getUserProperties()
                .get(HttpSession.class.getName());
        this.nickname=(String) httpSession.getAttribute("loginOperatorId");
        onlineUsers.add(this);
        String message = String.format("* %s %s", nickname, " from websocket 上线了...");
        broadcast(message);
    }

    @OnClose
    public void end(Session session) {
        onlineUsers.remove(this);
        String message = String.format("* %s %s",
                nickname, " from websocket 已经离开...");
        broadcast(message);
    }

    @OnMessage
    public void incoming(String message, EndpointConfig config) {
        // Never trust the client
        String filteredMessage = String.format("%s: %s",
                nickname, HTMLFilter.filter(message.toString()));
        broadcast(filteredMessage);
    }

    @OnError
    public void onError(Throwable t) throws Throwable {
        log.error("错误: " + t.toString(), t);
    }

    private static void broadcast(String msg) {
        for (ChatAction client : onlineUsers) {
            try {
                synchronized (client) {
                    client.session.getBasicRemote().sendText(msg);
                }
            } catch (IOException e) {
                log.debug("错误: 消息发送失败!", e);
                onlineUsers.remove(client);
                try {
                    client.session.close();
                } catch (IOException e1) {
                    // Ignore
                }
                String message = String.format("* %s %s",
                        client.nickname, " from websocket 已经离开...");
                broadcast(message);
            }
        }
    }
}

我参照代码可以启动就报错,如下:
javax.websocket.DeploymentException: A parameter of type [interface javax.websocket.server.ServerEndpointConfig] was found on method[onOpen] of class [java.lang.reflect.Method] that did not have a @PathParam annotation
请教这是什么原因啊?版本问题吗?
离合不骚
Apache Tomcat/7.0.53
刘学炜
刘学炜
tomcat什么版本?
返回顶部
顶部