Browse Source

merge from release_v4.1.2

deason 3 years ago
parent
commit
c71fa1b4bf
23 changed files with 651 additions and 491 deletions
  1. 1 0
      pom.xml
  2. 2 2
      src/main/java/cn/com/qmth/examcloud/ws/Tester.java
  3. 10 10
      src/main/java/cn/com/qmth/examcloud/ws/api/provider/WsCloudServiceProvider.java
  4. 0 1
      src/main/java/cn/com/qmth/examcloud/ws/config/ExamCloudWebMvcConfigurer.java
  5. 49 0
      src/main/java/cn/com/qmth/examcloud/ws/config/SwaggerConfig.java
  6. 42 41
      src/main/java/cn/com/qmth/examcloud/ws/handler/FileAnswerHandler.java
  7. 7 8
      src/main/java/cn/com/qmth/examcloud/ws/handler/TestHandler2.java
  8. 5 6
      src/main/java/cn/com/qmth/examcloud/ws/handler/TestHandler3.java
  9. 67 65
      src/main/java/cn/com/qmth/examcloud/ws/handler/bean/FileAnswerBean.java
  10. 14 14
      src/main/java/cn/com/qmth/examcloud/ws/handler/bean/TestBean.java
  11. 17 9
      src/main/java/cn/com/qmth/examcloud/ws/starter/api/controller/WebSocketController.java
  12. 3 6
      src/main/java/cn/com/qmth/examcloud/ws/starter/core/Message.java
  13. 3 6
      src/main/java/cn/com/qmth/examcloud/ws/starter/core/MessageHandler.java
  14. 72 74
      src/main/java/cn/com/qmth/examcloud/ws/starter/core/MessageHandlerHolder.java
  15. 103 103
      src/main/java/cn/com/qmth/examcloud/ws/starter/core/MessageOut.java
  16. 21 21
      src/main/java/cn/com/qmth/examcloud/ws/starter/core/SessionInfo.java
  17. 40 41
      src/main/java/cn/com/qmth/examcloud/ws/starter/core/Status.java
  18. 4 4
      src/main/java/cn/com/qmth/examcloud/ws/starter/core/WebSocketConfig.java
  19. 27 28
      src/main/java/cn/com/qmth/examcloud/ws/starter/core/WebSocketHelper.java
  20. 70 46
      src/main/java/cn/com/qmth/examcloud/ws/starter/core/WebSocketServerEndpoint.java
  21. 5 6
      src/main/java/cn/com/qmth/examcloud/ws/starter/handler/TestHandler.java
  22. 1 0
      src/main/resources/log4j2.xml
  23. 88 0
      src/main/resources/static/index.html

+ 1 - 0
pom.xml

@@ -69,6 +69,7 @@
                 <artifactId>maven-assembly-plugin</artifactId>
                 <configuration>
                     <finalName>examcloud-ws</finalName>
+                    <skipAssembly>${skipAssembly}</skipAssembly>
                     <descriptors>
                         <descriptor>assembly.xml</descriptor>
                     </descriptors>

+ 2 - 2
src/main/java/cn/com/qmth/examcloud/ws/Tester.java

@@ -5,8 +5,8 @@ import org.springframework.stereotype.Component;
 @Component
 public class Tester {
 
-	public void test() {
+    public void test() {
 
-	}
+    }
 
 }

+ 10 - 10
src/main/java/cn/com/qmth/examcloud/ws/api/provider/WsCloudServiceProvider.java

@@ -26,7 +26,7 @@ import org.springframework.web.bind.annotation.RestController;
 
 import javax.websocket.Session;
 
