更新websocket,非Stomp协议的原生WebSocket协议。

This commit is contained in:
Xiong Neng 2018-03-22 09:10:09 +08:00
parent 03cb51fd4a
commit 4b56e79eac
8 changed files with 349 additions and 18 deletions

View File

@ -0,0 +1,45 @@
package com.xncoding.jwt.commons;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
/**
* JacksonUtil
*
* @author XiongNeng
* @version 1.0
* @since 2018/3/4
*/
public class JacksonUtil {
private static ObjectMapper mapper = new ObjectMapper();
public static String bean2Json(Object obj) {
try {
return mapper.writeValueAsString(obj);
} catch (JsonProcessingException e) {
e.printStackTrace();
return "";
}
}
// public static <T> T json2Bean(String jsonStr, Class<T> objClass) {
// try {
// return mapper.readValue(jsonStr, objClass);
// } catch (IOException e) {
// e.printStackTrace();
// return null;
// }
// }
public static <T> T json2Bean(String jsonStr, TypeReference<T> typeReference) {
try {
return mapper.readValue(jsonStr, typeReference);
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}

View File

@ -1,31 +1,25 @@
package com.xncoding.jwt.config;
import com.xncoding.jwt.handler.SocketHandler;
import com.xncoding.jwt.interceptor.WebSocketInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
/**
* WebSocketConfig
*
* @author XiongNeng
* @version 1.0
* @since 2018/2/28
* @since 2018/3/22
*/
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
stompEndpointRegistry.addEndpoint("/simple")
.setAllowedOrigins("*") //解决跨域问题
.withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic");
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new SocketHandler(), "/app")
.addInterceptors(new WebSocketInterceptor())
.setAllowedOrigins("*");
}
}

View File

@ -0,0 +1,31 @@
package com.xncoding.jwt.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
/**
* STOMP协议的WebStocket
*
* @author XiongNeng
* @version 1.0
* @since 2018/2/28
*/
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketStompConfig extends AbstractWebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
stompEndpointRegistry.addEndpoint("/simple")
.setAllowedOrigins("*") //解决跨域问题
.withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic");
}
}

View File

