Explorar el Código

add nett-socket 例子

zcc hace 2 años
padre
commit
f43e22ecf0

+ 6 - 1
mec-websocket/pom.xml

@@ -66,7 +66,12 @@
 			<artifactId>easy-captcha</artifactId>
 			<version>1.6.2</version>
 		</dependency>
-
+    <!--	netty-socketio	-->
+		<dependency>
+			<groupId>com.corundumstudio.socketio</groupId>
+			<artifactId>netty-socketio</artifactId>
+			<version>1.7.7</version>
+		</dependency>
 	</dependencies>
 	<build>
 		<plugins>

+ 46 - 0
mec-websocket/src/main/java/com/ym/mec/web/config/SocketIoConfig.java

@@ -0,0 +1,46 @@
+package com.ym.mec.web.config;
+
+import com.corundumstudio.socketio.AuthorizationListener;
+import com.corundumstudio.socketio.HandshakeData;
+import com.corundumstudio.socketio.SocketConfig;
+import com.corundumstudio.socketio.SocketIOServer;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class SocketIoConfig {
+    @Value("${socket.server.host}")
+    private String host;
+
+    @Value("${socket.server.port}")
+    private Integer port;
+
+    @Bean
+    public SocketIOServer socketIOServer() {
+        com.corundumstudio.socketio.Configuration config = new com.corundumstudio.socketio.Configuration();
+        config.setHostname(host);
+        config.setPort(port);
+        config.setPingInterval(5000);
+        config.setPingTimeout(3000);
+        config.setWorkerThreads(100);
+
+        SocketConfig socketConfig = new SocketConfig();
+        socketConfig.setReuseAddress(true);
+        config.setSocketConfig(socketConfig);
+
+        //设置最大每帧处理数据的长度,防止他人利用大数据来攻击服务器
+        config.setMaxFramePayloadLength(1024 * 1024);
+        //设置http交互最大内容长度
+        config.setMaxHttpContentLength(1024 * 1024);
+        //授权
+        config.setAuthorizationListener(new AuthorizationListener() {
+            @Override
+            public boolean isAuthorized(HandshakeData data) {
+                return true;
+            }
+        });
+        return new SocketIOServer(config);
+    }
+
+}

+ 55 - 0
mec-websocket/src/main/java/com/ym/mec/web/handler/Chat1.java

@@ -0,0 +1,55 @@
+package com.ym.mec.web.handler;
+
+import com.corundumstudio.socketio.AckRequest;
+import com.corundumstudio.socketio.SocketIOClient;
+import com.corundumstudio.socketio.SocketIONamespace;
+import com.corundumstudio.socketio.annotation.OnConnect;
+import com.corundumstudio.socketio.annotation.OnDisconnect;
+import com.corundumstudio.socketio.annotation.OnEvent;
+import com.ym.mec.web.support.anno.NamespaceReference;
+import com.ym.mec.web.support.anno.OnNamespace;
+import com.ym.mec.web.support.mes.ChatObject;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.springframework.stereotype.Component;
+
+
+@Component
+@OnNamespace("/chat1")
+public class Chat1 {
+    @NamespaceReference
+    private SocketIONamespace namespace;
+
+    private Logger logger = LogManager.getLogger(getClass().getName());
+
+    /**
+     * 添加connect事件,当客户端发起连接时调用,本文中将clientid与sessionid存入数据库
+     * 方便后面发送消息时查找到对应的目标client
+     */
+    @OnConnect
+    public void onConnect(SocketIOClient client) {
+        ;
+
+    }
+
+    /**
+     * 添加@OnDisconnect事件,客户端断开连接时调用,刷新客户端信息
+     */
+    @OnDisconnect
+    public void onDisconnect(SocketIOClient client) {
+
+    }
+
+    @OnEvent(value = "message")
+    public void onEvent(SocketIOClient client, ChatObject data, AckRequest ackRequest) {
+        System.out.println("chat1 namespace " + namespace.getName());
+        namespace.getBroadcastOperations().sendEvent("message", data);
+        System.out.println("chat1 sessionId " + client.getSessionId());
+
+    }
+
+    @OnEvent(value = "send")
+    public void send(SocketIOClient client, ChatObject data, AckRequest ackRequest) {
+
+    }
+}

