Spring WebSocket 的 使用

在我的《使用Session实现一个用户只能登录一次》的这篇文章后有个遗留的问题,怎么实现第二个

账户登录,第一个用户马上就可以收到信息。我当时的想法是做一个轮询。但是这样的做法会给后

台很大的压力。

现在可以很好的解决这个问题,就是使用websocket。

websocket是什么?websocket是一个损耗小,可跨域,全双工通信的互联网技术,也就是说可以

从服务端向客户端推送消息,这样就可以不用以前的轮询和长连接的方式。

轮询:就是在前端做一个方法一直访问后台,一直从后台取数据。

长连接:一个连接可以连续发送多个数据包,损耗大。

下面就开始使用Spring websocket。

一、引入jar包(Spring 版本为4.3.8.RELEASE)

扫描二维码关注公众号,回复: 1694959 查看本文章
<!--servlet-api-->
   		<dependency>  
    		<groupId>javax.servlet</groupId>  
    		<artifactId>javax.servlet-api</artifactId>  
    		<version>3.1.0</version>  
		</dependency> 
<dependency>  
   			<groupId>org.springframework</groupId>  
   			<artifactId>spring-websocket</artifactId>  
   			<version>${spring.version}</version>  
		</dependency>  
		
		<dependency>  
		   <groupId>org.springframework</groupId>  
		   <artifactId>spring-messaging</artifactId>  
		   <version>${spring.version}</version>  
		</dependency>

二、实现拦截器

import java.util.Map;

import javax.servlet.http.HttpSession;

import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.HandshakeInterceptor;

public class MyHandlerInterceptors implements HandshakeInterceptor {

	public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
			Map<String, Object> attributes) throws Exception {
		if (request instanceof ServletServerHttpRequest) {
            ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
            HttpSession session = servletRequest.getServletRequest().getSession(false);
            if (session != null) {
                attributes.put("sessionId",session.getId());
            }
        }
		return true;
	}

	public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
			Exception exception) {
	}

}

在建立连接前拦截和建立连接后拦截,主要使用前者,因为我们可以给WebSocketSession绑定

一些属性,就是向Map<String, Object> attributes 里面put值。

三、实现处理器

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

@Component
public class MyHandler extends TextWebSocketHandler{

	private static final List<WebSocketSession> users = new ArrayList<>();
	
