1.导入相应的jar包(这里默认使用ssm框架)
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
</dependency>
2.xml配置
<!--webSocket配置-->
<websocket:handlers allowed-origins="*">
<!--配置消息处理器
handler:这里是消息处理器的id
path:是指前端与后端建立webSocket连接时要访问的url
-->
<websocket:mapping path="/myHandler.do" handler="myHandler"/>
<!--配置拦截器,在进去消息处理器之前会先来到这个拦截器-->
<websocket:handshake-interceptors>
<!--拦截器-->
<bean class="com.wmzx.view.websocket.WebSocketInterceptor"/>
</websocket:handshake-interceptors>
</websocket:handlers>
<!--配置消息体大小的限制-->
<bean class="org.springframework.web.socket.server.standard.ServletServerContainerFactoryBean">
<property name="maxTextMessageBufferSize" value="8192"/>
<property name="maxBinaryMessageBufferSize" value="8192"/>
</bean>
<!--消息处理器-->
<bean id="myHandler" class="com.wmzx.view.websocket.MyHandler"/>
3.拦截器
package com.wmzx.view.websocket;
import com.common.exception.WMZXException;
import com.common.util.json.APICase;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;
import java.util.Map;
/**
* 在webSocket请求过来时,会首先进入这个拦截器,在这里我们可以做授权登录等操作
*/
public class WebSocketInterceptor extends HttpSessionHandshakeInterceptor
{
@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
Map<String, Object> attributes) throws Exception
{
//获取shiro的subject
Subject subject = SecurityUtils.getSubject();
//校验是否登录
if (!subject.isRemembered() && !subject.isAuthenticated())
{
throw new WMZXException(APICase.NEED_LOGIN);
}
return super.beforeHandshake(request, response, wsHandler, attributes);
}
}
4.消息处理器
package com.wmzx.view.websocket;
import com.common.util.Logger;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
/**
* 这里处理消息,可以监听到消息连接的建立,消息请求到来,以及session失效等
*
*/
public class MyHandler extends TextWebSocketHandler
{
/**
* 这个map的key是用户的id,value是WebSocketSession
*/
private static volatile ConcurrentHashMap<String, WebSocketSession> map = new ConcurrentHashMap<>();
/**
* 消息发送过来后,会来到这里,这里可以根据收到的消息做处理,本方法只是将发
* 送过来的消息又转发到客户端
*/
@Override
public void handleTextMessage(WebSocketSession session, TextMessage message) throws IOException
{
WebSocketMessage textMessage = new TextMessage(message.getPayload());
for (WebSocketSession old : map.values())
{
old.sendMessage(textMessage);
}
}
/**
* 前端与后端的连接建立好之后会调用这个方法,这里我们可以保存客户端的连接
*/
@Override
public void afterConnectionEstablished(WebSocketSession session) throws IOException
{
String userId = session.getPrincipal().getName();
if (map.contains(userId))
{
session.close();
}
map.put(userId, session);
}
/**
*当前端主动关闭连接或者前端浏览器关闭或其他方式导致session失效时,会来到这里
*在这里我们可以做退出登录
*/
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws IOException
{
map.remove(session.getPrincipal().getName());
session.close();
}
}
5.nginx代理配置(主要指https访问)
WebSocket 和 HTTP 协议不同,但是 WebSocket 中的握手和 HTTP 中的握手兼容,它使用 HTTP 中的 Upgrade 协议头将连接从 HTTP 升级到 WebSocket,当客户端发过来一个 Connection: Upgrade
请求头时,Nginx 是不知道的,所以,当 Nginx 代理服务器拦截到一个客户端发来的 Upgrade
请求时,需要显式来设置 Connection
、 Upgrade
头信息,并使用 101(交换协议)返回响应,在客户端和代理服务器、后端服务器之间建立隧道来支持 WebSocket。
location /websocket {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
6.请求地址
http://www.blue-zero.com/WebSocket/ 这是一个在线的WebSocket 测试工具
如果使用tomcat部署服务,最好使用tomcat8及以上版本
ws和wss协议的区别就如同http和https
-
服务端使用http访问的服务器:ws://192.168.1.36:8080/myHandler.do
-
服务端使用https访问的服务器:wss://xxx.xxx.com/myHandler.do