+ 51 - 0
mec-websocket/src/main/java/com/ym/mec/web/handler/Chat2.java

@@ -0,0 +1,51 @@
+package com.ym.mec.web.handler;
+
+import com.corundumstudio.socketio.AckRequest;
+import com.corundumstudio.socketio.SocketIOClient;
+import com.corundumstudio.socketio.SocketIONamespace;
+import com.corundumstudio.socketio.annotation.OnConnect;
+import com.corundumstudio.socketio.annotation.OnDisconnect;
+import com.corundumstudio.socketio.annotation.OnEvent;
+import com.ym.mec.web.support.anno.NamespaceReference;
+import com.ym.mec.web.support.anno.OnNamespace;
+import com.ym.mec.web.support.mes.ChatObject;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.springframework.stereotype.Component;
+
+
+@Component
+@OnNamespace("/chat2")
+public class Chat2 {
+    @NamespaceReference
+    private SocketIONamespace namespace;
+
+    private Logger logger = LogManager.getLogger(getClass().getName());
+
+
+    /**
+     * 添加connect事件,当客户端发起连接时调用,本文中将clientid与sessionid存入数据库
+     * 方便后面发送消息时查找到对应的目标client
+     * //
+     */
+    @OnConnect
+    public void onConnect(SocketIOClient client) {
+
+    }
+
+    /**
+     * 添加@OnDisconnect事件,客户端断开连接时调用,刷新客户端信息
+     */
+    @OnDisconnect
+    public void onDisconnect(SocketIOClient client) {
+    }
+
+    @OnEvent(value = "message")
+    public void onEvent(SocketIOClient client, ChatObject data, AckRequest ackRequest) {
+        System.out.println("chat2 namespace " + namespace.getName());
+        namespace.getBroadcastOperations().sendEvent("message", data);
+
+        System.out.println("chat2 sessionId " + client.getSessionId());
+    }
+
+}

+ 11 - 0
mec-websocket/src/main/java/com/ym/mec/web/support/anno/NamespaceReference.java

@@ -0,0 +1,11 @@
+package com.ym.mec.web.support.anno;
+
+import java.lang.annotation.*;
+
+@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface NamespaceReference {
+
+
+}

+ 12 - 0
mec-websocket/src/main/java/com/ym/mec/web/support/anno/OnNamespace.java