@ -0,0 +1,106 @@
package com.xncoding.jwt.handler;
import com.fasterxml.jackson.core.type.TypeReference;
import com.xncoding.jwt.commons.JacksonUtil;
import com.xncoding.jwt.model.WsParam;
import com.xncoding.jwt.model.WsResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
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;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* SocketHandler
*
* @author XiongNeng
* @version 1.0
* @since 2018/3/22
*/
@Component
public class SocketHandler extends TextWebSocketHandler {
private Logger logger = LoggerFactory.getLogger(this.getClass());
List<WebSocketSession> sessions = new CopyOnWriteArrayList<>();
@Override
public void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
logger.info("handleTextMessage start");
// 将消息进行转化因为是消息是json数据可能里面包含了发送给某个人的信息所以需要用json相关的工具类处理之后再封装成TextMessage
// 我这儿并没有做处理消息的封装格式一般有{from:xxxx,to:xxxxx,msg:xxxxx}来自哪里发送给谁什么消息等等
String msg = message.getPayload();
logger.info("msg = " + msg);
WsParam wsParam = JacksonUtil.json2Bean(msg, new TypeReference<WsParam>(){});
if ("list".equals(wsParam.getMethod())) {
logger.info("call list method...");
WsResponse response = new WsResponse();
response.setResult("hello list");
sendMessageToUser(session, new TextMessage(JacksonUtil.bean2Json(response)));
}
logger.info("handleTextMessage end");
// 给所有用户群发消息
//sendMessagesToUsers(msg);
// 给指定用户群发消息
//sendMessageToUser(userId, msg);
}
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
logger.info("Connected ... " + session.getId());
sessions.add(session);
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
if (session.isOpen()) {
session.close();
}
sessions.remove(session);
logger.info(String.format("Session %s closed because of %s", session.getId(), status.getReason()));
}
@Override
public void handleTransportError(WebSocketSession session, Throwable throwable) throws Exception {
logger.error("error occured at sender " + session, throwable);
}
/**
* 给所有的用户发送消息
*/
public void sendMessagesToUsers(TextMessage message) {
for (WebSocketSession user : sessions) {
try {
// isOpen()在线就发送
if (user.isOpen()) {
user.sendMessage(message);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 发送消息给指定的用户
*/
private void sendMessageToUser(WebSocketSession user, TextMessage message) {
try {
// 在线就发送
if (user.isOpen()) {
user.sendMessage(message);
}
} catch (IOException e) {
logger.error("发送消息给指定的用户出错", e);
}
}
}

View File

@ -0,0 +1,40 @@
package com.xncoding.jwt.interceptor;
import javax.servlet.http.HttpServletRequest;
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.HandshakeInterceptor;
import java.util.Map;
/**
* WebSocketInterceptor
*
* @author XiongNeng
* @version 1.0
* @since 2018/3/22
*/
public class WebSocketInterceptor implements HandshakeInterceptor {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse arg1,
WebSocketHandler arg2, Map<String, Object> arg3) throws Exception {
// 将ServerHttpRequest转换成request请求相关的类用来获取request域中的用户信息
if (request instanceof ServletServerHttpRequest) {
ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
HttpServletRequest httpRequest = servletRequest.getServletRequest();
}
logger.info("beforeHandshake完成");
return true;
}
@Override
public void afterHandshake(ServerHttpRequest arg0, ServerHttpResponse arg1, WebSocketHandler arg2, Exception arg3) {
logger.info("afterHandshake完成");
}
}

View File

@ -0,0 +1,29 @@
package com.xncoding.jwt.model;
/**
* WsParam
*
* @author XiongNeng
* @version 1.0
* @since 2018/3/22
*/
public class WsParam {
private String method;
private Object param;
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
public Object getParam() {
return param;
}
public void setParam(Object param) {
this.param = param;
}
}

View File

@ -0,0 +1,20 @@
package com.xncoding.jwt.model;
/**
* WsResponse
*
* @author XiongNeng
* @version 1.0
* @since 2018/3/22
*/
public class WsResponse {
private Object result;
public Object getResult() {
return result;
}
public void setResult(Object result) {
this.result = result;
}
}

View File

@ -0,0 +1,66 @@
<html>
<head>
<meta charset="UTF-8"/>
<title>广播式WebSocket</title>
<script src="js/sockjs.min.js"></script>
<script src="js/stomp.js"></script>
<script src="js/jquery-3.1.1.js"></script>
</head>
<body onload="disconnect()">
<noscript><h2 style="color: #e80b0a;">Sorry浏览器不支持WebSocket</h2></noscript>
<div>
<div>
<button id="connect" onclick="connect();">连接</button>
<button id="disconnect" disabled="disabled" onclick="disconnect();">断开连接</button>
</div>
<div id="conversationDiv">
<label>输入你的名字</label><input type="text" id="name"/>
<button id="sendName" onclick="sendName();">发送</button>
<p id="response"></p>
<p id="callback"></p>
</div>
</div>
<script type="text/javascript">
var ws;
function connect() {
ws = new WebSocket('ws://localhost:8092/app');
ws.onmessage = function(data){
console.log("msg = " + JSON.stringify(data.data));
showResponse(data.data);
};
setConnected(true);
}
function disconnect() {
if (ws != null) {
ws.close();
}
setConnected(false);
console.log("Disconnected");
}
function sendName() {
var data = {
"method": "list",
"param": $("#name").val()
};
ws.send(JSON.stringify(data));
}
function showResponse(message) {
$("#response").html(message);
}
function showCallback(message) {
$("#callback").html(message);
}
function setConnected(connected) {
document.getElementById("connect").disabled = connected;
document.getElementById("disconnect").disabled = !connected;
document.getElementById("conversationDiv").style.visibility = connected ? 'visible' : 'hidden';
$("#response").html();
$("#callback").html();
}
</script>
</body>
</html>