ActiveMQ-Web应用
来源:互联网 发布:剑三男神捏脸数据 编辑:程序博客网 时间:2024/06/05 18:25
ActiveMQ-Web应用
sf2gis@163.com
2015年7月30日
1 目标:处理web请求消息,实现web客户端和服务端交互。
2 原理:使用servlet容器,使用ActiveMQ库将web请求转发到ActiveMQ服务器,并接收ActiveMQ的消息作为Web响应。自定义处理程序处理ActiveMQ的消息,实现对消息的控制。
3 方法:Tomcat(servlet容器)+ActiveMQ(消息服务器)+Java(消息处理程序)
参考:http://blog.sina.com.cn/s/blog_5a010cd10101djgl.html
http://jackyin5918.iteye.com/blog/2007422
http://blog.csdn.net/neareast/article/details/7588527
http://activemq.apache.org/ajax.html
3.1 建立Web网站:Tomcat,处理web请求与响应。
3.1.1添加ActiveMQ库:将下列库复制到web-inf\lib目录下。
3.2 Web消息与ActiveMQ消息映射:web.xml配置。
3.2.1web.xml设置ActiveMQ库作为响应Servlet,用于消息收发及消息与响应、请求的转换。
<servlet>
<servlet-name>AjaxServlet</servlet-name>
<servlet-class>org.apache.activemq.web.AjaxServlet</servlet-class>
<async-supported>true</async-supported>
</servlet>
<servlet-mapping>
<servlet-name>AjaxServlet</servlet-name>
<url-pattern>/amq/*</url-pattern>
</servlet-mapping>
3.2.2设置消息服务的url地址:context-param
参考:http://blog.csdn.net/liaoxiaohua1981/article/details/6759206
<context-param>
<param-name>org.apache.activemq.brokerURL</param-name>
<param-value>tcp://localhost:61616</param-value>
</context-param>
<welcome-file-list>
3.2.3示例
<?xmlversion="1.0" encoding="UTF-8"?>
<web-appxmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaeehttp://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"id="WebApp_ID" version="3.0">
<display-name>ajaxmq</display-name>
<servlet>
<servlet-name>AjaxServlet</servlet-name>
<servlet-class>org.apache.activemq.web.AjaxServlet</servlet-class>
<async-supported>true</async-supported>
</servlet>
<servlet-mapping>
<servlet-name>AjaxServlet</servlet-name>
<url-pattern>/amq/*</url-pattern>
</servlet-mapping>
<context-param>
<param-name>org.apache.activemq.brokerURL</param-name>
<param-value>tcp://localhost:61616</param-value>
</context-param>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
</web-app>
3.3 客户端页面ActiveMQ请求:amq.js,客户端消息操作。
以Ajax的方式进行前后台交互,接收消息使用Ajax轮询来实现服务器push。
3.3.1添加amq.js及相关库:
<scripttype="text/javascript"src="js/jquery-1.4.2.min.js"></script>
<scripttype="text/javascript"src="js/amq_jquery_adapter.js"></script>
<scripttype="text/javascript" src="js/amq.js"></script>
3.3.2构造amq对象:org.activemq.Amq。需要指定uri为amq。
var amq = org.activemq.Amq;
amq.init({
uri: 'amq',
logging: true,
timeout: 20
});
3.3.3发送消息:amq.sendMessage(Destination,message,type)。
目标消息队列:Destination,使用url格式。
消息:Message,使用XML格式。
示例:
amq.sendMessage("topic://FirstTopic","<message>"+ms+"</message>","amq-msg-type=>'text'");
3.3.4接收消息:amq.addListener(cliendId,Destination,callbackFun,selector)。
目标消息队列:Destination,使用url格式。
处理函数:callbackFunction,接受一个消息参数。
选择器:selector,过滤消息。
示例:
//receive message
functionreceiverMsg(message){
console.debug("receive="+message);
document.getElementById("msg").innerHTML +="receive="+message.textContent + "<br>";
}
amq.addListener("smeguangdong","topic://FirstTopic",receiverMsg);
3.3.5示例
<!DOCTYPE html PUBLIC"-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<metahttp-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>Insert titlehere</title>
<script type="text/javascript"src="js/jquery-1.4.2.min.js"></script>
<script type="text/javascript" src="js/amq_jquery_adapter.js"></script>
<script type="text/javascript"src="js/amq.js"></script>
</head>
<body>
leon's chating room:
<hr>
<divstyle="height:400px;width:600px;border:block;overflow:auto"id="msg">
</div>
<br>
<scripttype="text/javascript">
//create amq
var amq = org.activemq.Amq;
amq.init({
uri: 'amq',
logging: true,
timeout: 20
});
//receive message
functionreceiverMsg(message){
console.debug("receive="+message);
document.getElementById("msg").innerHTML +="receive="+message.textContent + "<br>";
}
amq.addListener("smeguangdong","topic://FirstTopic",receiverMsg);
//send message
function sendMsg()
{
var nickname =document.getElementById("nickname").value;
var content =document.getElementById("keymsg").value;
var ms = nickname + " : "+content;
amq.sendMessage("topic://FirstTopic","<message>"+ms+"</message>","amq-msg-type=>'text'");
}
</script>
昵称:
<inputtype="text" id="nickname">
内容:
<input type="text"id="keymsg">
<buttononclick="sendMsg()">submit</button>
</body>
</html>
3.3.6附:amq.js源码。
/**
*
* Licensed to the Apache Software Foundation(ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional informationregarding copyright ownership.
* The ASF licenses this file to You under theApache License, Version 2.0
* (the "License"); you may not usethis file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreedto in writing, software
* distributed under the License is distributedon an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANYKIND, either express or implied.
* See the License for the specific languagegoverning permissions and
* limitations under the License.
*/
// AMQ Ajax handler
// This class provides themain API for using the Ajax features of AMQ. It
// allows JMS messages to besent and received from javascript when used
// with theorg.apache.activemq.web.MessageListenerServlet.
//
// This version of the fileprovides an adapter interface for the jquery library
// and a namespace for theJavascript file, private/public variables and
// methods, and otherscripting niceties. -- jim cook 2007/08/28
var org = org || {};
org.activemq = org.activemq|| {};
org.activemq.Amq = function(){
var connectStatusHandler;
// Just a shortcut to eliminate some redundant typing.
var adapter = org.activemq.AmqAdapter;
if (typeof adapter == 'undefined') {
throw 'An org.activemq.AmqAdapter must be declared beforethe amq.js script file.'
}
// The URI of the AjaxServlet.
var uri;
// The number of seconds that the long-polling socket will stayconnected.
// Best to keep this to a value less than one minute.
var timeout;
// A session should not be considered initialized until theJSESSIONID is returned
// from the initial GET request. Otherwise subscription POSTS may register the
// subscription with the wrong session.
var sessionInitialized = false;
// This callback will be called after the first GET requestreturns.
var sessionInitializedCallback;
// Poll delay. if set to positive integer, this is the time towait in ms
// before sending the next poll after the last completes.
var pollDelay;
// Inidicates whether logging is active or not. Not by default.
var logging = false;
// 5 second delay if an error occurs during poll. This could bedue to
// server capacity problems or a timeout condition.
var pollErrorDelay = 5000;
// Map of handlers that will respond to message receipts. Theid used during
// addListener(id, destination, handler) is used to key thecallback
// handler.
var messageHandlers = {};
// Indicates whether an AJAX post call is in progress.
var batchInProgress = false;
// A collection of pending messages that accumulate when anAJAX call is in
// progress. These messages will be delivered as soon as thecurrent call
// completes. The array contains objects in the format {destination,
// message, messageType }.
var messageQueue = [];
// String to distinguish this client fromothers sharing the same session.
// This can occur when multiple browserwindows or tabs using amq.js simultaneously.
// All windows share the same JESSIONID, butneed to consume messages independently.
var clientId = null;
/**
* Iterate over thereturned XML and for each message in the response,
* invoke the handlerwith the matching id.
*/
var messageHandler = function(data) {
var response =data.getElementsByTagName("ajax-response");
if (response != null && response.length == 1) {
connectStatusHandler(true);
var responses = response[0].childNodes; // <response>
for (var i = 0; i < responses.length; i++) {
var responseElement = responses[i];
// only process nodes of type element.....
if (responseElement.nodeType != 1) continue;
var id = responseElement.getAttribute('id');
var handler = messageHandlers[id];
if (logging && handler == null) {
adapter.log('No handler found to matchmessage with id = ' + id);
continue;
}
// Loop thru and handle each <message>
for (var j = 0; j <responseElement.childNodes.length; j++) {
handler(responseElement.childNodes[j]);
}
}
}
};
var errorHandler = function(xhr, status, ex) {
connectStatusHandler(false);
if (logging) adapter.log('Error occurred in ajax call.HTTP result: ' +
xhr.status + ', status: ' + status);
}
var pollErrorHandler = function(xhr, status, ex) {
connectStatusHandler(false);
if (status === 'error' && xhr.status === 0) {
if (logging) adapter.log('Server connectiondropped.');
setTimeout(function() { sendPoll(); },pollErrorDelay);
return;
}
if (logging) adapter.log('Error occurred in poll. HTTPresult: ' +
xhr.status + ', status: ' + status);
setTimeout(function() { sendPoll(); }, pollErrorDelay);
}
var pollHandler = function(data) {
try {
messageHandler(data);
} catch(e) {
if (logging) adapter.log('Exception in the pollhandler: ' + data, e);
throw(e);
} finally {
setTimeout(sendPoll, pollDelay);
}
};
var initHandler = function(data) {
sessionInitialized = true;
if(sessionInitializedCallback) {
sessionInitializedCallback();
}
sendPoll();
}
var sendPoll = function() {
// Workaround IE6 bug where it caches the response
// Generate a unique query string with date and random
var now = new Date();
var timeoutArg = sessionInitialized ? timeout : 0.001;
var data = 'timeout=' + timeoutArg * 1000
+'&d=' + now.getTime()
+'&r=' + Math.random();
var successCallback = sessionInitialized ? pollHandler :initHandler;
var options = { method: 'get',
data: addClientId( data ),
success: successCallback,
error: pollErrorHandler};
adapter.ajax(uri, options);
};
var sendJmsMessage = function(destination, message, type, headers){
var message = {
destination: destination,
message: message,
messageType: type
};
// Add message to outbound queue
if (batchInProgress) {
messageQueue[messageQueue.length] ={message:message, headers:headers};
} else {
org.activemq.Amq.startBatch();
adapter.ajax(uri, { method: 'post',
data: addClientId( buildParams( [message] ) ),
error: errorHandler,
headers: headers,
success: org.activemq.Amq.endBatch});
}
};
var buildParams = function(msgs) {
var s = [];
for (var i = 0, c = msgs.length; i < c; i++) {
if (i != 0) s[s.length] = '&';
s[s.length] = ((i == 0) ? 'destination' : 'd' + i);
s[s.length] = '=';
s[s.length] = msgs[i].destination;
s[s.length] = ((i == 0) ? '&message' : '&m'+ i);
s[s.length] = '=';
s[s.length] = msgs[i].message;
s[s.length] = ((i == 0) ? '&type' : '&t' +i);
s[s.length] = '=';
s[s.length] = msgs[i].messageType;
}
return s.join('');
}
// add clientId to data if it exists, before passing data toajax connection adapter.
var addClientId = function( data ) {
var output = data || '';
if( clientId ) {
if( output.length > 0 ) {
output += '&';
}
output += 'clientId='+clientId;
}
return output;
}
return {
// optional clientId can be supplied to allow multipleclients (browser windows) within the same session.
init : function(options) {
connectStatusHandler = options.connectStatusHandler|| function(connected){};
uri = options.uri || '/amq';
pollDelay = typeof options.pollDelay == 'number' ?options.pollDelay : 0;
timeout = typeof options.timeout == 'number' ?options.timeout : 25;
logging = options.logging;
sessionInitializedCallback =options.sessionInitializedCallback
clientId = options.clientId;
adapter.init(options);
sendPoll();
},
startBatch : function() {
batchInProgress = true;
},
endBatch : function() {
if (messageQueue.length > 0) {
var messagesToSend = [];
var messagesToQueue = [];
var outgoingHeaders = null;
// we need to ensure that messages which setheaders are sent by themselves.
// if 2 'listen' messages were sent together,and a 'selector' header were added to one of them,
// AMQ would add the selector to both 'listen'commands.
for(i=0;i<messageQueue.length;i++) {
// a message with headers should alwaysbe sent by itself. if other messageshave been added, send this one later.
if ( messageQueue[ i ].headers &&messagesToSend.length == 0 ) {
messagesToSend[messagesToSend.length ] = messageQueue[ i ].message;
outgoingHeaders = messageQueue[ i].headers;
} else if ( ! messageQueue[ i ].headers&& ! outgoingHeaders ) {
messagesToSend[messagesToSend.length ] = messageQueue[ i ].message;
} else {
messagesToQueue[messagesToQueue.length ] = messageQueue[ i ];
}
}
var body = buildParams(messagesToSend);
messageQueue = messagesToQueue;
org.activemq.Amq.startBatch();
adapter.ajax(uri, {
method: 'post',
headers: outgoingHeaders,
data: addClientId( body ),
success: org.activemq.Amq.endBatch,
error: errorHandler});
} else {
batchInProgress = false;
}
},
// Send a JMS message to a destination (egtopic://MY.TOPIC). Message
// should be xml or encoded xml content.
sendMessage : function(destination, message) {
sendJmsMessage(destination, message, 'send');
},
// Listen on a channel or topic.
// handler must be a function taking a message argument
//
// Supportedoptions:
// selector: Ifsupplied, it should be a SQL92 string like "property-name='value'"
// http://activemq.apache.org/selectors.html
//
// Example: addListener( 'handler', 'topic://test-topic',function(msg) { return msg; }, { selector:"property-name='property-value'" } )
addListener : function(id, destination, handler, options){
messageHandlers[id] = handler;
var headers = options && options.selector ?{selector:options.selector} : null;
sendJmsMessage(destination, id, 'listen', headers);
},
// remove Listener from channel or topic.
removeListener : function(id, destination) {
messageHandlers[id] = null;
sendJmsMessage(destination, id, 'unlisten');
},
// for unit testing
getMessageQueue: function() {
return messageQueue;
},
testPollHandler: function( data ) {
return pollHandler( data );
}
};
}();
3.4 ActiveMQ服务器:设置消息处理服务器端口,activemq.xml
参见:JMS消息服务-ActiveMQ.docx
3.5 消息处理程序:处理MQ服务器的消息。
处理ActiveMQ接收的消息。
参见:JMS消息服务-ActiveMQ.docx
4 示例:ajax轮询实现web聊天室。
参考:http://blog.sina.com.cn/s/blog_5a010cd10101djgl.html
4.1 前端页面:chat.htm
<!DOCTYPE html PUBLIC"-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<metahttp-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>Insert titlehere</title>
<scripttype="text/javascript" src="js/jquery-1.4.2.min.js"></script>
<scripttype="text/javascript"src="js/amq_jquery_adapter.js"></script>
<scripttype="text/javascript" src="js/amq.js"></script>
</head>
<body>
leon's chating room:
<hr>
<divstyle="height:400px;width:600px;border:block;overflow:auto"id="msg">
</div>
<br>
<scripttype="text/javascript">
//create amq
var amq = org.activemq.Amq;
amq.init({
uri: 'amq',
logging: true,
timeout: 20
});
//receive message
functionreceiverMsg(message){
console.debug("receive="+message);
document.getElementById("msg").innerHTML +="receive="+message.textContent + "<br>";
}
amq.addListener("smeguangdong","topic://FirstTopic",receiverMsg);
//send message
function sendMsg()
{
var nickname =document.getElementById("nickname").value;
var content =document.getElementById("keymsg").value;
var ms = nickname + " : "+content;
amq.sendMessage("topic://FirstTopic","<message>"+ms+"</message>","amq-msg-type=>'text'");
}
</script>
昵称:
<inputtype="text" id="nickname">
内容:
<input type="text"id="keymsg">
<buttononclick="sendMsg()">submit</button>
</body>
</html>
4.2 Web服务器Tomcat:web.xml
<?xmlversion="1.0" encoding="UTF-8"?>
<web-appxmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaeehttp://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"id="WebApp_ID" version="3.0">
<display-name>ajaxmq</display-name>
<servlet>
<servlet-name>AjaxServlet</servlet-name>
<servlet-class>org.apache.activemq.web.AjaxServlet</servlet-class>
<async-supported>true</async-supported>
</servlet>
<servlet-mapping>
<servlet-name>AjaxServlet</servlet-name>
<url-pattern>/amq/*</url-pattern>
</servlet-mapping>
<context-param>
<param-name>org.apache.activemq.brokerURL</param-name>
<param-value>tcp://localhost:61616</param-value>
</context-param>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
</web-app>
4.3 ActiveMQ服务器:ActiveMQ.xml
4.4 消息处理程序Receiver.java,Sender.java
//Receiver.java
import java.util.Date;
import javax.jms.Connection;
importjavax.jms.ConnectionFactory;
import javax.jms.Destination;
importjavax.jms.JMSException;
import javax.jms.Message;
importjavax.jms.MessageConsumer;
import javax.jms.Session;
import javax.jms.TextMessage;
importorg.apache.activemq.ActiveMQConnectionFactory;
/**
* @author sf2gis@163.com
* @date 2015年7月28日下午3:56:20
*
*/
public class Receiver {
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
receiveMsg();
}
/**
* receive messages frommq server.
*
* @throws JMSException
*/
public static void receiveMsg() throws JMSException {
// create connection
ConnectionFactory cf = new ActiveMQConnectionFactory(
"tcp://localhost:61618");
Connection conn = cf.createConnection();
conn.start();
// create session
Session session = conn.createSession(false,Session.AUTO_ACKNOWLEDGE);
Destination dest =session.createTopic("FirstTopic");
MessageConsumer receiver = session.createConsumer(dest);
System.out.println("waiting msg...");
int i = 0;
while (i != 100) {
Message msg = receiver.receive();
// get msg
if (msg instanceof TextMessage) {
TextMessage txt = (TextMessage) msg;
System.out.println("ReceiveMsg " + i+ "=" + txt.getText()
+ ",now=" + newDate().toString());
} else {
System.out.println(msg);
}
++i;
}
// close
receiver.close();
session.close();
conn.close();
}
}
//Sender.java
import java.util.Date;
import javax.jms.Connection;
import javax.jms.Destination;
importjavax.jms.JMSException;
import javax.jms.Message;
importjavax.jms.MessageProducer;
import javax.jms.Session;
importorg.apache.activemq.ActiveMQConnectionFactory;
/**
* @author sf2gis@163.com
* @date 2015年7月28日上午11:10:51
*
*/
public class Sender {
public static void main(String[] args) throws JMSException,InterruptedException {
// TODO Auto-generated method stub
sendMsg();
}
/**
* send messages to mqserver.
*
* @throws JMSException
* @throwsInterruptedException
*/
public static void sendMsg() throws JMSException,InterruptedException {
// create connection
ActiveMQConnectionFactory cf = newActiveMQConnectionFactory(
"tcp://localhost:61616");
Connection conn = cf.createConnection("admin","admin");
conn.start();
System.out.println("create connection");
// create session
Session session = conn.createSession(false,Session.AUTO_ACKNOWLEDGE);
System.out.println("create session");
// create message
// Destination dest =session.createQueue("TEST.FOO");
Destination dest =session.createTopic("FirstTopic");
MessageProducer sender = session.createProducer(dest);
for (int i = 0; i < 3; ++i) {
Message msg = session
.createTextMessage("this is a msgfrom sender="+i+","
+ new Date().toString());
sender.send(msg);
Thread.sleep(1000);
}
System.out.println("send a msg");
// close
sender.close();
session.close();
conn.close();
}
}
- ActiveMQ-Web应用
- ActiveMQ消息队列的应用 C#客户端 Web后端
- jms activeMQ 应用
- ActiveMQ简单应用
- jms activeMQ 应用
- activeMq 的应用1
- ActiveMQ集群应用
- ActiveMQ集群应用
- ActiveMQ集群应用
- ActiveMQ集群应用
- ActiveMQ高级应用
- ActiveMQ集群应用
- ActiveMQ基本应用
- ActiveMQ集群应用
- ActiveMQ基本应用
- ActiveMQ高级应用
- ActiveMQ集群应用
- ActiveMQ基本应用
- HDOJ 5335 Walk Out 贪心+BFS
- JAVA基础一大堆0801接口+匿名类+IO流
- 查看文件常用指令cat,tac,nl,more,less,head,tail,od
- hdu 4638 Group (离线树状数组)
- 56 - 链表中环的入口节点
- ActiveMQ-Web应用
- zoj 3822 概率dp
- 最小公倍数和最大公约数
- 一种面向高维数据的集成聚类算法
- qt学习第六课:改变形状的对话框
- leetcode-242-Valid Anagram
- Linux系统入门学习:从VirtualBox中从主机访问NAT客户机
- MapReduce实现QQ好友推荐
- 正则表达式(专题)