现在的位置: 首页 > 综合 > 正文

ActiveMQ应用笔记四:Ajax应用

2014年08月24日 ⁄ 综合 ⁄ 共 8490字 ⁄ 字号 评论关闭
环境:
apache-activemq-5.8.0
Tomcat7.0.29
jdk1.7.0_03
win7
eclipse(Version: Helios Service Release 2Build id: 20110218-0911 )
 
1.一个全新的tomcat:E:\Tomcat7-MQ
2.新建一个Dynamic Web Project:MQAjax
3.创建文件 <webapp-root>/META-INF/context.xml. 参考:

<Context antiJARLocking="true">
    <Resource
        name="jms/ConnectionFactory"
        auth="Container"
        type="org.apache.activemq.ActiveMQConnectionFactory"
        description="JMS Connection Factory"
        factory="org.apache.activemq.jndi.JNDIReferenceFactory"
        brokerURL="tcp://localhost:61616"
        brokerName="LocalActiveMQBroker"
        useEmbeddedBroker="false"/>
    <Resource name="jms/topic/MyTopic"
        auth="Container"
        type="org.apache.activemq.command.ActiveMQTopic"
        factory="org.apache.activemq.jndi.JNDIReferenceFactory"
        physicalName="MY.TEST.FOO"/>
    <Resource name="jms/queue/MyQueue"
        auth="Container"
        type="org.apache.activemq.command.ActiveMQQueue"
        factory="org.apache.activemq.jndi.JNDIReferenceFactory"
        physicalName="MY.TEST.FOO.QUEUE"/>

</Context>

4.并将web.xml文件头替换为支持servlet3.0,3.0才能支持异步机制:

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                      http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
  version="3.0"
  metadata-complete="true">

 
在WEB-INF\web.xml中加入以下servlet配置,注意必须开启异步支持<async-supported>true</async-supported>:
<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>
 
 
 
 
5.在WEB-INF\lib中加入jar包:
activemq-web-5.8.0.jar
geronimo-j2ee-management_1.1_spec-1.0.1.jar
geronimo-jms_1.1_spec-1.1.1.jar
geronimo-jta_1.0.1B_spec-1.0.1.jar
activemq-client-5.8.0.jar
slf4j-api-1.6.6.jar
camel-core-2.10.3.jar
jetty-all-server-7.6.7.v20120910.jar
slf4j-log4j12-1.6.6.jar
log4j-1.2.17.jar
hawtbuf-1.9.jar
 
6. 在<webapp-root>下新建页面index.html,<head></head>中加入:
<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>
<script type="text/javascript">
  var amq = org.activemq.Amq;
  amq.init({
    uri: 'amq',
    logging: true,
    timeout: 20
  });
</script>
 
7.在<webapp-root>下新建js目录,将apache-activemq-5.8.0\webapps-demo\demo\js下的三个js文件拷贝到js目录中:
jquery-1.4.2.min.js
amq_jquery_adapter.js
amq.js
 
8.接下来启动Tomcat,不会报错,并且在ActiveMQ的管理界面能看到多了一个consumer
 
9.使用java程序发送消息
  注意,默认情况下,通过Stomp发布的消息如果包含了content-length消息头,则它将会被ActiveMQ转换为二进制消息,并且会对web客户端不可见。从ActiveMQ 5.4.0开始,你可以通过将amq-msg-type消息头 设置设为“text”,以使消息可以被web客户端消费。
message.setJMSType("text");
 
10.打开入站、出站端口
控制面板(右上角选择查看方式为大图标)---防火墙---高级设置---高级设置---出站规则/出站规则
开启TCP所有端口允许入站、出站
 
11.发现还是有问题,但是没有日志没法调试,现在解决log4j的问题
servlet支持:eclipse中,项目名称右键--properties--targeted runtime,把tomcat7勾上。
 
12.遇到Tomcat启动问题,并由于该问题造成Ajaxservlet运行不正常(这个问题卡了老子好久啊啊啊啊啊啊啊!!!!)
现象:
在eclipse中启动tomcat,tomcat一直处于starting状态,导致程序运行不正常,servlet运行不正常等现状。
 
解决办法:
在排除了端口冲突,防火墙之类的问题之后,实在没辙最后一招,在Servers窗口中删除现有的Tomcat,然后重建一个,在没有加入任何程序时测试,Tomcat顺利启动到started状态,停止后加入web工程,再次启动Tomcat,顺利进入started状态!
 
13.目前遇到问题,message被页面接收后无法显示
Be aware that, by default, messages published via Stomp which include a content-length header will be converted by ActiveMQ to binary messages, and will not be visible to your web clients. Beginning with ActiveMQ 5.4.0, you can resolve this problem by
always setting the amq-msg-type header to text in messages which will may be consumed by web clients.
 
通过以下几步解决该问题:
首先,参见amq.js,由于amq.sendMessage : function(destination, message) 仅支持两个参数,没法设定发送消息的header,所以得修改amq.js中的该方法:

sendMessage : function(destination, message) {
            sendJmsMessage(destination, message, 'send');
        },
改为

