Commit c10ab1753a78fe9a468ad3ce7c590ad12bd1f315

Authored by YunaiV
1 parent 2a349972

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

src/main/java/cn/iocoder/dashboard/framework/redis/core/listener/AbstractMessageListener.java
1 package cn.iocoder.dashboard.framework.redis.core.listener; 1 package cn.iocoder.dashboard.framework.redis.core.listener;
2 2
  3 +import cn.hutool.core.util.ArrayUtil;
  4 +import cn.iocoder.dashboard.util.json.JSONUtils;
  5 +import org.springframework.data.redis.connection.Message;
3 import org.springframework.data.redis.connection.MessageListener; 6 import org.springframework.data.redis.connection.MessageListener;
  7 +import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;
  8 +
  9 +import java.lang.reflect.Type;
4 10
5 /** 11 /**
6 * Redis Pub/Sub 监听器抽象类,用于实现广播消费 12 * Redis Pub/Sub 监听器抽象类,用于实现广播消费
7 * 13 *
  14 + * @param <T> 消息类型。一定要填写噢,不然会报错
  15 + *
8 * @author 芋道源码 16 * @author 芋道源码
9 */ 17 */
10 public abstract class AbstractMessageListener<T> implements MessageListener { 18 public abstract class AbstractMessageListener<T> implements MessageListener {
11 19
12 /** 20 /**
  21 + * 消息类型
  22 + */
  23 + private final Class<T> messageType;
  24 +
  25 + protected AbstractMessageListener() {
  26 + this.messageType = getMessageClass();
  27 + }
  28 +
  29 + /**
13 * 获得 Sub 订阅的 Redis Channel 通道 30 * 获得 Sub 订阅的 Redis Channel 通道
14 * 31 *
15 * @return channel 32 * @return channel
16 */ 33 */
17 public abstract String getChannel(); 34 public abstract String getChannel();
18 35
  36 + @Override
  37 + public final void onMessage(Message message, byte[] bytes) {
  38 + T messageObj = JSONUtils.parseObject(message.getBody(), messageType);
  39 + this.onMessage(messageObj);
  40 + }
  41 +
  42 + /**
  43 + * 处理消息
  44 + *
  45 + * @param message 消息
  46 + */
  47 + public abstract void onMessage(T message);
  48 +
  49 + /**
  50 + * 通过解析类上的泛型,获得消息类型
  51 + *
  52 + * @return 消息类型
  53 + */
  54 + @SuppressWarnings("unchecked")
  55 + private Class<T> getMessageClass() {
  56 + Class<?> targetClass = getClass();
  57 + while (targetClass.getSuperclass() != null) {
  58 + // 如果不是 AbstractMessageListener 父类,继续向上查找
  59 + if (targetClass.getSuperclass() != AbstractMessageListener.class) {
  60 + targetClass = targetClass.getSuperclass();
  61 + continue;
  62 + }
  63 + // 如果是 AbstractMessageListener 父类,则解析泛型
  64 + Type[] types = ((ParameterizedTypeImpl) targetClass.getGenericSuperclass()).getActualTypeArguments();
  65 + if (ArrayUtil.isEmpty(types)) {
  66 + throw new IllegalStateException(String.format("类型(%s) 需要设置消息类型", getClass().getName()));
  67 + }
  68 + return (Class<T>) types[0];
  69 + }
  70 + throw new IllegalStateException(String.format("类型(%s) 找不到 AbstractMessageListener 父类", getClass().getName()));
  71 + }
  72 +
19 } 73 }
src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/SysMenuRefreshConsumer.java
@@ -2,15 +2,23 @@ package cn.iocoder.dashboard.modules.system.mq.consumer; @@ -2,15 +2,23 @@ package cn.iocoder.dashboard.modules.system.mq.consumer;
2 2
3 import cn.iocoder.dashboard.framework.redis.core.listener.AbstractMessageListener; 3 import cn.iocoder.dashboard.framework.redis.core.listener.AbstractMessageListener;
4 import cn.iocoder.dashboard.modules.system.mq.message.permission.SysMenuRefreshMessage; 4 import cn.iocoder.dashboard.modules.system.mq.message.permission.SysMenuRefreshMessage;
5 -import org.springframework.data.redis.connection.Message; 5 +import cn.iocoder.dashboard.modules.system.service.permission.SysMenuService;
  6 +import lombok.extern.slf4j.Slf4j;