@@ -0,0 +1,12 @@
+package com.ym.mec.web.support.anno;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target({ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface OnNamespace {
+    String value() default "";
+}

+ 31 - 0
mec-websocket/src/main/java/com/ym/mec/web/support/mes/ChatObject.java

@@ -0,0 +1,31 @@
+package com.ym.mec.web.support.mes;
+
+public class ChatObject {
+
+    private String userName;
+    private String message;
+
+    public ChatObject() {
+    }
+
+    public ChatObject(String userName, String message) {
+        super();
+        this.userName = userName;
+        this.message = message;
+    }
+
+    public String getUserName() {
+        return userName;
+    }
+    public void setUserName(String userName) {
+        this.userName = userName;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+    public void setMessage(String message) {
+        this.message = message;
+    }
+
+}

+ 41 - 0
mec-websocket/src/main/java/com/ym/mec/web/support/socket/NamespaceFactoryBean.java

@@ -0,0 +1,41 @@
+package com.ym.mec.web.support.socket;
+
+import com.corundumstudio.socketio.SocketIONamespace;
+import com.corundumstudio.socketio.SocketIOServer;
+import com.ym.mec.web.support.anno.OnNamespace;
+import jodd.util.StringUtil;
+import org.springframework.beans.factory.FactoryBean;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.annotation.AnnotationUtils;
+import org.springframework.stereotype.Component;
+
+@Component
+public class NamespaceFactoryBean implements FactoryBean<SocketIONamespace> {
+
+    private Class originalBeanClass;
+    private final SocketIOServer server;
+
+    @Autowired
+    public NamespaceFactoryBean(SocketIOServer server) {
+        this.server = server;
+    }
+
+    @Override
+    public SocketIONamespace getObject() {
+        OnNamespace onNamespace = AnnotationUtils.findAnnotation(originalBeanClass, OnNamespace.class);
+        String namespace = onNamespace.value();
+        if (!namespace.startsWith("/") && StringUtil.isNotBlank(namespace)) {
+            namespace = "/" + namespace;
+        }
+        return server.addNamespace(namespace);
+    }
+
+    @Override
+    public Class<?> getObjectType() {
+        return SocketIONamespace.class;
+    }
+
+    public void setOriginalBeanClass(Class originalBeanClass) {
+        this.originalBeanClass = originalBeanClass;
+    }
+}

+ 23 - 0
mec-websocket/src/main/java/com/ym/mec/web/support/socket/ServerRunner.java

@@ -0,0 +1,23 @@
+package com.ym.mec.web.support.socket;
+
+import com.corundumstudio.socketio.SocketIOServer;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.stereotype.Component;
+
+
+@Component
+public class ServerRunner implements CommandLineRunner {
+
+    private final SocketIOServer server;
+
+    @Autowired
+    public ServerRunner(SocketIOServer server) {
+        this.server = server;
+    }
+
+    @Override
+    public void run(String... args) throws Exception {
+        server.start();
+    }
+}

+ 84 - 0
mec-websocket/src/main/java/com/ym/mec/web/support/socket/SocketEventScanner.java

@@ -0,0 +1,84 @@
+package com.ym.mec.web.support.socket;
+
+import com.corundumstudio.socketio.SocketIONamespace;
+import com.corundumstudio.socketio.annotation.OnConnect;
+import com.corundumstudio.socketio.annotation.OnDisconnect;
+import com.corundumstudio.socketio.annotation.OnEvent;
+import com.ym.mec.web.support.anno.NamespaceReference;
+import com.ym.mec.web.support.anno.OnNamespace;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.config.BeanPostProcessor;
+import org.springframework.stereotype.Component;
+import org.springframework.util.ReflectionUtils;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+@Component
+public class SocketEventScanner implements BeanPostProcessor {
+
+    @Autowired
+    private NamespaceFactoryBean factoryBean;
+    private static final Logger LOGGER = LoggerFactory.getLogger(SocketEventScanner.class);
+
+    private final List<Class<? extends Annotation>> annotations =
+            Arrays.asList(OnConnect.class, OnDisconnect.class, OnEvent.class);
+
+    private Class originalBeanClass;
+
+    @Override
+    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
+        OnNamespace onNamespace = bean.getClass().getAnnotation(OnNamespace.class);
+        if (originalBeanClass != null && onNamespace != null) {
+            //前端调用方式 var socket =  io.connect('http://localhost:9092/chat1');
+            factoryBean.setOriginalBeanClass(originalBeanClass);
+            SocketIONamespace socketIONamespace = factoryBean.getObject();
+            socketIONamespace.addListeners(bean, originalBeanClass);
+            LOGGER.info("{}  bean 手动 listeners added", beanName);
+            //注入属性
+            Field[] declaredFields = originalBeanClass.getDeclaredFields();
+            for (Field declaredField : declaredFields) {
+                if (declaredField.isAnnotationPresent(NamespaceReference.class)) {
+                    try {
+                        declaredField.setAccessible(true);
+                        declaredField.set(bean, socketIONamespace);
+                    } catch (IllegalAccessException e) {
+                        throw new RuntimeException(e);
+                    }
+                }
+
+            }
+            originalBeanClass = null;
+        }
+
+        return bean;
+    }
+
+
+    @Override
+    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
+
+        final AtomicBoolean add = new AtomicBoolean();
+        ReflectionUtils.doWithMethods(bean.getClass(),
+                method -> add.set(true),
+                method -> {
+                    //匹配符合的方法
+                    for (Class<? extends Annotation> annotationClass : annotations) {
+                        if (method.isAnnotationPresent(annotationClass)) {
+                            return true;
+                        }
+                    }
+                    return false;
+                });
+        if (add.get()) {
+            originalBeanClass = bean.getClass();
+        }
+        return bean;
+    }
+}