J2EE7版(JSR-356)
相关依赖请参考上文,spring需要4.x
1、websocket处理器
import org.apache.commons.collections.MapUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.BinaryWebSocketHandler;
import org.springframework.web.socket.handler.TextWebSocketHandler;
/**
* 功能说明:WebSocket处理器
* 可以继承 {@link TextWebSocketHandler}/{@link BinaryWebSocketHandler},
* 或者简单的实现{@link WebSocketHandler}接口
* 作者:liuxing(2015-01-25 03:42)
*/
public class TelWebSocketHandler extends TextWebSocketHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(TelWebSocketHandler.class);
/**
* 建立连接
* @param session
* @throws Exception
*/
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
String inquiryId = MapUtils.getString(session.getAttributes(), "inquiryId");
int empNo = MapUtils.getInteger(session.getAttributes(), "empNo");
TelSocketSessionUtils.add(inquiryId, empNo, session);
}
/**
* 收到客户端消息
* @param session
* @param message
* @throws Exception
*/
@Override
public void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
String inquiryId = MapUtils.getString(session.getAttributes(), "inquiryId");
int empNo = MapUtils.getInteger(session.getAttributes(), "empNo");
TelSocketSessionUtils.sendMessage(inquiryId, empNo, "【来自服务器的复读机】:" + message.getPayload().toString());
}
/**
* 出现异常
* @param session
* @param exception
* @throws Exception
*/
@Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
String inquiryId = MapUtils.getString(session.getAttributes(), "inquiryId");
int empNo = MapUtils.getInteger(session.getAttributes(), "empNo");
LOGGER.error("websocket connection exception: " + TelSocketSessionUtils.getKey(inquiryId, empNo));
LOGGER.error(exception.getMessage(), exception);
TelSocketSessionUtils.remove(inquiryId, empNo);
}
/**
* 连接关闭
* @param session
* @param closeStatus
* @throws Exception
*/
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
String inquiryId = MapUtils.getString(session.getAttributes(), "inquiryId");
int empNo = MapUtils.getInteger(session.getAttributes(), "empNo");
TelSocketSessionUtils.remove(inquiryId, empNo);
}
/**
* 是否分段发送消息
* @return
*/
@Override
public boolean supportsPartialMessages() {
return false;
}
}
2、websocket连接的拦截器
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.Map;
/**
* 功能说明:websocket连接的拦截器
* 有两种方式
* 一种是实现接口HandshakeInterceptor,实现beforeHandshake和afterHandshake函数
* 一种是继承HttpSessionHandshakeInterceptor,重载beforeHandshake和afterHandshake函数
* 我这里是参照spring官方文档中的继承HttpSessionHandshakeInterceptor的方式
* 作者:liuxing(2015-01-25 03:46)
*/
public class TelWebSocketHandshakeInterceptor extends HttpSessionHandshakeInterceptor {
private static final Logger LOGGER = LoggerFactory.getLogger(TelWebSocketHandshakeInterceptor.class);
/**
* 从请求中获取唯一标记参数,填充到数据传递容器attributes
* @param serverHttpRequest
* @param serverHttpResponse
* @param wsHandler
* @param attributes
* @return
* @throws Exception
*/
@Override
public boolean beforeHandshake(ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
if (getSession(serverHttpRequest) != null) {
ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) serverHttpRequest;
HttpServletRequest request = servletRequest.getServletRequest();
attributes.put("inquiryId", request.getParameter("inquiryId"));
attributes.put("empNo", request.getParameter("empNo"));
}
super.beforeHandshake(serverHttpRequest, serverHttpResponse, wsHandler, attributes);
return true;
}
@Override
public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception ex) {
super.afterHandshake(request, response, wsHandler, ex);
}
private HttpSession getSession(ServerHttpRequest request) {
if (request instanceof ServletServerHttpRequest) {
ServletServerHttpRequest serverRequest = (ServletServerHttpRequest) request;
return serverRequest.getServletRequest().getSession(false);
}
return null;
}
}
3.session工具类
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 功能说明:TelSocketSessionUtils
* 作者:liuxing(2014-12-26 02:32)
*/
public class TelSocketSessionUtils {
private static final Logger LOGGER = LoggerFactory.getLogger(TelSocketSessionUtils.class);
private static Map<String, WebSocketSession> clients = new ConcurrentHashMap<>();
/**
* 保存一个连接
* @param inquiryId
* @param empNo
* @param session
*/
public static void add(String inquiryId, int empNo, WebSocketSession session){
clients.put(getKey(inquiryId, empNo), session);
}
/**
* 获取一个连接
* @param inquiryId
* @param empNo
* @return
*/
public static WebSocketSession get(String inquiryId, int empNo){
return clients.get(getKey(inquiryId, empNo));
}
/**
* 移除一个连接
* @param inquiryId
* @param empNo
*/
public static void remove(String inquiryId, int empNo) throws IOException {
clients.remove(getKey(inquiryId, empNo));
}
/**
* 组装sessionId
* @param inquiryId
* @param empNo
* @return
*/
public static String getKey(String inquiryId, int empNo) {
return inquiryId + "_" + empNo;
}
/**
* 判断是否有效连接
* 判断是否存在
* 判断连接是否开启
* 无效的进行清除
* @param inquiryId
* @param empNo
* @return
*/
public static boolean hasConnection(String inquiryId, int empNo) {
String key = getKey(inquiryId, empNo);
if (clients.containsKey(key)) {
return true;
}
return false;
}
/**
* 获取连接数的数量
* @return
*/
public static int getSize() {
return clients.size();
}
/**
* 发送消息到客户端
* @param inquiryId
* @param empNo
* @param message
* @throws Exception
*/
public static void sendMessage(String inquiryId, int empNo, String message) throws Exception {
if (!hasConnection(inquiryId, empNo)) {
throw new NullPointerException(getKey(inquiryId, empNo) + " connection does not exist");
}
WebSocketSession session = get(inquiryId, empNo);
try {
session.sendMessage(new TextMessage(message));
} catch (IOException e) {
LOGGER.error("websocket sendMessage exception: " + getKey(inquiryId, empNo));
LOGGER.error(e.getMessage(), e);
clients.remove(getKey(inquiryId, empNo));
}
}
}
4.初始化配置
可以使用注解或xml风格
<!--websocket配置-->
<bean id="telWebSocketHandler" class="包.websocket.handler.TelWebSocketHandler"/>
<websocket:handlers allowed-origins="*">
<websocket:mapping path="webSocketStatus" handler="telWebSocketHandler"/>
<websocket:handshake-interceptors>
<bean class="包.websocket.interceptor.TelWebSocketHandshakeInterceptor"/>
</websocket:handshake-interceptors>
</websocket:handlers>
<bean class="org.springframework.web.socket.server.standard.ServletServerContainerFactoryBean">
<property name="maxTextMessageBufferSize" value="8192"/>
<property name="maxBinaryMessageBufferSize" value="8192"/>
<property name="maxSessionIdleTimeout" value="900000"/>
<property name="asyncSendTimeout" value="5000"/>
</bean>
spring官方文档已经写得很齐全了,更多场景和说明请参阅下文
http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#websocket