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();

      }

}

0 0
原创粉丝点击