• spring WebSocket详解


    场景

    websocket是Html5新增加特性之一,目的是浏览器与服务端建立全双工的通信方式,解决http请求-响应带来过多的资源消耗,同时对特殊场景应用提供了全新的实现方式,比如聊天、股票交易、游戏等对对实时性要求较高的行业领域。

    背景

    在浏览器中通过http仅能实现单向的通信,comet可以一定程度上模拟双向通信,但效率较低,并需要服务器有较好的支持; flash中的socket和xmlsocket可以实现真正的双向通信,通过 flex ajax bridge,可以在javascript中使用这两项功能. 可以预见,如果websocket一旦在浏览器中得到实现,将会替代上面两项技术,得到广泛的使用.面对这种状况,HTML5定义了WebSocket协议,能更好的节省服务器资源和带宽并达到实时通讯。目前各大主流浏览器都支持websocket,IE浏览器要IE10+

    一、POM依赖

    POM依赖,spring4.1.4.RELEASE,spring核心依赖请自行添加,下面是websocket相关jar

    <dependency>
    	<groupId>javax.websocket</groupId>
    	<artifactId>javax.websocket-api</artifactId>
    	<version>1.0</version>
    	<scope>provided</scope>
    </dependency>
    <dependency>
    	<groupId>org.springframework</groupId>
    	<artifactId>spring-websocket</artifactId>
    	<version>4.1.4.RELEASE</version>
    </dependency>
    

    二、WebSocket入口

    @Configuration
    @EnableWebMvc
    @EnableWebSocket
    public class WebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer {
        @Override
        public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
            //允许连接的域,只能以http或https开头
            String[] allowsOrigins = {"http://www.xxx.com"};
            
           //WebIM WebSocket通道
            registry.addHandler(chatWebSocketHandler(),"/			webSocketIMServer").setAllowedOrigins(allowsOrigins).addInterceptors(myInterceptor());
            registry.addHandler(chatWebSocketHandler(), "/sockjs/w			ebSocketIMServer").setAllowedOrigins(allowsOrigins).addInterceptors(myInterceptor()).withSockJS();
        }
        @Bean
        public ChatWebSocketHandler chatWebSocketHandler() {
            return new ChatWebSocketHandler();
        }
        @Bean
        public WebSocketHandshakeInterceptor myInterceptor(){
        	return new WebSocketHandshakeInterceptor();
        }
    }
    
    1. 实现WebSocketConfigurer接口,重写registerWebSocketHandlers方法,这是一个核心实现方法,配置websocket入口,允许访问的域、注册Handler、SockJs支持和拦截器。
    2. registry.addHandler注册和路由的功能,当客户端发起websocket连接,把/path交给对应的handler处理,而不实现具体的业务逻辑,可以理解为收集和任务分发中心。
    3. setAllowedOrigins(String[] domains),允许指定的域名或IP(含端口号)建立长连接,如果只允许自家域名访问,这里轻松设置。如果不限时使用"*"号,如果指定了域名,则必须要以http或https开头。
    4. addInterceptors,顾名思义就是为handler添加拦截器,可以在调用handler前后加入我们自己的逻辑代码。
    5. spring websocket也支持STOMP协议,下回再分享。

    三、拦截器实现

    public class WebSocketHandshakeInterceptor implements HandshakeInterceptor {
    
        @Override
        public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object
                    > attributes) throws Exception {
            if (request instanceof ServletServerHttpRequest) {
                attributes.put("username",userName);
            }
            return true;
        }
    
        @Override
        public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {
    
        }
    }
    

    beforeHandshake,在调用handler前处理方法。常用在注册用户信息,绑定WebSocketSession,在handler里根据用户信息获取WebSocketSession发送消息。

    四、Handler处理类

    public class ChatWebSocketHandler extends TextWebSocketHandler{
    	
    	private final static List<WebSocketSession> sessions = Collections.synchronizedList(new ArrayList<WebSocketSession>());
    	//接收文本消息,并发送出去
    	@Override
    	protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
    		chatTextMessageHandler(message.getPayload());
    		super.handleTextMessage(session, message);
    	}
    	//连接建立后处理
    	@SuppressWarnings("unchecked")
    	@Override
    	public void afterConnectionEstablished(WebSocketSession session) throws Exception {
    		logger.debug("connect to the websocket chat success......");
    		sessions.add(session);
    		//处理离线消息
    	}
    	//抛出异常时处理
    	@Override
    	public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
    		if(session.isOpen()){
    			session.close();
    		}
    		logger.debug("websocket chat connection closed......");
    		sessions.remove(session);
    	}
    	//连接关闭后处理
    	@Override
    	public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
    		logger.debug("websocket chat connection closed......");
    		sessions.remove(session);
    	}
    
    	@Override
    	public boolean supportsPartialMessages() {
    		return false;
    	}
    }
    

    五、客户端连接

    var host = window.location.host;
    var websocket;
    if ('WebSocket' in window) {
    	websocket = new ReconnectingWebSocket("ws://"
    		+ host + "/webSocketIMServer", null, {debug:true, maxReconnectAttempts:4});
    } else if ('MozWebSocket' in window) {
    	websocket = new MozWebSocket("ws://" + host
    		+ "/webSocketIMServer");
    } else {
    	websocket = new SockJS("http://" + host
    			+ "/sockjs/webSocketIMServer");
    }
    websocket.onopen = function(evnt) {
    	console.log("websocket连接上");
    };
    websocket.onmessage = function(evnt) {
    	messageHandler(evnt.data);
    };
    websocket.onerror = function(evnt) {
    	console.log("websocket错误");
    };
    websocket.onclose = function(evnt) {
    	console.log("websocket关闭");
    }
    

    这里用到了ReconnectingWebSocket.js,对浏览器自带websocket添加了扩展,例如重连,连接超时时间,失败重连间隔,尝试连接最大次数等。
    项目主页:ReconnectingWebSocket

    ps:如果有疑问,你也可以关注我的微信公众号『ITNotes』, 一起交流学习 。

  • 相关阅读:
    linux 防火墙管理
    自动化运维监控工具有哪些?常用的开源运维监控工具大全
    编程必备github代码仓库使用
    安全加密算法
    浅笑若风之高效工作流程
    jmeter压力测试工具使用
    ES扩容实战记录
    在5G+AI+CLCP下拉动互联网走向物联网
    设计模式之简单工厂模式
    设计模式之单例模式
  • 原文地址:https://www.cnblogs.com/nosqlcoco/p/5860730.html
Copyright © 2020-2023  润新知