-@Api(tags = "websocket服务")
+@Api(tags = "WebSocket服务")
 @RestController
 @RequestMapping("api/cloud/ws")
 public class WsCloudServiceProvider implements WsCloudService {
@@ -35,7 +35,7 @@ public class WsCloudServiceProvider implements WsCloudService {
 
     private static final Logger log = LoggerFactory.getLogger(WsCloudServiceProvider.class);
 
-    @ApiOperation(value = "发送消息")
+    @ApiOperation(value = "RPC发送消息接口")
     @PostMapping("sendText")
     @Override
     public SendTextResp sendText(@RequestBody SendTextReq req) {
@@ -50,18 +50,18 @@ public class WsCloudServiceProvider implements WsCloudService {
         user.setUserType(userType);
         user.setUserId(userId);
         user.setRootOrgId(rootOrgId);
-        String key = user.buildKey();
+        String userKey = user.buildKey();
 
-        Session session = WebSocketHelper.getSession(path, key);
+        Session session = WebSocketHelper.getSession(path, userKey);
         if (null == session) {
-            log.error("NO_WS_SESSION key={} path={}", key, path);
-            throw new StatusException("100001", "no ws session about path [" + path + "]");
+            log.error("NO_WS_SESSION user={} path={}", userKey, path);
+            throw new StatusException("100001", "WS会话不存在");
         }
 
         SessionInfo sessionInfo = WebSocketHelper.getSessionInfo(session);
         if (null == sessionInfo) {
-            log.error("NO_SESSION_INFO key={} path={}", key, path);
-            throw new StatusException("100002", "no ws session info");
+            log.error("NO_SESSION_INFO user={} path={}", userKey, path);
+            throw new StatusException("100002", "WS信息不存在");
         }
 
         MessageOut out = new MessageOut(path, sessionInfo.getSessionId());
@@ -72,8 +72,8 @@ public class WsCloudServiceProvider implements WsCloudService {
             try {
                 jsonEl = JsonParser.parseString(content);
             } catch (JsonSyntaxException e) {
-                log.error("WS_MESSAGE_INVALID key={} path={}", key, path);
-                throw new StatusException("100003", "message is not a json string");
+                log.error("WS_MESSAGE_INVALID user={} path={}", userKey, path);
+                throw new StatusException("100003", "WS信息格式有误");
             }
         }
 

+ 0 - 1
src/main/java/cn/com/qmth/examcloud/ws/config/ExamCloudWebMvcConfigurer.java

@@ -2,7 +2,6 @@ package cn.com.qmth.examcloud.ws.config;
 
 import cn.com.qmth.examcloud.web.interceptor.FirstInterceptor;
 import cn.com.qmth.examcloud.web.redis.RedisClient;
-import cn.com.qmth.examcloud.web.security.DataRuleInterceptor;
 import cn.com.qmth.examcloud.web.security.RequestPermissionInterceptor;
 import cn.com.qmth.examcloud.web.security.ResourceManager;
 import cn.com.qmth.examcloud.web.security.RpcInterceptor;

+ 49 - 0
src/main/java/cn/com/qmth/examcloud/ws/config/SwaggerConfig.java

@@ -0,0 +1,49 @@
+package cn.com.qmth.examcloud.ws.config;
+
+import io.swagger.annotations.ApiOperation;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.ParameterBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.schema.ModelRef;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.service.Parameter;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Configuration
+@EnableSwagger2WebMvc
+public class SwaggerConfig {
+
+    @Bean
+    public Docket buildDocket() {
+        List<Parameter> parameters = new ArrayList<>();
+        parameters.add(new ParameterBuilder().name("key").modelRef(new ModelRef("String")).parameterType("header").required(false).build());
+        parameters.add(new ParameterBuilder().name("token").modelRef(new ModelRef("String")).parameterType("header").required(false).build());
+
+        return new Docket(DocumentationType.SWAGGER_2)
+                .groupName("default")
+                .apiInfo(buildApiInfo())
+                .globalOperationParameters(parameters)
+                .useDefaultResponseMessages(false)
+                .select()
+                .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
+                // .apis(RequestHandlerSelectors.basePackage("cn.com.qmth.examcloud.ws"))
+                .paths(PathSelectors.any())
+                .build();
+    }
+
+    public ApiInfo buildApiInfo() {
+        return new ApiInfoBuilder()
+                .title("考试云平台接口文档")
+                .version("v4.x.x")
+                .build();
+    }
+
+}

+ 42 - 41
src/main/java/cn/com/qmth/examcloud/ws/handler/FileAnswerHandler.java

@@ -15,46 +15,47 @@ import java.util.Map;
 @MessageHandler("fileAnswer")
 public class FileAnswerHandler {
 
-	@MessageHandler
-	public Map<String,Object> message(User user, @Message FileAnswerBean fileAnswerBean) {
-		try {
-			//事件类型
-			String eventType = fileAnswerBean.getEventType();
-
-			if (StringUtils.isNullOrEmpty(eventType)) {
-				return buildSystemErrorMap("无效的消息请求");
-			}
-			if (eventType.equals(WebSocketEventType.HEARTBEAT.toString())) {
-				return buildHeartbeatMessage(eventType);
-			} else {
-				return buildSystemErrorMap("无效的消息请求");
-			}
-		} catch (Exception e) {
-			return buildSystemErrorMap("无效的消息请求,详情:" + e.getMessage());
-		}
-	}
-
-	/**
-	 * 构建系统错误消息体
-	 *
-	 * @param message
-	 */
-	private Map<String,Object> buildSystemErrorMap(String message) {
-		Map<String,Object> errorMap = new HashMap<>();
-		errorMap.put("eventType", WebSocketEventType.SYSTEM_ERROR.toString());
-		errorMap.put("errorMessage", message);
-		return errorMap;
-	}
-
-	/**
-	 * 构建心跳消息体
-	 * @param eventType
-	 * @return
-	 */
-	private Map<String,Object> buildHeartbeatMessage(String eventType) {
-		Map<String,Object> heartbeatMap = new HashMap<>();
-		heartbeatMap.put("eventType", eventType);
-		return heartbeatMap;
-	}
+    @MessageHandler
+    public Map<String, Object> message(User user, @Message FileAnswerBean fileAnswerBean) {
+        try {
+            //事件类型
+            String eventType = fileAnswerBean.getEventType();
+
+            if (StringUtils.isNullOrEmpty(eventType)) {
+                return buildSystemErrorMap("无效的消息请求");
+            }
+            if (eventType.equals(WebSocketEventType.HEARTBEAT.toString())) {
+                return buildHeartbeatMessage(eventType);
+            } else {
+                return buildSystemErrorMap("无效的消息请求");
+            }
+        } catch (Exception e) {
+            return buildSystemErrorMap("无效的消息请求,详情:" + e.getMessage());
+        }
+    }
+
+    /**
+     * 构建系统错误消息体
+     *
+     * @param message
+     */
+    private Map<String, Object> buildSystemErrorMap(String message) {
+        Map<String, Object> errorMap = new HashMap<>();
+        errorMap.put("eventType", WebSocketEventType.SYSTEM_ERROR.toString());
+        errorMap.put("errorMessage", message);
+        return errorMap;
+    }
+
+    /**
+     * 构建心跳消息体
+     *
+     * @param eventType
+     * @return
+     */
+    private Map<String, Object> buildHeartbeatMessage(String eventType) {
+        Map<String, Object> heartbeatMap = new HashMap<>();
+        heartbeatMap.put("eventType", eventType);
+        return heartbeatMap;
+    }
 
 }

+ 7 - 8
src/main/java/cn/com/qmth/examcloud/ws/handler/TestHandler2.java

@@ -1,21 +1,20 @@
 package cn.com.qmth.examcloud.ws.handler;
 
-import org.springframework.stereotype.Component;
-
 import cn.com.qmth.examcloud.api.commons.security.bean.User;
 import cn.com.qmth.examcloud.ws.handler.bean.TestBean;
 import cn.com.qmth.examcloud.ws.starter.core.Message;
 import cn.com.qmth.examcloud.ws.starter.core.MessageHandler;
+import org.springframework.stereotype.Component;
 
 @Component
 @MessageHandler("test2")
 public class TestHandler2 {
 
-	@MessageHandler
-	public TestBean test(User user, @Message TestBean message) {
-		message.setS1(String.valueOf(System.currentTimeMillis()));
-		message.setS2(String.valueOf(System.currentTimeMillis()));
-		return message;
-	}
+    @MessageHandler
+    public TestBean test(User user, @Message TestBean message) {
+        message.setS1(String.valueOf(System.currentTimeMillis()));
+        message.setS2(String.valueOf(System.currentTimeMillis()));
+        return message;
+    }
 
 }

+ 5 - 6
src/main/java/cn/com/qmth/examcloud/ws/handler/TestHandler3.java

@@ -1,19 +1,18 @@
 package cn.com.qmth.examcloud.ws.handler;
 
-import org.springframework.stereotype.Component;
-
 import cn.com.qmth.examcloud.api.commons.security.bean.User;
 import cn.com.qmth.examcloud.commons.util.DateUtil;
 import cn.com.qmth.examcloud.ws.starter.core.Message;
 import cn.com.qmth.examcloud.ws.starter.core.MessageHandler;
+import org.springframework.stereotype.Component;
 
 @Component
 @MessageHandler("test3")
 public class TestHandler3 {
 
-	@MessageHandler
-	public String test(User user, @Message String message) {
-		return DateUtil.chinaNow();
-	}
+    @MessageHandler
+    public String test(User user, @Message String message) {
+        return DateUtil.chinaNow();
+    }
 
 }

+ 67 - 65
src/main/java/cn/com/qmth/examcloud/ws/handler/bean/FileAnswerBean.java

@@ -4,69 +4,71 @@ import cn.com.qmth.examcloud.api.commons.exchange.JsonSerializable;
 
 public class FileAnswerBean implements JsonSerializable {
 
-	private static final long serialVersionUID = -2201601873884785173L;
-	/**
-	 * 事件类型
-	 */
-	private String eventType;
-
-	/**
-	 * 题目序号
-	 */
-	private Integer order;
-
-	/**
-	 *是否为环境监测
-	 */
-	private Boolean testEnv;
-
-	/**
-	 * 传输文件类型(用于标识,通过二维码传输文件的类型)
-	 */
-	private String transferFileType;
-
-	/**
-	 * 考试记录id
-	 */
-	private Long examRecordDataId;
-
-	public String getEventType() {
-		return eventType;
-	}
-
-	public void setEventType(String eventType) {
-		this.eventType = eventType;
-	}
-
-	public Integer getOrder() {
-		return order;
-	}
-
-	public void setOrder(Integer order) {
-		this.order = order;
-	}
-
-	public Boolean getTestEnv() {
-		return testEnv;
-	}
-
-	public void setTestEnv(Boolean testEnv) {
-		this.testEnv = testEnv;
-	}
-
-	public String getTransferFileType() {
-		return transferFileType;
-	}
-
-	public void setTransferFileType(String transferFileType) {
-		this.transferFileType = transferFileType;
-	}
-
-	public Long getExamRecordDataId() {
-		return examRecordDataId;
-	}
-
-	public void setExamRecordDataId(Long examRecordDataId) {
-		this.examRecordDataId = examRecordDataId;
-	}
+    private static final long serialVersionUID = -2201601873884785173L;
+
+    /**
+     * 事件类型
+     */
+    private String eventType;
+
+    /**
+     * 题目序号
+     */
+    private Integer order;
+
+    /**
+     * 是否为环境监测
+     */
+    private Boolean testEnv;
+
+    /**
+     * 传输文件类型(用于标识,通过二维码传输文件的类型)
+     */
+    private String transferFileType;
+
+    /**
+     * 考试记录id
+     */
+    private Long examRecordDataId;
+
+    public String getEventType() {
+        return eventType;
+    }
+
+    public void setEventType(String eventType) {
+        this.eventType = eventType;
+    }
+
+    public Integer getOrder() {
+        return order;
+    }
+
+    public void setOrder(Integer order) {
+        this.order = order;
+    }
+
+    public Boolean getTestEnv() {
+        return testEnv;
+    }
+
+    public void setTestEnv(Boolean testEnv) {
+        this.testEnv = testEnv;
+    }
+
+    public String getTransferFileType() {
+        return transferFileType;
+    }
+
+    public void setTransferFileType(String transferFileType) {
+        this.transferFileType = transferFileType;
+    }
+
+    public Long getExamRecordDataId() {
+        return examRecordDataId;
+    }
+
+    public void setExamRecordDataId(Long examRecordDataId) {
+        this.examRecordDataId = examRecordDataId;
+    }
+
 }

+ 14 - 14
src/main/java/cn/com/qmth/examcloud/ws/handler/bean/TestBean.java

@@ -2,24 +2,24 @@ package cn.com.qmth.examcloud.ws.handler.bean;
 
 public class TestBean {
 
-	private String s1;
+    private String s1;
 
-	private String s2;
+    private String s2;
 
-	public String getS1() {
-		return s1;
-	}
+    public String getS1() {
+        return s1;
+    }
 
-	public void setS1(String s1) {
-		this.s1 = s1;
-	}
+    public void setS1(String s1) {
+        this.s1 = s1;
+    }
 
-	public String getS2() {
-		return s2;
-	}
+    public String getS2() {
+        return s2;
+    }
 
-	public void setS2(String s2) {
-		this.s2 = s2;
-	}
+    public void setS2(String s2) {
+        this.s2 = s2;
+    }
 
 }

+ 17 - 9
src/main/java/cn/com/qmth/examcloud/ws/starter/api/controller/WebSocketController.java

@@ -12,32 +12,40 @@ import cn.com.qmth.examcloud.ws.starter.core.WebSocketHelper;
 import com.google.gson.JsonElement;
 import com.google.gson.JsonParser;
 import com.google.gson.JsonSyntaxException;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.logging.log4j.ThreadContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.web.bind.annotation.*;
 
 import javax.websocket.Session;
 
+@Api(tags = "WebSocket服务")
 @RestController
 @RequestMapping("api/ctr/ws")
 public class WebSocketController extends ControllerSupport {
 
+    private static final Logger log = LoggerFactory.getLogger(WebSocketController.class);
+
     @WithoutStackTrace
+    @ApiOperation(value = "API发送消息接口")
     @PostMapping("{path}")
     public String post(@PathVariable String path, @RequestBody String message) {
-
         User accessUser = getAccessUser();
+        String userKey = accessUser.buildKey();
 
-        Session session = WebSocketHelper.getSession(path, accessUser.getKey());
-
+        Session session = WebSocketHelper.getSession(path, userKey);
         if (null == session) {
-            throw new StatusException("100001", "no ws session about path [" + path + "]");
+            log.error("NO_WS_SESSION user={} path={}", userKey, path);
+            throw new StatusException("100001", "WS会话不存在");
         }
 
         SessionInfo sessionInfo = WebSocketHelper.getSessionInfo(session);
-
         if (null == sessionInfo) {
-            throw new StatusException("100002", "no ws session info");
+            log.error("NO_SESSION_INFO user={} path={}", userKey, path);
+            throw new StatusException("100002", "WS信息不存在");
         }
 
         MessageOut out = new MessageOut(path, sessionInfo.getSessionId());
@@ -47,7 +55,8 @@ public class WebSocketController extends ControllerSupport {
             try {
                 jsonEl = JsonParser.parseString(message);
             } catch (JsonSyntaxException e) {
-                throw new StatusException("100003", "message is not a json string");
+                log.error("WS_MESSAGE_INVALID user={} path={}", userKey, path);
+                throw new StatusException("100003", "WS信息格式有误");
             }
         }
 
@@ -60,8 +69,7 @@ public class WebSocketController extends ControllerSupport {
             ThreadContext.put("TRACE_ID", ThreadLocalUtil.getTraceId());
         }
 
-        String json = JsonUtil.toJson(out);
-        return json;
+        return JsonUtil.toJson(out);
     }
 
 }

+ 3 - 6
src/main/java/cn/com/qmth/examcloud/ws/starter/core/Message.java

@@ -1,10 +1,6 @@
 package cn.com.qmth.examcloud.ws.starter.core;
 
-import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
+import java.lang.annotation.*;
 
 /**
  * 接口ID 注解
@@ -18,5 +14,6 @@ import java.lang.annotation.Target;
 @Documented
 public @interface Message {
 
-	String value() default "";
+    String value() default "";
+
 }

+ 3 - 6
src/main/java/cn/com/qmth/examcloud/ws/starter/core/MessageHandler.java

@@ -1,10 +1,6 @@
 package cn.com.qmth.examcloud.ws.starter.core;
 
-import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
+import java.lang.annotation.*;
 
 /**
  * 接口ID 注解
@@ -18,5 +14,6 @@ import java.lang.annotation.Target;
 @Documented
 public @interface MessageHandler {
 
-	String value() default "";
+    String value() default "";
+
 }

+ 72 - 74
src/main/java/cn/com/qmth/examcloud/ws/starter/core/MessageHandlerHolder.java

@@ -1,8 +1,7 @@
 package cn.com.qmth.examcloud.ws.starter.core;
 
-import java.lang.reflect.Method;
-import java.util.Map;
-
+import cn.com.qmth.examcloud.web.support.SpringContextHolder;
+import com.google.common.collect.Maps;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.boot.ApplicationArguments;
 import org.springframework.boot.ApplicationRunner;
@@ -10,9 +9,8 @@ import org.springframework.core.annotation.AnnotationUtils;
 import org.springframework.core.annotation.Order;
 import org.springframework.stereotype.Component;
 
-import com.google.common.collect.Maps;
-
-import cn.com.qmth.examcloud.web.support.SpringContextHolder;
+import java.lang.reflect.Method;
+import java.util.Map;
 
 /**
  * 消息处理器 管理器
@@ -25,73 +23,73 @@ import cn.com.qmth.examcloud.web.support.SpringContextHolder;
 @Order(100)
 public class MessageHandlerHolder implements ApplicationRunner {
 
-	private static Map<String, Method> methodMap = Maps.newConcurrentMap();
-
-	private static Map<String, Object> beanMap = Maps.newConcurrentMap();
-
-	public static Method getMethod(String path) {
-		return methodMap.get(path);
-	}
-
-	public static Object getBean(String path) {
-		return beanMap.get(path);
-	}
-
-	@Override
-	public void run(ApplicationArguments args) throws Exception {
-
-		Map<String, Object> map = SpringContextHolder.getApplicationContext()
-				.getBeansWithAnnotation(MessageHandler.class);
-
-		for (Object bean : map.values()) {
-			MessageHandler messageHandlerOfClass = AnnotationUtils.findAnnotation(bean.getClass(),
-					MessageHandler.class);
-			String valueOfClass = messageHandlerOfClass.value();
-
-			Method[] methods = bean.getClass().getDeclaredMethods();
-
-			for (Method method : methods) {
-				MessageHandler messageHandlerOfMethod = method.getAnnotation(MessageHandler.class);
-				if (null == messageHandlerOfMethod) {
-					continue;
-				}
-				String valueOfMethod = messageHandlerOfMethod.value();
-
-				String path = join(valueOfClass, valueOfMethod);
-				methodMap.put(path, method);
-				beanMap.put(path, bean);
-			}
-
-		}
-
-	}
-
-	private String join(String valueOfClass, String valueOfMethod) {
-		valueOfClass = valueOfClass.trim();
-		valueOfMethod = valueOfMethod.trim();
-
-		if (valueOfClass.startsWith("/")) {
-			valueOfClass = valueOfClass.substring(1);
-		}
-		if (valueOfClass.endsWith("/")) {
-			valueOfClass = valueOfClass.substring(0, valueOfClass.length() - 1);
-		}
-		if (valueOfMethod.startsWith("/")) {
-			valueOfMethod = valueOfMethod.substring(1);
-		}
-		if (valueOfMethod.endsWith("/")) {
-			valueOfMethod = valueOfMethod.substring(0, valueOfMethod.length() - 1);
-		}
-
-		if (StringUtils.isNotEmpty(valueOfClass) && StringUtils.isNotEmpty(valueOfMethod)) {
-			return valueOfClass + "/" + valueOfMethod;
-		} else if (StringUtils.isNotEmpty(valueOfClass)) {
-			return valueOfClass;
-		} else if (StringUtils.isNotEmpty(valueOfMethod)) {
-			return valueOfMethod;
-		} else {
-			return "";
-		}
-	}
+    private static Map<String, Method> methodMap = Maps.newConcurrentMap();
+
+    private static Map<String, Object> beanMap = Maps.newConcurrentMap();
+
+    public static Method getMethod(String path) {
+        return methodMap.get(path);
+    }
+
+    public static Object getBean(String path) {
+        return beanMap.get(path);
+    }
+
+    @Override
+    public void run(ApplicationArguments args) throws Exception {
+
+        Map<String, Object> map = SpringContextHolder.getApplicationContext()
+                .getBeansWithAnnotation(MessageHandler.class);
+
+        for (Object bean : map.values()) {
+            MessageHandler messageHandlerOfClass = AnnotationUtils.findAnnotation(bean.getClass(),
+                    MessageHandler.class);
+            String valueOfClass = messageHandlerOfClass.value();
+
+            Method[] methods = bean.getClass().getDeclaredMethods();
+
+            for (Method method : methods) {
+                MessageHandler messageHandlerOfMethod = method.getAnnotation(MessageHandler.class);
+                if (null == messageHandlerOfMethod) {
+                    continue;
+                }
+                String valueOfMethod = messageHandlerOfMethod.value();
+
+                String path = join(valueOfClass, valueOfMethod);
+                methodMap.put(path, method);
+                beanMap.put(path, bean);
+            }
+
+        }
+
+    }
+
+    private String join(String valueOfClass, String valueOfMethod) {
+        valueOfClass = valueOfClass.trim();
+        valueOfMethod = valueOfMethod.trim();
+
+        if (valueOfClass.startsWith("/")) {
+            valueOfClass = valueOfClass.substring(1);
+        }
+        if (valueOfClass.endsWith("/")) {
+            valueOfClass = valueOfClass.substring(0, valueOfClass.length() - 1);
+        }
+        if (valueOfMethod.startsWith("/")) {
+            valueOfMethod = valueOfMethod.substring(1);
+        }
+        if (valueOfMethod.endsWith("/")) {
+            valueOfMethod = valueOfMethod.substring(0, valueOfMethod.length() - 1);
+        }
+
+        if (StringUtils.isNotEmpty(valueOfClass) && StringUtils.isNotEmpty(valueOfMethod)) {
+            return valueOfClass + "/" + valueOfMethod;
+        } else if (StringUtils.isNotEmpty(valueOfClass)) {
+            return valueOfClass;
+        } else if (StringUtils.isNotEmpty(valueOfMethod)) {
+            return valueOfMethod;
+        } else {
+            return "";
+        }
+    }
 
 }

+ 103 - 103
src/main/java/cn/com/qmth/examcloud/ws/starter/core/MessageOut.java

@@ -1,9 +1,9 @@
 package cn.com.qmth.examcloud.ws.starter.core;
 
-import java.util.Date;
-
 import cn.com.qmth.examcloud.api.commons.exchange.JsonSerializable;
 
+import java.util.Date;
+
 /**
  * 服务端消息
  *
@@ -13,106 +13,106 @@ import cn.com.qmth.examcloud.api.commons.exchange.JsonSerializable;
  */
 public class MessageOut implements JsonSerializable {
 
-	private static final long serialVersionUID = -2255327250550304236L;
-
-	private Date date;
-
-	private String path;
-
-	private String sessionId;
-
-	private Status status;
-
-	private String eventId;
-
-	private Object content;
-
-	/**
-	 * 构造函数
-	 *
-	 * @param path
-	 */
-	public MessageOut(String path) {
-		super();
-		this.path = path;
-		this.status = new Status();
-	}
-
-	/**
-	 * 构造函数
-	 *
-	 * @param path
-	 * @param sessionId
-	 */
-	public MessageOut(String path, String sessionId) {
-		super();
-		this.path = path;
-		this.sessionId = sessionId;
-		this.status = new Status();
-	}
-
-	/**
-	 * 设置状态
-	 *
-	 * @author WANGWEI
-	 * @param code
-	 * @param desc
-	 */
-	public void setStatus(String code, String desc) {
-		if (null == this.status) {
-			this.status = new Status();
-		}
-
-		this.status.setCode(code);
-		this.status.setDesc(desc);
-	}
-
-	public Date getDate() {
-		return date;
-	}
-
-	public void setDate(Date date) {
-		this.date = date;
-	}
-
-	public String getPath() {
-		return path;
-	}
-
-	public void setPath(String path) {
-		this.path = path;
-	}
-
-	public String getSessionId() {
-		return sessionId;
-	}
-
-	public void setSessionId(String sessionId) {
-		this.sessionId = sessionId;
-	}
-
-	public Status getStatus() {
-		return status;
-	}
-
-	public void setStatus(Status status) {
-		this.status = status;
-	}
-
-	public String getEventId() {
-		return eventId;
-	}
-
-	public void setEventId(String eventId) {
-		this.eventId = eventId;
-	}
-
-	public Object getContent() {
-		return content;
-	}
-
-	public void setContent(Object content) {
-		this.content = content;
-	}
+    private static final long serialVersionUID = -2255327250550304236L;
+
+    private Date date;
+
+    private String path;
+
+    private String sessionId;
+
+    private Status status;
+
+    private String eventId;
+
+    private Object content;
+
+    /**
+     * 构造函数
+     *
+     * @param path
+     */
+    public MessageOut(String path) {
+        super();
+        this.path = path;
+        this.status = new Status();
+    }
+
+    /**
+     * 构造函数
+     *
+     * @param path
+     * @param sessionId
+     */
+    public MessageOut(String path, String sessionId) {
+        super();
+        this.path = path;
+        this.sessionId = sessionId;
+        this.status = new Status();
+    }
+
+    /**
+     * 设置状态
+     *
+     * @param code
+     * @param desc
+     * @author WANGWEI
+     */
+    public void setStatus(String code, String desc) {
+        if (null == this.status) {
+            this.status = new Status();
+        }
+
+        this.status.setCode(code);
+        this.status.setDesc(desc);
+    }
+
+    public Date getDate() {
+        return date;
+    }
+
+    public void setDate(Date date) {
+        this.date = date;
+    }
+
+    public String getPath() {
+        return path;
+    }
+
+    public void setPath(String path) {
+        this.path = path;
+    }
+
+    public String getSessionId() {
+        return sessionId;
+    }
+
+    public void setSessionId(String sessionId) {
+        this.sessionId = sessionId;
+    }
+
+    public Status getStatus() {
+        return status;
+    }
+
+    public void setStatus(Status status) {
+        this.status = status;
+    }
+
+    public String getEventId() {
+        return eventId;
+    }
+
+    public void setEventId(String eventId) {
+        this.eventId = eventId;
+    }
+
+    public Object getContent() {
+        return content;
+    }
+
+    public void setContent(Object content) {
+        this.content = content;
+    }
 
 }

+ 21 - 21
src/main/java/cn/com/qmth/examcloud/ws/starter/core/SessionInfo.java

@@ -11,34 +11,34 @@ import cn.com.qmth.examcloud.api.commons.security.bean.User;
  */
 public class SessionInfo {
 
-	private String index;
+    private String index;
 
-	private String sessionId;
+    private String sessionId;
 
-	private User user;
+    private User user;
 
-	public String getIndex() {
-		return index;
-	}
+    public String getIndex() {
+        return index;
+    }
 
-	public void setIndex(String index) {
-		this.index = index;
-	}
+    public void setIndex(String index) {
+        this.index = index;
+    }
 
-	public String getSessionId() {
-		return sessionId;
-	}
+    public String getSessionId() {
+        return sessionId;
+    }
 
-	public void setSessionId(String sessionId) {
-		this.sessionId = sessionId;
-	}
+    public void setSessionId(String sessionId) {
+        this.sessionId = sessionId;
+    }
 
-	public User getUser() {
-		return user;
-	}
+    public User getUser() {
+        return user;
+    }
 
-	public void setUser(User user) {
-		this.user = user;
-	}
+    public void setUser(User user) {
+        this.user = user;
+    }
 
 }

+ 40 - 41
src/main/java/cn/com/qmth/examcloud/ws/starter/core/Status.java

@@ -11,46 +11,45 @@ import cn.com.qmth.examcloud.api.commons.exchange.JsonSerializable;
  */
 public class Status implements JsonSerializable {
 
-	private static final long serialVersionUID = 6990729545055549495L;
-
-	private String code = "200";
-
-	private String desc = "OK";
-
-	/**
-	 * 构造函数
-	 *
-	 */
-	public Status() {
-		super();
-	}
-
-	/**
-	 * 构造函数
-	 *
-	 * @param code
-	 * @param desc
-	 */
-	public Status(String code, String desc) {
-		super();
-		this.code = code;
-		this.desc = desc;
-	}
-
-	public String getCode() {
-		return code;
-	}
-
-	public void setCode(String code) {
-		this.code = code;
-	}
-
-	public String getDesc() {
-		return desc;
-	}
-
-	public void setDesc(String desc) {
-		this.desc = desc;
-	}
+    private static final long serialVersionUID = 6990729545055549495L;
+
+    private String code = "200";
+
+    private String desc = "OK";
+
+    /**
+     * 构造函数
+     */
+    public Status() {
+        super();
+    }
+
+    /**
+     * 构造函数
+     *
+     * @param code
+     * @param desc
+     */
+    public Status(String code, String desc) {
+        super();
+        this.code = code;
+        this.desc = desc;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+
+    public String getDesc() {
+        return desc;
+    }
+
+    public void setDesc(String desc) {
+        this.desc = desc;
+    }
 
 }

+ 4 - 4
src/main/java/cn/com/qmth/examcloud/ws/starter/core/WebSocketConfig.java

@@ -9,9 +9,9 @@ import org.springframework.web.socket.server.standard.ServerEndpointExporter;
 @EnableWebSocket
 public class WebSocketConfig {
 
-	@Bean
-	public ServerEndpointExporter serverEndpointExporter() {
-		return new ServerEndpointExporter();
-	}
+    @Bean
+    public ServerEndpointExporter serverEndpointExporter() {
+        return new ServerEndpointExporter();
+    }
 
 }

+ 27 - 28
src/main/java/cn/com/qmth/examcloud/ws/starter/core/WebSocketHelper.java

@@ -24,9 +24,9 @@ public class WebSocketHelper {
 
     private static final Logger LOG = LoggerFactory.getLogger(WebSocketHelper.class);
 
-    private static final Map<String, Session> INDEX_MAP = Maps.newConcurrentMap();
+    private static final Map<String, Session> SESSION_MAP = Maps.newConcurrentMap();
 
-    private static final Map<Session, SessionInfo> SESESION_INFO_MAP = Maps.newConcurrentMap();
+    private static final Map<Session, SessionInfo> SESSION_INFO_MAP = Maps.newConcurrentMap();
 
     /**
      * 重新设置session
@@ -38,23 +38,22 @@ public class WebSocketHelper {
      * @author WANGWEI
      */
     public static void setSession(String path, User user, Session session, String sessionId) {
-
         String index = user.getKey() + ":" + path;
-        Session oldSession = INDEX_MAP.get(index);
+        Session oldSession = SESSION_MAP.get(index);
         if (null != oldSession && !oldSession.equals(session)) {
-            SESESION_INFO_MAP.remove(oldSession);
+            SESSION_INFO_MAP.remove(oldSession);
             IOUtils.closeQuietly(oldSession);
         }
 
-        INDEX_MAP.put(index, session);
+        SESSION_MAP.put(index, session);
 
-        SessionInfo si = new SessionInfo();
-        si.setIndex(index);
-        si.setUser(user);
-        si.setSessionId(sessionId);
-        SESESION_INFO_MAP.put(session, si);
+        SessionInfo sessionInfo = new SessionInfo();
+        sessionInfo.setIndex(index);
+        sessionInfo.setUser(user);
+        sessionInfo.setSessionId(sessionId);
+        SESSION_INFO_MAP.put(session, sessionInfo);
 
-        LOG.info("WS_SESSION_IN key={} cacheSize={}", index, INDEX_MAP.size());
+        LOG.info("WS_SESSION_IN key={} wsCacheSize={}", index, SESSION_MAP.size());
     }
 
     /**
@@ -64,16 +63,13 @@ public class WebSocketHelper {
      * @author WANGWEI
      */
     public static void closeSession(Session session) {
-        SessionInfo si = SESESION_INFO_MAP.get(session);
-
-        if (null != si) {
-            INDEX_MAP.remove(si.getIndex());
-
-            LOG.info("WS_SESSION_OUT key={} cacheSize={}", si.getIndex(), INDEX_MAP.size());
+        SessionInfo sessionInfo = SESSION_INFO_MAP.get(session);
+        if (null != sessionInfo) {
+            SESSION_MAP.remove(sessionInfo.getIndex());
+            LOG.info("WS_SESSION_OUT key={} wsCacheSize={}", sessionInfo.getIndex(), SESSION_MAP.size());
         }
 
-        SESESION_INFO_MAP.remove(session);
-
+        SESSION_INFO_MAP.remove(session);
         IOUtils.closeQuietly(session);
     }
 
@@ -87,7 +83,7 @@ public class WebSocketHelper {
      */
     public static Session getSession(String path, String key) {
         String index = key + ":" + path;
-        Session session = INDEX_MAP.get(index);
+        Session session = SESSION_MAP.get(index);
         return session;
     }
 
@@ -102,9 +98,7 @@ public class WebSocketHelper {
      * @author WANGWEI
      */
     public static Session getSession(String path, Long rootOrgId, UserType userType, Long userId) {
-
         String key = StringUtil.join("U_", userType.getCode(), "_", rootOrgId, "_", userId);
-
         return getSession(path, key);
     }
 
@@ -116,7 +110,7 @@ public class WebSocketHelper {
      * @author WANGWEI
      */
     public static SessionInfo getSessionInfo(Session session) {
-        return SESESION_INFO_MAP.get(session);
+        return SESSION_INFO_MAP.get(session);
     }
 
     /**
@@ -131,12 +125,15 @@ public class WebSocketHelper {
         try {
             out.setDate(new Date());
             String message = JsonUtil.toJson(out);
+
             if (LOG.isDebugEnabled()) {
-                LOG.debug("[sendText]. path=" + path + "; message=" + message);
+                LOG.debug("[sendText] path={} message={}", path, message);
             }
+
             session.getBasicRemote().sendText(message);
         } catch (Exception e) {
-            LOG.error("[sendText-FAIL]. path=" + path, e);
+            LOG.error("[sendText] error... path={}", path, e);
+
             IOUtils.closeQuietly(session);
             return;
         }
@@ -153,11 +150,13 @@ public class WebSocketHelper {
     public static void sendText(Session session, String path, String out) {
         try {
             if (LOG.isDebugEnabled()) {
-                LOG.error("[sendText]. path=" + path + "; message=" + out);
+                LOG.debug("[sendText] path={} message={}", path, out);
             }
+
             session.getBasicRemote().sendText(out);
         } catch (Exception e) {
-            LOG.error("[sendText-FAIL]. path=" + path, e);
+            LOG.error("[sendText] error... path={}", path, e);
+
             IOUtils.closeQuietly(session);
             return;
         }

+ 70 - 46
src/main/java/cn/com/qmth/examcloud/ws/starter/core/WebSocketServerEndpoint.java

@@ -19,6 +19,7 @@ import org.springframework.stereotype.Component;
 import javax.websocket.*;
 import javax.websocket.server.PathParam;
 import javax.websocket.server.ServerEndpoint;
+import java.io.EOFException;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Method;
 import java.util.List;
@@ -59,8 +60,17 @@ public class WebSocketServerEndpoint {
         this.sessionId = UUID.randomUUID().toString().replace("-", "");
         ThreadContext.put("TRACE_ID", sessionId);
 
-        if (LOG.isInfoEnabled()) {
-            LOG.info("[onOpen] into... path={} curSessionSize={}", path, amount);
+        String key = getRequestParameter(session, "key");
+        String token = getRequestParameter(session, "token");
+        if (StringUtils.isBlank(key)) {
+            LOG.warn("[onOpen] refused... path={}, user key is empty", path);
+            IOUtils.closeQuietly(session);
+            return;
+        }
+        if (StringUtils.isBlank(token)) {
+            LOG.warn("[onOpen] refused... path={}, user token is empty", path);
+            IOUtils.closeQuietly(session);
+            return;
         }
 
         MessageOut out = new MessageOut(path, sessionId);
@@ -68,35 +78,28 @@ public class WebSocketServerEndpoint {
 
         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");
+            LOG.warn("[onOpen] refused... user={} path={}, 404 not found", key, path);
 
-        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");
+            out.setStatus("404", "not found");
+            WebSocketHelper.sendText(session, path, out);
             IOUtils.closeQuietly(session);
             return;
         }
 
         User user = getRedisClient().get(key, User.class);
-
         if (null == user) {
+            LOG.warn("[onOpen] refused... user={} path={}, 403 no login", key, path);
+
             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");
+        }
+
+        if (!token.equals(user.getToken())) {
+            LOG.warn("[onOpen] refused... user={} path={}, 403 token invalid", key, path);
+
+            out.setStatus("403", "token invalid");
             WebSocketHelper.sendText(session, path, out);
             IOUtils.closeQuietly(session);
             return;
@@ -105,7 +108,7 @@ public class WebSocketServerEndpoint {
         ThreadContext.put("CALLER", user.getKey());
 
         if (LOG.isInfoEnabled()) {
-            LOG.info("[onOpen] sendText... path={} curSessionSize={} user={}", path, amount, user.getKey());
+            LOG.info("[onOpen] into... user={} path={} wsSessionSize={}", key, path, amount);
         }
 
         WebSocketHelper.sendText(session, path, out);
@@ -128,26 +131,27 @@ public class WebSocketServerEndpoint {
         if (CollectionUtils.isEmpty(list)) {
             return null;
         }
-        String value = StringUtils.join(list, ",");
-        return value;
+
+        return StringUtils.join(list, ",");
     }
 
     @OnClose
     public void onClose(Session session, @PathParam("path") String path) {
         long amount = counter.decrementAndGet();
 
-        String user = "";
+        String user = "unknown";
         SessionInfo sessionInfo = WebSocketHelper.getSessionInfo(session);
         if (null != sessionInfo) {
             user = sessionInfo.getUser().getKey();
             ThreadContext.put("TRACE_ID", sessionInfo.getSessionId());
             ThreadContext.put("CALLER", user);
         } else {
+            // 临时会话
             ThreadContext.put("TRACE_ID", this.sessionId);
         }
 
         if (LOG.isInfoEnabled()) {
-            LOG.info("[onClose] path={} curSessionSize={} user={}", path, amount, user);
+            LOG.info("[onClose] user={} path={} wsSessionSize={}", user, path, amount);
         }
 
         WebSocketHelper.closeSession(session);
@@ -155,45 +159,46 @@ public class WebSocketServerEndpoint {
 
     @OnMessage
     public void onMessage(Session session, @PathParam("path") String path, String message) {
-
         SessionInfo sessionInfo = WebSocketHelper.getSessionInfo(session);
+        String userKey = sessionInfo.getUser().getKey();
         ThreadContext.put("TRACE_ID", sessionInfo.getSessionId());
-        ThreadContext.put("CALLER", sessionInfo.getUser().getKey());
+        ThreadContext.put("CALLER", userKey);
 
         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");
+            LOG.warn("[onMessage] fail... user={} path={}, 500 message invalid: {}", userKey, path, message);
+
+            out.setStatus("500", "message invalid");
             WebSocketHelper.sendText(session, path, out);
             IOUtils.closeQuietly(session);
             return;
         }
 
-        if (LOG.isInfoEnabled()) {
-            LOG.info("[onMessage] path={} user={}", path, sessionInfo.getUser().getKey());
-        }
-
-        SessionInfo si = WebSocketHelper.getSessionInfo(session);
-
-        User user = getRedisClient().get(si.getUser().getKey(), User.class);
-
+        User user = getRedisClient().get(userKey, User.class);
         if (null == user) {
+            LOG.warn("[onMessage] fail... user={} path={}, 403 token invalid", userKey, path);
+
             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");
+        }
+
+        if (!sessionInfo.getUser().getToken().equals(user.getToken())) {
+            LOG.warn("[onMessage] fail... user={} path={}, 403 token invalid", userKey, path);
+
+            out.setStatus("403", "token invalid");
             WebSocketHelper.sendText(session, path, out);
             IOUtils.closeQuietly(session);
             return;
         }
 
+        boolean hasErr = false;
         Object result = null;
         try {
-
             Method method = MessageHandlerHolder.getMethod(path);
             Object bean = MessageHandlerHolder.getBean(path);
 
@@ -221,7 +226,7 @@ public class WebSocketServerEndpoint {
                     try {
                         args[i] = JsonUtil.fromJson(message, curType);
                     } catch (Exception e) {
-                        throw new StatusException("500", "fail to parse message to object");
+                        throw new StatusException("500", "message parse fail...");
                     }
                     continue;
                 }
@@ -234,31 +239,50 @@ public class WebSocketServerEndpoint {
             result = method.invoke(bean, args);
 
             out.setContent(result);
-
         } catch (StatusException e) {
-            LOG.error("[onMessage-FAIL]. path=" + path + "", e);
+            LOG.error("[onMessage] error... user={} path={}", userKey, path, e);
             out.setStatus(e.getCode(), e.getDesc());
+            hasErr = true;
         } catch (Exception e) {
-            LOG.error("[onMessage-FAIL]. path=" + path + "", e);
+            LOG.error("[onMessage] error... user={} path={}", userKey, path, e);
             out.setStatus("500", "系统异常");
+            hasErr = true;
+        }
+
+        if (LOG.isInfoEnabled() && !hasErr) {
+            if (result != null) {
+                LOG.info("[onMessage] user={} path={} content={}", userKey, path, result);
+            } else {
+                LOG.info("[onMessage] user={} path={}", userKey, path);
+            }
         }
 
         WebSocketHelper.sendText(session, path, out);
     }
 
     @OnError
-    public void onError(Session session, @PathParam("path") String path, Throwable t) {
-        String user = "";
+    public void onError(Session session, @PathParam("path") String path, Throwable err) {
+        String user = "unknown";
         SessionInfo sessionInfo = WebSocketHelper.getSessionInfo(session);
         if (null != sessionInfo) {
             user = sessionInfo.getUser().getKey();
             ThreadContext.put("TRACE_ID", sessionInfo.getSessionId());
             ThreadContext.put("CALLER", user);
         } else {
+            // 临时会话
             ThreadContext.put("TRACE_ID", this.sessionId);
         }
 
-        LOG.error("[onError] path={} user={} ", path, user, t);
+        if (err != null) {
+            if (err instanceof EOFException) {
+                // WebSocket 默认60秒内无心跳会关闭连接
+                LOG.error("[onError] user={} path={}, cause = connection closed, EOFException...", user, path);
+            } else {
+                LOG.error("[onError] user={} path={}", user, path, err);
+            }
+        } else {
+            LOG.error("[onError] user={} path={}, no err msg...", user, path);
+        }
 
         WebSocketHelper.closeSession(session);
     }

+ 5 - 6
src/main/java/cn/com/qmth/examcloud/ws/starter/handler/TestHandler.java

@@ -1,18 +1,17 @@
 package cn.com.qmth.examcloud.ws.starter.handler;
 
-import org.springframework.stereotype.Component;
-
 import cn.com.qmth.examcloud.api.commons.security.bean.User;
 import cn.com.qmth.examcloud.ws.starter.core.Message;
 import cn.com.qmth.examcloud.ws.starter.core.MessageHandler;
+import org.springframework.stereotype.Component;
 
 @Component
 @MessageHandler("test")
 public class TestHandler {
 
-	@MessageHandler
-	public String test(User user, @Message String message) {
-		return "Hello";
-	}
+    @MessageHandler
+    public String test(User user, @Message String message) {
+        return "Hello";
+    }
 
 }

+ 1 - 0
src/main/resources/log4j2.xml

@@ -36,6 +36,7 @@
 
     <Loggers>
         <logger name="springfox.documentation" level="WARN"/>
+        <logger name="org.mongodb.driver" level="WARN"/>
         <logger name="org.springframework" level="WARN"/>
         <logger name="org.hibernate" level="WARN"/>
         <logger name="org.apache" level="WARN"/>

+ 88 - 0
src/main/resources/static/index.html

@@ -0,0 +1,88 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <title>Demo</title>
+</head>
+<body>
+<div>
+    <button onclick="openWebSocket()" style="color: green">Open</button>
+    <button onclick="closeWebSocket()" style="color: red">Close</button>
+    <br/>
+
+    <textarea id="content" type="text" rows="5" cols="50"/></textarea>
+
+    <p>
+        <button onclick="sendMessage()" style="color: orange;width: 385px">发送</button>
+    </p>
+
+    <textarea id="message" rows="20" cols="50" style="background-color:lightcyan"></textarea>
+</div>
+
+<script type="text/javascript">
+    let websocket = null;
+    let key = "U_C_0_9";
+    let token = "8fde06cd6b5d488b92aa2053eea2949c";
+
+    function openWebSocket() {
+        // 创建WebSocket连接
+        if (websocket && websocket.readyState === 1) {
+            showMessage("已连接!");
+            return;
+        }
+
+        websocket = new WebSocket("ws://localhost:8010/api/ws/fileAnswer?key=" + key + "&token=" + token);
+
+        websocket.onopen = function (event) {
+            // 连接成功回调
+            console.log(event);
+            showMessage("连接成功!");
+        }
+
+        websocket.onclose = function (event) {
+            // 连接关闭回调
+            console.log(event);
+            showMessage("连接关闭!");
+        }
+
+        websocket.onerror = function (event) {
+            // 连接错误回调
+            console.log(event);
+            showMessage("连接错误!");
+        };
+
+        websocket.onmessage = function (event) {
+            // 接收消息回调
+            console.log(event);
+            showMessage(event.data);
+        }
+    }
+
+    function closeWebSocket() {
+        // 关闭WebSocket连接
+        if (websocket) {
+            websocket.close();
+        }
+    }
+
+    function sendMessage() {
+        if (!websocket || websocket.readyState !== 1) {
+            showMessage("未连接!");
+            return;
+        }
+
+        // 发送消息
+        let message = document.getElementById("content").value;
+        websocket.send(message);
+    }
+
+    let index = 1;
+
+    function showMessage(msg) {
+        let lines = document.getElementById("message").innerHTML;
+        document.getElementById("message").innerHTML = index + "-->" + msg + "\n\n" + lines;
+        index++;
+    }
+</script>
+</body>
+</html>