spring websocket 项目搭建以及请求的基本过程

浏览器客户端和服务器建立起websocket的链接,最初也是http请求握手,通过httpServletRequest发送http请求到服务器,其中头部就包含需要请求websocket链接的一系列信息,大概过程如下

1.客户端请求一个链接,头部中包含如下信息

GET /demo HTTP/1.1 
Host: example.com 
Connection: Upgrade 
Sec-WebSocket-Key2: 12998 5 Y3 1 .P00 
Upgrade: WebSocket 
Sec-WebSocket-Key1: 4@1 46546xW%0l 1 5 
Origin: http://example.com 
[8-byte security key] 

2.服务器根据头部中的Sec-WebSocket-Key2,Sec-WebSocket-Key1,Upgrade,[8-byte security key] 知道客户端需要一个websocket协议链接,于是返回一个消息,包含如下头部

HTTP/1.1 101 WebSocket Protocol Handshake 
Upgrade: WebSocket 
Connection: Upgrade 
WebSocket-Origin: http://example.com 
WebSocket-Location: ws://example.com/demo 
[16-byte hash response]

3.客户端收到消息之后,建立起websocket链接,这时就可以进行实时通信了

我们可以定义一个处理器来实现WebSocketHandler处理请求

public class MyWebSocketHandler implements  WebSocketHandler{

    /**
     * webscoket建立好链接之后的处理函数
     * @param session 当前websocket的会话id,打开一个websocket通过都会生成唯一的一个会话,可以通过该id进行发送消息到浏览器客户端
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
         // TODO Auto-generated method stub
    }

    /**
     * 客户端发送服务器的消息时,的处理函数,在这里收到消息之后可以分发消息
     */
    @Override
    public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
        // TODO Auto-generated method stub

    }

    /**
     * 消息传输过程中出现的异常处理函数
     */
    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        // TODO Auto-generated method stub

    }


    /**
     * websocket链接关闭的回调
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
        // TODO Auto-generated method stub

    }

    /**
     * 是否支持处理拆分消息,返回true返回拆分消息
     */
    @Override
    public boolean supportsPartialMessages() {
        // TODO Auto-generated method stub
        return false;
    }

}

websocket的链接建立是基于http握手协议,我们可以添加一个拦截器处理握手之前和握手之后过程

public class MyHandShakeInterceptor implements HandshakeInterceptor{

    /**
     * 握手之前,若返回false,则不建立链接
     */
    @Override
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
            Map<String, Object> attributes) throws Exception {
        // TODO Auto-generated method stub
        return true;
    }

    /**
     * 握手之后
     */
    @Override
    public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
            Exception exception) {
        // TODO Auto-generated method stub

    }

}

接下来,需要我们把处理器和拦截器注册到spring websocket中

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
         registry.addHandler(new MyWebSocketHandler(), "/portfolio")//添加一个处理器还有定义处理器的处理路径
         .addInterceptors(new MyHandShakeInterceptor())
         .withSockJS();
    }
}

在这里我们用到.withSockJS(),SockJS是spring用来处理浏览器对websocket的兼容性,目前浏览器支持websocket还不是很好,特别是IE11以下.SockJS能关键浏览器能否支持websocket来提供三种方式用于websocket请求,三种方式分别是 WebSocket, HTTP Streaming以及 HTTP Long Polling

SockJS提供了浏览器客户端的js库,在浏览器我们请求websocket就这么用

var socket = new SockJS('/whats/portfolio');//项目名称 + 处理器拦截路径名就会打开的目的websocket链接口

/**
 * 建立成功的回调函数
 */
socket.onopen = function() {
    console.log('open');
};

/**
 * 服务器有消息返回的回调函数
 */
socket.onmessage = function(e) {
    console.log('message', e.data);
};

/**
 * websocket链接关闭的回调函数
 */
socket.onclose = function() {
    console.log('close');
};

然后客户端发送一个消息

document.getElementById("ws").onclick = function() {
    socket.send("fff");
}

服务器MyWebSocketHandler中,通过handlemessage接收消息并进行分发

/**
  * 客户端发送服务器的消息时,的处理函数,在这里收到消息之后可以分发消息
  */
@Override
public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
    //获取消息
   String body = (String) message.getPayload(); 

   //一系列的处理之后...

   //发送消息 
    session.sendMessage(message);   
}

session可以用来标注客户端id,相对于我们的httpsession,这样,如果我们想做一个精准推送和全部推送,我们可以这么做

首先在自定义的处理其中,建一个队列来存储连进来的websocketsession

public class MyWebSocketHandler implements  WebSocketHandler{

    private List<WebSocketSession> users = new ArrayList<WebSocketSession>(); //存放WebSocketSession的队列

    /**
     * webscoket建立好链接之后的处理函数
     * @param session 当前websocket的会话id,打开一个websocket通过都会生成唯一的一个会话,可以通过该id进行发送消息到浏览器客户端
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {

        session.getAttributes().put("userid", "xxxx");//如果有用户登录,可以把用户的id绑定到session里面,便于后面做精准推送

        users.add(session); //每个链接来的客户端都把WebSocketSession保存进来
    }

   //...
}

然后呢,我们在接收到消息的时候,就可以直接的根据需要精准推送到用户或者全部推送了

/**
 * 客户端发送服务器的消息时,的处理函数,在这里收到消息之后可以分发消息
 */
@Override
public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
    // TODO Auto-generated method stub
    for (WebSocketSession webSocketSession : users) {
        //Long id = (Long) session.getAttributes().get("userid");//可以通过获取userid进行匹配,从而进行精准推送
        message = new TextMessage("ggg");
        webSocketSession.sendMessage(message); //全部推送
    }

}

spring websocket大概的请求过程就是这样子,这是基础的请求过程,细心的同学可能发现,如果我有很多种不同的业务请求,是不是要写很多个处理器??能不能只实现一个处理器,然后由这个处理器来进行分发处理,做到类似springmvc的DispatcherServlet那样子??下次研究看看

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值