RabbitMQ安装和使用(和Spring集成)

一、安装Rabbit MQ  

  Rabbit MQ 是建立在强大的Erlang OTP平台上,因此安装Rabbit MQ的前提是安装Erlang。通过下面两个连接下载安装3.2.3 版本:

  1. 下载并安装 Eralng OTP For Windows (vR16B03)
  2. 运行安装 Rabbit MQ Server Windows Installer (v3.2.3)
  3. 具体操作步骤参考:在 Windows 上安装Rabbit MQ 指南
  4. 本人遇到的问题
  当安装RabbitMQ后,使用rabbitmqctl,rabbitmq-plugins等相应的命令,出现如下错误:* connected to epmd (port 4369) on mqmaster* epmd reports node 'rabbit' running on port 25672* TCP connection succeeded but Erlang distribution failed* suggestion: hostname mismatch?* suggestion: is the cookie set correctly?* suggestion: is the Erlang distribution using TLS?

  原因是,安装 Rabbit MQ的过程中没有使用默认的安装路径。重新安装并使用默认的安装路径就没有问题了。如果使用自定义路径,需要同步 Erlang Cookies。具体解释请参考官网中的解释:http://www.rabbitmq.com/install-windows-manual.html (在Finding Command Scripts and App Data 标题下)。

二、Spring集成Rabbit MQ示例1

  1.创建一个新的maven工程demo1。

  2.pom文件依赖如下。

    <dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><dependency><groupId>org.springframework.amqp</groupId><artifactId>spring-rabbit</artifactId><version>1.6.1.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-beans</artifactId><version>4.3.1.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>4.3.1.RELEASE</version></dependency>
View Code

  3.创建application.properties文件。

#mq
mq.username=guest
mq.password=guest
mq.addresses=127.0.0.1:5672

  4.创建spring公共配置文件applicationContext.xml。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"default-lazy-init="true"><description>Spring公共配置</description><bean id="propertyConfigurer"class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"><property name="locations"><list><value>classpath*:application.properties</value></list></property></bean><bean id="configProperties"class="org.springframework.beans.factory.config.PropertiesFactoryBean"><property name="locations"><list><value>classpath*:application.properties</value></list></property></bean><context:component-scan base-package="com.hjz.rabbit" />
</beans>
View Code

  5.创建Rabbit MQ的配置文件。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context" xmlns:rabbit="http://www.springframework.org/schema/rabbit"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/rabbithttp://www.springframework.org/schema/rabbit/spring-rabbit-1.4.xsd"><description>rabbitmq 连接服务配置</description><!-- 连接配置 --><rabbit:connection-factory id="connectionFactory" addresses="${mq.addresses}"  username="${mq.username}" password="${mq.password}" /><rabbit:admin connection-factory="connectionFactory"/><!-- spring template声明--><rabbit:template id="amqpTemplate" exchange="test-mq-exchange"  connection-factory="connectionFactory"  message-converter="jsonMessageConverter" /><!-- 消息对象json转换类 --><bean id="jsonMessageConverter" class="org.springframework.amqp.support.converter.Jackson2JsonMessageConverter" /><!-- 消息队列Queue durable:是否持久化exclusive: 仅创建者可以使用的私有队列,断开后自动删除auto_delete: 当所有消费客户端连接断开后,是否自动删除队列--><rabbit:queue id="test_queue_id" name="test_queue_name" durable="true" auto-delete="false" exclusive="false" /><!-- 交换机定义rabbit:direct-exchange:定义exchange模式为direct,意思就是消息与一个特定的路由键完全匹配,才会转发。 rabbit:binding:设置消息queue匹配的key 打印的消息实体:(Body:'{"id":"02cf5aee-d56d-4b54-ad76-a7ec6d4720b6","type":null,"params":null,"body":"大家好,我是hjzgg!!!"}' MessageProperties [headers={__TypeId__=com.hjz.rabbit.common.MqMessage}, timestamp=null, messageId=null, userId=null, receivedUserId=null, appId=null, clusterId=null, type=null, correlationId=null, correlationIdString=null, replyTo=null, contentType=application/json, contentEncoding=UTF-8, contentLength=0, deliveryMode=null, receivedDeliveryMode=PERSISTENT, expiration=null, priority=0, redelivered=false, receivedExchange=, receivedRoutingKey=test_queue_name, receivedDelay=null, deliveryTag=1, messageCount=0, consumerTag=amq.ctag-HyePMBO-c59W3z9q9DRaug, consumerQueue=test_queue_name])key 对应的就是  receivedRoutingKey 对应的值, 而这个值就是在 amqpTemplate.convertAndSend(queueName, message) 中的 queueName。如果rabbit:template 不配置 exchange属性,那么 receivedRoutingKey 就是 队列的 name值--><rabbit:direct-exchange name="test-mq-exchange" durable="true" auto-delete="false" id="test-mq-exchange"><rabbit:bindings><rabbit:binding queue="test_queue_name" key="test_queue_routing_key"/></rabbit:bindings></rabbit:direct-exchange><!-- 监听配置queues:监听的队列,多个的话用逗号(,)分隔 ref:监听器--><rabbit:listener-container connection-factory="connectionFactory" acknowledge="auto"><rabbit:listener queues="test_queue_name" ref="queueListenter"/></rabbit:listener-container> 
