WebSocket 及与 SpringBoot 的集成
WebSocket 对象
以下 API 用于创建 WebSocket 对象。
var Socket = new WebSocket(url, [protocol] );
WebSocket 属性
WebSocket 事件
WebSocket 方法
WebSocket 服务器端实现
1)、编写通信握手拦截器
/**
* WebSocket通信握手拦截器
* 它只拦截握手
*/
@Component
public class SpringBootHandshakeInterceptor implements HandshakeInterceptor{
/**
* 握手之前
* ServerHttpRequest : 请求对象
* ServerHttpResponse : 响应对象
* * WebSocketHandler : WebSocket服务处理类,在这里指的是SpringBootWebSocketHandler
* attributes : WebSocketSession.getAttributes()
*/
@Override
public boolean beforeHandshake(ServerHttpRequest serverHttpRequest, ServerHttpResponse
serverHttpResponse, WebSocketHandler wsHandler,Map<String, Object> attributes) throws Exception {
ServletServerHttpRequest servletServerHttpRequest = (ServletServerHttpRequest) serverHttpRequest;
//得到Http协议的请求对象
HttpServletRequest request = servletServerHttpRequest.getServletRequest();
HttpSession session = request.getSession(true);
System.out.println("握手拦截器^^^^^^^^^^^^
request.getParameter(\"param\")=>"+request.getParameter("param"));
System.out.println("握手拦截器^^^^^^^^^^^^
request.getParameter(\"token\")=>"+request.getParameter("token"));
System.out.println("握手拦截器^^^^^^^^^^^^
HttpSession.getAttribute(\"user\")=>"+session.getAttribute("user"));
//数据中转 可以把http协议的会话对象数据中转到ws协议的会话对象中
attributes.put("param", request.getParameter("param"));
//非前后端分离架构:把HttpSession中的数据中转到WebSocketSession中
if(session.getAttribute("user") != null)attributes.put("user", session.getAttribute("user"));
//如果是前后端分离架构:把Http协议中的token令牌中转到ws协议的WebSocketSession中
attributes.put("token", request.getParameter("token"));
return true;
}
/**
* 握手之后
*/
@Override
public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler
wsHandler,Exception exception) {
System.out.println(“握手之后”);
}
}
2)、 编写 WebSocket 服务配置类
/**
* WebSocket服务配置类
*
*/
@Configuration //单例模式bean
@EnableWebSocket //启动WebSocket服务器
public class SpringBootWebSocketConfigurer implements WebMvcConfigurer , WebSocketConfigurer{
@Autowired
private SpringBootWebSocketHandler handler;
@Autowired
private SpringBootHandshakeInterceptor handshakeInterceptor;
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
//-------------------- 允许跨域访问WebSocket ------------------------
String[] allowsOrigins = {"*"};//允许连接的域,只能以http或https开头
/**
* http://localhost:8080
* http://localhost:8080/index.html
*/
//7. 设置websocket服务器地址 ws://localhost:8080/SpringBootWebSocket
registry.addHandler(handler,
"/SpringBootWebSocket").addInterceptors(handshakeInterceptor).setAllowedOrigins(allowsOrigins);
}
}
3)、自定义实现 WebSocket 服务处理类
@Component
public class SpringBootWebSocketHandler implements WebSocketHandler{
//存储所有客户端的会话WebSocketSession,key使用客户端的唯一标识方便存取
private static Map<String, WebSocketSession> allWebSocketSession = new HashMap<String,
WebSocketSession>();
/**
* 1. 客户端成功建立连接时触发
*/
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
System.out.println("客户端成功建立连接=>"+session.getId());
//在ws服务类中任何位置都可以使用以下取值
System.out.println("WebSocketSession.getAttributes().get(\"param\")"+session.getAttributes().get("param"));
System.out.println("WebSocketSession.getAttributes().get(\"user\")"+session.getAttributes().get("user"));
System.out.println("WebSocketSession.getAttributes().get(\"token\")"+session.getAttributes().get("token"));
//存储所有客户端的WebSocketSession
allWebSocketSession.put((String)session.getAttributes().get("param"), session);
}
/**
* 2. 接收客户端数据时触发
*/
@Override
public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
System.out.println("接收客户端数据=>"+message.getPayload().toString());
//给客户端回一句话意思意思,随便给客户端发数据
this.send(session, "&&&&&&服务器回复的&&&&&&"+message.getPayload().toString());
}
/**
* 3. 通信异常时触发
*/
@Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
System.out.println("通信异常=>"+session.getId());
}
/**
* 4.客户端关闭连接时触发
*/
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
System.out.println("客户端关闭连接=>"+session.getId());
//移除通行关闭的客户端
allWebSocketSession.remove((String)session.getAttributes().get("param"));
}
/**
* 是否支持分段传输
*/
@Override
public boolean supportsPartialMessages() {
return false; //一次输出完毕
}
/**
* 5.服务器主动发送数据
* @param webSocketSession
* @param msg
*/
public void send(WebSocketSession webSocketSession,String msg) {
try {
webSocketSession.sendMessage(new TextMessage(msg));
} catch (IOException e) {
e.printStackTrace();}
}
/**
* 6. 服务器主动关闭通信
* @param webSocketSession
* @param msg
*/
public void close(WebSocketSession webSocketSession,String msg) {
try {
webSocketSession.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
4)、 编写 MVC 页面访问的 Controller
@Controller
public class WelcomeController {
/**
* http://localhost:8080
* @return
*/
@RequestMapping("/")
public String welcome(HttpSession session) {
session.setAttribute("user", "我是HttpSession中的数据");
return "index.html";
}
}
WebSocket 客户端实现
客户端发送消息的页面 index.html,代码如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>WebSocket客户端</title>
<script type="text/javascript" src="jquery.min.js" ></script>
</head>
<body>
<input type="text" id="msg" /><button onclick="sendMsg()">发给服务器</button>
<script type="text/javascript">
//6. 主动发送数据给服务器
function sendMsg(){
websocket.send( $('#msg').val() );
}
//7. 主动关闭通信
function close(){
websocket.close();
}
</script>
<script type="text/javascript">
//WebSocket服务器地址
var wsurl = "ws://localhost:8080/SpringBootWebSocket?token=cocococococcoc¶m=张三";
//1. 与服务器建立websocket连接
var websocket = new WebSocket(wsurl);
// 2. 连接成功
websocket.onopen = function(event){
console.log("成功与服务器建立连接!!!");
console.log(event);
}
//3. 接收服务器数据
websocket.onmessage = function(event){
console.log("wesocket接收服务器数据event.data=>"+event.data);
console.log(event);
}
//4. 服务器发生异常错误
websocket.onerror = function(event) {
console.log("WebSocket:服务器发生异常错误 ");
console.log(event);
};
//5. 服务器关闭
websocket.onclose = function(event) {
console.log("WebSocket:已关闭");
console.log(event);
};
</script>
</body>
</html>