فهرست منبع

1、搭建happy-cloud-starter模块,方便后期更多启动Starter搭建
2、happy-cloud-starter-rabbitmq搭建

ZhangWenQiang 5 سال پیش
والد
کامیت
596430d4b9
20فایلهای تغییر یافته به همراه1028 افزوده شده و 0 حذف شده
  1. 23 0
      happy-cloud-starter/happy-cloud-starter-rabbitmq/pom.xml
  2. 366 0
      happy-cloud-starter/happy-cloud-starter-rabbitmq/src/main/java/org/jeecg/boot/starter/rabbitmq/client/RabbitMqClient.java
  3. 61 0
      happy-cloud-starter/happy-cloud-starter-rabbitmq/src/main/java/org/jeecg/boot/starter/rabbitmq/config/RabbitMqConfig.java
  4. 31 0
      happy-cloud-starter/happy-cloud-starter-rabbitmq/src/main/java/org/jeecg/boot/starter/rabbitmq/core/BaseRabbiMqHandler.java
  5. 39 0
      happy-cloud-starter/happy-cloud-starter-rabbitmq/src/main/java/org/jeecg/boot/starter/rabbitmq/core/MapMessageConverter.java
  6. 28 0
      happy-cloud-starter/happy-cloud-starter-rabbitmq/src/main/java/org/jeecg/boot/starter/rabbitmq/event/BaseApplicationEvent.java
  7. 21 0
      happy-cloud-starter/happy-cloud-starter-rabbitmq/src/main/java/org/jeecg/boot/starter/rabbitmq/event/EventObj.java
  8. 8 0
      happy-cloud-starter/happy-cloud-starter-rabbitmq/src/main/java/org/jeecg/boot/starter/rabbitmq/event/JeecgBusEventHandler.java
  9. 29 0
      happy-cloud-starter/happy-cloud-starter-rabbitmq/src/main/java/org/jeecg/boot/starter/rabbitmq/event/JeecgRemoteApplicationEvent.java
  10. 33 0
      happy-cloud-starter/happy-cloud-starter-rabbitmq/src/main/java/org/jeecg/boot/starter/rabbitmq/exchange/DelayExchangeBuilder.java
  11. 10 0
      happy-cloud-starter/happy-cloud-starter-rabbitmq/src/main/java/org/jeecg/boot/starter/rabbitmq/listenter/MqListener.java
  12. 42 0
      happy-cloud-starter/pom.xml
  13. 33 0
      happy-common/happy-common-tools/pom.xml
  14. 23 0
      happy-common/happy-common-tools/src/main/java/org/jeecg/common/annotation/RabbitComponent.java
  15. 141 0
      happy-common/happy-common-tools/src/main/java/org/jeecg/common/base/BaseMap.java
  16. 22 0
      happy-common/happy-common-tools/src/main/java/org/jeecg/common/config/CommonConfig.java
  17. 14 0
      happy-common/happy-common-tools/src/main/java/org/jeecg/common/constant/GlobalConstants.java
  18. 81 0
      happy-common/happy-common-tools/src/main/java/org/jeecg/common/util/SpringContextHolder.java
  19. 1 0
      happy-common/pom.xml
  20. 22 0
      pom.xml

+ 23 - 0
happy-cloud-starter/happy-cloud-starter-rabbitmq/pom.xml

@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>happy-cloud-starter</artifactId>
+        <groupId>org.happyframework.cloud</groupId>
+        <version>2.2.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>happy-cloud-starter-rabbitmq</artifactId>
+    <version>2.2.0</version>
+    <description>happy-cloud-starter-消息队列</description>
+
+    <dependencies>
+        <!-- 消息总线 rabbitmq -->
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-bus-amqp</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>

+ 366 - 0
happy-cloud-starter/happy-cloud-starter-rabbitmq/src/main/java/org/jeecg/boot/starter/rabbitmq/client/RabbitMqClient.java