</beans>
View Code

  6.新建MQ消息实体类(MqMessage.java)。

public class MqMessage implements Serializable {private static final long serialVersionUID = -6791105187137215924L;private String id;private String type;//保留参数private Object params;private Object body;public String getId() {return id;}public void setId(String id) {this.id = id;}public String getType() {return type;}public void setType(String type) {this.type = type;}public Object getBody() {return body;}public void setBody(Object body) {this.body = body;}public Object getParams() {return params;}public void setParams(Object params) {this.params = params;}}
View Code

  7.新建MQ消息发送接口 (MQSender.java)。

import com.hjz.rabbit.common.MqMessage;
public interface MQSender {/*** 发送消息到指定队列* @param message* @param queueName*/void sendMessage(MqMessage message, String queueName);
}

   8.新建MQ消息发送实现类 MQSenderImpl.java。

import java.util.UUID;import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import com.hjz.rabbit.api.MQSender;
import com.hjz.rabbit.common.MqMessage;@Component
public class MQSenderImpl implements MQSender {@Autowiredprivate AmqpTemplate amqpTemplate;@Overridepublic void sendMessage(MqMessage message, String queueName) {if(message==null){System.out.println("消息发送失败:消息为null");return;}if(message.getId()==null){message.setId(UUID.randomUUID().toString());            }amqpTemplate.convertAndSend(queueName, message);}
}/*convertAndSend:将Java对象转换为消息发送到匹配Key的交换机中Exchange,由于配置了JSON转换,这里是将Java对象转换成JSON字符串的形式。
  原文:Convert a Java object to an Amqp Message and send it to a default exchange with a specific routing key.
*/

  9.创建消息监听器QueueListenter.java。

import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageListener;
import org.springframework.stereotype.Component;@Component("queueListenter")
public class QueueListenter implements MessageListener {@Overridepublic void onMessage(Message msg) {try{System.out.print(msg.toString());}catch(Exception e){e.printStackTrace();}}}