	//连接关闭后
	public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
		users.remove(session);
		super.afterConnectionClosed(session, status);
	}

	//在连接建立
	public void afterConnectionEstablished(WebSocketSession session) throws Exception {
		users.add(session);
		session.sendMessage(new TextMessage("连接成功!!!"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())));
	}

	//处理Text消息
	protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
		System.out.println(message);
		session.sendMessage(new TextMessage("消息已接受!会及时处理"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())));
		super.handleTextMessage(session, message);
	}

	//抛出异常时处理
	public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
		if(session.isOpen()){
			session.close();
		}
        users.remove(session);
	}

	//支持部分信息(将一个信息拆分多个进行发送)
	public boolean supportsPartialMessages() {
		return false;
	}

	//单发消息
	public void sendMessageToUser(String httpSessionId, TextMessage message) {
        for (WebSocketSession user : users) {
            if (user.getAttributes().get("sessionId").equals(httpSessionId)) {
                try {
                    if (user.isOpen()) {
                        user.sendMessage(message);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
                break;
            }
        }
    }
	
	//服务端主动关闭连接
	public void close(String httpSessionId, TextMessage message) {
        for (WebSocketSession user : users) {
            if (user.getAttributes().get("sessionId").equals(httpSessionId)) {
                try {
                    if (user.isOpen()) {
                        user.sendMessage(message);
                        user.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
                break;
            }
        }
    }
	
	//群发消息(给所有的在线用户发送消息)
	public void sendMessageToUsers(TextMessage message) {
        for (WebSocketSession user : users) {
            try {
                if (user.isOpen()) {
                    user.sendMessage(message);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
	
	//给指定的多个用户发送消息
	public void sendMessageToUsers(String[] httpSessionIds, TextMessage message) {
        for (int i = 0; i < httpSessionIds.length; i++) {
			String httpSessionId = httpSessionIds[i];
			sendMessageToUser(httpSessionId, message);
		}
    }
}

四、使用java配置Spring-WebSocket

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;

import com.it.handle.MyHandler;
import com.it.interceptors.MyHandlerInterceptors;

@Configuration
@EnableWebSocket
public class WebScoketConfig implements WebSocketConfigurer {

	@Autowired
	MyHandler myHandler;
	
	@Override
	public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
		registry.addHandler(myHandler,"/test").addInterceptors(new MyHandlerInterceptors());
		registry.addHandler(myHandler,"/sockjs").addInterceptors(new MyHandlerInterceptors()).withSockJS();
	}

}
addHandler(handler,"url"),使用哪个处理器处理"url"过来的请求。addInterceptors(HandlerInt

erceptor),给这个请求绑定拦截器。setAllowedOrigins(String[ ])设置跨的域。withSockJS()

是该请求是通过JS的方式过来的,因为websocket 是html5技术,部分浏览器不支持,则需要通

过JS的方式。

五、使用websocket

因为MyHandler使用了@Component的注解则可以在你需要的地方把处理器注入进来即可,然后使用其方法。

如:

//登出
	@GetMapping("/logout")
	public @ResponseBody String logout(HttpSession session) {
		myHandler.close(session.getId(), new TextMessage("登出成功"));
		//销毁session
		session.invalidate();	
		return "success";
	}
六、前端的使用

1.创建连接

var ws = new WebSocket("ws://ip:port/项目名/url");addHandler(handler,url)。这两个要url相同。

2.发送消息

ws.send(data);

3.接收到消息触发

ws.onmessage = function(evt){

 var received_msg = evt.data;//received_msg就是传过来的消息

}

4.连接断开触发

ws.onclose = function(){

}

5.连接打开触发

ws.onopen = function(){
       

}

6.连接错误触发

ws.onerror = function(evt){

}

7.客户端关闭连接

ws.close();

例子:

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

<%
	String path = request.getContextPath();
	String basePath = request.getScheme() + "://"
			+ request.getServerName() + ":" + request.getServerPort()
			+ path + "/";
%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>主页</title>
<base href="<%=basePath%>">

<style type="text/css">
*{
	padding:0px;
	margin: 0px;
}
</style>
	<script type="text/javascript" src="./static/js/jquery.js"></script>


	<script type="text/javascript">
		function x() {
			$.get("logout",function (data) {
				alert(data=='success'?'登出成功':'登出失败');
				location.href='login';
			});
		}
	
         function WebSocketTest()
         {
            if ("WebSocket" in window)
            {
               alert("您的浏览器支持 WebSocket!");
               
               // 打开一个 web socket
               var ws = new WebSocket("ws://127.0.0.1/SSMWebSocket/test");
                
               //alert(ws);
               ws.onopen = function()
               {
                  // Web Socket 已连接上,使用 send() 方法发送数据
                  ws.send("发送数据");
                  alert("数据发送中...");
               };
                
               ws.onmessage = function (evt) 
               { 
                  var received_msg = evt.data;
                  alert("数据已接收:"+received_msg);
               };
                
               ws.onclose = function()
               { 
                  // 关闭 websocket
                  alert("连接已关闭..."); 
               };
               
               ws.onerror = function(evt){
            	   ws.close();
               }
               
            }
            
            else
            {
               // 浏览器不支持 WebSocket
               alert("您的浏览器不支持 WebSocket!");
            }
         }
      </script>

</head>
<body>
<div style="width:100%;height:auto;text-align:center;">
	<div id="sse">
        <a href="javascript:WebSocketTest()">运行 WebSocket</a>
    </div>
    
    <button onclick="x()">登出</button>
</div>
</body>
</html>


猜你喜欢

转载自blog.csdn.net/qq_33422712/article/details/79269857