|
@@ -1,20 +1,13 @@
|
|
|
package cn.com.qmth.examcloud.ws.starter.core;
|
|
|
|
|
|
-import java.lang.annotation.Annotation;
|
|
|
-import java.lang.reflect.Method;
|
|
|
-import java.util.List;
|
|
|
-import java.util.Map;
|
|
|
-import java.util.UUID;
|
|
|
-import java.util.concurrent.atomic.AtomicLong;
|
|
|
-
|
|
|
-import javax.websocket.OnClose;
|
|
|
-import javax.websocket.OnError;
|
|
|
-import javax.websocket.OnMessage;
|
|
|
-import javax.websocket.OnOpen;
|
|
|
-import javax.websocket.Session;
|
|
|
-import javax.websocket.server.PathParam;
|
|
|
-import javax.websocket.server.ServerEndpoint;
|
|
|
-
|
|
|
+import cn.com.qmth.examcloud.api.commons.security.bean.User;
|
|
|
+import cn.com.qmth.examcloud.commons.exception.StatusException;
|
|
|
+import cn.com.qmth.examcloud.commons.util.JsonUtil;
|
|
|
+import cn.com.qmth.examcloud.web.redis.RedisClient;
|
|
|
+import cn.com.qmth.examcloud.web.support.SpringContextHolder;
|
|
|
+import com.google.gson.JsonElement;
|
|
|
+import com.google.gson.JsonParser;
|
|
|
+import com.google.gson.JsonSyntaxException;
|
|
|
import org.apache.commons.collections.CollectionUtils;
|
|
|
import org.apache.commons.io.IOUtils;
|
|
|
import org.apache.commons.lang.StringUtils;
|
|
@@ -23,15 +16,15 @@ import org.slf4j.Logger;
|
|
|
import org.slf4j.LoggerFactory;
|
|
|
import org.springframework.stereotype.Component;
|
|
|
|
|
|
-import com.google.gson.JsonElement;
|
|
|
-import com.google.gson.JsonParser;
|
|
|
-import com.google.gson.JsonSyntaxException;
|
|
|
-
|
|
|
-import cn.com.qmth.examcloud.api.commons.security.bean.User;
|
|
|
-import cn.com.qmth.examcloud.commons.exception.StatusException;
|
|
|
-import cn.com.qmth.examcloud.commons.util.JsonUtil;
|
|
|
-import cn.com.qmth.examcloud.web.redis.RedisClient;
|
|
|
-import cn.com.qmth.examcloud.web.support.SpringContextHolder;
|
|
|
+import javax.websocket.*;
|
|
|
+import javax.websocket.server.PathParam;
|
|
|
+import javax.websocket.server.ServerEndpoint;
|
|
|
+import java.lang.annotation.Annotation;
|
|
|
+import java.lang.reflect.Method;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.UUID;
|
|
|
+import java.util.concurrent.atomic.AtomicLong;
|
|
|
|
|
|
/**
|
|
|
* websocket ServerEndpoint
|
|
@@ -44,221 +37,222 @@ import cn.com.qmth.examcloud.web.support.SpringContextHolder;
|
|
|
@Component
|
|
|
public class WebSocketServerEndpoint {
|
|
|
|
|
|
- private static final Logger LOG = LoggerFactory.getLogger(WebSocketServerEndpoint.class);
|
|
|
-
|
|
|
- private static RedisClient redisClient;
|
|
|
-
|
|
|
- private static AtomicLong counter = new AtomicLong(0L);
|
|
|
-
|
|
|
- private String sessionId;
|
|
|
-
|
|
|
- private static RedisClient getRedisClient() {
|
|
|
- if (null != redisClient) {
|
|
|
- return redisClient;
|
|
|
- }
|
|
|
- redisClient = SpringContextHolder.getBean(RedisClient.class);
|
|
|
- return redisClient;
|
|
|
- }
|
|
|
-
|
|
|
- @OnOpen
|
|
|
- public void onOpen(Session session, @PathParam("path") String path) {
|
|
|
- long amount = counter.incrementAndGet();
|
|
|
-
|
|
|
- this.sessionId = UUID.randomUUID().toString().replace("-", "");
|
|
|
-
|
|
|
- ThreadContext.put("TRACE_ID", sessionId);
|
|
|
-
|
|
|
- if (LOG.isDebugEnabled()) {
|
|
|
- LOG.debug("[onOpen]. path=" + path + "; sessionsAmount=" + amount);
|
|
|
- }
|
|
|
-
|
|
|
- MessageOut out = new MessageOut(path, sessionId);
|
|
|
- out.setEventId("open");
|
|
|
-
|
|
|
- Method method = MessageHandlerHolder.getMethod(path);
|
|
|
- if (null == method) {
|
|
|
- out.setStatus("404", "NOT FOUND");
|
|
|
- WebSocketHelper.sendText(session, path, out);
|
|
|
- IOUtils.closeQuietly(session);
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- String key = getRequestParameter(session, "key");
|
|
|
- String token = getRequestParameter(session, "token");
|
|
|
-
|
|
|
- if (StringUtils.isBlank(key)) {
|
|
|
- LOG.error("[onOpen-FAIL]. path=" + path + ". key is blank");
|
|
|
- IOUtils.closeQuietly(session);
|
|
|
- return;
|
|
|
- }
|
|
|
- if (StringUtils.isBlank(token)) {
|
|
|
- LOG.error("[onOpen-FAIL]. path=" + path + ". token is blank");
|
|
|
- IOUtils.closeQuietly(session);
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- User user = getRedisClient().get(key, User.class);
|
|
|
-
|
|
|
- if (null == user) {
|
|
|
- out.setStatus("403", "no login");
|
|
|
- WebSocketHelper.sendText(session, path, out);
|
|
|
- IOUtils.closeQuietly(session);
|
|
|
- return;
|
|
|
- } else if (!token.equals(user.getToken())) {
|
|
|
- out.setStatus("403", "token is wrong");
|
|
|
- WebSocketHelper.sendText(session, path, out);
|
|
|
- IOUtils.closeQuietly(session);
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- ThreadContext.put("CALLER", user.getKey());
|
|
|
-
|
|
|
- WebSocketHelper.sendText(session, path, out);
|
|
|
-
|
|
|
- WebSocketHelper.setSession(path, user, session, sessionId);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 获取请求参数
|
|
|
- *
|
|
|
- * @author WANGWEI
|
|
|
- * @param session
|
|
|
- * @param key
|
|
|
- * @return
|
|
|
- */
|
|
|
- private String getRequestParameter(Session session, String key) {
|
|
|
- Map<String, List<String>> params = session.getRequestParameterMap();
|
|
|
- List<String> list = params.get(key);
|
|
|
-
|
|
|
- if (CollectionUtils.isEmpty(list)) {
|
|
|
- return null;
|
|
|
- }
|
|
|
- String value = StringUtils.join(list, ",");
|
|
|
- return value;
|
|
|
- }
|
|
|
-
|
|
|
- @OnClose
|
|
|
- public void onClose(Session session, @PathParam("path") String path) {
|
|
|
-
|
|
|
- long amount = counter.decrementAndGet();
|
|
|
-
|
|
|
- SessionInfo sessionInfo = WebSocketHelper.getSessionInfo(session);
|
|
|
- if (null != sessionInfo) {
|
|
|
- ThreadContext.put("TRACE_ID", sessionInfo.getSessionId());
|
|
|
- ThreadContext.put("CALLER", sessionInfo.getUser().getKey());
|
|
|
- } else {
|
|
|
- ThreadContext.put("TRACE_ID", this.sessionId);
|
|
|
- }
|
|
|
-
|
|
|
- LOG.debug("[onClose]. path=" + path + "; sessionsAmount=" + amount);
|
|
|
- WebSocketHelper.closeSession(session);
|
|
|
- }
|
|
|
-
|
|
|
- @OnMessage
|
|
|
- public void onMessage(Session session, @PathParam("path") String path, String message) {
|
|
|
-
|
|
|
- SessionInfo sessionInfo = WebSocketHelper.getSessionInfo(session);
|
|
|
- ThreadContext.put("TRACE_ID", sessionInfo.getSessionId());
|
|
|
- ThreadContext.put("CALLER", sessionInfo.getUser().getKey());
|
|
|
-
|
|
|
- MessageOut out = new MessageOut(path, sessionInfo.getSessionId());
|
|
|
- try {
|
|
|
- JsonElement jsonEl = JsonParser.parseString(message);
|
|
|
- message = JsonUtil.toJson(jsonEl);
|
|
|
- } catch (JsonSyntaxException e) {
|
|
|
- out.setStatus("500", "message is not a json string");
|
|
|
- WebSocketHelper.sendText(session, path, out);
|
|
|
- IOUtils.closeQuietly(session);
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if (LOG.isDebugEnabled()) {
|
|
|
- LOG.debug("[onMessage]. path=" + path + ". message=" + message);
|
|
|
- }
|
|
|
-
|
|
|
- SessionInfo si = WebSocketHelper.getSessionInfo(session);
|
|
|
-
|
|
|
- User user = getRedisClient().get(si.getUser().getKey(), User.class);
|
|
|
-
|
|
|
- if (null == user) {
|
|
|
- out.setStatus("403", "no login");
|
|
|
- WebSocketHelper.sendText(session, path, out);
|
|
|
- IOUtils.closeQuietly(session);
|
|
|
- return;
|
|
|
- } else if (!si.getUser().getToken().equals(user.getToken())) {
|
|
|
- out.setStatus("403", "token is wrong");
|
|
|
- WebSocketHelper.sendText(session, path, out);
|
|
|
- IOUtils.closeQuietly(session);
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- Object result = null;
|
|
|
- try {
|
|
|
-
|
|
|
- Method method = MessageHandlerHolder.getMethod(path);
|
|
|
- Object bean = MessageHandlerHolder.getBean(path);
|
|
|
-
|
|
|
- Annotation[][] an2 = method.getParameterAnnotations();
|
|
|
-
|
|
|
- boolean hasMessageParam = false;
|
|
|
- int messageParamIndex = 0;
|
|
|
- OUTER : for (int i = 0; i < an2.length; i++) {
|
|
|
- Annotation[] an1 = an2[i];
|
|
|
- for (Annotation an : an1) {
|
|
|
- if (an.annotationType().equals(Message.class)) {
|
|
|
- hasMessageParam = true;
|
|
|
- messageParamIndex = i;
|
|
|
- break OUTER;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- Class<?>[] parameterTypes = method.getParameterTypes();
|
|
|
- Object[] args = new Object[parameterTypes.length];
|
|
|
- for (int i = 0; i < parameterTypes.length; i++) {
|
|
|
- Class<?> curType = parameterTypes[i];
|
|
|
- if (hasMessageParam && i == messageParamIndex) {
|
|
|
- try {
|
|
|
- args[i] = JsonUtil.fromJson(message, curType);
|
|
|
- } catch (Exception e) {
|
|
|
- throw new StatusException("500", "fail to parse message to object");
|
|
|
- }
|
|
|
- continue;
|
|
|
- }
|
|
|
- if (curType.equals(User.class)) {
|
|
|
- args[i] = user;
|
|
|
- continue;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- result = method.invoke(bean, args);
|
|
|
-
|
|
|
- out.setContent(result);
|
|
|
-
|
|
|
- } catch (StatusException e) {
|
|
|
- LOG.error("[onMessage-FAIL]. path=" + path + "", e);
|
|
|
- out.setStatus(e.getCode(), e.getDesc());
|
|
|
- } catch (Exception e) {
|
|
|
- LOG.error("[onMessage-FAIL]. path=" + path + "", e);
|
|
|
- out.setStatus("500", "系统异常");
|
|
|
- }
|
|
|
-
|
|
|
- WebSocketHelper.sendText(session, path, out);
|
|
|
- }
|
|
|
-
|
|
|
- @OnError
|
|
|
- public void onError(Session session, @PathParam("path") String path, Throwable t) {
|
|
|
-
|
|
|
- SessionInfo sessionInfo = WebSocketHelper.getSessionInfo(session);
|
|
|
- if (null != sessionInfo) {
|
|
|
- ThreadContext.put("TRACE_ID", sessionInfo.getSessionId());
|
|
|
- ThreadContext.put("CALLER", sessionInfo.getUser().getKey());
|
|
|
- } else {
|
|
|
- ThreadContext.put("TRACE_ID", this.sessionId);
|
|
|
- }
|
|
|
-
|
|
|
- LOG.error("[onError]. path=" + path, t);
|
|
|
- WebSocketHelper.closeSession(session);
|
|
|
- }
|
|
|
+ private static final Logger LOG = LoggerFactory.getLogger(WebSocketServerEndpoint.class);
|
|
|
+
|
|
|
+ private static RedisClient redisClient;
|
|
|
+
|
|
|
+ private static AtomicLong counter = new AtomicLong(0L);
|
|
|
+
|
|
|
+ private String sessionId;
|
|
|
+
|
|
|
+ private static RedisClient getRedisClient() {
|
|
|
+ if (null != redisClient) {
|
|
|
+ return redisClient;
|
|
|
+ }
|
|
|
+ redisClient = SpringContextHolder.getBean(RedisClient.class);
|
|
|
+ return redisClient;
|
|
|
+ }
|
|
|
+
|
|
|
+ @OnOpen
|
|
|
+ public void onOpen(Session session, @PathParam("path") String path) {
|
|
|
+ long amount = counter.incrementAndGet();
|
|
|
+
|
|
|
+ this.sessionId = UUID.randomUUID().toString().replace("-", "");
|
|
|
+
|
|
|
+ ThreadContext.put("TRACE_ID", sessionId);
|
|
|
+
|
|
|
+ if (LOG.isDebugEnabled()) {
|
|
|
+ LOG.debug("[onOpen]. path=" + path + "; sessionsAmount=" + amount);
|
|
|
+ }
|
|
|
+
|
|
|
+ MessageOut out = new MessageOut(path, sessionId);
|
|
|
+ out.setEventId("open");
|
|
|
+
|
|
|
+ Method method = MessageHandlerHolder.getMethod(path);
|
|
|
+ if (null == method) {
|
|
|
+ out.setStatus("404", "NOT FOUND");
|
|
|
+ WebSocketHelper.sendText(session, path, out);
|
|
|
+ IOUtils.closeQuietly(session);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ String key = getRequestParameter(session, "key");
|
|
|
+ String token = getRequestParameter(session, "token");
|
|
|
+
|
|
|
+ if (StringUtils.isBlank(key)) {
|
|
|
+ LOG.error("[onOpen-FAIL]. path=" + path + ". key is blank");
|
|
|
+ IOUtils.closeQuietly(session);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (StringUtils.isBlank(token)) {
|
|
|
+ LOG.error("[onOpen-FAIL]. path=" + path + ". token is blank");
|
|
|
+ IOUtils.closeQuietly(session);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ User user = getRedisClient().get(key, User.class);
|
|
|
+
|
|
|
+ if (null == user) {
|
|
|
+ out.setStatus("403", "no login");
|
|
|
+ WebSocketHelper.sendText(session, path, out);
|
|
|
+ IOUtils.closeQuietly(session);
|
|
|
+ return;
|
|
|
+ } else if (!token.equals(user.getToken())) {
|
|
|
+ out.setStatus("403", "token is wrong");
|
|
|
+ WebSocketHelper.sendText(session, path, out);
|
|
|
+ IOUtils.closeQuietly(session);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ ThreadContext.put("CALLER", user.getKey());
|
|
|
+
|
|
|
+ WebSocketHelper.sendText(session, path, out);
|
|
|
+
|
|
|
+ WebSocketHelper.setSession(path, user, session, sessionId);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取请求参数
|
|
|
+ *
|
|
|
+ * @param session
|
|
|
+ * @param key
|
|
|
+ * @return
|
|
|
+ * @author WANGWEI
|
|
|
+ */
|
|
|
+ private String getRequestParameter(Session session, String key) {
|
|
|
+ Map<String, List<String>> params = session.getRequestParameterMap();
|
|
|
+ List<String> list = params.get(key);
|
|
|
+
|
|
|
+ if (CollectionUtils.isEmpty(list)) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ String value = StringUtils.join(list, ",");
|
|
|
+ return value;
|
|
|
+ }
|
|
|
+
|
|
|
+ @OnClose
|
|
|
+ public void onClose(Session session, @PathParam("path") String path) {
|
|
|
+
|
|
|
+ long amount = counter.decrementAndGet();
|
|
|
+
|
|
|
+ SessionInfo sessionInfo = WebSocketHelper.getSessionInfo(session);
|
|
|
+ if (null != sessionInfo) {
|
|
|
+ ThreadContext.put("TRACE_ID", sessionInfo.getSessionId());
|
|
|
+ ThreadContext.put("CALLER", sessionInfo.getUser().getKey());
|
|
|
+ } else {
|
|
|
+ ThreadContext.put("TRACE_ID", this.sessionId);
|
|
|
+ }
|
|
|
+
|
|
|
+ LOG.debug("[onClose]. path=" + path + "; sessionsAmount=" + amount);
|
|
|
+ WebSocketHelper.closeSession(session);
|
|
|
+ }
|
|
|
+
|
|
|
+ @OnMessage
|
|
|
+ public void onMessage(Session session, @PathParam("path") String path, String message) {
|
|
|
+
|
|
|
+ SessionInfo sessionInfo = WebSocketHelper.getSessionInfo(session);
|
|
|
+ ThreadContext.put("TRACE_ID", sessionInfo.getSessionId());
|
|
|
+ ThreadContext.put("CALLER", sessionInfo.getUser().getKey());
|
|
|
+
|
|
|
+ MessageOut out = new MessageOut(path, sessionInfo.getSessionId());
|
|
|
+ try {
|
|
|
+ JsonElement jsonEl = JsonParser.parseString(message);
|
|
|
+ message = JsonUtil.toJson(jsonEl);
|
|
|
+ } catch (JsonSyntaxException e) {
|
|
|
+ out.setStatus("500", "message is not a json string");
|
|
|
+ WebSocketHelper.sendText(session, path, out);
|
|
|
+ IOUtils.closeQuietly(session);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (LOG.isDebugEnabled()) {
|
|
|
+ LOG.debug("[onMessage]. path=" + path + ". message=" + message);
|
|
|
+ }
|
|
|
+
|
|
|
+ SessionInfo si = WebSocketHelper.getSessionInfo(session);
|
|
|
+
|
|
|
+ User user = getRedisClient().get(si.getUser().getKey(), User.class);
|
|
|
+
|
|
|
+ if (null == user) {
|
|
|
+ out.setStatus("403", "no login");
|
|
|
+ WebSocketHelper.sendText(session, path, out);
|
|
|
+ IOUtils.closeQuietly(session);
|
|
|
+ return;
|
|
|
+ } else if (!si.getUser().getToken().equals(user.getToken())) {
|
|
|
+ out.setStatus("403", "token is wrong");
|
|
|
+ WebSocketHelper.sendText(session, path, out);
|
|
|
+ IOUtils.closeQuietly(session);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ Object result = null;
|
|
|
+ try {
|
|
|
+
|
|
|
+ Method method = MessageHandlerHolder.getMethod(path);
|
|
|
+ Object bean = MessageHandlerHolder.getBean(path);
|
|
|
+
|
|
|
+ Annotation[][] an2 = method.getParameterAnnotations();
|
|
|
+
|
|
|
+ boolean hasMessageParam = false;
|
|
|
+ int messageParamIndex = 0;
|
|
|
+ OUTER:
|
|
|
+ for (int i = 0; i < an2.length; i++) {
|
|
|
+ Annotation[] an1 = an2[i];
|
|
|
+ for (Annotation an : an1) {
|
|
|
+ if (an.annotationType().equals(Message.class)) {
|
|
|
+ hasMessageParam = true;
|
|
|
+ messageParamIndex = i;
|
|
|
+ break OUTER;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ Class<?>[] parameterTypes = method.getParameterTypes();
|
|
|
+ Object[] args = new Object[parameterTypes.length];
|
|
|
+ for (int i = 0; i < parameterTypes.length; i++) {
|
|
|
+ Class<?> curType = parameterTypes[i];
|
|
|
+ if (hasMessageParam && i == messageParamIndex) {
|
|
|
+ try {
|
|
|
+ args[i] = JsonUtil.fromJson(message, curType);
|
|
|
+ } catch (Exception e) {
|
|
|
+ throw new StatusException("500", "fail to parse message to object");
|
|
|
+ }
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if (curType.equals(User.class)) {
|
|
|
+ args[i] = user;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ result = method.invoke(bean, args);
|
|
|
+
|
|
|
+ out.setContent(result);
|
|
|
+
|
|
|
+ } catch (StatusException e) {
|
|
|
+ LOG.error("[onMessage-FAIL]. path=" + path + "", e);
|
|
|
+ out.setStatus(e.getCode(), e.getDesc());
|
|
|
+ } catch (Exception e) {
|
|
|
+ LOG.error("[onMessage-FAIL]. path=" + path + "", e);
|
|
|
+ out.setStatus("500", "系统异常");
|
|
|
+ }
|
|
|
+
|
|
|
+ WebSocketHelper.sendText(session, path, out);
|
|
|
+ }
|
|
|
+
|
|
|
+ @OnError
|
|
|
+ public void onError(Session session, @PathParam("path") String path, Throwable t) {
|
|
|
+
|
|
|
+ SessionInfo sessionInfo = WebSocketHelper.getSessionInfo(session);
|
|
|
+ if (null != sessionInfo) {
|
|
|
+ ThreadContext.put("TRACE_ID", sessionInfo.getSessionId());
|
|
|
+ ThreadContext.put("CALLER", sessionInfo.getUser().getKey());
|
|
|
+ } else {
|
|
|
+ ThreadContext.put("TRACE_ID", this.sessionId);
|
|
|
+ }
|
|
|
+
|
|
|
+ LOG.error("[onError]. path=" + path, t);
|
|
|
+ WebSocketHelper.closeSession(session);
|
|
|
+ }
|
|
|
|
|
|
}
|