注意事项:
1.如果出现握手失败,检查路径之外还可以去查看拦截器是否做了什么处理
WebSocket和sharedWork简介
WebSocket是持久化连接,用于解决浏览器与后台服务器双向通讯的问题
sharedWorker共享工作线程允许多个页面共享使用,每个页面都是链接到该共享工作线程的某个端口号上。页面通过该端口与共享工作线程进行通信
配置所需jar包
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
<version>${spring.framework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>${spring.framework.version}</version>
</dependency>
这里所用的版本最好和项目中所用到的spring其他内容统一,避免出现版本不兼容问题。
对版本的要求是:spring版本为 4.0 版本及以上, Tomcat 7.047 以上版本。
websocket入口
/**
* Component注解告诉SpringMVC该类是一个SpringIOC容器下管理的类
* 其实@Controller, @Service, @Repository是@Component的细化
* @Configuration注解该类,等价于XML中配置beans标签
*/
@Configuration
@EnableWebSocket
public class MyWebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer {
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
//一般浏览器都会支持
registry.addHandler(WebSocketPushHandler(),"/webSocketServer").addInterceptors(new MyHandShakeInterceptor());
//低版本浏览器使用此路径,等下页面上会讲到
registry.addHandler(WebSocketPushHandler(), "/sockjs/webSocketServer").addInterceptors(new MyHandShakeInterceptor())
.withSockJS();
}
@Bean
public WebSocketHandler WebSocketPushHandler(){
return new MyWebSocketHander();
}
}
实现WebSocketConfigurer接口,重写registerWebSocketHandlers方法,这是一个核心实现方法,配置websocket入口,允许访问的域、注册Handler、SockJs支持和拦截器。
registry.addHandler注册和路由的功能,当客户端发起websocket连接,把/path交给对应的handler处理, 而不实现具体的业务逻辑,可以理解为收集和任务分发中心。
setAllowedOrigins(String[] domains),允许指定的域名或IP(含端口号)建立长连接,如果只允许自家域名访问,这里轻松设置。 如果不限时使用”*”号,如果指定了域名,则必须要以http或https开头。
拦截器实现
/**
* websocket握手拦截器
* 拦截握手前,握手后的两个切面
*/
public class MyHandShakeInterceptor implements HandshakeInterceptor {
@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
Map<String, Object> attributes) throws Exception {
System.out.println("准备进行握手");
if (request instanceof ServletServerHttpRequest) {
// attributes.put("username",userName);
}
return true;
}
@Override
public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
Exception exception) {
System.out.println("握手成功,进入服务端");
}
}
1.beforeHandshake,在调用handler前处理方法。常用在注册用户信息,绑定WebSocketSession,在handler里根据用户信息获取WebSocketSession发送消息。
Handler处理类
/**WebSocket处理器
* Created by qiumeng on 2017/8/7 0007.
*/
public class MyWebSocketHander extends TextWebSocketHandler {
private static final List<WebSocketSession> users = new ArrayList<>();
//用户进入系统监听
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
System.out.println("成功进入了系统。。。");
users.add(session);
}
@Override
public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
System.out.println("成功接收到消息");
// 把客户端的消息解析为JSON对象
if(message instanceof TextMessage) {
TextMessage msg = new TextMessage("发送的数据"+message.getPayload());
//给所有浏览器群发消息
sendMessagesToUsers(msg);
// this.handleTextMessage(session, (TextMessage)message);
} else if(message instanceof BinaryMessage) {
BinaryMessage msg = new BinaryMessage((byte[]) message.getPayload());
//给所有浏览器群发消息
sendMessagesToUsers(msg);
// this.handleBinaryMessage(session, (BinaryMessage)message);
} else {
if(!(message instanceof PongMessage)) {
throw new IllegalStateException("Unexpected WebSocket message type: " + message);
}
// this.handlePongMessage(session, (PongMessage)message);
}
}
@Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {System.out.println("安全退出了系统");}
@Override
public boolean supportsPartialMessages() {
return false;
}
/**
* 给所有的用户发送消息
*/
public void sendMessagesToUsers(WebSocketMessage<?> message){
for(WebSocketSession user : users){
try {
//isOpen()在线就发送
if(user.isOpen()){
user.sendMessage(message);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
//进行实例化bean可以在其他controller实例化 调用所发送的信息
@Bean
public MyWebSocketHander myWebSocketHander(){
return myWebSocketHander();
}
}
客户端连接
这里只写出javascript代码
<script type="text/javascript">
var receive_text = document.getElementById("up");
var myWorker = new SharedWorker('http://localhost:8081/portal/resources/js/worker.js');
console.log("创建sharedwork");
myWorker.onerror = function(e)
{
console.log('myWorker.onerror : ' + e.message);
}
function myOnMessage(e) {
receive_text.innerHTML += "<br/>" + e.data;
receive_text.scrollTop = receive_text.scrollHeight;
}
if(1){
// 4 绑定消息处理函数,仅设置 onmessage
myWorker.port.onmessage = myOnMessage;
}
else{
// 5 另外一种消息绑定方式, addEventListener 和 start 配合使用
myWorker.port.addEventListener('message', myOnMessage);
myWorker.port.start();
}
function send(){
var ret = myWorker.port.postMessage(JSON.stringify($("#message").val()))
}
//页面发送消息
function sendMessage() {
// var ret = myWorker.port.postMessage(stringToBytes($("#message").val()))
var file=$("#file")[0].files[0];
var reader = new FileReader();
if(""==file){
alert("请选择文件")
}
// reader.readAsBinaryString(file)
reader.readAsArrayBuffer(file)
reader.onload = function (e) {
if (e.target.readyState == FileReader.DONE) {
var data = new Uint8Array(e.target.result);
//这里有一个问题,目前没有解决 就是传输二进制数据大小的问题 好像为100万字节左右
//在大的话,目前没有找到解决办法
var jsondata=JSON.stringify(data.slice(0, 100))
var ret = myWorker.port.postMessage(jsondata);
}
}
}
</script>
下面是创建sharedWorker主线程代码work.js
var count = 0;
var ports = [];
var webSocket = new WebSocket("ws://localhost:8081/portal/webSocketServer");
var websocketMessage=null;
// 唯一的事件处理函数
onconnect = function(e) {
console.log('onconnect from home');
// 1 网页建立连接获取端口
var port = e.ports[0];
ports.push({
port:port,
lastRecv: new Date()
});
// 2 绑定事件处理函数
port.addEventListener('message', function(e) {
var ret = e.data;
//因为WebSockets只能通过连接发送纯文本数据,所以对于复杂的数据结构,在通过连接发送之前,必须进行序列化
//发送消息到后台
if(""!=ret){
console.log("向websocket后台发送消息")
webSocket.send(ret);
}
});
// 3 启动端口
port.start();
}
webSocket.onopen = function(event) {
console.log("websocket创建");
};
webSocket.onmessage = function(event) {
console.log("websocket返回消息")
websocketMessage=event.data
//data的数据格式也是字符串,如果想得到其他格式的数据,必须手工解析这些数据
for(var i=0;i<ports.length;i++){
var p=ports[i];
p.port.postMessage(websocketMessage)
}
};
webSocket.onerror = function(event) {
};