sendMessage : function(destination, message,headers) {
            sendJmsMessage(destination, message, 'send',headers);
        },
 使其支持在发送消息时设定头部。
 
然后页面上的发送消息js修改为:
amq.sendMessage("topic://FirstTopic","<message>"+ms+"</message>","amq-msg-type=>'text'");
注意第三个参数是通过修改amp.js才支持的。
 
这样修改后,通过页面发送的消息,就能在页面中显示了。
目前的index.html源码如下,该页面实现了一个简单的多人聊天室,注意接收到的消息要用message.text 
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</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>
<div style="height:400px;width:600px;border:block;overflow:autoid="msg">
</div>
<br>
<script type="text/javascript">
var amq = org.activemq.Amq;
amq.init({ 
  uri: 'amq'
  logging: true,
  timeout: 20
});
var myHandler =
{
  rcvMessage: function(message)
  {
      //alert("received data:"+message.text);
      document.getElementById("msg").innerHTML += message.text + "<br>";
  }
};
amq.addListener("smeguangdong","topic://FirstTopic",myHandler.rcvMessage);
function go()
{
    var nickname = document.getElementById("nickname").value;
    var content = document.getElementById("keymsg").value;
    var ms = nickname + " : " +content;
    //alert("msg is "+ms);
    amq.sendMessage("topic://FirstTopic","<message>"+ms+"</message>","amq-msg-type=>'text'");
    }
</script>
昵称:
<input type="text" id="nickname">
内容:
<input type="text" id="keymsg">
<button onclick="go()">submit</button>
</body>

</html>

 

 
13.IE和CHROME兼容性显示问题
在IE中用message.text可以成功显示收到信息;在CHROME中用message.textContent可以成功显示收到信息,没有一种方式可以兼容多浏览器??
原理
1.ActiveMQ的Ajax插件自动把消息内容解释成了DOM格式,也就是说Listener回调函数中的message参数是DOM结构的,更有意思的是如果像这样一个消息:“<message>aaa</message><message>bbb</message>”,那么Listener回调函数会执行两次,因为里面包含了两个Element,如果是这样的消息:“<message>aaa</message>asdfasdfaksd”,
Listener回调函数也会执行两次,““<message>aaa</message>”是Element,而“asdfasdfaksd”是Text
2.而用java代码TextMessage message = session.createTextMessage("MSG sent from java 2");创建的消息,就是字符串文本形式。
 
了解了原理后就简单了,用js操作dom的方法来解析收到的信息即可,以inde.html页面可以兼容多浏览器,兼容web发送消息和java发送消息两种场景的消息接收:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</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>
<div style="height:400px;width:600px;border:block;overflow:autoid="msg">
</div>
<br>
<script type="text/javascript">
var amq = org.activemq.Amq;
amq.init({ 
  uri: 'amq'
  logging: true,
  timeout: 20
});
var myHandler =
{
  rcvMessage: function(message)
  {
      //alert("received data:"+message.text);
      //alert("message.textContent :"+message.textContent)
      //alert("message.childNodes.item(0).nodeValue:"+message.childNodes.item(0).nodeValue)   兼容IE和CHROME
      //alert("message.childNodes[0].nodeValue:"+message.childNodes[0].nodeValue);   兼容IE和CHROME
      if(message.childNodes.length > 0)       //web页面发送的消息
          document.getElementById("msg").innerHTML += message.childNodes[0].nodeValue + "<br>";
      else      //java代码发送的消
          document.getElementById("msg").innerHTML += message.nodeValue + "<br>";
  }
};
amq.addListener("smeguangdong","topic://FirstTopic",myHandler.rcvMessage,{selector:"user='liyang'"});
//amq.addListener("smeguangdong","topic://FirstTopic",myHandler.rcvMessage);
function go()
{
    var nickname = document.getElementById("nickname").value;
    var content = document.getElementById("keymsg").value;
    var ms = nickname + " : " +content;
    //alert("msg is "+ms);
    amq.sendMessage("topic://FirstTopic","<message>"+ms+"</message>","amq-msg-type=>'text'");
    }
</script>
昵称:
<input type="text" id="nickname">
内容:
<input type="text" id="keymsg">
<button onclick="go()">submit</button>
</body>

</html>

 
 

 
14.接收消息时,selector的支持
一旦支持了selector,我们就可以实现指定用户的实时消息提醒了!!!(可以通过java代码发送指定属性的消息,web接收时指定selector过滤条件即可)
官方文档已经提到 : http://activemq.apache.org/ajax.html 在添加监听器时指定第三个参数即可实现接收消息时的过滤。
amq.addListener( myId, myDestination, myHandler.rcvMessage, { selector:"identifier='TEST'" } );
这样的话通过jsp标签之类的技术,在渲染页面时将参数渲染为当前登录用户名即可实现根据当前登录用户过滤消息的目的
 
至此为止,已经实现了在页面中通过指定destination(topic/queue)和selector来接受消息,基本已经满足实时消息提醒的需求(消息由java程序发送,指定)。
 
15.问题
发消息时设置属性
账号登录发消息
。。。

抱歉!评论已关闭.