From 5c1c2b18e45bab8b8dd04ffe53ebf06c0fa00b6b Mon Sep 17 00:00:00 2001 From: Redkale <22250530@qq.com> Date: Fri, 26 Jan 2018 11:10:45 +0800 Subject: [PATCH] =?UTF-8?q?WebSocket=E5=AE=9E=E7=8E=B0preOnMessage?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/org/redkale/convert/ObjectDecoder.java | 1 + src/org/redkale/convert/ObjectEncoder.java | 1 + src/org/redkale/net/http/Rest.java | 97 ++++++++++++++----- src/org/redkale/net/http/WebSocket.java | 6 +- src/org/redkale/net/http/WebSocketParam.java | 19 ++++ .../redkale/net/http/WebSocketServlet.java | 17 ---- test/org/redkale/test/ws/ChatWebSocket.java | 12 ++- .../wsdync/_DyncChatWebSocketServlet.java | 52 ++++++++-- 8 files changed, 152 insertions(+), 53 deletions(-) create mode 100644 src/org/redkale/net/http/WebSocketParam.java diff --git a/src/org/redkale/convert/ObjectDecoder.java b/src/org/redkale/convert/ObjectDecoder.java index 6b5acf4e7..8ae248613 100644 --- a/src/org/redkale/convert/ObjectDecoder.java +++ b/src/org/redkale/convert/ObjectDecoder.java @@ -75,6 +75,7 @@ public final class ObjectDecoder implements Decodeable implements Encodeable 9 ? i : ("0" + i)); ClassWriter cw2 = new ClassWriter(COMPUTE_FRAMES); - cw2.visit(V1_8, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynMessageFullName + endfix, null, "java/lang/Object", null); - + cw2.visit(V1_8, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynMessageFullName + endfix, null, "java/lang/Object", new String[]{webSocketParamName, "java/lang/Runnable"}); cw2.visitInnerClass(newDynMessageFullName + endfix, newDynName, newDynMessageSimpleName + endfix, ACC_PUBLIC + ACC_STATIC); Set paramnames = new HashSet<>(); String methodesc = method.getName() + ":" + Type.getMethodDescriptor(method); List names = asmParamMap.get(methodesc); Parameter[] params = method.getParameters(); - for (int j = 0; j < params.length; j++) { + final LinkedHashMap paramap = new LinkedHashMap(); //必须使用LinkedHashMap确保顺序 + for (int j = 0; j < params.length; j++) { //字段列表 Parameter param = params[j]; String paramname = param.getName(); RestParam rp = param.getAnnotation(RestParam.class); @@ -404,11 +405,18 @@ public final class Rest { } if (paramnames.contains(paramname)) throw new RuntimeException(method + " has same @RestParam.name"); paramnames.add(paramname); + paramap.put(paramname, param); fv = cw2.visitField(ACC_PUBLIC, paramname, Type.getDescriptor(param.getType()), param.getType() == param.getParameterizedType() ? null : Utility.getTypeDescriptor(param.getParameterizedType()), null); fv.visitEnd(); } - { //构造函数 + { //_redkale_websocket + fv = cw2.visitField(ACC_PUBLIC, "_redkale_websocket", "L" + newDynWebSokcetFullName + ";", null, null); + av0 = fv.visitAnnotation(convertDisabledDesc, true); + av0.visitEnd(); + fv.visitEnd(); + } + { //空构造函数 mv = new AsmMethodVisitor(cw2.visitMethod(ACC_PUBLIC, "", "()V", null, null)); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); @@ -416,6 +424,59 @@ public final class Rest { mv.visitMaxs(1, 1); mv.visitEnd(); } + { //getValue + mv = new AsmMethodVisitor(cw2.visitMethod(ACC_PUBLIC, "getValue", "(Ljava/lang/String;)Ljava/lang/Object;", "(Ljava/lang/String;)TT;", null)); + for (Map.Entry en : paramap.entrySet()) { + Class paramType = en.getValue().getType(); + mv.visitLdcInsn(en.getKey()); + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z", false); + Label l1 = new Label(); + mv.visitJumpInsn(IFEQ, l1); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynMessageFullName + endfix, en.getKey(), Type.getDescriptor(paramType)); + if (paramType.isPrimitive()) { + Class bigclaz = java.lang.reflect.Array.get(java.lang.reflect.Array.newInstance(paramType, 1), 0).getClass(); + mv.visitMethodInsn(INVOKESTATIC, bigclaz.getName().replace('.', '/'), "valueOf", "(" + Type.getDescriptor(paramType) + ")" + Type.getDescriptor(bigclaz), false); + } + mv.visitInsn(ARETURN); + mv.visitLabel(l1); + mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); + } + mv.visitInsn(ACONST_NULL); + mv.visitInsn(ARETURN); + mv.visitMaxs(2, 2); + mv.visitEnd(); + } + { //execute + mv = new AsmMethodVisitor(cw2.visitMethod(ACC_PUBLIC, "execute", "(L" + newDynWebSokcetFullName + ";)V", null, null)); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 1); + mv.visitFieldInsn(PUTFIELD, newDynMessageFullName + endfix, "_redkale_websocket", "L" + newDynWebSokcetFullName + ";"); + mv.visitVarInsn(ALOAD, 1); + mv.visitLdcInsn(method.getAnnotation(RestOnMessage.class).name()); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKEVIRTUAL, newDynWebSokcetFullName, "preOnMessage", "(Ljava/lang/String;Lorg/redkale/net/http/WebSocketParam;Ljava/lang/Runnable;)V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(4, 2); + mv.visitEnd(); + } + { //run + mv = new AsmMethodVisitor(cw2.visitMethod(ACC_PUBLIC, "run", "()V", null, null)); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynMessageFullName + endfix, "_redkale_websocket", "L" + newDynWebSokcetFullName + ";"); + + for (Map.Entry en : paramap.entrySet()) { + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, (newDynMessageFullName + endfix), en.getKey(), Type.getDescriptor(en.getValue().getType())); + } + mv.visitMethodInsn(INVOKEVIRTUAL, newDynWebSokcetFullName, method.getName(), Type.getMethodDescriptor(method), false); + + mv.visitInsn(RETURN); + mv.visitMaxs(3, 1); + mv.visitEnd(); + } { //toString mv = new AsmMethodVisitor(cw2.visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null)); mv.visitMethodInsn(INVOKESTATIC, "org/redkale/convert/json/JsonConvert", "root", "()Lorg/redkale/convert/json/JsonConvert;", false); @@ -523,32 +584,16 @@ public final class Rest { final Method method = messageMethods.get(i); String endfix = "_" + method.getName() + "_" + (i > 9 ? i : ("0" + i)); final String messagename = method.getAnnotation(RestOnMessage.class).name(); - String methodesc = method.getName() + ":" + Type.getMethodDescriptor(method); - List names = asmParamMap.get(methodesc); - Parameter[] params = method.getParameters(); mv.visitVarInsn(ALOAD, 4); mv.visitFieldInsn(GETFIELD, newDynMessageFullName, messagename, "L" + (newDynMessageFullName + endfix) + ";"); Label ifLabel = new Label(); mv.visitJumpInsn(IFNULL, ifLabel); + mv.visitVarInsn(ALOAD, 4); + mv.visitFieldInsn(GETFIELD, newDynMessageFullName, messagename, "L" + (newDynMessageFullName + endfix) + ";"); mv.visitVarInsn(ALOAD, 3); - - for (int j = 0; j < params.length; j++) { - Parameter param = params[j]; - String paramname = param.getName(); - RestParam rp = param.getAnnotation(RestParam.class); - if (rp != null && !rp.name().isEmpty()) { - paramname = rp.name(); - } else if (names != null && names.size() > j) { - paramname = names.get(j); - } - - mv.visitVarInsn(ALOAD, 4); - mv.visitFieldInsn(GETFIELD, newDynMessageFullName, messagename, "L" + (newDynMessageFullName + endfix) + ";"); - mv.visitFieldInsn(GETFIELD, (newDynMessageFullName + endfix), paramname, Type.getDescriptor(param.getType())); - } - mv.visitMethodInsn(INVOKEVIRTUAL, newDynWebSokcetFullName, method.getName(), Type.getMethodDescriptor(method), false); + mv.visitMethodInsn(INVOKEVIRTUAL, (newDynMessageFullName + endfix), "execute", "(L" + newDynWebSokcetFullName + ";)V", false); mv.visitInsn(RETURN); mv.visitLabel(ifLabel); } diff --git a/src/org/redkale/net/http/WebSocket.java b/src/org/redkale/net/http/WebSocket.java index c97a656f4..c307d0be3 100644 --- a/src/org/redkale/net/http/WebSocket.java +++ b/src/org/redkale/net/http/WebSocket.java @@ -695,15 +695,15 @@ public abstract class WebSocket { } /** - * 尚未实现~~ - * + * * 接收到消息前的拦截方法, ping/pong不在其内
* 注意:处理完后需要调用 messageEvent.run() 才能响应onMessage * * @param restmapping Rest的方法名,没有则为空字符串 + * @param param onMessage方法的参数 * @param messageEvent onMessage事件 */ - public void preOnMessage(String restmapping, Runnable messageEvent) { + public void preOnMessage(String restmapping, WebSocketParam param, Runnable messageEvent) { messageEvent.run(); } diff --git a/src/org/redkale/net/http/WebSocketParam.java b/src/org/redkale/net/http/WebSocketParam.java new file mode 100644 index 000000000..6cd807289 --- /dev/null +++ b/src/org/redkale/net/http/WebSocketParam.java @@ -0,0 +1,19 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.net.http; + +/** + * + * 供WebSocket.preOnMessage 方法获取RestWebSocket里OnMessage方法的参数
+ *

+ * 详情见: https://redkale.org + * + * @author zhangjx + */ +public interface WebSocketParam { + + public T getValue(String name); +} diff --git a/src/org/redkale/net/http/WebSocketServlet.java b/src/org/redkale/net/http/WebSocketServlet.java index 5529d7a07..78924c12e 100644 --- a/src/org/redkale/net/http/WebSocketServlet.java +++ b/src/org/redkale/net/http/WebSocketServlet.java @@ -307,23 +307,6 @@ public abstract class WebSocketServlet extends HttpServlet implements Resourcabl return null; } - //供Rest构建RestWebSocket时使用 - protected static interface MessageEventRunner extends Runnable { - - public void execute() throws Throwable; - - @Override - default void run() { - try { - execute(); - } catch (RuntimeException e) { - throw e; - } catch (Throwable t) { - throw new RuntimeException(t); - } - } - } - private static MessageDigest getMessageDigest() { try { return MessageDigest.getInstance("SHA-1"); diff --git a/test/org/redkale/test/ws/ChatWebSocket.java b/test/org/redkale/test/ws/ChatWebSocket.java index 51ba06e5b..8a75c49fc 100644 --- a/test/org/redkale/test/ws/ChatWebSocket.java +++ b/test/org/redkale/test/ws/ChatWebSocket.java @@ -5,7 +5,8 @@ */ package org.redkale.test.ws; -import java.util.Map; +import java.lang.reflect.Method; +import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicInteger; import javax.annotation.Resource; @@ -42,4 +43,13 @@ public class ChatWebSocket extends WebSocket { System.out.println("加入房间: roomid: " + roomid); } + public static void main(String[] args) throws Throwable { + + Method method = Arrays.asList(Rest.class.getDeclaredMethods()) + .stream().filter(m -> "createRestWebSocketServlet".equals(m.getName())) + .findFirst().get(); + method.setAccessible(true); + System.out.println(method.invoke(null, Thread.currentThread().getContextClassLoader(), ChatWebSocket.class)); + } + } diff --git a/test/org/redkale/test/wsdync/_DyncChatWebSocketServlet.java b/test/org/redkale/test/wsdync/_DyncChatWebSocketServlet.java index 1e5cb2c32..d86568975 100644 --- a/test/org/redkale/test/wsdync/_DyncChatWebSocketServlet.java +++ b/test/org/redkale/test/wsdync/_DyncChatWebSocketServlet.java @@ -9,6 +9,7 @@ import java.io.Serializable; import java.util.Map; import java.util.function.BiConsumer; import javax.annotation.Resource; +import org.redkale.convert.ConvertDisabled; import org.redkale.convert.json.JsonConvert; import org.redkale.net.http.*; import org.redkale.test.ws.ChatMessage; @@ -50,9 +51,9 @@ public final class _DyncChatWebSocketServlet extends WebSocketServlet { public static class _DyncChatWebSocketMessage { - public _DyncChatWebSocketMessage_sendmessagee sendmessage; + public _DyncChatWebSocketMessage_sendmessagee_00 sendmessage; - public _DyncChatWebSocketMessage_joinroom joinroom; + public _DyncChatWebSocketMessage_joinroom_01 joinroom; @Override public String toString() { @@ -60,22 +61,61 @@ public final class _DyncChatWebSocketServlet extends WebSocketServlet { } } - public static class _DyncChatWebSocketMessage_sendmessagee { + public static class _DyncChatWebSocketMessage_sendmessagee_00 implements WebSocketParam, Runnable { public ChatMessage message; public Map extmap; + @ConvertDisabled + public _DyncChatWebSocket _redkale_websocket; + + @Override + public T getValue(String name) { + if ("message".equals(name)) return (T) message; + if ("extmap".equals(name)) return (T) extmap; + return null; + } + + public void execute(_DyncChatWebSocket websocket) { + this._redkale_websocket = websocket; + websocket.preOnMessage("sendmessage", this, this); + } + + @Override + public void run() { + _redkale_websocket.onChatMessage(this.message, this.extmap); + } + @Override public String toString() { return JsonConvert.root().convertTo(this); } } - public static class _DyncChatWebSocketMessage_joinroom { + public static class _DyncChatWebSocketMessage_joinroom_01 implements WebSocketParam, Runnable { public int roomid; + @ConvertDisabled + public _DyncChatWebSocket _redkale_websocket; + + @Override + public T getValue(String name) { + if ("roomid".equals(name)) return (T) (Integer) roomid; + return null; + } + + public void execute(_DyncChatWebSocket websocket) { + this._redkale_websocket = websocket; + websocket.preOnMessage("joinroom", this, this); + } + + @Override + public void run() { + _redkale_websocket.onJoinRoom(this.roomid); + } + @Override public String toString() { return JsonConvert.root().convertTo(this); @@ -89,11 +129,11 @@ public final class _DyncChatWebSocketServlet extends WebSocketServlet { _DyncChatWebSocket websocket = (_DyncChatWebSocket) websocket0; _DyncChatWebSocketMessage message = (_DyncChatWebSocketMessage) message0; if (message.sendmessage != null) { - websocket.onChatMessage(message.sendmessage.message, message.sendmessage.extmap); + message.sendmessage.execute(websocket); return; } if (message.joinroom != null) { - websocket.onJoinRoom(message.joinroom.roomid); + message.joinroom.execute(websocket); return; } }