Commit c10ab1753a78fe9a468ad3ce7c590ad12bd1f315

Authored by YunaiV
1 parent 2a349972

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

src/main/java/cn/iocoder/dashboard/framework/redis/core/listener/AbstractMessageListener.java
1 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 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 12 * Redis Pub/Sub 监听器抽象类,用于实现广播消费
7 13 *
  14 + * @param <T> 消息类型。一定要填写噢,不然会报错
  15 + *
8 16 * @author 芋道源码
9 17 */
10 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 30 * 获得 Sub 订阅的 Redis Channel 通道
14 31 *
15 32 * @return channel
16 33 */
17 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 2  
3 3 import cn.iocoder.dashboard.framework.redis.core.listener.AbstractMessageListener;
4 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 7 import org.springframework.stereotype.Component;
7 8  
  9 +import javax.annotation.Resource;
  10 +
8 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 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 24 @Override
... ...
src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/permission/SysMenuProducer.java
1 1 package cn.iocoder.dashboard.modules.system.mq.producer.permission;
2 2  
3 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 6 import org.springframework.stereotype.Component;
6 7  
7 8 import javax.annotation.Resource;
... ... @@ -13,14 +14,14 @@ import javax.annotation.Resource;
13 14 public class SysMenuProducer {
14 15  
15 16 @Resource
16   - private RedisTemplate<String, Object> redisTemplate;
  17 + private StringRedisTemplate stringRedisTemplate;
17 18  
18 19 /**
19 20 * 发送 {@link SysMenuRefreshMessage} 消息
20 21 */
21 22 public void sendMenuRefreshMessage() {
22 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 1 package cn.iocoder.dashboard.util.json;
2 2  
  3 +import com.alibaba.fastjson.JSON;
  4 +
3 5 /**
4 6 * JSON 工具类
5 7 *
... ... @@ -7,15 +9,16 @@ package cn.iocoder.dashboard.util.json;
7 9 */
8 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 }
... ...