From 8b552fa63235240d83aa005222c15e915f7a201f Mon Sep 17 00:00:00 2001
From: XSWL1018 <824576966@qq.com>
Date: Mon, 14 Oct 2024 15:36:01 +0800
Subject: [PATCH 1/3] init
---
ruoyi-plugins/pom.xml | 6 +
ruoyi-plugins/ruoyi-websocket/pom.xml | 5 +
.../ruoyi/websocket/NettyServerRunner.java | 22 +++
.../annotations/NettyWebSocketEndpoint.java | 12 ++
.../NettyWebSocketEndpointHandler.java | 74 ++++++++
.../nettyServer/NettyWebSocketServer.java | 64 +++++++
.../nettyServer/handler/WebSocketHandler.java | 168 ++++++++++++++++++
.../com/ruoyi/websocket/utils/CommonUtil.java | 78 ++++++++
8 files changed, 429 insertions(+)
create mode 100644 ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/NettyServerRunner.java
create mode 100644 ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/annotations/NettyWebSocketEndpoint.java
create mode 100644 ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/nettyServer/NettyWebSocketEndpointHandler.java
create mode 100644 ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/nettyServer/NettyWebSocketServer.java
create mode 100644 ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/nettyServer/handler/WebSocketHandler.java
create mode 100644 ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/utils/CommonUtil.java
diff --git a/ruoyi-plugins/pom.xml b/ruoyi-plugins/pom.xml
index 358faf8..ba12644 100644
--- a/ruoyi-plugins/pom.xml
+++ b/ruoyi-plugins/pom.xml
@@ -13,6 +13,7 @@
3.10.8
3.5.8
+ 4.1.112.Final
@@ -72,6 +73,11 @@
ruoyi-mybatis-interceptor
${ruoyi.version}
+
+ io.netty
+ netty-all
+ ${netty.version}
+
diff --git a/ruoyi-plugins/ruoyi-websocket/pom.xml b/ruoyi-plugins/ruoyi-websocket/pom.xml
index 66fccdb..ee7ac53 100644
--- a/ruoyi-plugins/ruoyi-websocket/pom.xml
+++ b/ruoyi-plugins/ruoyi-websocket/pom.xml
@@ -26,6 +26,11 @@
spring-boot-starter-websocket
+
+ io.netty
+ netty-all
+
+
diff --git a/ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/NettyServerRunner.java b/ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/NettyServerRunner.java
new file mode 100644
index 0000000..9e5632c
--- /dev/null
+++ b/ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/NettyServerRunner.java
@@ -0,0 +1,22 @@
+package com.ruoyi.websocket;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.ApplicationArguments;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.boot.web.embedded.netty.NettyWebServer;
+import org.springframework.stereotype.Component;
+
+import com.ruoyi.websocket.nettyServer.NettyWebSocketServer;
+
+@Component
+public class NettyServerRunner implements ApplicationRunner {
+
+ @Autowired
+ private NettyWebSocketServer server;
+
+ @Override
+ public void run(ApplicationArguments args) throws Exception {
+ server.start();
+ }
+
+}
diff --git a/ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/annotations/NettyWebSocketEndpoint.java b/ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/annotations/NettyWebSocketEndpoint.java
new file mode 100644
index 0000000..dbe0541
--- /dev/null
+++ b/ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/annotations/NettyWebSocketEndpoint.java
@@ -0,0 +1,12 @@
+package com.ruoyi.websocket.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface NettyWebSocketEndpoint {
+ String path();
+}
diff --git a/ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/nettyServer/NettyWebSocketEndpointHandler.java b/ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/nettyServer/NettyWebSocketEndpointHandler.java
new file mode 100644
index 0000000..b2e7eaf
--- /dev/null
+++ b/ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/nettyServer/NettyWebSocketEndpointHandler.java
@@ -0,0 +1,74 @@
+package com.ruoyi.websocket.nettyServer;
+
+import java.nio.channels.Channel;
+import java.util.Map;
+
+import io.netty.channel.ChannelFutureListener;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.group.ChannelGroup;
+import io.netty.channel.group.DefaultChannelGroup;
+import io.netty.handler.codec.http.FullHttpMessage;
+import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
+import io.netty.util.concurrent.GlobalEventExecutor;
+
+public abstract class NettyWebSocketEndpointHandler {
+
+ private final ChannelGroup group = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
+
+ private Map pathParam;
+
+ private Map urlParam;
+
+ public void sendAll(String msg) {
+ group.writeAndFlush(msg);
+ }
+
+ public static void sendMsg(ChannelHandlerContext context, String msg) {
+ TextWebSocketFrame textWebSocketFrame = new TextWebSocketFrame(msg);
+ context.channel().writeAndFlush(textWebSocketFrame);
+ }
+
+ public abstract void onMessage(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame textWebSocketFrame);
+
+ public abstract void onOpen(ChannelHandlerContext channelHandlerContext, FullHttpMessage fullHttpMessage);
+
+ public abstract void onClose(ChannelHandlerContext channelHandlerContext);
+
+ public abstract void onError(ChannelHandlerContext channelHandlerContext, Throwable throwable);
+
+ public ChannelGroup getGroup() {
+ return group;
+ }
+
+ public Map getPathParam() {
+ return pathParam;
+ }
+
+ public void setPathParam(Map pathParam) {
+ this.pathParam = pathParam;
+ }
+
+ public Map getUrlParam() {
+ return urlParam;
+ }
+
+ public void setUrlParam(Map urlParam) {
+ this.urlParam = urlParam;
+ }
+
+ public Long getLongPathParam(String key) {
+ return Long.valueOf(pathParam.get(key));
+ }
+
+ public String getPathParam(String key) {
+ return pathParam.get(key);
+ }
+
+ public Double getDoublePathParam(String key) {
+ return Double.parseDouble(pathParam.get(key));
+ }
+
+ public void closeChannel(ChannelHandlerContext channelHandlerContext) {
+ channelHandlerContext.close().addListener(ChannelFutureListener.CLOSE);
+ }
+}
\ No newline at end of file
diff --git a/ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/nettyServer/NettyWebSocketServer.java b/ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/nettyServer/NettyWebSocketServer.java
new file mode 100644
index 0000000..94dd558
--- /dev/null
+++ b/ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/nettyServer/NettyWebSocketServer.java
@@ -0,0 +1,64 @@
+package com.ruoyi.websocket.nettyServer;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import com.ruoyi.websocket.nettyServer.handler.WebSocketHandler;
+import io.netty.bootstrap.ServerBootstrap;
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelOption;
+import io.netty.channel.ChannelPipeline;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.nio.NioServerSocketChannel;
+import io.netty.channel.socket.nio.NioSocketChannel;
+import io.netty.handler.codec.http.HttpObjectAggregator;
+import io.netty.handler.codec.http.HttpServerCodec;
+import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
+
+@Component
+public class NettyWebSocketServer {
+
+ private static ServerBootstrap serverBootstrap;
+
+ @Value("${netty.websocket.maxMessageSize}")
+ private Long messageSize;
+
+ @Value("${netty.websocket.bossThreads}")
+ private Long bossThreads;
+
+ @Value("${netty.websocket.workerThreads}")
+ private Long workerThreads;
+
+ @Value("${netty.websocket.port}")
+ private Long port;
+
+ @Value("${netty.websocket.enable}")
+ private Boolean enable;
+
+ public ServerBootstrap start() throws InterruptedException {
+ if (!enable) {
+ return null;
+ }
+ ServerBootstrap serverBootstrap = new ServerBootstrap();
+ NioEventLoopGroup boss = new NioEventLoopGroup(4);
+ NioEventLoopGroup worker = new NioEventLoopGroup(workerThreads.intValue());
+ serverBootstrap.group(boss, worker);
+ serverBootstrap.channel(NioServerSocketChannel.class);
+ serverBootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
+ serverBootstrap.childHandler(new ChannelInitializer() {
+ @Override
+ protected void initChannel(NioSocketChannel channel) throws Exception {
+ ChannelPipeline pipeline = channel.pipeline();
+ pipeline.addLast(new HttpServerCodec());
+ pipeline.addLast(new HttpObjectAggregator(messageSize.intValue()));
+ pipeline.addLast(new WebSocketHandler());
+ pipeline.addLast(new WebSocketServerProtocolHandler("/", true));
+ }
+ });
+ serverBootstrap.bind(port.intValue()).sync();
+ System.out.println(
+ "----------------------------------------------------------------------------------- \n Arknights!");
+ NettyWebSocketServer.serverBootstrap = serverBootstrap;
+ return serverBootstrap;
+ }
+}
diff --git a/ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/nettyServer/handler/WebSocketHandler.java b/ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/nettyServer/handler/WebSocketHandler.java
new file mode 100644
index 0000000..79407c0
--- /dev/null
+++ b/ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/nettyServer/handler/WebSocketHandler.java
@@ -0,0 +1,168 @@
+package com.ruoyi.websocket.nettyServer.handler;
+
+import java.util.concurrent.ConcurrentHashMap;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.websocket.annotations.NettyWebSocketEndpoint;
+import com.ruoyi.websocket.nettyServer.NettyWebSocketEndpointHandler;
+import com.ruoyi.websocket.utils.CommonUtil;
+import io.netty.channel.ChannelFutureListener;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelId;
+import io.netty.channel.SimpleChannelInboundHandler;
+import io.netty.channel.group.ChannelGroup;
+import io.netty.channel.group.DefaultChannelGroup;
+import io.netty.handler.codec.http.DefaultFullHttpResponse;
+import io.netty.handler.codec.http.FullHttpRequest;
+import io.netty.handler.codec.http.HttpResponseStatus;
+import io.netty.handler.codec.http.HttpVersion;
+import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
+import io.netty.util.concurrent.GlobalEventExecutor;
+import jakarta.annotation.PostConstruct;
+
+import java.lang.reflect.Constructor;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.*;
+
+@Component
+public class WebSocketHandler extends SimpleChannelInboundHandler {
+
+ @Autowired
+ private List handlers;
+
+ private static final Map uriHandlerMapper = new ConcurrentHashMap<>();
+
+ public static final ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
+
+ public static final Map channelHandlerMap = new ConcurrentHashMap<>();
+
+ @PostConstruct
+ private void init() throws URISyntaxException, NoSuchMethodException, SecurityException {
+ for (NettyWebSocketEndpointHandler handler : handlers) {
+ Class> handlerClass = handler.getClass();
+ NettyWebSocketEndpoint annotation = handlerClass.getAnnotation(NettyWebSocketEndpoint.class);
+ if (annotation == null || StringUtils.isEmpty(annotation.path())) {
+ throw new RuntimeException("未配置路径的 netty websocket endpoint ");
+ }
+ // uriHandlerMap.put(uri.getPath(), handler);
+ PathMatchModel pathMachModel = parseHandler(annotation.path(), handlerClass);
+ uriHandlerMapper.put(pathMachModel.path, pathMachModel);
+ }
+ }
+
+ @Override
+ protected void channelRead0(ChannelHandlerContext context, TextWebSocketFrame webSocketFrame) throws Exception {
+ NettyWebSocketEndpointHandler handler = channelHandlerMap.get(context.channel().id());
+ handler.onMessage(context, webSocketFrame);
+ }
+
+ @Override
+ public void channelActive(ChannelHandlerContext ctx) throws Exception {
+ channelGroup.add(ctx.channel());
+ }
+
+ @Override
+ public void channelInactive(ChannelHandlerContext ctx) throws Exception {
+ NettyWebSocketEndpointHandler handler = channelHandlerMap.get(ctx.channel().id());
+ if (handler != null) {
+ handler.onClose(ctx);
+ handler.getGroup().remove(ctx.channel());
+ }
+
+ channelHandlerMap.remove(ctx.channel().id());
+ channelGroup.remove(ctx.channel());
+ }
+
+ @Override
+ public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
+
+ }
+
+ @Override
+ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
+ channelHandlerMap.get(ctx.channel().id()).onError(ctx, cause);
+ }
+
+ @Override
+ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
+ if (msg instanceof FullHttpRequest) {
+ FullHttpRequest fullHttpRequest = (FullHttpRequest) msg;
+ if (channelHandlerMap.get(ctx.channel().id()) != null) {
+ super.channelRead(ctx, fullHttpRequest);
+ return;
+ }
+ URI uri = new URI(fullHttpRequest.uri());
+ PathMatchModel mathPathMachModel = mathPathMachModel(uri.getPath());
+ if (mathPathMachModel == null) {
+ ctx.channel()
+ .writeAndFlush(new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.NOT_FOUND));
+ ctx.close().addListener(ChannelFutureListener.CLOSE);
+ return;
+ }
+ NettyWebSocketEndpointHandler newInstance = (NettyWebSocketEndpointHandler) mathPathMachModel.handlerConstructor
+ .newInstance();
+ if (!(mathPathMachModel.pathParams == null || mathPathMachModel.pathParams.isEmpty())) {
+ newInstance.setPathParam(
+ CommonUtil.parsePathParam(uri.getPath(), mathPathMachModel.pathParams, mathPathMachModel.path));
+ super.channelRead(ctx, msg);
+ }
+ newInstance.setUrlParam(CommonUtil.parseQueryParameters(uri.getQuery()));
+
+ channelHandlerMap.put(ctx.channel().id(), newInstance);
+ newInstance.onOpen(ctx, fullHttpRequest);
+ } else if (msg instanceof TextWebSocketFrame) {
+ super.channelRead(ctx, msg);
+ }
+
+ }
+
+ private static PathMatchModel parseHandler(String path, Class> handlerClass)
+ throws NoSuchMethodException, SecurityException {
+ List paramName = new ArrayList<>();
+ String[] split = path.split("/");
+ for (int index = 1; index < split.length; index++) {
+ String item = split[index];
+ if (item.startsWith("{") && item.endsWith("}")) {
+ paramName.add(item.substring(1, item.length() - 1).trim());
+ split[index] = "?";
+ }
+ }
+ StringBuilder finalPath = new StringBuilder("");
+ for (int index = 1; index < split.length; index++) {
+ finalPath.append("/").append(split[index]);
+ }
+ return new PathMatchModel(paramName, finalPath.toString(), handlerClass.getDeclaredConstructor());
+ }
+
+ private static PathMatchModel mathPathMachModel(String uri) {
+ Map map = new HashMap<>();
+ for (String key : uriHandlerMapper.keySet()) {
+ int mathUri = CommonUtil.mathUri(uri, key);
+ if (mathUri > 0) {
+ map.put(mathUri, uriHandlerMapper.get(key));
+ }
+ }
+ if (map.keySet() == null || map.keySet().isEmpty()) {
+ return null;
+ }
+ Integer max = CommonUtil.getMax(map.keySet());
+ return map.get(max);
+ }
+
+ private static final class PathMatchModel {
+ private final List pathParams;
+
+ private final String path;
+
+ private final Constructor> handlerConstructor;
+
+ public PathMatchModel(List pathParams, String path, Constructor> handlerConstructor) {
+ this.pathParams = pathParams;
+ this.path = path;
+ this.handlerConstructor = handlerConstructor;
+ }
+
+ }
+}
diff --git a/ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/utils/CommonUtil.java b/ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/utils/CommonUtil.java
new file mode 100644
index 0000000..d2b0228
--- /dev/null
+++ b/ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/utils/CommonUtil.java
@@ -0,0 +1,78 @@
+package com.ruoyi.websocket.utils;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
+public class CommonUtil {
+
+ /**
+ * @param uri
+ * @param uriTemplates
+ * @return
+ */
+ public static int mathUri(String uri, String uriTemplate) {
+ String[] uriSplit = uri.split("/");
+ String[] tempalteSplit = uriTemplate.split("/");
+ if (uriSplit.length != tempalteSplit.length) {
+ return -1;
+ }
+ int mathLevel = 0;
+ for (int index = 1; index < tempalteSplit.length; index++) {
+ if (tempalteSplit[index].equals("?")) {
+ mathLevel = mathLevel + index;
+ continue;
+ }
+ if (!tempalteSplit[index].equals(uriSplit[index])) {
+ return -1;
+ } else {
+ mathLevel = mathLevel + tempalteSplit.length + 1;
+ }
+ }
+ return mathLevel;
+ }
+
+ public static Map parseQueryParameters(String query) {
+ if (query == null || query.isEmpty()) {
+ return Map.of();
+ }
+
+ Map params = new HashMap<>();
+ String[] pairs = query.split("&");
+ for (String pair : pairs) {
+ String[] keyValue = pair.split("=");
+ if (keyValue.length > 1) {
+ params.put(keyValue[0], keyValue[1]);
+ } else {
+ params.put(keyValue[0], "");
+ }
+ }
+ return params;
+ }
+
+ public static Map parsePathParam(String uri, List pathParams, String uriTemplate) {
+ int index = 0;
+ String[] split = uriTemplate.split("/");
+ String[] split2 = uri.split("/");
+ Map map = new HashMap<>();
+ for (int i = 1; i < split.length; i++) {
+ if (split[i].equals("?")) {
+ map.put(pathParams.get(index), split2[i]);
+ index++;
+ }
+ }
+ return map;
+ }
+
+ public static Integer getMax(Set set) {
+ Optional maxNumber = set.stream().max(Integer::compare);
+ if (maxNumber.isPresent()) {
+ System.out.println("Max number: " + maxNumber.get());
+ } else {
+ System.out.println("The list is empty");
+ }
+ return maxNumber.get();
+ }
+}
--
Gitee
From 59ccedce9bb243a04956020032261a06f238393b Mon Sep 17 00:00:00 2001
From: XSWL1018 <824576966@qq.com>
Date: Tue, 15 Oct 2024 23:21:32 +0800
Subject: [PATCH 2/3] u
---
ruoyi-plugins/pom.xml | 9 +
.../aspectj/DataSecurityAspect.java | 9 +-
.../SqlContextHolder.java | 24 ++-
.../{sql => handler}/MybatisAfterHandler.java | 2 +-
.../{sql => handler}/MybatisPreHandler.java | 3 +-
.../dataSecurity/DataSecurityPreHandler.java | 63 +++++--
.../page/PageAfterHandler.java | 4 +-
.../{sql => handler}/page/PagePreHandler.java | 4 +-
.../mybatis/MybatisInterceptor.java | 4 +-
.../util/DataSecurityUtil.java | 3 +-
ruoyi-plugins/ruoyi-netty/pom.xml | 30 ++++
.../netty/websocket/NettyServerRunner.java | 21 +++
.../annotations/NettyWebSocketEndpoint.java | 12 ++
.../endpoints/TestNettyWebSocket.java | 44 +++++
.../NettyWebSocketEndpointHandler.java | 66 +++++++
.../nettyServer/NettyWebSocketServer.java | 64 +++++++
.../nettyServer/handler/WebSocketHandler.java | 167 ++++++++++++++++++
.../netty/websocket/utils/CommonUtil.java | 78 ++++++++
ruoyi-plugins/ruoyi-plugins-starter/pom.xml | 5 +
.../com/ruoyi/websocket/utils/CommonUtil.java | 1 +
20 files changed, 574 insertions(+), 39 deletions(-)
rename ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/context/{dataSecurity => sqlContext}/SqlContextHolder.java (67%)
rename ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/{sql => handler}/MybatisAfterHandler.java (68%)
rename ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/{sql => handler}/MybatisPreHandler.java (92%)
rename ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/{sql => handler}/dataSecurity/DataSecurityPreHandler.java (58%)
rename ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/{sql => handler}/page/PageAfterHandler.java (87%)
rename ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/{sql => handler}/page/PagePreHandler.java (98%)
create mode 100644 ruoyi-plugins/ruoyi-netty/pom.xml
create mode 100644 ruoyi-plugins/ruoyi-netty/src/main/java/com/ruoyi/netty/websocket/NettyServerRunner.java
create mode 100644 ruoyi-plugins/ruoyi-netty/src/main/java/com/ruoyi/netty/websocket/annotations/NettyWebSocketEndpoint.java
create mode 100644 ruoyi-plugins/ruoyi-netty/src/main/java/com/ruoyi/netty/websocket/endpoints/TestNettyWebSocket.java
create mode 100644 ruoyi-plugins/ruoyi-netty/src/main/java/com/ruoyi/netty/websocket/nettyServer/NettyWebSocketEndpointHandler.java
create mode 100644 ruoyi-plugins/ruoyi-netty/src/main/java/com/ruoyi/netty/websocket/nettyServer/NettyWebSocketServer.java
create mode 100644 ruoyi-plugins/ruoyi-netty/src/main/java/com/ruoyi/netty/websocket/nettyServer/handler/WebSocketHandler.java
create mode 100644 ruoyi-plugins/ruoyi-netty/src/main/java/com/ruoyi/netty/websocket/utils/CommonUtil.java
diff --git a/ruoyi-plugins/pom.xml b/ruoyi-plugins/pom.xml
index ba12644..9807d98 100644
--- a/ruoyi-plugins/pom.xml
+++ b/ruoyi-plugins/pom.xml
@@ -68,11 +68,19 @@
ruoyi-plugins-starter
${ruoyi.version}
+
com.ruoyi
ruoyi-mybatis-interceptor
${ruoyi.version}
+
+
+ com.ruoyi
+ ruoyi-netty
+ ${ruoyi.version}
+
+
io.netty
netty-all
@@ -90,6 +98,7 @@
ruoyi-websocket
ruoyi-plugins-starter
ruoyi-mybatis-interceptor
+ ruoyi-netty
pom
diff --git a/ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/aspectj/DataSecurityAspect.java b/ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/aspectj/DataSecurityAspect.java
index 166b87f..d6ee916 100644
--- a/ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/aspectj/DataSecurityAspect.java
+++ b/ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/aspectj/DataSecurityAspect.java
@@ -1,21 +1,19 @@
package com.ruoyi.mybatisinterceptor.aspectj;
import com.ruoyi.mybatisinterceptor.annotation.DataSecurity;
+import com.ruoyi.mybatisinterceptor.context.sqlContext.SqlContextHolder;
import com.ruoyi.mybatisinterceptor.model.JoinTableModel;
import com.ruoyi.mybatisinterceptor.model.WhereModel;
-import com.ruoyi.mybatisinterceptor.context.dataSecurity.SqlContextHolder;
+
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
-
-
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
-
@Aspect
@Component
public class DataSecurityAspect {
@@ -50,7 +48,6 @@ public class DataSecurityAspect {
if (!StringUtils.isEmpty(dataSecurity.joinTableAlise())) {
createByTableModel.setJoinTableAlise(dataSecurity.joinTableAlise());
}
-
createByTableModel.setFromTableColumn("create_by");
createByTableModel.setJoinTableColumn("user_name");
SqlContextHolder.addJoinTable(createByTableModel);
@@ -63,12 +60,10 @@ public class DataSecurityAspect {
if (!StringUtils.isEmpty(dataSecurity.joinTableAlise())) {
userIdTableModel.setJoinTableAlise(dataSecurity.joinTableAlise());
}
-
userIdTableModel.setFromTableColumn("user_id");
userIdTableModel.setJoinTableColumn("user_id");
SqlContextHolder.addJoinTable(userIdTableModel);
break;
-
default:
break;
}
diff --git a/ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/context/dataSecurity/SqlContextHolder.java b/ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/context/sqlContext/SqlContextHolder.java
similarity index 67%
rename from ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/context/dataSecurity/SqlContextHolder.java
rename to ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/context/sqlContext/SqlContextHolder.java
index 54407a6..150856b 100644
--- a/ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/context/dataSecurity/SqlContextHolder.java
+++ b/ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/context/sqlContext/SqlContextHolder.java
@@ -1,4 +1,4 @@
-package com.ruoyi.mybatisinterceptor.context.dataSecurity;
+package com.ruoyi.mybatisinterceptor.context.sqlContext;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
@@ -10,11 +10,11 @@ public class SqlContextHolder {
private static final ThreadLocal SQL_CONTEXT_HOLDER = new ThreadLocal<>();
public static void startDataSecurity() {
- JSONObject jsonObject = new JSONObject();
- jsonObject.put("isSecurity", Boolean.TRUE);
- jsonObject.put(SqlType.WHERE.getSqlType(), new JSONArray());
- jsonObject.put(SqlType.JOIN.getSqlType(), new JSONArray());
- SQL_CONTEXT_HOLDER.set(jsonObject);
+ SQL_CONTEXT_HOLDER.get().put("isSecurity", Boolean.TRUE);
+ }
+
+ public static void startLogicSelect() {
+ SQL_CONTEXT_HOLDER.get().put("isLogic", Boolean.TRUE);
}
public static void addWhereParam(WhereModel whereModel) {
@@ -26,7 +26,6 @@ public class SqlContextHolder {
}
public static boolean isSecurity() {
-
return SQL_CONTEXT_HOLDER.get() != null
&& SQL_CONTEXT_HOLDER.get().getBooleanValue("isSecurity");
}
@@ -42,4 +41,15 @@ public class SqlContextHolder {
public static JSONArray getJoinTables() {
return SQL_CONTEXT_HOLDER.get().getJSONArray(SqlType.JOIN.getSqlType());
}
+
+ public static void startInterceptor() {
+ JSONObject jsonObject = SQL_CONTEXT_HOLDER.get();
+ if (jsonObject != null) {
+ return;
+ }
+ JSONObject object = new JSONObject();
+ object.put(SqlType.JOIN.getSqlType(), new JSONArray());
+ object.put(SqlType.WHERE.getSqlType(), new JSONArray());
+ SQL_CONTEXT_HOLDER.set(object);
+ }
}
diff --git a/ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/sql/MybatisAfterHandler.java b/ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/handler/MybatisAfterHandler.java
similarity index 68%
rename from ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/sql/MybatisAfterHandler.java
rename to ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/handler/MybatisAfterHandler.java
index 133f111..dafed1e 100644
--- a/ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/sql/MybatisAfterHandler.java
+++ b/ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/handler/MybatisAfterHandler.java
@@ -1,4 +1,4 @@
-package com.ruoyi.mybatisinterceptor.sql;
+package com.ruoyi.mybatisinterceptor.handler;
public interface MybatisAfterHandler {
diff --git a/ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/sql/MybatisPreHandler.java b/ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/handler/MybatisPreHandler.java
similarity index 92%
rename from ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/sql/MybatisPreHandler.java
rename to ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/handler/MybatisPreHandler.java
index b0a61fe..db17e53 100644
--- a/ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/sql/MybatisPreHandler.java
+++ b/ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/handler/MybatisPreHandler.java
@@ -1,4 +1,4 @@
-package com.ruoyi.mybatisinterceptor.sql;
+package com.ruoyi.mybatisinterceptor.handler;
import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
@@ -6,6 +6,7 @@ import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
+
public interface MybatisPreHandler {
void preHandle(Executor executor, MappedStatement mappedStatement, Object params,
diff --git a/ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/sql/dataSecurity/DataSecurityPreHandler.java b/ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/handler/dataSecurity/DataSecurityPreHandler.java
similarity index 58%
rename from ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/sql/dataSecurity/DataSecurityPreHandler.java
rename to ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/handler/dataSecurity/DataSecurityPreHandler.java
index c1e8c86..0bc4a5e 100644
--- a/ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/sql/dataSecurity/DataSecurityPreHandler.java
+++ b/ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/handler/dataSecurity/DataSecurityPreHandler.java
@@ -1,6 +1,7 @@
-package com.ruoyi.mybatisinterceptor.sql.dataSecurity;
+package com.ruoyi.mybatisinterceptor.handler.dataSecurity;
import java.lang.reflect.Field;
+import java.util.ArrayList;
import java.util.List;
import org.apache.ibatis.cache.CacheKey;
@@ -12,13 +13,14 @@ import org.apache.ibatis.session.RowBounds;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;
+import com.alibaba.fastjson2.JSONArray;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.sql.SqlUtil;
import com.ruoyi.mybatisinterceptor.annotation.MybatisHandlerOrder;
-import com.ruoyi.mybatisinterceptor.context.dataSecurity.SqlContextHolder;
+import com.ruoyi.mybatisinterceptor.context.sqlContext.SqlContextHolder;
+import com.ruoyi.mybatisinterceptor.handler.MybatisPreHandler;
import com.ruoyi.mybatisinterceptor.model.JoinTableModel;
import com.ruoyi.mybatisinterceptor.model.WhereModel;
-import com.ruoyi.mybatisinterceptor.sql.MybatisPreHandler;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.Alias;
@@ -28,9 +30,11 @@ import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.Statement;
+import net.sf.jsqlparser.statement.delete.Delete;
import net.sf.jsqlparser.statement.select.Join;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
+import net.sf.jsqlparser.statement.update.Update;
@MybatisHandlerOrder(1)
@Component
@@ -43,7 +47,7 @@ public class DataSecurityPreHandler implements MybatisPreHandler {
@Override
public void preHandle(Executor executor, MappedStatement mappedStatement, Object params, RowBounds rowBounds,
- ResultHandler> resultHandler, CacheKey cacheKey, BoundSql boundSql) throws Throwable {
+ ResultHandler> resultHandler, CacheKey cacheKey, BoundSql boundSql) throws Throwable {
if (SqlContextHolder.isSecurity()) {
Statement sql = parseSql(SqlUtil.parseSql(boundSql.getSql()));
sqlFiled.set(boundSql, sql.toString());
@@ -62,27 +66,56 @@ public class DataSecurityPreHandler implements MybatisPreHandler {
}
}
- private static void handleWhere(Select select) throws JSQLParserException {
- PlainSelect plain = select.getPlainSelect();
- Expression expWhere = plain.getWhere();
+ private static void handleWhere(Statement statement) throws JSQLParserException {
+ if (statement instanceof Select) {
+ Select select = (Select) statement;
+ PlainSelect plainSelect = select.getPlainSelect();
+ plainSelect.setWhere(getConfigedWhereExpression(plainSelect.getWhere()));
+ } else if (statement instanceof Update) {
+ Update update = (Update) statement;
+ update.setWhere(getConfigedWhereExpression(update.getWhere()));
+ } else if (statement instanceof Delete) {
+ Delete delete = (Delete) statement;
+ delete.setWhere(getConfigedWhereExpression(delete.getWhere()));
+ }
+
+ }
+
+ private static Expression getConfigedWhereExpression(Expression expWhere) throws JSQLParserException {
StringBuilder whereParam = new StringBuilder(" ");
String where = expWhere != null ? expWhere.toString() : null;
if (SqlContextHolder.getWhere() == null || SqlContextHolder.getWhere().size() <= 0) {
- return;
+ return expWhere;
}
- SqlContextHolder.getWhere().forEach(item -> {
+ JSONArray wehreArray = SqlContextHolder.getWhere();
+ wehreArray.forEach(item -> {
whereParam.append(((WhereModel) item).getSqlString());
});
- where = StringUtils.isEmpty(where) ? whereParam.toString().substring(5, whereParam.length())
+ WhereModel whereModel = (WhereModel) wehreArray.get(0);
+ where = StringUtils.isEmpty(where)
+ ? whereParam.toString().substring(whereModel.getConnectType().length() + 2, whereParam.length())
: where + " " + whereParam.toString();
- plain.setWhere(CCJSqlParserUtil.parseCondExpression(where));
+ return CCJSqlParserUtil.parseCondExpression(where);
}
- private static void handleJoin(Select select) {
- PlainSelect selectBody = select.getPlainSelect();
+ private static void handleJoin(Statement statement) {
if (SqlContextHolder.getJoinTables() == null || SqlContextHolder.getJoinTables().size() <= 0) {
return;
}
+ if (statement instanceof Select) {
+ Select select = (Select) statement;
+ select.getPlainSelect().addJoins(getConfigedJoinExpression());
+ } else if (statement instanceof Update) {
+ Update update = (Update) statement;
+ update.addJoins(getConfigedJoinExpression());
+ } else if (statement instanceof Delete) {
+ Delete delete = (Delete) statement;
+ delete.addJoins(getConfigedJoinExpression());
+ }
+ }
+
+ private static List getConfigedJoinExpression() {
+ List joins = new ArrayList<>();
SqlContextHolder.getJoinTables().forEach(item -> {
JoinTableModel tableModel = (JoinTableModel) item;
Table table = new Table(tableModel.getJoinTable());
@@ -93,8 +126,8 @@ public class DataSecurityPreHandler implements MybatisPreHandler {
Expression onExpression = new EqualsTo(new Column(tableModel.getFromTableColumnString()),
new Column(tableModel.getJoinTableColumnString()));
join.setOnExpressions(List.of(onExpression));
- selectBody.addJoins(join);
+ joins.add(join);
});
+ return joins;
}
-
}
diff --git a/ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/sql/page/PageAfterHandler.java b/ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/handler/page/PageAfterHandler.java
similarity index 87%
rename from ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/sql/page/PageAfterHandler.java
rename to ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/handler/page/PageAfterHandler.java
index 4826924..bdd91b1 100644
--- a/ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/sql/page/PageAfterHandler.java
+++ b/ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/handler/page/PageAfterHandler.java
@@ -1,4 +1,4 @@
-package com.ruoyi.mybatisinterceptor.sql.page;
+package com.ruoyi.mybatisinterceptor.handler.page;
import java.util.List;
@@ -7,7 +7,7 @@ import org.springframework.stereotype.Component;
import com.ruoyi.mybatisinterceptor.annotation.MybatisHandlerOrder;
import com.ruoyi.mybatisinterceptor.context.page.PageContextHolder;
import com.ruoyi.mybatisinterceptor.context.page.model.TableInfo;
-import com.ruoyi.mybatisinterceptor.sql.MybatisAfterHandler;
+import com.ruoyi.mybatisinterceptor.handler.MybatisAfterHandler;
@MybatisHandlerOrder(1)
@Component
diff --git a/ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/sql/page/PagePreHandler.java b/ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/handler/page/PagePreHandler.java
similarity index 98%
rename from ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/sql/page/PagePreHandler.java
rename to ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/handler/page/PagePreHandler.java
index 0e21921..5fde0b1 100644
--- a/ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/sql/page/PagePreHandler.java
+++ b/ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/handler/page/PagePreHandler.java
@@ -1,4 +1,4 @@
-package com.ruoyi.mybatisinterceptor.sql.page;
+package com.ruoyi.mybatisinterceptor.handler.page;
import java.lang.reflect.Field;
import java.sql.SQLException;
@@ -21,7 +21,7 @@ import com.ruoyi.common.utils.sql.SqlUtil;
import com.ruoyi.mybatisinterceptor.annotation.MybatisHandlerOrder;
import com.ruoyi.mybatisinterceptor.context.page.PageContextHolder;
import com.ruoyi.mybatisinterceptor.context.page.model.PageInfo;
-import com.ruoyi.mybatisinterceptor.sql.MybatisPreHandler;
+import com.ruoyi.mybatisinterceptor.handler.MybatisPreHandler;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.statement.Statement;
diff --git a/ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/interceptor/mybatis/MybatisInterceptor.java b/ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/interceptor/mybatis/MybatisInterceptor.java
index 98af73a..2afd1d2 100644
--- a/ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/interceptor/mybatis/MybatisInterceptor.java
+++ b/ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/interceptor/mybatis/MybatisInterceptor.java
@@ -17,8 +17,8 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.ruoyi.mybatisinterceptor.annotation.MybatisHandlerOrder;
-import com.ruoyi.mybatisinterceptor.sql.MybatisAfterHandler;
-import com.ruoyi.mybatisinterceptor.sql.MybatisPreHandler;
+import com.ruoyi.mybatisinterceptor.handler.MybatisAfterHandler;
+import com.ruoyi.mybatisinterceptor.handler.MybatisPreHandler;
import jakarta.annotation.PostConstruct;
diff --git a/ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/util/DataSecurityUtil.java b/ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/util/DataSecurityUtil.java
index cb360d5..a7590fa 100644
--- a/ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/util/DataSecurityUtil.java
+++ b/ruoyi-plugins/ruoyi-mybatis-interceptor/src/main/java/com/ruoyi/mybatisinterceptor/util/DataSecurityUtil.java
@@ -1,7 +1,6 @@
package com.ruoyi.mybatisinterceptor.util;
-
-import com.ruoyi.mybatisinterceptor.context.dataSecurity.SqlContextHolder;
+import com.ruoyi.mybatisinterceptor.context.sqlContext.SqlContextHolder;
public class DataSecurityUtil {
diff --git a/ruoyi-plugins/ruoyi-netty/pom.xml b/ruoyi-plugins/ruoyi-netty/pom.xml
new file mode 100644
index 0000000..71b0b47
--- /dev/null
+++ b/ruoyi-plugins/ruoyi-netty/pom.xml
@@ -0,0 +1,30 @@
+
+
+
+ ruoyi-plugins
+ com.ruoyi
+ 3.8.8.3.1
+
+ 4.0.0
+
+ ruoyi-netty
+
+
+ 19
+ 19
+ UTF-8
+
+
+
+
+ io.netty
+ netty-all
+
+
+ com.ruoyi
+ ruoyi-common
+
+
+
diff --git a/ruoyi-plugins/ruoyi-netty/src/main/java/com/ruoyi/netty/websocket/NettyServerRunner.java b/ruoyi-plugins/ruoyi-netty/src/main/java/com/ruoyi/netty/websocket/NettyServerRunner.java
new file mode 100644
index 0000000..fa69d6d
--- /dev/null
+++ b/ruoyi-plugins/ruoyi-netty/src/main/java/com/ruoyi/netty/websocket/NettyServerRunner.java
@@ -0,0 +1,21 @@
+package com.ruoyi.netty.websocket;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.ApplicationArguments;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.stereotype.Component;
+
+import com.ruoyi.netty.websocket.nettyServer.NettyWebSocketServer;
+
+@Component
+public class NettyServerRunner implements ApplicationRunner {
+
+ @Autowired
+ private NettyWebSocketServer server;
+
+ @Override
+ public void run(ApplicationArguments args) throws Exception {
+ server.start();
+ }
+
+}
diff --git a/ruoyi-plugins/ruoyi-netty/src/main/java/com/ruoyi/netty/websocket/annotations/NettyWebSocketEndpoint.java b/ruoyi-plugins/ruoyi-netty/src/main/java/com/ruoyi/netty/websocket/annotations/NettyWebSocketEndpoint.java
new file mode 100644
index 0000000..15f64ae
--- /dev/null
+++ b/ruoyi-plugins/ruoyi-netty/src/main/java/com/ruoyi/netty/websocket/annotations/NettyWebSocketEndpoint.java
@@ -0,0 +1,12 @@
+package com.ruoyi.netty.websocket.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface NettyWebSocketEndpoint {
+ String path();
+}
diff --git a/ruoyi-plugins/ruoyi-netty/src/main/java/com/ruoyi/netty/websocket/endpoints/TestNettyWebSocket.java b/ruoyi-plugins/ruoyi-netty/src/main/java/com/ruoyi/netty/websocket/endpoints/TestNettyWebSocket.java
new file mode 100644
index 0000000..3e827f6
--- /dev/null
+++ b/ruoyi-plugins/ruoyi-netty/src/main/java/com/ruoyi/netty/websocket/endpoints/TestNettyWebSocket.java
@@ -0,0 +1,44 @@
+package com.ruoyi.netty.websocket.endpoints;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.springframework.stereotype.Component;
+
+import com.ruoyi.netty.websocket.annotations.NettyWebSocketEndpoint;
+import com.ruoyi.netty.websocket.nettyServer.NettyWebSocketEndpointHandler;
+
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.http.FullHttpMessage;
+import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
+
+@Component
+@NettyWebSocketEndpoint(path = "/test/{seqNumber}")
+public class TestNettyWebSocket extends NettyWebSocketEndpointHandler {
+
+ private static final Map map = new ConcurrentHashMap<>();
+
+ @Override
+ public void onMessage(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame textWebSocketFrame) {
+ System.out.println(textWebSocketFrame.text());
+ }
+
+ @Override
+ public void onOpen(ChannelHandlerContext channelHandlerContext, FullHttpMessage fullHttpMessage) {
+ map.put(getPathParam("seqNumber"), channelHandlerContext);
+ }
+
+ @Override
+ public void onClose(ChannelHandlerContext channelHandlerContext) {
+ map.remove(getPathParam("seqNumber"));
+ }
+
+ @Override
+ public void onError(ChannelHandlerContext channelHandlerContext, Throwable throwable) {
+
+ }
+
+ public static void send(String seqNumber, String msg) {
+ sendMsg(map.get(seqNumber), msg);
+ }
+}
diff --git a/ruoyi-plugins/ruoyi-netty/src/main/java/com/ruoyi/netty/websocket/nettyServer/NettyWebSocketEndpointHandler.java b/ruoyi-plugins/ruoyi-netty/src/main/java/com/ruoyi/netty/websocket/nettyServer/NettyWebSocketEndpointHandler.java
new file mode 100644
index 0000000..357c1c4
--- /dev/null
+++ b/ruoyi-plugins/ruoyi-netty/src/main/java/com/ruoyi/netty/websocket/nettyServer/NettyWebSocketEndpointHandler.java
@@ -0,0 +1,66 @@
+package com.ruoyi.netty.websocket.nettyServer;
+
+import java.util.Map;
+
+import io.netty.channel.ChannelFutureListener;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.group.ChannelGroup;
+import io.netty.channel.group.DefaultChannelGroup;
+import io.netty.handler.codec.http.FullHttpMessage;
+import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
+import io.netty.util.concurrent.GlobalEventExecutor;
+
+public abstract class NettyWebSocketEndpointHandler {
+
+
+ private Map pathParam;
+
+ private Map urlParam;
+
+
+ public static void sendMsg(ChannelHandlerContext context, String msg) {
+ TextWebSocketFrame textWebSocketFrame = new TextWebSocketFrame(msg);
+ context.channel().writeAndFlush(textWebSocketFrame);
+ }
+
+ public abstract void onMessage(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame textWebSocketFrame);
+
+ public abstract void onOpen(ChannelHandlerContext channelHandlerContext, FullHttpMessage fullHttpMessage);
+
+ public abstract void onClose(ChannelHandlerContext channelHandlerContext);
+
+ public abstract void onError(ChannelHandlerContext channelHandlerContext, Throwable throwable);
+
+
+ public Map getPathParam() {
+ return pathParam;
+ }
+
+ public void setPathParam(Map pathParam) {
+ this.pathParam = pathParam;
+ }
+
+ public Map getUrlParam() {
+ return urlParam;
+ }
+
+ public void setUrlParam(Map urlParam) {
+ this.urlParam = urlParam;
+ }
+
+ public Long getLongPathParam(String key) {
+ return Long.valueOf(pathParam.get(key));
+ }
+
+ public String getPathParam(String key) {
+ return pathParam.get(key);
+ }
+
+ public Double getDoublePathParam(String key) {
+ return Double.parseDouble(pathParam.get(key));
+ }
+
+ public void closeChannel(ChannelHandlerContext channelHandlerContext) {
+ channelHandlerContext.close().addListener(ChannelFutureListener.CLOSE);
+ }
+}
diff --git a/ruoyi-plugins/ruoyi-netty/src/main/java/com/ruoyi/netty/websocket/nettyServer/NettyWebSocketServer.java b/ruoyi-plugins/ruoyi-netty/src/main/java/com/ruoyi/netty/websocket/nettyServer/NettyWebSocketServer.java
new file mode 100644
index 0000000..6350541
--- /dev/null
+++ b/ruoyi-plugins/ruoyi-netty/src/main/java/com/ruoyi/netty/websocket/nettyServer/NettyWebSocketServer.java
@@ -0,0 +1,64 @@
+package com.ruoyi.netty.websocket.nettyServer;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import com.ruoyi.netty.websocket.nettyServer.handler.WebSocketHandler;
+import io.netty.bootstrap.ServerBootstrap;
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelOption;
+import io.netty.channel.ChannelPipeline;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.nio.NioServerSocketChannel;
+import io.netty.channel.socket.nio.NioSocketChannel;
+import io.netty.handler.codec.http.HttpObjectAggregator;
+import io.netty.handler.codec.http.HttpServerCodec;
+import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
+
+@Component
+public class NettyWebSocketServer {
+
+ private static ServerBootstrap serverBootstrap;
+
+ @Value("${netty.websocket.maxMessageSize}")
+ private Long messageSize;
+
+ @Value("${netty.websocket.bossThreads}")
+ private Long bossThreads;
+
+ @Value("${netty.websocket.workerThreads}")
+ private Long workerThreads;
+
+ @Value("${netty.websocket.port}")
+ private Long port;
+
+ @Value("${netty.websocket.enable}")
+ private Boolean enable;
+
+ public ServerBootstrap start() throws InterruptedException {
+ if (!enable) {
+ return null;
+ }
+ ServerBootstrap serverBootstrap = new ServerBootstrap();
+ NioEventLoopGroup boss = new NioEventLoopGroup(4);
+ NioEventLoopGroup worker = new NioEventLoopGroup(workerThreads.intValue());
+ serverBootstrap.group(boss, worker);
+ serverBootstrap.channel(NioServerSocketChannel.class);
+ serverBootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
+ serverBootstrap.childHandler(new ChannelInitializer() {
+ @Override
+ protected void initChannel(NioSocketChannel channel) throws Exception {
+ ChannelPipeline pipeline = channel.pipeline();
+ pipeline.addLast(new HttpServerCodec());
+ pipeline.addLast(new HttpObjectAggregator(messageSize.intValue()));
+ pipeline.addLast(new WebSocketHandler());
+ pipeline.addLast(new WebSocketServerProtocolHandler("/", true));
+ }
+ });
+ serverBootstrap.bind(port.intValue()).sync();
+ System.out.println(
+ "----------------------------------------------------------------------------------- \n Arknights!");
+ NettyWebSocketServer.serverBootstrap = serverBootstrap;
+ return serverBootstrap;
+ }
+}
diff --git a/ruoyi-plugins/ruoyi-netty/src/main/java/com/ruoyi/netty/websocket/nettyServer/handler/WebSocketHandler.java b/ruoyi-plugins/ruoyi-netty/src/main/java/com/ruoyi/netty/websocket/nettyServer/handler/WebSocketHandler.java
new file mode 100644
index 0000000..da50f71
--- /dev/null
+++ b/ruoyi-plugins/ruoyi-netty/src/main/java/com/ruoyi/netty/websocket/nettyServer/handler/WebSocketHandler.java
@@ -0,0 +1,167 @@
+package com.ruoyi.netty.websocket.nettyServer.handler;
+
+import java.util.concurrent.ConcurrentHashMap;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.netty.websocket.annotations.NettyWebSocketEndpoint;
+import com.ruoyi.netty.websocket.nettyServer.NettyWebSocketEndpointHandler;
+import com.ruoyi.netty.websocket.utils.CommonUtil;
+import io.netty.channel.ChannelFutureListener;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelId;
+import io.netty.channel.SimpleChannelInboundHandler;
+import io.netty.channel.group.ChannelGroup;
+import io.netty.channel.group.DefaultChannelGroup;
+import io.netty.handler.codec.http.DefaultFullHttpResponse;
+import io.netty.handler.codec.http.FullHttpRequest;
+import io.netty.handler.codec.http.HttpResponseStatus;
+import io.netty.handler.codec.http.HttpVersion;
+import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
+import io.netty.util.concurrent.GlobalEventExecutor;
+import jakarta.annotation.PostConstruct;
+
+import java.lang.reflect.Constructor;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.*;
+
+@Component
+public class WebSocketHandler extends SimpleChannelInboundHandler {
+
+ @Autowired
+ private List handlers;
+
+ private static final Map uriHandlerMapper = new ConcurrentHashMap<>();
+
+ public static final ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
+
+ public static final Map channelHandlerMap = new ConcurrentHashMap<>();
+
+ @PostConstruct
+ private void init() throws URISyntaxException, NoSuchMethodException, SecurityException {
+ for (NettyWebSocketEndpointHandler handler : handlers) {
+ Class> handlerClass = handler.getClass();
+ NettyWebSocketEndpoint annotation = handlerClass.getAnnotation(NettyWebSocketEndpoint.class);
+ if (annotation == null || StringUtils.isEmpty(annotation.path())) {
+ throw new RuntimeException("未配置路径的 netty websocket endpoint ");
+ }
+ // uriHandlerMap.put(uri.getPath(), handler);
+ PathMatchModel pathMachModel = parseHandler(annotation.path(), handlerClass);
+ uriHandlerMapper.put(pathMachModel.path, pathMachModel);
+ }
+ }
+
+ @Override
+ protected void channelRead0(ChannelHandlerContext context, TextWebSocketFrame webSocketFrame) throws Exception {
+ NettyWebSocketEndpointHandler handler = channelHandlerMap.get(context.channel().id());
+ handler.onMessage(context, webSocketFrame);
+ }
+
+ @Override
+ public void channelActive(ChannelHandlerContext ctx) throws Exception {
+ channelGroup.add(ctx.channel());
+ }
+
+ @Override
+ public void channelInactive(ChannelHandlerContext ctx) throws Exception {
+ NettyWebSocketEndpointHandler handler = channelHandlerMap.get(ctx.channel().id());
+ if (handler != null) {
+ handler.onClose(ctx);
+ }
+
+ channelHandlerMap.remove(ctx.channel().id());
+ channelGroup.remove(ctx.channel());
+ }
+
+ @Override
+ public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
+
+ }
+
+ @Override
+ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
+ channelHandlerMap.get(ctx.channel().id()).onError(ctx, cause);
+ }
+
+ @Override
+ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
+ if (msg instanceof FullHttpRequest) {
+ FullHttpRequest fullHttpRequest = (FullHttpRequest) msg;
+ if (channelHandlerMap.get(ctx.channel().id()) != null) {
+ super.channelRead(ctx, fullHttpRequest);
+ return;
+ }
+ URI uri = new URI(fullHttpRequest.uri());
+ PathMatchModel mathPathMachModel = mathPathMachModel(uri.getPath());
+ if (mathPathMachModel == null) {
+ ctx.channel()
+ .writeAndFlush(new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.NOT_FOUND));
+ ctx.close().addListener(ChannelFutureListener.CLOSE);
+ return;
+ }
+ NettyWebSocketEndpointHandler newInstance = (NettyWebSocketEndpointHandler) mathPathMachModel.handlerConstructor
+ .newInstance();
+ if (!(mathPathMachModel.pathParams == null || mathPathMachModel.pathParams.isEmpty())) {
+ newInstance.setPathParam(
+ CommonUtil.parsePathParam(uri.getPath(), mathPathMachModel.pathParams, mathPathMachModel.path));
+ super.channelRead(ctx, msg);
+ }
+ newInstance.setUrlParam(CommonUtil.parseQueryParameters(uri.getQuery()));
+
+ channelHandlerMap.put(ctx.channel().id(), newInstance);
+ newInstance.onOpen(ctx, fullHttpRequest);
+ } else if (msg instanceof TextWebSocketFrame) {
+ super.channelRead(ctx, msg);
+ }
+
+ }
+
+ private static PathMatchModel parseHandler(String path, Class> handlerClass)
+ throws NoSuchMethodException, SecurityException {
+ List paramName = new ArrayList<>();
+ String[] split = path.split("/");
+ for (int index = 1; index < split.length; index++) {
+ String item = split[index];
+ if (item.startsWith("{") && item.endsWith("}")) {
+ paramName.add(item.substring(1, item.length() - 1).trim());
+ split[index] = "?";
+ }
+ }
+ StringBuilder finalPath = new StringBuilder("");
+ for (int index = 1; index < split.length; index++) {
+ finalPath.append("/").append(split[index]);
+ }
+ return new PathMatchModel(paramName, finalPath.toString(), handlerClass.getDeclaredConstructor());
+ }
+
+ private static PathMatchModel mathPathMachModel(String uri) {
+ Map map = new HashMap<>();
+ for (String key : uriHandlerMapper.keySet()) {
+ int mathUri = CommonUtil.mathUri(uri, key);
+ if (mathUri > 0) {
+ map.put(mathUri, uriHandlerMapper.get(key));
+ }
+ }
+ if (map.keySet() == null || map.keySet().isEmpty()) {
+ return null;
+ }
+ Integer max = CommonUtil.getMax(map.keySet());
+ return map.get(max);
+ }
+
+ private static final class PathMatchModel {
+ private final List pathParams;
+
+ private final String path;
+
+ private final Constructor> handlerConstructor;
+
+ public PathMatchModel(List pathParams, String path, Constructor> handlerConstructor) {
+ this.pathParams = pathParams;
+ this.path = path;
+ this.handlerConstructor = handlerConstructor;
+ }
+
+ }
+}
diff --git a/ruoyi-plugins/ruoyi-netty/src/main/java/com/ruoyi/netty/websocket/utils/CommonUtil.java b/ruoyi-plugins/ruoyi-netty/src/main/java/com/ruoyi/netty/websocket/utils/CommonUtil.java
new file mode 100644
index 0000000..9c029db
--- /dev/null
+++ b/ruoyi-plugins/ruoyi-netty/src/main/java/com/ruoyi/netty/websocket/utils/CommonUtil.java
@@ -0,0 +1,78 @@
+package com.ruoyi.netty.websocket.utils;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
+public class CommonUtil {
+
+ /**
+ * @param uri
+ * @param uriTemplates
+ * @return
+ */
+ public static int mathUri(String uri, String uriTemplate) {
+ String[] uriSplit = uri.split("/");
+ String[] tempalteSplit = uriTemplate.split("/");
+ if (uriSplit.length != tempalteSplit.length) {
+ return -1;
+ }
+ int mathLevel = 0;
+ for (int index = 1; index < tempalteSplit.length; index++) {
+ if (tempalteSplit[index].equals("?")) {
+ mathLevel = mathLevel + index;
+ continue;
+ }
+ if (!tempalteSplit[index].equals(uriSplit[index])) {
+ return -1;
+ } else {
+ mathLevel = mathLevel + tempalteSplit.length + 1;
+ }
+ }
+ return mathLevel;
+ }
+
+ public static Map parseQueryParameters(String query) {
+ if (query == null || query.isEmpty()) {
+ return Map.of();
+ }
+
+ Map params = new HashMap<>();
+ String[] pairs = query.split("&");
+ for (String pair : pairs) {
+ String[] keyValue = pair.split("=");
+ if (keyValue.length > 1) {
+ params.put(keyValue[0], keyValue[1]);
+ } else {
+ params.put(keyValue[0], "");
+ }
+ }
+ return params;
+ }
+
+ public static Map parsePathParam(String uri, List pathParams, String uriTemplate) {
+ int index = 0;
+ String[] split = uriTemplate.split("/");
+ String[] split2 = uri.split("/");
+ Map map = new HashMap<>();
+ for (int i = 1; i < split.length; i++) {
+ if (split[i].equals("?")) {
+ map.put(pathParams.get(index), split2[i]);
+ index++;
+ }
+ }
+ return map;
+ }
+
+ public static Integer getMax(Set set) {
+ Optional maxNumber = set.stream().max(Integer::compare);
+ if (maxNumber.isPresent()) {
+ System.out.println("Max number: " + maxNumber.get());
+ } else {
+ System.out.println("The list is empty");
+ }
+ return maxNumber.get();
+ }
+}
diff --git a/ruoyi-plugins/ruoyi-plugins-starter/pom.xml b/ruoyi-plugins/ruoyi-plugins-starter/pom.xml
index 183d4cd..fc7eb6d 100644
--- a/ruoyi-plugins/ruoyi-plugins-starter/pom.xml
+++ b/ruoyi-plugins/ruoyi-plugins-starter/pom.xml
@@ -50,6 +50,11 @@
com.ruoyi
ruoyi-mybatis-interceptor
+
+
+ com.ruoyi
+ ruoyi-netty
+
diff --git a/ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/utils/CommonUtil.java b/ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/utils/CommonUtil.java
index d2b0228..cd3bf70 100644
--- a/ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/utils/CommonUtil.java
+++ b/ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/utils/CommonUtil.java
@@ -75,4 +75,5 @@ public class CommonUtil {
}
return maxNumber.get();
}
+
}
--
Gitee
From e6736e99b197e4ec1d9763d2c5a2ebbbed54c223 Mon Sep 17 00:00:00 2001
From: XSWL1018 <824576966@qq.com>
Date: Sat, 19 Oct 2024 15:20:49 +0800
Subject: [PATCH 3/3] u
---
.../ruoyi/websocket/NettyServerRunner.java | 22 ---
.../annotations/NettyWebSocketEndpoint.java | 12 --
.../NettyWebSocketEndpointHandler.java | 74 --------
.../nettyServer/NettyWebSocketServer.java | 64 -------
.../nettyServer/handler/WebSocketHandler.java | 168 ------------------
.../com/ruoyi/websocket/utils/CommonUtil.java | 79 --------
6 files changed, 419 deletions(-)
delete mode 100644 ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/NettyServerRunner.java
delete mode 100644 ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/annotations/NettyWebSocketEndpoint.java
delete mode 100644 ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/nettyServer/NettyWebSocketEndpointHandler.java
delete mode 100644 ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/nettyServer/NettyWebSocketServer.java
delete mode 100644 ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/nettyServer/handler/WebSocketHandler.java
delete mode 100644 ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/utils/CommonUtil.java
diff --git a/ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/NettyServerRunner.java b/ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/NettyServerRunner.java
deleted file mode 100644
index 9e5632c..0000000
--- a/ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/NettyServerRunner.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.ruoyi.websocket;
-
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.ApplicationArguments;
-import org.springframework.boot.ApplicationRunner;
-import org.springframework.boot.web.embedded.netty.NettyWebServer;
-import org.springframework.stereotype.Component;
-
-import com.ruoyi.websocket.nettyServer.NettyWebSocketServer;
-
-@Component
-public class NettyServerRunner implements ApplicationRunner {
-
- @Autowired
- private NettyWebSocketServer server;
-
- @Override
- public void run(ApplicationArguments args) throws Exception {
- server.start();
- }
-
-}
diff --git a/ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/annotations/NettyWebSocketEndpoint.java b/ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/annotations/NettyWebSocketEndpoint.java
deleted file mode 100644
index dbe0541..0000000
--- a/ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/annotations/NettyWebSocketEndpoint.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package com.ruoyi.websocket.annotations;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.TYPE)
-public @interface NettyWebSocketEndpoint {
- String path();
-}
diff --git a/ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/nettyServer/NettyWebSocketEndpointHandler.java b/ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/nettyServer/NettyWebSocketEndpointHandler.java
deleted file mode 100644
index b2e7eaf..0000000
--- a/ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/nettyServer/NettyWebSocketEndpointHandler.java
+++ /dev/null
@@ -1,74 +0,0 @@
-package com.ruoyi.websocket.nettyServer;
-
-import java.nio.channels.Channel;
-import java.util.Map;
-
-import io.netty.channel.ChannelFutureListener;
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.channel.group.ChannelGroup;
-import io.netty.channel.group.DefaultChannelGroup;
-import io.netty.handler.codec.http.FullHttpMessage;
-import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
-import io.netty.util.concurrent.GlobalEventExecutor;
-
-public abstract class NettyWebSocketEndpointHandler {
-
- private final ChannelGroup group = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
-
- private Map pathParam;
-
- private Map urlParam;
-
- public void sendAll(String msg) {
- group.writeAndFlush(msg);
- }
-
- public static void sendMsg(ChannelHandlerContext context, String msg) {
- TextWebSocketFrame textWebSocketFrame = new TextWebSocketFrame(msg);
- context.channel().writeAndFlush(textWebSocketFrame);
- }
-
- public abstract void onMessage(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame textWebSocketFrame);
-
- public abstract void onOpen(ChannelHandlerContext channelHandlerContext, FullHttpMessage fullHttpMessage);
-
- public abstract void onClose(ChannelHandlerContext channelHandlerContext);
-
- public abstract void onError(ChannelHandlerContext channelHandlerContext, Throwable throwable);
-
- public ChannelGroup getGroup() {
- return group;
- }
-
- public Map getPathParam() {
- return pathParam;
- }
-
- public void setPathParam(Map pathParam) {
- this.pathParam = pathParam;
- }
-
- public Map getUrlParam() {
- return urlParam;
- }
-
- public void setUrlParam(Map urlParam) {
- this.urlParam = urlParam;
- }
-
- public Long getLongPathParam(String key) {
- return Long.valueOf(pathParam.get(key));
- }
-
- public String getPathParam(String key) {
- return pathParam.get(key);
- }
-
- public Double getDoublePathParam(String key) {
- return Double.parseDouble(pathParam.get(key));
- }
-
- public void closeChannel(ChannelHandlerContext channelHandlerContext) {
- channelHandlerContext.close().addListener(ChannelFutureListener.CLOSE);
- }
-}
\ No newline at end of file
diff --git a/ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/nettyServer/NettyWebSocketServer.java b/ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/nettyServer/NettyWebSocketServer.java
deleted file mode 100644
index 94dd558..0000000
--- a/ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/nettyServer/NettyWebSocketServer.java
+++ /dev/null
@@ -1,64 +0,0 @@
-package com.ruoyi.websocket.nettyServer;
-
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.stereotype.Component;
-
-import com.ruoyi.websocket.nettyServer.handler.WebSocketHandler;
-import io.netty.bootstrap.ServerBootstrap;
-import io.netty.channel.ChannelInitializer;
-import io.netty.channel.ChannelOption;
-import io.netty.channel.ChannelPipeline;
-import io.netty.channel.nio.NioEventLoopGroup;
-import io.netty.channel.socket.nio.NioServerSocketChannel;
-import io.netty.channel.socket.nio.NioSocketChannel;
-import io.netty.handler.codec.http.HttpObjectAggregator;
-import io.netty.handler.codec.http.HttpServerCodec;
-import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
-
-@Component
-public class NettyWebSocketServer {
-
- private static ServerBootstrap serverBootstrap;
-
- @Value("${netty.websocket.maxMessageSize}")
- private Long messageSize;
-
- @Value("${netty.websocket.bossThreads}")
- private Long bossThreads;
-
- @Value("${netty.websocket.workerThreads}")
- private Long workerThreads;
-
- @Value("${netty.websocket.port}")
- private Long port;
-
- @Value("${netty.websocket.enable}")
- private Boolean enable;
-
- public ServerBootstrap start() throws InterruptedException {
- if (!enable) {
- return null;
- }
- ServerBootstrap serverBootstrap = new ServerBootstrap();
- NioEventLoopGroup boss = new NioEventLoopGroup(4);
- NioEventLoopGroup worker = new NioEventLoopGroup(workerThreads.intValue());
- serverBootstrap.group(boss, worker);
- serverBootstrap.channel(NioServerSocketChannel.class);
- serverBootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
- serverBootstrap.childHandler(new ChannelInitializer() {
- @Override
- protected void initChannel(NioSocketChannel channel) throws Exception {
- ChannelPipeline pipeline = channel.pipeline();
- pipeline.addLast(new HttpServerCodec());
- pipeline.addLast(new HttpObjectAggregator(messageSize.intValue()));
- pipeline.addLast(new WebSocketHandler());
- pipeline.addLast(new WebSocketServerProtocolHandler("/", true));
- }
- });
- serverBootstrap.bind(port.intValue()).sync();
- System.out.println(
- "----------------------------------------------------------------------------------- \n Arknights!");
- NettyWebSocketServer.serverBootstrap = serverBootstrap;
- return serverBootstrap;
- }
-}
diff --git a/ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/nettyServer/handler/WebSocketHandler.java b/ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/nettyServer/handler/WebSocketHandler.java
deleted file mode 100644
index 79407c0..0000000
--- a/ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/nettyServer/handler/WebSocketHandler.java
+++ /dev/null
@@ -1,168 +0,0 @@
-package com.ruoyi.websocket.nettyServer.handler;
-
-import java.util.concurrent.ConcurrentHashMap;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.websocket.annotations.NettyWebSocketEndpoint;
-import com.ruoyi.websocket.nettyServer.NettyWebSocketEndpointHandler;
-import com.ruoyi.websocket.utils.CommonUtil;
-import io.netty.channel.ChannelFutureListener;
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.channel.ChannelId;
-import io.netty.channel.SimpleChannelInboundHandler;
-import io.netty.channel.group.ChannelGroup;
-import io.netty.channel.group.DefaultChannelGroup;
-import io.netty.handler.codec.http.DefaultFullHttpResponse;
-import io.netty.handler.codec.http.FullHttpRequest;
-import io.netty.handler.codec.http.HttpResponseStatus;
-import io.netty.handler.codec.http.HttpVersion;
-import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
-import io.netty.util.concurrent.GlobalEventExecutor;
-import jakarta.annotation.PostConstruct;
-
-import java.lang.reflect.Constructor;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.*;
-
-@Component
-public class WebSocketHandler extends SimpleChannelInboundHandler {
-
- @Autowired
- private List handlers;
-
- private static final Map uriHandlerMapper = new ConcurrentHashMap<>();
-
- public static final ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
-
- public static final Map channelHandlerMap = new ConcurrentHashMap<>();
-
- @PostConstruct
- private void init() throws URISyntaxException, NoSuchMethodException, SecurityException {
- for (NettyWebSocketEndpointHandler handler : handlers) {
- Class> handlerClass = handler.getClass();
- NettyWebSocketEndpoint annotation = handlerClass.getAnnotation(NettyWebSocketEndpoint.class);
- if (annotation == null || StringUtils.isEmpty(annotation.path())) {
- throw new RuntimeException("未配置路径的 netty websocket endpoint ");
- }
- // uriHandlerMap.put(uri.getPath(), handler);
- PathMatchModel pathMachModel = parseHandler(annotation.path(), handlerClass);
- uriHandlerMapper.put(pathMachModel.path, pathMachModel);
- }
- }
-
- @Override
- protected void channelRead0(ChannelHandlerContext context, TextWebSocketFrame webSocketFrame) throws Exception {
- NettyWebSocketEndpointHandler handler = channelHandlerMap.get(context.channel().id());
- handler.onMessage(context, webSocketFrame);
- }
-
- @Override
- public void channelActive(ChannelHandlerContext ctx) throws Exception {
- channelGroup.add(ctx.channel());
- }
-
- @Override
- public void channelInactive(ChannelHandlerContext ctx) throws Exception {
- NettyWebSocketEndpointHandler handler = channelHandlerMap.get(ctx.channel().id());
- if (handler != null) {
- handler.onClose(ctx);
- handler.getGroup().remove(ctx.channel());
- }
-
- channelHandlerMap.remove(ctx.channel().id());
- channelGroup.remove(ctx.channel());
- }
-
- @Override
- public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
-
- }
-
- @Override
- public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
- channelHandlerMap.get(ctx.channel().id()).onError(ctx, cause);
- }
-
- @Override
- public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
- if (msg instanceof FullHttpRequest) {
- FullHttpRequest fullHttpRequest = (FullHttpRequest) msg;
- if (channelHandlerMap.get(ctx.channel().id()) != null) {
- super.channelRead(ctx, fullHttpRequest);
- return;
- }
- URI uri = new URI(fullHttpRequest.uri());
- PathMatchModel mathPathMachModel = mathPathMachModel(uri.getPath());
- if (mathPathMachModel == null) {
- ctx.channel()
- .writeAndFlush(new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.NOT_FOUND));
- ctx.close().addListener(ChannelFutureListener.CLOSE);
- return;
- }
- NettyWebSocketEndpointHandler newInstance = (NettyWebSocketEndpointHandler) mathPathMachModel.handlerConstructor
- .newInstance();
- if (!(mathPathMachModel.pathParams == null || mathPathMachModel.pathParams.isEmpty())) {
- newInstance.setPathParam(
- CommonUtil.parsePathParam(uri.getPath(), mathPathMachModel.pathParams, mathPathMachModel.path));
- super.channelRead(ctx, msg);
- }
- newInstance.setUrlParam(CommonUtil.parseQueryParameters(uri.getQuery()));
-
- channelHandlerMap.put(ctx.channel().id(), newInstance);
- newInstance.onOpen(ctx, fullHttpRequest);
- } else if (msg instanceof TextWebSocketFrame) {
- super.channelRead(ctx, msg);
- }
-
- }
-
- private static PathMatchModel parseHandler(String path, Class> handlerClass)
- throws NoSuchMethodException, SecurityException {
- List paramName = new ArrayList<>();
- String[] split = path.split("/");
- for (int index = 1; index < split.length; index++) {
- String item = split[index];
- if (item.startsWith("{") && item.endsWith("}")) {
- paramName.add(item.substring(1, item.length() - 1).trim());
- split[index] = "?";
- }
- }
- StringBuilder finalPath = new StringBuilder("");
- for (int index = 1; index < split.length; index++) {
- finalPath.append("/").append(split[index]);
- }
- return new PathMatchModel(paramName, finalPath.toString(), handlerClass.getDeclaredConstructor());
- }
-
- private static PathMatchModel mathPathMachModel(String uri) {
- Map map = new HashMap<>();
- for (String key : uriHandlerMapper.keySet()) {
- int mathUri = CommonUtil.mathUri(uri, key);
- if (mathUri > 0) {
- map.put(mathUri, uriHandlerMapper.get(key));
- }
- }
- if (map.keySet() == null || map.keySet().isEmpty()) {
- return null;
- }
- Integer max = CommonUtil.getMax(map.keySet());
- return map.get(max);
- }
-
- private static final class PathMatchModel {
- private final List pathParams;
-
- private final String path;
-
- private final Constructor> handlerConstructor;
-
- public PathMatchModel(List pathParams, String path, Constructor> handlerConstructor) {
- this.pathParams = pathParams;
- this.path = path;
- this.handlerConstructor = handlerConstructor;
- }
-
- }
-}
diff --git a/ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/utils/CommonUtil.java b/ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/utils/CommonUtil.java
deleted file mode 100644
index cd3bf70..0000000
--- a/ruoyi-plugins/ruoyi-websocket/src/main/java/com/ruoyi/websocket/utils/CommonUtil.java
+++ /dev/null
@@ -1,79 +0,0 @@
-package com.ruoyi.websocket.utils;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-
-public class CommonUtil {
-
- /**
- * @param uri
- * @param uriTemplates
- * @return
- */
- public static int mathUri(String uri, String uriTemplate) {
- String[] uriSplit = uri.split("/");
- String[] tempalteSplit = uriTemplate.split("/");
- if (uriSplit.length != tempalteSplit.length) {
- return -1;
- }
- int mathLevel = 0;
- for (int index = 1; index < tempalteSplit.length; index++) {
- if (tempalteSplit[index].equals("?")) {
- mathLevel = mathLevel + index;
- continue;
- }
- if (!tempalteSplit[index].equals(uriSplit[index])) {
- return -1;
- } else {
- mathLevel = mathLevel + tempalteSplit.length + 1;
- }
- }
- return mathLevel;
- }
-
- public static Map parseQueryParameters(String query) {
- if (query == null || query.isEmpty()) {
- return Map.of();
- }
-
- Map params = new HashMap<>();
- String[] pairs = query.split("&");
- for (String pair : pairs) {
- String[] keyValue = pair.split("=");
- if (keyValue.length > 1) {
- params.put(keyValue[0], keyValue[1]);
- } else {
- params.put(keyValue[0], "");
- }
- }
- return params;
- }
-
- public static Map parsePathParam(String uri, List pathParams, String uriTemplate) {
- int index = 0;
- String[] split = uriTemplate.split("/");
- String[] split2 = uri.split("/");
- Map map = new HashMap<>();
- for (int i = 1; i < split.length; i++) {
- if (split[i].equals("?")) {
- map.put(pathParams.get(index), split2[i]);
- index++;
- }
- }
- return map;
- }
-
- public static Integer getMax(Set set) {
- Optional maxNumber = set.stream().max(Integer::compare);
- if (maxNumber.isPresent()) {
- System.out.println("Max number: " + maxNumber.get());
- } else {
- System.out.println("The list is empty");
- }
- return maxNumber.get();
- }
-
-}
--
Gitee