  10.终于到最后一步了,新建测试类。

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;import com.hjz.rabbit.api.MQSender;
import com.hjz.rabbit.common.MqMessage;@RunWith(value = SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath*:applicationContext.xml", "classpath*:applicationContext-mq.xml"})
public class TestQueue{@Autowiredprivate MQSender mqSender;final String queueName = "test_queue_routing_key";@Testpublic void send(){MqMessage message = new MqMessage();message.setBody("大家好,我是hjzgg!!!");mqSender.sendMessage(message, queueName);}
}

   11.最终结果,消息监听器中的输出如下。

(Body:'{"id":"723db571-1b0e-4ea5-aad4-dbfed01d158a","type":null,"params":null,"body":"大家好,我是hjzgg!!!"}' MessageProperties [headers={__TypeId__=com.hjz.rabbit.common.MqMessage}, timestamp=null, messageId=null, userId=null, receivedUserId=null, appId=null, clusterId=null, type=null, correlationId=null, correlationIdString=null, replyTo=null, contentType=application/json, contentEncoding=UTF-8, contentLength=0, deliveryMode=null, receivedDeliveryMode=PERSISTENT, expiration=null, priority=0, redelivered=false, receivedExchange=test-mq-exchange, receivedRoutingKey=test_queue_routing_key, receivedDelay=null, deliveryTag=1, messageCount=0, consumerTag=amq.ctag-PSySAf57jb5fU99UgoG2kA, consumerQueue=test_queue_name])

   12.浏览器中输入“http://localhost:15672/”,进入 Rabbit MQ的管理系统,查看 queue和exchange对应的相关信息如下。

  

   

  

三、Spring集成Rabbit MQ示例2

  1.对MQ的生产者和消费者做了一些简单的封装,同一放到了一个工程下面里。无论是生产者还是消费者,只需要依赖上这个工程对应的jar就可以了。另外就是依赖上这个工程中MQ对应的XML文件。工程的基本结构如下所示。

  

  2.XML文件如下。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context" xmlns:rabbit="http://www.springframework.org/schema/rabbit"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/rabbithttp://www.springframework.org/schema/rabbit/spring-rabbit-1.4.xsd"><!-- 连接服务配置  --><rabbit:connection-factory id="myConnectionFactory" addresses="${mq.addresses}"  username="${mq.username}" password="${mq.password}" publisher-confirms="false"/><!-- spring amqp默认的是jackson 的一个插件,目的将生产者生产的数据转换为json存入消息队列,由于fastjson的速度快于jackson,这里替换为fastjson的一个实现 --><bean id="myJsonMessageConverter" class="com.hjz.mq.converter.FastJsonMessageConverter"></bean><bean id="myRetryConnTemplate" class="org.springframework.retry.support.RetryTemplate"><property name="backOffPolicy"><bean class="org.springframework.retry.backoff.ExponentialBackOffPolicy"><property name="initialInterval" value="500"/><property name="multiplier" value="10.0"/><property name="maxInterval" value="5000"/></bean></property></bean><bean id="myRabbitAdmin" class="org.springframework.amqp.rabbit.core.RabbitAdmin">    <constructor-arg ref="myConnectionFactory" />    </bean>    <bean id="myRabbitTemplate"  class="org.springframework.amqp.rabbit.core.RabbitTemplate">    <constructor-arg ref="myConnectionFactory"></constructor-arg><property name="messageConverter" ref="myJsonMessageConverter"></property>    </bean><!-- 消费端用于监听 --><!-- <bean id="myListenerContainer"  class="org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer">    <property name="connectionFactory" ref="myConnectionFactory"></property> </bean>  --><!-- 发送端 --><bean id="msgSender" class="com.hjz.mq.sender.impl.MsgSenderImpl" /><!-- <rabbit:queue id="dev_spot_queue_ack" name="dev_spot_queue_ack" durable="true" auto-delete="false" exclusive="false"/><rabbit:listener-container connection-factory="connectionFactory" acknowledge="manual"><rabbit:listener queues="dev_spot_queue_ack" ref="xxx"/></rabbit:listener-container>-->
</beans>
View Code

  3.消费者。

package com.hjz.mq.consumer;import javax.annotation.Resource;import org.apache.commons.lang3.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.AcknowledgeMode;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.core.ChannelAwareMessageListener;
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.DisposableBean;
import org.springframework.beans.factory.InitializingBean;import com.alibaba.fastjson.JSON;
import com.hjz.mq.common.MqMessage;
import com.rabbitmq.client.Channel;public abstract class BaseConsumer implements  InitializingBean,ChannelAwareMessageListener,DisposableBean {protected static Logger logger = LoggerFactory.getLogger(BaseConsumer.class); @Resource(name="myRabbitAdmin")private RabbitAdmin rabbitAdmin;@Resource(name="myRabbitTemplate")private RabbitTemplate rabbitTemplate;//@Resource(name="myListenerContainer")private SimpleMessageListenerContainer listenerContainer;private static final String EXCHANGE_NAME = "directExchange";public static final String DEFAULT_CHARSET = "UTF-8";public void afterPropertiesSet(){String[] queueNames = this.getQueueNames();if(ArrayUtils.isEmpty(queueNames)){//throw new RuntimeException("请设置需要消费的队列");logger.warn("没有设置需要消费的队列");return;}// 声明交换器/*DirectExchange exchange = new DirectExchange(EXCHANGE_NAME);rabbitAdmin.declareExchange(exchange);Binding binding = BindingBuilder.bind(queue).to(exchange).with(getRoutingKey());rabbitAdmin.declareBinding(binding);*///声明一个监听容器listenerContainer = new SimpleMessageListenerContainer();listenerContainer.setConnectionFactory(rabbitTemplate.getConnectionFactory());Queue[] queues = new Queue[queueNames.length];//注册监听for(int i=0,len=queueNames.length;i<len;i++){String queueName = queueNames[i];Queue queue = new Queue(queueName,true,false,false);rabbitAdmin.declareQueue(queue);queues[i] = queue;}listenerContainer.addQueues(queues);listenerContainer.setPrefetchCount(1);listenerContainer.setAcknowledgeMode(AcknowledgeMode.MANUAL);listenerContainer.setMessageListener(this);listenerContainer.start();}public void destroy(){logger.debug("关闭监听...");if(listenerContainer!=null){listenerContainer.stop();}}@Overridepublic void onMessage(Message message, Channel channel) throws Exception {String msg = new String(message.getBody(), DEFAULT_CHARSET);logger.debug("接收到消息:"+msg);MessageProperties msgProps = message.getMessageProperties();//确认接收到消息channel.basicAck(msgProps.getDeliveryTag(), false);try{MqMessage mqMessage = JSON.parseObject(msg, MqMessage.class);if(mqMessage==null || mqMessage.getBody() == null){logger.error("消息体为空,舍弃!");return;}doConsumeMsg(mqMessage);logger.debug("消息消费完成");}catch(Exception ex){logger.error("消息消费失败:",ex);}}protected abstract void doConsumeMsg(MqMessage mqMessage);protected abstract String[] getQueueNames();//    protected abstract String[] getRoutingKey();
}
View Code

  4.生产者。

package com.hjz.mq.sender.impl;import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import javax.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;import com.hjz.mq.common.MqMessage;
import com.hjz.mq.sender.MsgSender;public class MsgSenderImpl implements MsgSender {private Logger logger = LoggerFactory.getLogger(MsgSenderImpl.class);@Resource(name="myRabbitAdmin")private RabbitAdmin rabbitAdmin;@Resource(name="myRabbitTemplate")private RabbitTemplate rabbitTemplate;private static final String defaultRouteKey = "";private static final String utf8Encode = "UTF-8";private static Set<String> queueHashSet=new HashSet<String>();/*** appcode:exchange* businessCode:routekey*/@Overridepublic void sendMessage(MqMessage message, String queueName) {if(message==null){logger.warn("消息发送失败:消息为null");return;}if(!queueHashSet.contains(queueName)){Queue queue = new Queue(queueName,true,false,false);rabbitAdmin.declareQueue(queue);//添加到集合中用于判断
            queueHashSet.add(queueName);}if(message.getId()==null){message.setId(UUID.randomUUID().toString());            }rabbitTemplate.convertAndSend(queueName, message);}
}
View Code

  示例中去掉了 Exchange,可以在完整项目中查看关于Exchange的配置。

  5.消费者web2工程

  继承封装过的MQ消费者抽象类,实现为实现的方法,将消息放入全局application对象中。

package com.hjz.rabbit.consumer;import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.hjz.mq.common.MqConfig;
import com.hjz.mq.common.MqMessage;
import com.hjz.mq.consumer.BaseConsumer;@Component
public class Consumer extends BaseConsumer {@Autowiredprivate ServletContext application;//    private ServletContext application = ContextLoader.getCurrentWebApplicationContext().getServletContext();
    @SuppressWarnings("unchecked")@Overrideprotected void doConsumeMsg(MqMessage mqMessage) {if(application.getAttribute("MQ_MESSAGE") == null) {application.setAttribute("MQ_MESSAGE", new ArrayList<Object>());}((List<Object>)application.getAttribute("MQ_MESSAGE")).add(mqMessage.getBody());}@Overrideprotected String[] getQueueNames() {return new String[] {MqConfig.MQ_QUEUE_ADD, MqConfig.MQ_QUEUE_SAVE, MqConfig.MQ_QUEUE_UPDATE};}
}
View Code

  从全局application对象中获取消息并返回。

package com.hjz.rabbit.web;import java.util.ArrayList;
import java.util.List;import javax.servlet.ServletContext;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;import com.alibaba.fastjson.JSONObject;
import com.hjz.mq.util.CloneUtils;
import com.hjz.mq.util.ReturnCode;@Controller
@RequestMapping("consumer")
public class MQConsumer {@Autowiredprivate ServletContext application;@SuppressWarnings("unchecked")@RequestMapping("process")@ResponseBodypublic JSONObject consumer() {JSONObject ans = new JSONObject();try {if(application.getAttribute("MQ_MESSAGE") == null) {application.setAttribute("MQ_MESSAGE", new ArrayList<Object>());}List<Object> data = (List<Object>) application.getAttribute("MQ_MESSAGE");ans.put("code", ReturnCode.SUCCESS.getValue());ans.put("data", CloneUtils.clone(data));data.clear();} catch(Exception e) {e.printStackTrace();ans.put("code", ReturnCode.FAILURE.getValue());ans.put("msg", e.getMessage().matches(ReturnCode.REGEX_CHINESE.getValue()) ? e.getMessage() : "内部异常");}return ans;}
}
View Code

  spring公共配置文件中<beans/>属相中加入如下配置。

default-lazy-init="false"

  6.生产者web1工程

package com.hjz.rabbit.web;import java.util.UUID;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;import com.alibaba.fastjson.JSONObject;
import com.hjz.mq.common.MqConfig;
import com.hjz.mq.common.MqMessage;
import com.hjz.mq.sender.MsgSender;
import com.hjz.mq.util.ReturnCode;@Controller
@RequestMapping("producer")
public class MQProducer {@Autowiredprivate MsgSender mqSender;@RequestMapping("process")@ResponseBodypublic JSONObject producer() {JSONObject ans = new JSONObject();try {String msg = "随机消息 " + UUID.randomUUID().toString();MqMessage message = new MqMessage();message.setBody(msg);mqSender.sendMessage(message, MqConfig.MQ_QUEUE_ADD);ans.put("code", ReturnCode.SUCCESS.getValue());ans.put("data", msg);} catch(Exception e) {ans.put("code", ReturnCode.FAILURE.getValue());ans.put("msg", e.getMessage().matches(ReturnCode.REGEX_CHINESE.getValue()) ? e.getMessage() : "內部錯誤");}return ans;}
}
View Code

  7.简单模拟MQ消息发送和接收web工程

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>消息展示</title>
<script src="/web/scripts/boot.js" type="text/javascript"></script>
<link href="/web/scripts/miniui/themes/default/large-mode.css"rel="stylesheet" type="text/css" />
<link href="/web/scripts/miniui/themes/bootstrap/skin.css"rel="stylesheet" type="text/css" /><style>
.container {padding: 30px;
}.container .mini-panel {margin-right: 20px;margin-bottom: 20px;
}
</style>
</head>
<body><div class="container"><div class="mini-clearfix "><div class="mini-col-6"><div class="mini-panel" title="发送消息" width="auto" height="auto"showCollapseButton="true" showCloseButton="false"><div id="panel_send" class="mini-panel" title="模拟消息发送"iconCls="icon-upload" style="width: 600px; height: 300px;"showToolbar="false" showCollapseButton="true" showFooter="false"allowResize="true" collapseOnTitleClick="true"></div></div></div><div class="mini-col-6"><div class="mini-panel mini-panel-primary" title="接收消息" width="auto"showCollapseButton="true" showCloseButton="false"><div id="panel_receive" class="mini-panel mini-panel-primary"title="模拟消息接收" iconCls="icon-download"style="width: 600px; height: 300px;" showToolbar="false"showCollapseButton="true" showFooter="false" allowResize="true"collapseOnTitleClick="true"></div></div></div></div></div>
</body>
<script type="text/javascript">mini.parse();var panel_send = mini.get('panel_send');var panel_receive = mini.get('panel_receive');$(function() {var myInterval = setInterval(function() {$.ajax({type : "GET",url : "http://localhost:8080/web1/producer/process",//data : "{}",//contentType : "application/json; charset=utf-8",
                dataType : "json",success : function(data) {if(data.code == 'success') {$(panel_send.getBodyEl()).append('<p>' + data.data + '</p>');} else {report(data.msg);}},error : function(msg) {report(msg);}});$.ajax({type : "GET",url : "http://localhost:8080/web2/consumer/process",dataType : "json",success : function(data) {if(data.code == 'success') {var div = $('<div></div>');data.data.forEach(function(value) {div.append('<p>' + value + '</p>');});$(panel_receive.getBodyEl()).append(div);} else {report(data.msg);}},error : function(msg) {report(msg);}});}, 3000);function report(msg) {clearInterval(myInterval);mini.showMessageBox({showModal: false,title: "提示",iconCls: "mini-messagebox-warning",message: typeof msg === 'object' ? JSON.stringify(msg) : msg,timeout: 3000,});}})
</script>
</html>
View Code

  8.tomcat下启动demo2中的web,web1,web2三个工程。浏览器中输入:http://127.0.0.1:port/web,参看 MQ 模拟示例。

  

四、完整项目下载地址

  https://github.com/hjzgg/Rabbit-MQ-demo

转载于:https://www.cnblogs.com/hujunzheng/p/6321860.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/531275.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

单点登录实现(spring session+redis完成session共享)

一、前言 项目中用到的SSO&#xff0c;使用开源框架cas做的。简单的了解了一下cas&#xff0c;并学习了一下 单点登录的原理&#xff0c;有兴趣的同学也可以学习一下&#xff0c;写个demo玩一玩。 二、工程结构 我模拟了 sso的客户端和sso的服务端&#xff0c; sso-core中主要是…

加密策略

一、前言 这两天研究了一下项目中的密码加密&#xff0c;可以说得上是学到了很多。下面来大致说一下。 二、常用加密 1.单向加密算法 单向加密算法主要用来验证数据传输的过程中&#xff0c;是否被篡改过。 BASE64 严格地说&#xff0c;属于编码格式&#xff0c;而非加密算法 …

Spring Data JPA: 实现自定义Repository

一、前言 由于项目中的 实体&#xff08;entity&#xff09;默认都是继承一个父类&#xff08;包含一些公共的属性&#xff0c;比如创建时间&#xff0c;修改时间&#xff0c;是否删除&#xff0c;主键id&#xff09;。为了实现逻辑删除&#xff0c;一般会自己实现RepositoryFa…

js冲刺一下

js中__proto__和prototype的区别和关系 1.对象有属性__proto__,指向该对象的构造函数的原型对象。  2.方法除了有属性__proto__,还有属性prototype&#xff0c;prototype指向该方法的原型对象。 深入浅出妙用 Javascript 中 apply、call、bind ***两道面试题*** 关于js中伪数…

Jackson序列化实例

参考文章 Jackson使用ContextualSerializer在序列化时获取字段注解的属性 使用BeanSerializerModifier定制jackson的自定义序列化(null值的处理) 关于使用ContextualSerializer的补充 BeanSerializerFactory中有如下代码&#xff0c; 关于设置SerializerModifier&#xff0c;如…

cas4.2.7实现单点登录

准备前参考&#xff1a;  cas server下载地址 cas client 下载地址 安全cookie setSecure详解 Spring通过构造方法注入的四种方式 cas 学习博文 自定义登录页和登录认证 cas server端的login-webflow详细流程 CAS服务端自定义数据库认证用户 准备工作 1. cas server下载之后解…

swagger restful api form映射实体对象和body映射实体对象配置

实体Model ModelAttribute一个具有如下三个作用&#xff1a; ①绑定请求参数到命令对象&#xff1a;放在功能处理方法的入参上时&#xff0c;用于将多个请求参数绑定到一个命令对象&#xff0c;从而简化绑定流程&#xff0c;而且自动暴露为模型数据用于视图页面展示时使用&…

ssh端口转发(之kettle ssh方式连接数据库)

ssh参数解释 格式  ssh [user]host [command] 选项&#xff1a; -1&#xff1a;强制使用ssh协议版本1&#xff1b; -2&#xff1a;强制使用ssh协议版本2&#xff1b; -4&#xff1a;强制使用IPv4地址&#xff1b; -6&#xff1a;强制使用IPv6地址&#xff1b; -A&#xff1a…

ThreadLocal和InheritableThreadLocal使用

InheritableThreadLocal代码 public class InheritableThreadLocal<T> extends ThreadLocal<T> {protected T childValue(T parentValue) {return parentValue;}ThreadLocalMap getMap(Thread t) {return t.inheritableThreadLocals;}void createMap(Thread t, T f…

mybatis generator修改默认生成的sql模板

相关连接&#xff1a; mybatis-generator扩展教程系列 -- 自定义sql xml文件 git项目地址 转载于:https://www.cnblogs.com/hujunzheng/p/7110510.html

oauth简单使用

一、oauth原理参考 理解OAuth 2.0 二、本例中采用授权码模式 大致流程 &#xff08;A&#xff09;用户访问客户端&#xff0c;后者将前者导向认证服务器。  &#xff08;B&#xff09;用户选择是否给予客户端授权。  &#xff08;C&#xff09;假设用户给予授权&#xff0c…

我眼中的服务提供和服务消费

服务提供和消费脑图 服务提供和消费脑图 参见: 服务提供者, 服务消费者, 服务注册中心 服务提供者 1.服务提供者启动&#xff0c;解析xml文件中配置的服务&#xff0c;这里使用Dom4j解析。 2.将服务的一些相关信息注册到 服务注册中心。 注&#xff1a;服务相关信息&#xff1a…

shiro整合oauth

前言 如果oauth原理还不清楚的地方&#xff0c;其参考这里。 一、基本思路脑图 二、客户端shiro配置 shiro配置文件 <?xml version"1.0" encoding"UTF-8"?> <beans xmlns"http://www.springframework.org/schema/beans"xmlns:util&q…

springmvc+swagger2

一、swagger2依赖 <!--swagger--> <dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><exclusions><exclusion><artifactId>spring-aop</artifactId><groupId>org.s…

获取资源文件工具类

如果没有依赖spring&#xff0c;可以将分割线下的方法去掉 import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframe…

无状态shiro认证组件(禁用默认session)

准备内容 简单的shiro无状态认证 无状态认证拦截器 import com.hjzgg.stateless.shiroSimpleWeb.Constants; import com.hjzgg.stateless.shiroSimpleWeb.realm.StatelessToken; import org.apache.shiro.web.filter.AccessControlFilter;import javax.servlet.ServletRequest;…

Spring根据包名获取包路径下的所有类

参考mybatis MapperScannerConfigurer.java 最终找到 Spring的一个类 ClassPathBeanDefinitionScanner.java 参考ClassPathBeanDefinitionScanner 和它的父类 ClassPathScanningCandidateComponentProvider&#xff0c;将一些代码进行抽取&#xff0c;得到如下工具类。 import…

idea模板注释

类文件头部的注释 #if (${PACKAGE_NAME} && ${PACKAGE_NAME} ! "")package ${PACKAGE_NAME};#end #parse("File Header.java") /** * ${DESCRIPTION} * author ${USER} hujunzheng * create ${YEAR}-${MONTH}-${DAY} ${TIME} **/ public class ${N…

redis分布式锁小试

一、场景 项目A监听mq中的其他项目的部署消息&#xff08;包括push_seq, status, environment&#xff0c;timestamp等&#xff09;&#xff0c;然后将部署消息同步到数据库中&#xff08;项目X在对应环境[environment]上部署的push_seq[项目X的版本]&#xff09;。那么问题来了…

Jackson ObjectMapper readValue过程

1.整体调用栈 2.看一下调用栈的两个方法 resolve 方法中通过 Iterator i$ this._beanProperties.iterator() 遍历属性的所有子属性&#xff0c;缓存对应的 deserializer。观察调用栈的方法&#xff0c;可以发现是循环调用的。 3.比如寻找自定义的 LocalDateTime类的序列化实现…