常规的WebSocket服务,有不同的连接来源(比方说浏览器开发模式、业务平台、自己写的测试页面等。如果要屏蔽这些外来人员,可通过session控制)
服务器端
1.依赖包,和spring同一版本
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>${spring.version}</version>
</dependency>
2.WebSocket配置监听
@Configuration
@EnableWebMvc
@EnableWebSocket
public class SpringWebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) {
webSocketHandlerRegistry.addHandler(webSocketHandler(), "/ws")
.addInterceptors(new WebSocketInterceptor()).setAllowedOrigins("*");
webSocketHandlerRegistry.addHandler(webSocketHandler(), "/sj")
.addInterceptors(new WebSocketInterceptor()).setAllowedOrigins("*").withSockJS();
}
@Bean
public TextWebSocketHandler webSocketHandler() {
return new MsgWebSocketHandler();
}
}
此处除了常规的websocket监听url,还设置了备选方案sockjs(部分浏览器不支持websocket可使用sockjs)
3.WebSocket拦截配置
@Component
public class WebSocketInterceptor extends HttpSessionHandshakeInterceptor {
private Logger logger = LoggerFactory.getLogger(WebSocketInterceptor.class);
@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
logger.info("beforeHandshake");
//todo 待添加
return super.beforeHandshake(request, response, wsHandler, attributes);
}
@Override
public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception ex) {
logger.info("afterHandshake");
super.afterHandshake(request, response, wsHandler, ex);
}
}
可以基于自身业务情况,在握手之前(beforeHandshake),对session里的内容进行读取处理。
4.WebSocket消息处理
public class MsgWebSocketHandler extends TextWebSocketHandler {
private Logger logger = LoggerFactory.getLogger(MsgWebSocketHandler.class);
private static ConcurrentHashMap<String, WebSocketSession> sessionMap = new ConcurrentHashMap<>();
private static Pattern msgPattern = Pattern.compile(".*::.*::.*");
/**
* 接收消息并处理
* 格式 ==> 指令类型::对方身份证::extension
* @param session
* @param message
* @throws Exception
*/
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
logger.info("ws msg={}", message.toString());
logger.info("ws msg payload={}", message.getPayload());
//解析信息
UserDetail userDetail = (UserDetail) session.getAttributes().get(Constants.USER_KEYNAME);
if (userDetail == null) return;//游客忽略
if (StringUtils.isBlank(message.getPayload())) return;
Matcher matcher = msgPattern.matcher(message.getPayload());
if (!matcher.matches()) {
logger.warn("ws msg format error!");
return;
}
String[] infos = message.getPayload().split("::");
String type = infos[0];
String target = infos[1];
String extension = userDetail.getUsernumber()+"@@"+infos[2];
String payload = String.format("%s::%s::%s", type, userDetail.getUsername(), extension);
TextMessage textMsg = new TextMessage(payload);
//todo 此处要基于target找到对应session,然后发送消息
session.sendMessage(textMsg);
}
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
UserDetail userDetail = (UserDetail) session.getAttributes().get(Constants.USER_KEYNAME);
if (userDetail != null) {
sessionMap.put(userDetail.getUsernumber(), session);
logger.info("ws conn established {}", userDetail.getUsernumber());
logger.info("ws conn {}", String.valueOf(sessionMap.size()));
} else {
logger.warn("ws conn established with visitor id={}", session.getId());
}
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
UserDetail userDetail = (UserDetail) session.getAttributes().get(Constants.USER_KEYNAME);
if (userDetail != null) {
sessionMap.remove(userDetail.getUsernumber());
logger.info("ws conn close, session {} out", userDetail.getUsernumber());
logger.info("ws conn {}", String.valueOf(sessionMap.size()));
} else {
logger.warn("ws conn close with visitor id={}", session.getId());
}
}
}
此处,基于session,判断了当前连接是否是访问业务平台过来的还是其他直连过来的。通过一个map保存session信息
浏览器前端
前端WebSocket注册
<script type="text/javascript" src="<%=path%>/js/main/sockjs.js"></script>
<script type="text/javascript" >
var ws = null;
var url = window.location.host+"/backAdmin";
$(function () {
if ('WebSocket' in window) {
ws = new WebSocket("ws://"+url+"/ws");
} else if ("MozWebSocket" in window) {
ws = new MozWebSocket("ws://"+url+"/ws");
} else {
ws = new SockJS("http://"+url+"/sj");
}
ws.onopen = onOpen;
ws.onmessage = onMessage;
ws.onerror = onError;
ws.onclose = onClose;
});
function onOpen(result) {
console.log(result);
}
function onMessage(result) {
console.log(result);
}
function onError(result) {
console.log(result);
}
function onClose(result) {
console.log(result);
}
function doSend(msg) {
if (ws.readyState == ws.OPEN) {
ws.send(msg);
} else {
console.error('ws lost connection!');
}
}
window.close = function () {
ws.onclose();
}
</script>