@@ -0,0 +1,366 @@
+package org.jeecg.boot.starter.rabbitmq.client;
+
+
+import cn.hutool.core.util.ObjectUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.jeecg.boot.starter.rabbitmq.event.EventObj;
+import org.jeecg.boot.starter.rabbitmq.event.JeecgRemoteApplicationEvent;
+import org.jeecg.boot.starter.rabbitmq.exchange.DelayExchangeBuilder;
+import org.jeecg.common.annotation.RabbitComponent;
+import org.jeecg.common.base.BaseMap;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.amqp.core.*;
+import org.springframework.amqp.rabbit.annotation.RabbitListener;
+import org.springframework.amqp.rabbit.core.RabbitAdmin;
+import org.springframework.amqp.rabbit.core.RabbitTemplate;
+import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cloud.bus.BusProperties;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import javax.annotation.Resource;
+import java.lang.reflect.Method;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 消息队列客户端
+ */
+@Slf4j
+@Configuration
+public class RabbitMqClient {
+
+    private static final Logger logger = LoggerFactory.getLogger(RabbitMqClient.class);
+
+    private final RabbitAdmin rabbitAdmin;
+
+    private final RabbitTemplate rabbitTemplate;
+
+
+    @Resource
+    private SimpleMessageListenerContainer messageListenerContainer;
+
+    @Resource
+    BusProperties busProperties;
+    @Resource
+    private ApplicationEventPublisher publisher;
+
+
+    @Resource
+    private ApplicationContext applicationContext;
+
+
+    @Bean
+    public void initQueue() {
+        Map<String, Object> beansWithRqbbitComponentMap = this.applicationContext.getBeansWithAnnotation(RabbitComponent.class);
+        Class<? extends Object> clazz = null;
+        for (Map.Entry<String, Object> entry : beansWithRqbbitComponentMap.entrySet()) {
+            log.info("初始化队列............");
+            //获取到实例对象的class信息
+            clazz = entry.getValue().getClass();
+            Method[] methods = clazz.getMethods();
+            RabbitListener rabbitListener = clazz.getAnnotation(RabbitListener.class);
+            if (ObjectUtil.isNotEmpty(rabbitListener)) {
+                createQueue(rabbitListener);
+            }
+            for (Method method : methods) {
+                RabbitListener methodRabbitListener = method.getAnnotation(RabbitListener.class);
+                if (ObjectUtil.isNotEmpty(methodRabbitListener)) {
+                    createQueue(methodRabbitListener);
+                }
+            }
+
+        }
+    }
+
+    /**
+     * 初始化队列
+     *
+     * @param rabbitListener
+     */
+    private void createQueue(RabbitListener rabbitListener) {
+        String[] queues = rabbitListener.queues();
+        DirectExchange directExchange = createExchange(DelayExchangeBuilder.DELAY_EXCHANGE);
+        //创建交换机
+        rabbitAdmin.declareExchange(directExchange);
+        if (ObjectUtil.isNotEmpty(queues)) {
+            for (String queueName : queues) {
+                Queue queue = new Queue(queueName);
+                addQueue(queue);
+                Binding binding = BindingBuilder.bind(queue).to(directExchange).with(queueName);
+                rabbitAdmin.declareBinding(binding);
+                log.info("队列创建成功:" + queueName);
+            }
+        }
+    }
+
+
+    private Map sentObj = new HashMap<>();
+
+
+    @Autowired
+    public RabbitMqClient(RabbitAdmin rabbitAdmin, RabbitTemplate rabbitTemplate) {
+        this.rabbitAdmin = rabbitAdmin;
+        this.rabbitTemplate = rabbitTemplate;
+    }
+
+
+    /**
+     * 发送远程事件
+     *
+     * @param handlerName
+     * @param baseMap
+     */
+    public void publishEvent(String handlerName, BaseMap baseMap) {
+        EventObj eventObj = new EventObj();
+        eventObj.setHandlerName(handlerName);
+        eventObj.setBaseMap(baseMap);
+        publisher.publishEvent(new JeecgRemoteApplicationEvent(eventObj, busProperties.getId()));
+    }
+
+    /**
+     * 转换Message对象
+     *
+     * @param messageType 返回消息类型 MessageProperties类中常量
+     * @param msg
+     * @return
+     */
+    public Message getMessage(String messageType, Object msg) {
+        MessageProperties messageProperties = new MessageProperties();
+        messageProperties.setContentType(messageType);
+        Message message = new Message(msg.toString().getBytes(), messageProperties);
+        return message;
+    }
+
+    /**
+     * 有绑定Key的Exchange发送
+     *
+     * @param routingKey
+     * @param msg
+     */
+    public void sendMessageToExchange(TopicExchange topicExchange, String routingKey, Object msg) {
+        Message message = getMessage(MessageProperties.CONTENT_TYPE_JSON, msg);
+        rabbitTemplate.send(topicExchange.getName(), routingKey, message);
+    }
+
+    /**
+     * 没有绑定KEY的Exchange发送
+     *
+     * @param exchange
+     * @param msg
+     */
+    public void sendMessageToExchange(TopicExchange topicExchange, AbstractExchange exchange, String msg) {
+        addExchange(exchange);
+        logger.info("RabbitMQ send " + exchange.getName() + "->" + msg);
+        rabbitTemplate.convertAndSend(topicExchange.getName(), msg);
+    }
+
+
+    /**
+     * 发送消息
+     *
+     * @param queueName 队列名称
+     * @param params    消息内容map
+     */
+    public void sendMessage(String queueName, Object params) {
+        log.info("发送消息到mq");
+        try {
+            rabbitTemplate.convertAndSend(DelayExchangeBuilder.DELAY_EXCHANGE, queueName, params, message -> {
+                return message;
+            });
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * 发送消息
+     *
+     * @param queueName 队列名称
+     */
+    public void sendMessage(String queueName) {
+        this.send(queueName, this.sentObj, 0);
+        this.sentObj.clear();
+    }
+
+
+    public RabbitMqClient put(String key, Object value) {
+        this.sentObj.put(key, value);
+        return this;
+    }
+
+    /**
+     * 延迟发送消息
+     *
+     * @param queueName  队列名称
+     * @param params     消息内容params
+     * @param expiration 延迟时间 单位毫秒
+     */
+    public void sendMessage(String queueName, Object params, Integer expiration) {
+        this.send(queueName, params, expiration);
+    }
+
+    private void send(String queueName, Object params, Integer expiration) {
+        Queue queue = new Queue(queueName);
+        addQueue(queue);
+        CustomExchange customExchange = DelayExchangeBuilder.buildExchange();
+        rabbitAdmin.declareExchange(customExchange);
+        Binding binding = BindingBuilder.bind(queue).to(customExchange).with(queueName).noargs();
+        rabbitAdmin.declareBinding(binding);
+        //发送时间
+        LocalDateTime now = LocalDateTime.now(ZoneId.of("+8"));
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+        log.debug("发送时间:" + formatter.format(now));
+        messageListenerContainer.setQueueNames(queueName);
+/*        messageListenerContainer.setMessageListener(new MqListener<Message>() {
+            @Override
+            public void onMessage(Message message, Channel channel) {
+                MqListener messageListener = SpringContextHolder.getHandler(queueName + "Listener", MqListener.class);
+                if (ObjectUtil.isNotEmpty(messageListener)) {
+                    messageListener.onMessage(message, channel);
+                }
+            }
+        });*/
+        rabbitTemplate.convertAndSend(DelayExchangeBuilder.DEFAULT_DELAY_EXCHANGE, queueName, params, message -> {
+            if (expiration != null && expiration > 0) {
+                message.getMessageProperties().setHeader("x-delay", expiration);
+            }
+            return message;
+        });
+    }
+
+
+    /**
+     * 给queue发送消息
+     *
+     * @param queueName
+     */
+    public String receiveFromQueue(String queueName) {
+        return receiveFromQueue(DirectExchange.DEFAULT, queueName);
+    }
+
+    /**
+     * 给direct交换机指定queue发送消息
+     *
+     * @param directExchange
+     * @param queueName
+     */
+    public String receiveFromQueue(DirectExchange directExchange, String queueName) {
+        Queue queue = new Queue(queueName);
+        addQueue(queue);
+        Binding binding = BindingBuilder.bind(queue).to(directExchange).withQueueName();
+        rabbitAdmin.declareBinding(binding);
+        String messages = (String) rabbitTemplate.receiveAndConvert(queueName);
+        System.out.println("Receive:" + messages);
+        return messages;
+    }
+
+    /**
+     * 创建Exchange
+     *
+     * @param exchange
+     */
+    public void addExchange(AbstractExchange exchange) {
+        rabbitAdmin.declareExchange(exchange);
+    }
+
+    /**
+     * 删除一个Exchange
+     *
+     * @param exchangeName
+     */
+    public boolean deleteExchange(String exchangeName) {
+        return rabbitAdmin.deleteExchange(exchangeName);
+    }
+
+
+    /**
+     * 声明其名称自动命名的队列。它是用exclusive=true、autoDelete=true和 durable = false
+     *
+     * @return Queue
+     */
+    public Queue addQueue() {
+        return rabbitAdmin.declareQueue();
+    }
+
+    /**
+     * 创建一个指定的Queue
+     *
+     * @param queue
+     * @return queueName
+     */
+    public String addQueue(Queue queue) {
+        return rabbitAdmin.declareQueue(queue);
+    }
+
+    /**
+     * 删除一个队列
+     *
+     * @param queueName the name of the queue.
+     * @param unused    true if the queue should be deleted only if not in use.
+     * @param empty     true if the queue should be deleted only if empty.
+     */
+    public void deleteQueue(String queueName, boolean unused, boolean empty) {
+        rabbitAdmin.deleteQueue(queueName, unused, empty);
+    }
+
+    /**
+     * 删除一个队列
+     *
+     * @param queueName
+     * @return true if the queue existed and was deleted.
+     */
+    public boolean deleteQueue(String queueName) {
+        return rabbitAdmin.deleteQueue(queueName);
+    }
+
+    /**
+     * 绑定一个队列到一个匹配型交换器使用一个routingKey
+     *
+     * @param queue
+     * @param exchange
+     * @param routingKey
+     */
+    public void addBinding(Queue queue, TopicExchange exchange, String routingKey) {
+        Binding binding = BindingBuilder.bind(queue).to(exchange).with(routingKey);
+        rabbitAdmin.declareBinding(binding);
+    }
+
+    /**
+     * 绑定一个Exchange到一个匹配型Exchange 使用一个routingKey
+     *
+     * @param exchange
+     * @param topicExchange
+     * @param routingKey
+     */
+    public void addBinding(Exchange exchange, TopicExchange topicExchange, String routingKey) {
+        Binding binding = BindingBuilder.bind(exchange).to(topicExchange).with(routingKey);
+        rabbitAdmin.declareBinding(binding);
+    }
+
+    /**
+     * 去掉一个binding
+     *
+     * @param binding
+     */
+    public void removeBinding(Binding binding) {
+        rabbitAdmin.removeBinding(binding);
+    }
+
+    /**
+     * 创建交换器
+     *
+     * @param exchangeName
+     * @return
+     */
+    public DirectExchange createExchange(String exchangeName) {
+        return new DirectExchange(exchangeName, true, false);
+    }
+}

+ 61 - 0
happy-cloud-starter/happy-cloud-starter-rabbitmq/src/main/java/org/jeecg/boot/starter/rabbitmq/config/RabbitMqConfig.java

@@ -0,0 +1,61 @@
+package org.jeecg.boot.starter.rabbitmq.config;
+
+
+import org.jeecg.boot.starter.rabbitmq.event.JeecgRemoteApplicationEvent;
+import org.jeecg.boot.starter.rabbitmq.exchange.DelayExchangeBuilder;
+import org.springframework.amqp.core.AcknowledgeMode;
+import org.springframework.amqp.core.CustomExchange;
+import org.springframework.amqp.rabbit.connection.ConnectionFactory;
+import org.springframework.amqp.rabbit.core.RabbitAdmin;
+import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
+import org.springframework.amqp.support.ConsumerTagStrategy;
+import org.springframework.cloud.bus.jackson.RemoteApplicationEventScan;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.UUID;
+
+/**
+ * 消息队列配置类
+ *
+ * @author zyf
+ */
+@Configuration
+@RemoteApplicationEventScan(basePackageClasses = JeecgRemoteApplicationEvent.class)
+public class RabbitMqConfig {
+
+
+    @Bean
+    public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory) {
+        RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
+        //设置忽略声明异常
+        rabbitAdmin.setIgnoreDeclarationExceptions(true);
+        return rabbitAdmin;
+    }
+
+
+
+    @Bean
+    public SimpleMessageListenerContainer messageListenerContainer(ConnectionFactory connectionFactory) {
+        SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
+        container.setConnectionFactory(connectionFactory);
+        //手动确认
+        container.setAcknowledgeMode(AcknowledgeMode.MANUAL);
+        //当前的消费者数量
+        container.setConcurrentConsumers(1);
+        //最大的消费者数量
+        container.setMaxConcurrentConsumers(1);
+        //是否重回队列
+        container.setDefaultRequeueRejected(true);
+
+        //消费端的标签策略
+        container.setConsumerTagStrategy(new ConsumerTagStrategy() {
+            @Override
+            public String createConsumerTag(String queue) {
+                return queue + "_" + UUID.randomUUID().toString();
+            }
+        });
+        return container;
+    }
+
+}

+ 31 - 0
happy-cloud-starter/happy-cloud-starter-rabbitmq/src/main/java/org/jeecg/boot/starter/rabbitmq/core/BaseRabbiMqHandler.java

@@ -0,0 +1,31 @@
+package org.jeecg.boot.starter.rabbitmq.core;
+
+import com.rabbitmq.client.Channel;
+import lombok.extern.slf4j.Slf4j;
+import org.jeecg.boot.starter.rabbitmq.listenter.MqListener;
+
+import java.io.IOException;
+
+@Slf4j
+public class BaseRabbiMqHandler<T> {
+
+    public void onMessage(T t, Long deliveryTag, Channel channel, MqListener mqListener) {
+        try {
+            mqListener.handler(t, channel);
+            channel.basicAck(deliveryTag, false);
+        } catch (Exception e) {
+            log.info("接收消息失败,重新放回队列");
+            try {
+                /**
+                 * deliveryTag:该消息的index
+                 * multiple:是否批量.true:将一次性拒绝所有小于deliveryTag的消息。
+                 * requeue:被拒绝的是否重新入队列
+                 */
+                channel.basicNack(deliveryTag, false, true);
+            } catch (IOException ex) {
+                ex.printStackTrace();
+            }
+        }
+
+    }
+}

+ 39 - 0
happy-cloud-starter/happy-cloud-starter-rabbitmq/src/main/java/org/jeecg/boot/starter/rabbitmq/core/MapMessageConverter.java

@@ -0,0 +1,39 @@
+package org.jeecg.boot.starter.rabbitmq.core;
+
+import org.springframework.amqp.core.Message;
+import org.springframework.amqp.core.MessageProperties;
+import org.springframework.amqp.support.converter.MessageConversionException;
+import org.springframework.amqp.support.converter.MessageConverter;
+
+import java.io.ByteArrayInputStream;
+import java.io.ObjectInputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+public class MapMessageConverter implements MessageConverter {
+    @Override
+    public Message toMessage(Object object, MessageProperties messageProperties) throws MessageConversionException {
+        return new Message(object.toString().getBytes(), messageProperties);
+    }
+
+    @Override
+    public Object fromMessage(Message message) throws MessageConversionException {
+        String contentType = message.getMessageProperties().getContentType();
+        if (null != contentType && contentType.contains("text")) {
+            return new String(message.getBody());
+        } else {
+            ObjectInputStream objInt = null;
+            try {
+                ByteArrayInputStream byteInt = new ByteArrayInputStream(message.getBody());
+                objInt = new ObjectInputStream(byteInt);
+                //byte[]转map
+                Map map = (HashMap) objInt.readObject();
+                return map;
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+        return null;
+
+    }
+}

+ 28 - 0
happy-cloud-starter/happy-cloud-starter-rabbitmq/src/main/java/org/jeecg/boot/starter/rabbitmq/event/BaseApplicationEvent.java

@@ -0,0 +1,28 @@
+package org.jeecg.boot.starter.rabbitmq.event;
+
+import cn.hutool.core.util.ObjectUtil;
+
+import org.jeecg.common.util.SpringContextHolder;
+import org.springframework.context.ApplicationListener;
+import org.springframework.stereotype.Component;
+
+/**
+ * 监听远程事件,并分发消息到业务模块消息处理器
+ */
+@Component
+public class BaseApplicationEvent implements ApplicationListener<JeecgRemoteApplicationEvent> {
+
+    @Override
+    public void onApplicationEvent(JeecgRemoteApplicationEvent jeecgRemoteApplicationEvent) {
+        EventObj eventObj = jeecgRemoteApplicationEvent.getEventObj();
+        if (ObjectUtil.isNotEmpty(eventObj)) {
+            //获取业务模块消息处理器
+            JeecgBusEventHandler busEventHandler = SpringContextHolder.getHandler(eventObj.getHandlerName(), JeecgBusEventHandler.class);
+            if (ObjectUtil.isNotEmpty(busEventHandler)) {
+                //通知业务模块
+                busEventHandler.onMessage(eventObj);
+            }
+        }
+    }
+
+}

+ 21 - 0
happy-cloud-starter/happy-cloud-starter-rabbitmq/src/main/java/org/jeecg/boot/starter/rabbitmq/event/EventObj.java

@@ -0,0 +1,21 @@
+package org.jeecg.boot.starter.rabbitmq.event;
+
+import lombok.Data;
+import org.jeecg.common.base.BaseMap;
+
+import java.io.Serializable;
+
+/**
+ * 远程事件数据对象
+ */
+@Data
+public class EventObj implements Serializable {
+    /**
+     * 数据对象
+     */
+    private BaseMap baseMap;
+    /**
+     * 自定义业务模块消息处理器beanName
+     */
+    private String handlerName;
+}

+ 8 - 0
happy-cloud-starter/happy-cloud-starter-rabbitmq/src/main/java/org/jeecg/boot/starter/rabbitmq/event/JeecgBusEventHandler.java

@@ -0,0 +1,8 @@
+package org.jeecg.boot.starter.rabbitmq.event;
+
+/**
+ * 业务模块消息处理器接口
+ */
+public interface JeecgBusEventHandler {
+    void onMessage(EventObj map);
+}

+ 29 - 0
happy-cloud-starter/happy-cloud-starter-rabbitmq/src/main/java/org/jeecg/boot/starter/rabbitmq/event/JeecgRemoteApplicationEvent.java

@@ -0,0 +1,29 @@
+package org.jeecg.boot.starter.rabbitmq.event;
+
+import lombok.Data;
+import org.springframework.cloud.bus.event.RemoteApplicationEvent;
+
+/**
+ * 自定义网关刷新远程事件
+ *
+ * @author : zyf
+ * @date :2020-11-10
+ */
+@Data
+public class JeecgRemoteApplicationEvent extends RemoteApplicationEvent {
+
+    private JeecgRemoteApplicationEvent() {
+    }
+
+    private EventObj eventObj;
+
+    public JeecgRemoteApplicationEvent(EventObj source, String originService, String destinationService) {
+        super(source, originService, destinationService);
+        this.eventObj = source;
+    }
+
+    public JeecgRemoteApplicationEvent(EventObj source, String originService) {
+        super(source, originService, null);
+        this.eventObj = source;
+    }
+}

+ 33 - 0
happy-cloud-starter/happy-cloud-starter-rabbitmq/src/main/java/org/jeecg/boot/starter/rabbitmq/exchange/DelayExchangeBuilder.java

@@ -0,0 +1,33 @@
+package org.jeecg.boot.starter.rabbitmq.exchange;
+
+import org.springframework.amqp.core.CustomExchange;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 延迟交换器构造器
+ * @author: zyf
+ * @date: 2019/3/8 13:31
+ * @description:
+ */
+public class DelayExchangeBuilder {
+    /**
+     * 默认延迟消息交换器
+     */
+    public final static  String DEFAULT_DELAY_EXCHANGE = "happy.delayed.exchange";
+    /**
+     * 普通交换器
+     */
+    public final static  String DELAY_EXCHANGE = "happy.direct.exchange";
+
+    /**
+     * 构建延迟消息交换器
+     * @return
+     */
+    public static CustomExchange buildExchange() {
+        Map<String, Object> args = new HashMap<String, Object>();
+        args.put("x-delayed-type", "direct");
+        return new CustomExchange(DEFAULT_DELAY_EXCHANGE, "x-delayed-message", true, false, args);
+    }
+}

+ 10 - 0
happy-cloud-starter/happy-cloud-starter-rabbitmq/src/main/java/org/jeecg/boot/starter/rabbitmq/listenter/MqListener.java

@@ -0,0 +1,10 @@
+package org.jeecg.boot.starter.rabbitmq.listenter;
+
+import com.rabbitmq.client.Channel;
+
+public interface MqListener<T> {
+
+    default void handler(T map, Channel channel) {
+    }
+
+}

+ 42 - 0
happy-cloud-starter/pom.xml

@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>happy-cloud</artifactId>
+        <groupId>org.happyframework.cloud</groupId>
+        <version>2.2.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>happy-cloud-starter</artifactId>
+    <version>2.2.0</version>
+    <packaging>pom</packaging>
+
+    <properties>
+        <java.version>1.8</java.version>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <modules>
+        <module>happy-cloud-starter-rabbitmq</module>
+    </modules>
+
+    <dependencies>
+        <!-- happy tools -->
+        <dependency>
+            <groupId>org.happyframework.cloud</groupId>
+            <artifactId>happy-common-tools</artifactId>
+        </dependency>
+        <!--加载配置信息-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-autoconfigure</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-configuration-processor</artifactId>
+            <optional>true</optional>
+        </dependency>
+    </dependencies>
+
+</project>

+ 33 - 0
happy-common/happy-common-tools/pom.xml

@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>happy-common</artifactId>
+        <groupId>org.happyframework.cloud</groupId>
+        <version>2.2.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>happy-common-tools</artifactId>
+    <version>2.2.0</version>
+
+    <dependencies>
+        <!-- web -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+            <optional>true</optional>
+        </dependency>
+        <!-- web -->
+        <!--加载hutool-->
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-all</artifactId>
+        </dependency>
+        <!--加载beanutils-->
+        <dependency>
+            <groupId>commons-beanutils</groupId>
+            <artifactId>commons-beanutils</artifactId>
+        </dependency>
+    </dependencies>
+</project>

+ 23 - 0
happy-common/happy-common-tools/src/main/java/org/jeecg/common/annotation/RabbitComponent.java

@@ -0,0 +1,23 @@
+package org.jeecg.common.annotation;
+
+import org.springframework.core.annotation.AliasFor;
+import org.springframework.stereotype.Component;
+
+import java.lang.annotation.*;
+
+/**
+ * @Author:zyf
+ * @Date:2019-07-31 10:43
+ * @Description: 消息队列初始化注解
+ **/
+@Documented
+@Inherited
+@Target({ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Component
+public @interface RabbitComponent {
+    @AliasFor(
+            annotation = Component.class
+    )
+    String value();
+}

+ 141 - 0
happy-common/happy-common-tools/src/main/java/org/jeecg/common/base/BaseMap.java

@@ -0,0 +1,141 @@
+package org.jeecg.common.base;
+
+
+import cn.hutool.core.util.ObjectUtil;
+
+import org.apache.commons.beanutils.ConvertUtils;
+
+import java.math.BigDecimal;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+/**
+ * 自定义Map
+ */
+public class BaseMap extends HashMap<String, Object> {
+
+    private static final long serialVersionUID = 1L;
+
+
+    public BaseMap() {
+
+    }
+
+    public BaseMap(Map<String, Object> map) {
+        this.putAll(map);
+    }
+
+
+    @Override
+    public BaseMap put(String key, Object value) {
+        super.put(key, Optional.ofNullable(value).orElse(""));
+        return this;
+    }
+
+    public BaseMap add(String key, Object value) {
+        super.put(key, Optional.ofNullable(value).orElse(""));
+        return this;
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T> T get(String key) {
+        Object obj = super.get(key);
+        if (ObjectUtil.isNotEmpty(obj)) {
+            return (T) obj;
+        } else {
+            return null;
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public Boolean getBoolean(String key) {
+        Object obj = super.get(key);
+        if (ObjectUtil.isNotEmpty(obj)) {
+            return Boolean.valueOf(obj.toString());
+        } else {
+            return false;
+        }
+    }
+
+    public Long getLong(String key) {
+        Object v = get(key);
+        if (ObjectUtil.isNotEmpty(v)) {
+            return new Long(v.toString());
+        }
+        return null;
+    }
+
+    public Long[] getLongs(String key) {
+        Object v = get(key);
+        if (ObjectUtil.isNotEmpty(v)) {
+            return (Long[]) v;
+        }
+        return null;
+    }
+
+    public List<Long> getListLong(String key) {
+        List<String> list = get(key);
+        if (ObjectUtil.isNotEmpty(list)) {
+            return list.stream().map(e -> new Long(e)).collect(Collectors.toList());
+        } else {
+            return null;
+        }
+    }
+
+    public Long[] getLongIds(String key) {
+        Object ids = get(key);
+        if (ObjectUtil.isNotEmpty(ids)) {
+            return (Long[]) ConvertUtils.convert(ids.toString().split(","), Long.class);
+        } else {
+            return null;
+        }
+    }
+
+
+    public Integer getInt(String key, Integer def) {
+        Object v = get(key);
+        if (ObjectUtil.isNotEmpty(v)) {
+            return Integer.parseInt(v.toString());
+        } else {
+            return def;
+        }
+    }
+
+    public Integer getInt(String key) {
+        Object v = get(key);
+        if (ObjectUtil.isNotEmpty(v)) {
+            return Integer.parseInt(v.toString());
+        } else {
+            return 0;
+        }
+    }
+
+    public BigDecimal getBigDecimal(String key) {
+        Object v = get(key);
+        if (ObjectUtil.isNotEmpty(v)) {
+            return new BigDecimal(v.toString());
+        }
+        return new BigDecimal("0");
+    }
+
+
+    @SuppressWarnings("unchecked")
+    public <T> T get(String key, T def) {
+        Object obj = super.get(key);
+        if (ObjectUtil.isEmpty(obj)) {
+            return def;
+        }
+        return (T) obj;
+    }
+
+    public static BaseMap toBaseMap(Map<String, Object> obj) {
+        BaseMap map = new BaseMap();
+        map.putAll(obj);
+        return map;
+    }
+
+
+}

+ 22 - 0
happy-common/happy-common-tools/src/main/java/org/jeecg/common/config/CommonConfig.java

@@ -0,0 +1,22 @@
+package org.jeecg.common.config;
+
+import org.jeecg.common.util.SpringContextHolder;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class CommonConfig {
+
+    /**
+     * Spring上下文工具配置
+     *
+     * @return
+     */
+    @Bean
+    @ConditionalOnMissingBean(SpringContextHolder.class)
+    public SpringContextHolder springContextHolder() {
+        SpringContextHolder holder = new SpringContextHolder();
+        return holder;
+    }
+}

+ 14 - 0
happy-common/happy-common-tools/src/main/java/org/jeecg/common/constant/GlobalConstants.java

@@ -0,0 +1,14 @@
+package org.jeecg.common.constant;
+
+public class GlobalConstants {
+
+    /**
+     * 业务处理器beanName传递参数
+     */
+    public static final String HANDLER_NAME = "handlerName";
+
+    /**
+     * redis消息通道名称
+     */
+    public static final String REDIS_TOPIC_NAME="happy_redis_topic";
+}

+ 81 - 0
happy-common/happy-common-tools/src/main/java/org/jeecg/common/util/SpringContextHolder.java

@@ -0,0 +1,81 @@
+
+package org.jeecg.common.util;
+
+import cn.hutool.core.util.ObjectUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+
+/**
+ * 以静态变量保存Spring ApplicationContext, 可在任何代码任何地方任何时候中取出ApplicaitonContext.
+ *
+ * @author zyf
+ */
+@Slf4j
+public class SpringContextHolder implements ApplicationContextAware {
+    private static ApplicationContext applicationContext;
+
+    /**
+     * 实现ApplicationContextAware接口的context注入函数, 将其存入静态变量.
+     */
+    @Override
+    public void setApplicationContext(ApplicationContext applicationContext) {
+        // NOSONAR
+        SpringContextHolder.applicationContext = applicationContext;
+    }
+
+    /**
+     * 取得存储在静态变量中的ApplicationContext.
+     */
+    public static ApplicationContext getApplicationContext() {
+        checkApplicationContext();
+        return applicationContext;
+    }
+
+    /**
+     * 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型.
+     */
+    public static <T> T getBean(String name) {
+        checkApplicationContext();
+        return (T) applicationContext.getBean(name);
+    }
+
+    /**
+     * 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型.
+     */
+    public static <T> T getHandler(String name, Class<T> cls) {
+        T t = null;
+        if (ObjectUtil.isNotEmpty(name)) {
+            checkApplicationContext();
+            try {
+                t = applicationContext.getBean(name, cls);
+            } catch (Exception e) {
+                log.error("####################" + name + "未定义");
+            }
+        }
+        return t;
+    }
+
+
+    /**
+     * 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型.
+     */
+    public static <T> T getBean(Class<T> clazz) {
+        checkApplicationContext();
+        return applicationContext.getBean(clazz);
+    }
+
+    /**
+     * 清除applicationContext静态变量.
+     */
+    public static void cleanApplicationContext() {
+        applicationContext = null;
+    }
+
+    private static void checkApplicationContext() {
+        if (applicationContext == null) {
+            throw new IllegalStateException("applicaitonContext未注入,请在applicationContext.xml中定义SpringContextHolder");
+        }
+    }
+
+}

+ 1 - 0
happy-common/pom.xml

@@ -15,6 +15,7 @@
         <module>happy-common-core</module>
         <module>happy-common-cloud</module>
         <module>happy-common-cloud-starter</module>
+        <module>happy-common-tools</module>
     </modules>
 
 

+ 22 - 0
pom.xml

@@ -24,6 +24,7 @@
         <module>happy-cloud-auth</module>
         <module>happy-cloud-sentinel</module>
 		<module>happy-cloud-xxl-job</module>
+		<module>happy-cloud-starter</module>
 	</modules>
 
 	<distributionManagement>
@@ -76,6 +77,8 @@
 		<swagger2.version>2.9.2</swagger2.version>
 		<knife4j.version>2.0.3</knife4j.version>
 		<logstash-logback-encoder.version>6.1</logstash-logback-encoder.version>
+		<hutool-all.version>5.3.8</hutool-all.version>
+		<commons-beanutils.version>1.9.4</commons-beanutils.version>
     </properties>
 
 	<dependencies>
@@ -340,12 +343,31 @@
 				<artifactId>happy-cloud-system-api</artifactId>
 				<version>${happyboot.version}</version>
 			</dependency>
+			<!-- happy-common-tools -->
+			<dependency>
+				<groupId>org.happyframework.cloud</groupId>
+				<artifactId>happy-common-tools</artifactId>
+				<version>${happyboot.version}</version>
+			</dependency>
 	    	<!-- 七牛云SDK -->
 			<dependency>
 				<groupId>com.qiniu</groupId>
 				<artifactId>qiniu-java-sdk</artifactId>
 				<version>7.2.23</version>
 			</dependency>
+			<!-- hutool工具类-->
+			<dependency>
+				<groupId>cn.hutool</groupId>
+				<artifactId>hutool-all</artifactId>
+				<version>${hutool-all.version}</version>
+			</dependency>
+
+			<!-- commons-beanutils -->
+			<dependency>
+				<groupId>commons-beanutils</groupId>
+				<artifactId>commons-beanutils</artifactId>
+				<version>${commons-beanutils.version}</version>
+			</dependency>
 			<!-- spring-cloud-->
 			<dependency>
 				<groupId>org.springframework.cloud</groupId>