6 import org.springframework.stereotype.Component; 7 import org.springframework.stereotype.Component;
7 8
  9 +import javax.annotation.Resource;
  10 +
8 @Component 11 @Component
9 -public class SysMenuRefreshConsumer extends AbstractMessageListener { 12 +@Slf4j
  13 +public class SysMenuRefreshConsumer extends AbstractMessageListener<SysMenuRefreshMessage> {
  14 +
  15 + @Resource
  16 + private SysMenuService menuService;
10 17
11 @Override 18 @Override
12 - public void onMessage(Message message, byte[] bytes) {  
13 - System.out.println(message); 19 + public void onMessage(SysMenuRefreshMessage message) {
  20 + log.info("[onMessage][收到 Menu 刷新消息]");
  21 + menuService.init();
14 } 22 }
15 23
16 @Override 24 @Override
src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/permission/SysMenuProducer.java
1 package cn.iocoder.dashboard.modules.system.mq.producer.permission; 1 package cn.iocoder.dashboard.modules.system.mq.producer.permission;
2 2
3 import cn.iocoder.dashboard.modules.system.mq.message.permission.SysMenuRefreshMessage; 3 import cn.iocoder.dashboard.modules.system.mq.message.permission.SysMenuRefreshMessage;
4 -import org.springframework.data.redis.core.RedisTemplate; 4 +import cn.iocoder.dashboard.util.json.JSONUtils;
  5 +import org.springframework.data.redis.core.StringRedisTemplate;
5 import org.springframework.stereotype.Component; 6 import org.springframework.stereotype.Component;
6 7
7 import javax.annotation.Resource; 8 import javax.annotation.Resource;
@@ -13,14 +14,14 @@ import javax.annotation.Resource; @@ -13,14 +14,14 @@ import javax.annotation.Resource;
13 public class SysMenuProducer { 14 public class SysMenuProducer {
14 15
15 @Resource 16 @Resource
16 - private RedisTemplate<String, Object> redisTemplate; 17 + private StringRedisTemplate stringRedisTemplate;
17 18
18 /** 19 /**
19 * 发送 {@link SysMenuRefreshMessage} 消息 20 * 发送 {@link SysMenuRefreshMessage} 消息
20 */ 21 */
21 public void sendMenuRefreshMessage() { 22 public void sendMenuRefreshMessage() {
22 SysMenuRefreshMessage message = new SysMenuRefreshMessage(); 23 SysMenuRefreshMessage message = new SysMenuRefreshMessage();
23 - redisTemplate.convertAndSend(SysMenuRefreshMessage.TOPIC, message); 24 + stringRedisTemplate.convertAndSend(SysMenuRefreshMessage.TOPIC, JSONUtils.toJSONString(message));
24 } 25 }
25 26
26 } 27 }
src/main/java/cn/iocoder/dashboard/util/json/JSONUtils.java
1 package cn.iocoder.dashboard.util.json; 1 package cn.iocoder.dashboard.util.json;
2 2
  3 +import com.alibaba.fastjson.JSON;
  4 +
3 /** 5 /**
4 * JSON 工具类 6 * JSON 工具类
5 * 7 *
@@ -7,15 +9,16 @@ package cn.iocoder.dashboard.util.json; @@ -7,15 +9,16 @@ package cn.iocoder.dashboard.util.json;
7 */ 9 */
8 public class JSONUtils { 10 public class JSONUtils {
9 11
10 -// public static Map<String, Object> toJSONMap(Object javaObject) {  
11 -// return (Map<String, Object>) JSON.toJSON(javaObject);  
12 -// }  
13 -//  
14 -// public static void main(String[] args) {  
15 -// SysDictTypeCreateReqVO createReqVO = new SysDictTypeCreateReqVO();  
16 -// createReqVO.setType("1");  
17 -// createReqVO.setRemark("2");  
18 -// System.out.println(toJSONMap(createReqVO));  
19 -// } 12 + public static String toJSONString(Object object) {
  13 + return JSON.toJSONString(object);
  14 + }
  15 +
  16 + public static <T> T parseObject(String text, Class<T> clazz) {
  17 + return JSON.parseObject(text, clazz);
  18 + }
  19 +
  20 + public static <T> T parseObject(byte[] bytes, Class<T> clazz) {
  21 + return JSON.parseObject(bytes, clazz);
  22 + }
20 23
21 } 24 }