# spring-websocket接入文档
> 本次是第二次接入spring-websocket到项目。此次接入遇到的问题与上一次完全不一样。
>
### 本次接入要点的前端说明
> 前端会判断当前浏览器是否支付websocket,支持的话,使用原生服务连接; 不支持的话采用sockjs库。
### 服务器端要点说明
> 为了区分前端是否采用原生库的服务创建websocket,所以配置了两个Mapping-url.
## 前端相关
1. 前端首先判断当前使用平台的http协议类型(http OR https)。对应websocket的ws 和 wss。
2. 判断当前浏览器的websocket原生库类型(其实是浏览器分类),支持的用原生库,不支持的用sockjs库。
3. 编写websocket数据通信事件的默认实现。
- 前端的代码
var ws = null, ws_uri = "/sba/ws/srv"; // /sba是spring-mvc的拦截前缀。
/** websocket */
function initWebSocket(){
var ws_pre = "ws://" + window.location.host;
var protocolStr = document.location.protocol;
if(protocolStr == "https:") {
ws_pre = "wss://" + window.location.host;
}
//判断当前浏览器是否支持WebSocket。浏览器的原生ws组件,没有心跳机制,默认是5分钟超时,具体需要参照http代理的超时配置。
if ('WebSocket' in window) {
ws = new WebSocket(ws_pre + ws_uri);
}
else if ('MozWebSocket' in window) {
ws = new MozWebSocket(ws_pre + ws_uri);
}
else { // 有心跳协议,可以一直保持连接。
ws_uri = "/sba/ws/sockjs";
if(protocolStr == "https:") {
ws = new SockJS("https://"+window.location.host + ws_uri);
} else {
ws = new SockJS("http://"+window.location.host + ws_uri);
}
}
ws.onopen = function () {
alert("WS服务已开启。");
};
//这个事件是接受后端传过来的数据
ws.onmessage = function (event) {
//根据业务逻辑解析数据
var data = JSON.parse(event.data);
alert(data);
};
ws.onclose = function (event) {
alert("WS服务已关闭.");
};
ws.onerror = function (event) {
alert("WS服务出现异常:" + +event.data);
};
}
## 服务器端相关
1. 配置spring-websocket,接入spring的上下文(将webskocket配置文件import到sping 的配置文件里)。
2. 实现spring-websocket握手和协议升级的拦截器(HttpSessionHandshakeInterceptor)。将httpsession的用户标识与websocket会话关联.
3. 实现spring-websocket的消息处理器(TextWebSocketHandler)。
4. 如果使用了权限控制,应对 /ws/srv 与 /ws/sockjs 进行访问控制。
5. com.jahelai.ws 是项目的前缀包名。
### spring-websocket的配置文件
### WsHandshakeInterceptor
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.support.HttpSessionHandshakeInterceptor;
public class WsHandshakeInterceptor extends HttpSessionHandshakeInterceptor {
@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
Map attributes) throws Exception {
///获取请求参数,首先我们要获取HttpServletRequest对象才能获取请求参数;当ServerHttpRequset的层次结构打开后其子类可以获取到我们想要的http对象,那么就简单了。
//我这里是把获取的请求数据绑定到session的map对象中(attributes)
ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
HttpSession session = servletRequest.getServletRequest().getSession(false);
if (session != null) {
String userName = (String) session.getAttribute("SESSION_USERNAME");
if(userName == null){
userName = "WEBSOCKET_USERNAME_IS_NULL";
}
// httpsession的用户标识与websocket的WebSocketSession建立关联。
attributes.put("username", session.getAttribute("username"));
}
return super.beforeHandshake(request, response, wsHandler, attributes);
}
@Override
public void afterHandshake(ServerHttpRequest request,
ServerHttpResponse response, WebSocketHandler wsHandler,
Exception ex) {
super.afterHandshake(request, response, wsHandler, ex);
}
}
### WsMesssageHandler
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;
/**
* ws服务的消息处理器。
* 接入spring-websocket的步骤:
* 1。配置ws的url,开发消息处理器,协议升级处理器
* 2。将配置文件加入到spring的上下文。
* 3。 spring-security开放ws的url校验
* 4。开发前端的连接,消息处理。
* @author jahe.lai
*
*/
public class WsMesssageHandler extends TextWebSocketHandler {
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
super.afterConnectionEstablished(session);
// username=session.getAttributes().get("username").toString()
// 将WebSocketSession与用户的标识关联,以供调用。可以Map
WsSessionManager.addOnline(session);
}
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
super.handleTextMessage(session, message);
// Todo 你对交互消息的处理写在这里。
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
super.afterConnectionClosed(session, status);
WsSessionManager.remove(session);
}
}
## nginx代理websocket.
见: http://nginx.org/en/docs/http/websocket.html