websocket
WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议.
允许服务器端主动向客户端发送数据
引入pom依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
<version>1.3.5.RELEASE</version>
</dependency>
websocket的配置文件
WebSocket服务器处理器
package com.medical.medical.util;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.*;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* WebSocket服务器处理器
*/
@Component
public class MyWebSocketHandler implements WebSocketHandler {
private static Map<String, WebSocketSession> userIdMap = new HashMap<String, WebSocketSession>();//map中存储当前登录用户的ID,和客户端WebSocketSession
@Autowired
private ObjectMapper jackson;
/**
* @OnOpen
* 连接建立后处理
*/
@Override
public void afterConnectionEstablished(WebSocketSession webSocketSession)throws Exception {
// System.out.println("@OnOpen webSocketSession中的 userName=>"+webSocketSession.getAttributes().get("userName"));//取出weSocketSession中的当前用户名称
// System.out.println("@OnOpen webSocketSession中的 uId=>"+webSocketSession.getAttributes().get("uId"));//取出weSocketSession中的当前用户Id
String uId = (String) webSocketSession.getAttributes().get("uId");
if (uId != null) {
userIdMap.put(uId, webSocketSession);//客户端连接服务器时,把当前用户Id和当前用户weSocketSession存储起来备用,以后用weSocketSession给客户端发消息
}
//测试发送一句回复的话
//sendMessageToUser(uId, uId+"你好我是服务器发送来的数据你接收到显示在控制台了吧");
}
/**
* @OnMessage
*
*/
@Override
public void handleMessage(WebSocketSession webSocketSession, WebSocketMessage<?> message)
throws Exception {
System.err.println("@OnMessage服务器接收到客户端的数据 =>"+message.getPayload().toString());
if(message.getPayloadLength()==0)return;
//Message msg=jackson.readValue(message.getPayload().toString(),Message.class);
//Message msg=newObjectMapper().readValue(message.getPayload().toString(),Message.class);
//sendMessageToUser(msg.getTo(), new TextMessage(newObjectMapper().writeValueAsString(msg)));
String toUserId = (String) webSocketSession.getAttributes().get("uId");//取出自己的uId
String toUserMessage = "你好你自己发的你自己收到我的数据了吗";
sendMessageToUser(toUserId, toUserMessage);//给指定userId的用户发送信息
String broadMessage = "大家好,我是新来的,请多多关照!!!";
broadcast(broadMessage);//给当前服务器所有客户端发送信息
}
/**
* @OnError
* 抛出异常时处理
*/
@Override
public void handleTransportError(WebSocketSession webSocketSession,Throwable exception)
throws Exception {
String uId = (String) webSocketSession.getAttributes().get("uId");
System.err.println("@OnError服务器与"+uId+"客户 端"+webSocketSession.getAttributes().get("userName")+"通信异常错误=>"+exception);
}
/**
* @OnClose
* 客户端关闭连接后
*/
@Override
public void afterConnectionClosed(WebSocketSession webSocketSession, CloseStatus closeStatus) throws Exception {
String uId = (String) webSocketSession.getAttributes().get("uId");
System.out.println("@OnClose客户端浏览器关闭"+uId+"客户端"+webSocketSession.getAttributes().get("userName"));
// 移除WebSocket会话
userIdMap.remove(uId);//移除已经关闭的客户端
}
/**
* WebSocketHandler是否处理部分消息。
*/
@Override
public boolean supportsPartialMessages() {
return false;//WebSocket接收信息不拆分.
}
/**
* 给所有在线用户发送消息
* 多线程发送
* @param message
* @throws IOException
*/
public void broadcast(final String message) throws IOException {
final TextMessage textMessage = new TextMessage(message);
Iterator<Map.Entry<String, WebSocketSession>> it = userIdMap.entrySet().iterator();
// 多线程群发
while (it.hasNext()) {
final Map.Entry<String, WebSocketSession> entry = it.next();
if (entry.getValue().isOpen()) {
// entry.getValue().sendMessage(message);
new Thread(new Runnable() {
public void run() {
try {
if (entry.getValue().isOpen()) {
entry.getValue().sendMessage(textMessage);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
}
}
/**
* 给某个用户发送消息
* @param uid
* @param message
* @throws IOException
*/
public void sendMessageToUser(String uid, String message)throws IOException {
WebSocketSession session = userIdMap.get(uid);
if (session != null && session.isOpen()){ ;
session.sendMessage(new TextMessage(message));
}
}
}
启动websocket服务器
package com.medical.medical.util;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.socket.WebSocketHandler;
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 javax.annotation.Resource;
@Component //扫描到Spring IOC容器
@EnableWebSocket //启用WebSocket服务器
public class MyWebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer {
@Resource
MyWebSocketHandler myWebSocketHandler;
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
//WebSocket通道
registry.addHandler((WebSocketHandler) myWebSocketHandler, "/myWebsocket").addInterceptors(new
MyHandShakeInterceptor());
registry.addHandler((WebSocketHandler) myWebSocketHandler, "/myWebsocket/sockjs").addInterceptors(new
MyHandShakeInterceptor()).withSockJS();
//-------------------- 允许跨域访问WebSocket ------------------------
String[] allowsOrigins = {"*"};//允许连接的域,只能以http或https开头
}
}
websocket拦截器
package com.medical.medical.util;
import com.sun.javafx.collections.MappingChange;
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;
import javax.servlet.http.HttpSession;
import java.util.Map;
/**
* 拦截器实现
* Socket建立连接(握手)和断开
*/
public class MyHandShakeInterceptor implements HandshakeInterceptor {
/**
* 在握手之前执行该方法, 继续握手返回true, 中断握手返回false. 通过attributes参数设置
WebSocketSession的属性
*/
@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
//取出javax.servlet.http.HttpSession中的 uId 属性值
System.out.println("在握手之前执行该方法.Websocket:用户连接成功 [HttpSession中属性 uId:" + ((ServletServerHttpRequest) request).getServletRequest().getSession(false).getAttribute("uId") + "]已经建立连接");
if (request instanceof ServletServerHttpRequest) {
ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
HttpSession session = servletRequest.getServletRequest().getSession(false);
String sessionId = session.getId();
System.out.println("HandshakeInterceptor 开始处理一次WebSocket服务+sessionId=>"+sessionId);
System.out.println("HttpSession中的userName=>"+session.getAttribute("userName"));
System.out.println("HttpSession中的uId=>"+session.getAttribute("uId"));
System.out.println("HandshakeInterceptor WebSocketSession中的uId设置值之前 =>"+attributes.get("uId"));
// 标记用户
String uId = (String) session.getAttribute("uId");
if( uId != null ){
attributes.put("uId", uId);//向WebSocketSession中放入uId属性值
attributes.put("userName", session.getAttribute("userName"));
}else{
//return false;//禁止访问WebSocket服务
return true;//放行 WebSocket服务
}
}
return true;
}
/**
* 在握手之后执行该方法. 无论是否握手成功都指明了响应状态码和相应头.
*/
@Override
public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response,
WebSocketHandler wsHandler, Exception exception) {
ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
HttpSession session = servletRequest.getServletRequest().getSession(false);
String sessionId = session.getId();
System.out.println("在握手之后执行该方法.处理完一次WebSocket服务 sessionId=>"+sessionId);
}
}
##controller
–注入socket
@Autowired
MyWebSocketHandler myWebSocketHandler;
myWebSocketHandler.broadcast(json.toJSONString()); // 给所有用户发送消息
//发送消息 拦截器中webSocketsession中存入的uId json 要发送的消息
myWebSocketHandler.sendMessageToUser(uId,json.toJSONString()); //调用方法给用户发送新消息
##前台
–将代码放在js文件中 ,使用js函数将声明的webSocket客户端返回 在需要的页面接收
定义function getWebSocket()
var wsurl = "ws://localhost:8080/myWebsocket"; //WebSocket服务器地址
var regissocket;//声明一个WebSocket客户端
//检测浏览器兼容性
if ('WebSocket' in window) {
regissocket = new WebSocket(wsurl);//当前所有浏览器全部都支持
console.log("当前所有浏览器全部都支持 WebSocket in window =>"+regissocket);
} else if ('MozWebSocket' in window) {
regissocket = new MozWebSocket(wsurl);//基本没用
console.log("基本没用 MozWebSocket in window =>"+regissocket);
} else {
regissocket = new SockJS(sockurl);//基本没用
console.log("基本没用 else new SockJS=>"+regissocket);
}
//方法
//********* 成功连接服务器 *********
regissocket.onopen = function(event) {
console.log("WebSocket:成功连接服务器 ");
};
//一般放在界面使用
regissocket.onmessage = function(event) {
console.log("wesocket接收服务器数据event=>"+event);
console.log("wesocket接收服务器数据event.data=>"+event.data);
var mage=JSON.parse(event.data);//event.data是JSON格式字符串,转为JS对象
console.log("wesocket接收服务器data=>"+mage.data.id);
}
//********* 服务器发生异常错误 *********
regissocket.onerror = function(event) {
console.log("WebSocket:服务器发生异常错误 ");
console.log(event);
};
//********* 服务器关闭 *********
regissocket.onclose = function(event) {
console.log("WebSocket:已关闭");
console.log(event);
};
返回 regissocket
页面引入js文件
页面 打开webSocket 调用onmessage方法接收 (页面中接收请将js中的onmessage注释)
var socket = getWebSocket();
socket.onmessage=function(even){}接收信息 同上