소스 검색

优化 Redis pub/sub 的封装,提升使用的便利性

YunaiV 4 년 전
부모
커밋
c10ab1753a

+ 54 - 0
src/main/java/cn/iocoder/dashboard/framework/redis/core/listener/AbstractMessageListener.java

@@ -1,14 +1,31 @@
 package cn.iocoder.dashboard.framework.redis.core.listener;
 
+import cn.hutool.core.util.ArrayUtil;
+import cn.iocoder.dashboard.util.json.JSONUtils;
+import org.springframework.data.redis.connection.Message;
 import org.springframework.data.redis.connection.MessageListener;
+import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;
+
+import java.lang.reflect.Type;
 
 /**
  * Redis Pub/Sub 监听器抽象类,用于实现广播消费
  *
+ * @param <T> 消息类型。一定要填写噢,不然会报错
+ *
  * @author 芋道源码
  */
 public abstract class AbstractMessageListener<T> implements MessageListener {
 
+    /**
+     * 消息类型
+     */
+    private final Class<T> messageType;
+
+    protected AbstractMessageListener() {
+        this.messageType = getMessageClass();
+    }
+
     /**
      * 获得 Sub 订阅的 Redis Channel 通道
      *
@@ -16,4 +33,41 @@ public abstract class AbstractMessageListener<T> implements MessageListener {
      */
     public abstract String getChannel();
 
+    @Override
+    public final void onMessage(Message message, byte[] bytes) {
+        T messageObj = JSONUtils.parseObject(message.getBody(), messageType);
+        this.onMessage(messageObj);
+    }
+
+    /**
+     * 处理消息
+     *
+     * @param message 消息
+     */
+    public abstract void onMessage(T message);
+
+    /**
+     * 通过解析类上的泛型,获得消息类型
+     *
+     * @return 消息类型
+     */
+    @SuppressWarnings("unchecked")
+    private Class<T> getMessageClass() {
+        Class<?> targetClass = getClass();
+        while (targetClass.getSuperclass() != null) {
+            // 如果不是 AbstractMessageListener 父类,继续向上查找
+            if (targetClass.getSuperclass() != AbstractMessageListener.class) {
+                targetClass = targetClass.getSuperclass();
+                continue;
+            }
+            // 如果是 AbstractMessageListener 父类,则解析泛型
+            Type[] types = ((ParameterizedTypeImpl) targetClass.getGenericSuperclass()).getActualTypeArguments();
+            if (ArrayUtil.isEmpty(types)) {
+                throw new IllegalStateException(String.format("类型(%s) 需要设置消息类型", getClass().getName()));
+            }
+            return (Class<T>) types[0];
+        }
+        throw new IllegalStateException(String.format("类型(%s) 找不到 AbstractMessageListener 父类", getClass().getName()));
+    }
+
 }

+ 12 - 4
src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/SysMenuRefreshConsumer.java

@@ -2,15 +2,23 @@ package cn.iocoder.dashboard.modules.system.mq.consumer;
 
 import cn.iocoder.dashboard.framework.redis.core.listener.AbstractMessageListener;
 import cn.iocoder.dashboard.modules.system.mq.message.permission.SysMenuRefreshMessage;
-import org.springframework.data.redis.connection.Message;
+import cn.iocoder.dashboard.modules.system.service.permission.SysMenuService;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Component;
 
+import javax.annotation.Resource;
+
 @Component
-public class SysMenuRefreshConsumer extends AbstractMessageListener {
+@Slf4j
+public class SysMenuRefreshConsumer extends AbstractMessageListener<SysMenuRefreshMessage> {
+
+    @Resource
+    private SysMenuService menuService;
 
     @Override
-    public void onMessage(Message message, byte[] bytes) {
-        System.out.println(message);
+    public void onMessage(SysMenuRefreshMessage message) {
+        log.info("[onMessage][收到 Menu 刷新消息]");
+        menuService.init();
     }
 
     @Override

+ 4 - 3
src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/permission/SysMenuProducer.java

@@ -1,7 +1,8 @@
 package cn.iocoder.dashboard.modules.system.mq.producer.permission;
 
 import cn.iocoder.dashboard.modules.system.mq.message.permission.SysMenuRefreshMessage;
-import org.springframework.data.redis.core.RedisTemplate;
+import cn.iocoder.dashboard.util.json.JSONUtils;
+import org.springframework.data.redis.core.StringRedisTemplate;
 import org.springframework.stereotype.Component;
 
 import javax.annotation.Resource;
@@ -13,14 +14,14 @@ import javax.annotation.Resource;
 public class SysMenuProducer {
 
     @Resource
-    private RedisTemplate<String, Object> redisTemplate;
+    private StringRedisTemplate stringRedisTemplate;
 
     /**
      * 发送 {@link SysMenuRefreshMessage} 消息
      */
     public void sendMenuRefreshMessage() {
         SysMenuRefreshMessage message = new SysMenuRefreshMessage();
-        redisTemplate.convertAndSend(SysMenuRefreshMessage.TOPIC, message);
+        stringRedisTemplate.convertAndSend(SysMenuRefreshMessage.TOPIC, JSONUtils.toJSONString(message));
     }
 
 }

+ 13 - 10
src/main/java/cn/iocoder/dashboard/util/json/JSONUtils.java

@@ -1,5 +1,7 @@
 package cn.iocoder.dashboard.util.json;
 
+import com.alibaba.fastjson.JSON;
+
 /**
  * JSON 工具类
  *
@@ -7,15 +9,16 @@ package cn.iocoder.dashboard.util.json;
  */
 public class JSONUtils {
 
-//    public static Map<String, Object> toJSONMap(Object javaObject) {
-//        return (Map<String, Object>) JSON.toJSON(javaObject);
-//    }
-//
-//    public static void main(String[] args) {
-//        SysDictTypeCreateReqVO createReqVO = new SysDictTypeCreateReqVO();
-//        createReqVO.setType("1");
-//        createReqVO.setRemark("2");
-//        System.out.println(toJSONMap(createReqVO));
-//    }
+    public static String toJSONString(Object object) {
+        return JSON.toJSONString(object);
+    }
+
+    public static <T> T parseObject(String text, Class<T> clazz) {
+        return JSON.parseObject(text, clazz);
+    }
+
+    public static <T> T parseObject(byte[] bytes, Class<T> clazz) {
+        return JSON.parseObject(bytes, clazz);
+    }
 
 }