Pushlet实现消息推送

Pushlet是使用较多的后台向前台推送信息的工具。前台订阅某个感兴趣的事件joinListen,触发后台的Pushlet的servlet,为该请求会话建立session,默认这个sessionID是随机的java.rmi.server.UID(后面会介绍pushlet二次开发,改掉这个UID,以便可以自由控制向某一个特点前台推送信息)。之后前台会向后台发送refresh请求,后台返回给前台下一次发送refresh的时间间隔,如此循环,以便维持session会话,宏观上就实现了前后台之间的长连接。

这里首先列出最简单的后台利用PullSource周期性地向订阅了某事件的所有网页客户端推送信息。

下载最新版本的Pushlet。MyEclipse下建立一个web工程,我这里叫PushletTest,将pushlet.jar加入引用路径,pushlet.properties和sources.properties放入WebRoot/WEB-INF下,工程结构如下图:

 

在web.xml中添加pushlet的servlet的声明,让这个servlet在服务器启动时就启动(load-on-startup为正数),web.xml代码如下:

Xml代码   收藏代码
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <web-app version="2.5"   
  3.     xmlns="http://java.sun.com/xml/ns/javaee"   
  4.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   
  5.     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee   
  6.     http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">  
  7.     <servlet>  
  8.        <servlet-name>pushlet</servlet-name>  
  9.        <servlet-class>nl.justobjects.pushlet.servlet.Pushlet</servlet-class>  
  10.        <load-on-startup>3</load-on-startup>  
  11.     </servlet>  
  12.     <servlet-mapping>  
  13.        <servlet-name>pushlet</servlet-name>  
  14.        <url-pattern>/pushlet.srv</url-pattern>  
  15.     </servlet-mapping>      
  16.       
  17.     <welcome-file-list>  
  18.        <welcome-file>index.jsp</welcome-file>  
  19.     </welcome-file-list>  
  20. </web-app>  

 注意触发pushlet这个servlet的条件是请求pushlet.srv。

接下来就是自定义推送源,MyPushSource.java代码如下:

Java代码   收藏代码
  1. package com.mysrc;  
  2.   
  3. import java.io.Serializable;  
  4. import nl.justobjects.pushlet.core.Event;  
  5. import nl.justobjects.pushlet.core.EventPullSource;  
  6.   
  7. public class MyPushSource implements Serializable {  
  8.      public static class MySource1 extends EventPullSource {   
  9.         @Override   
  10.         protected long getSleepTime() {   
  11.             return 1000;     
  12.         }   
  13.         @Override   
  14.         protected Event pullEvent() {   
  15.             Event event =Event.createDataEvent("myevent1");   
  16.             event.setField("key1","my_value1");   
  17.             return event;    
  18.         }   
  19.      }   
  20. }  

 每隔一秒钟就向订阅了myevent1的所有前端页面推送信息,这里是一个键值对。

然后需要在sources.properties声明该源(该文件现在只有这一行内容):

source1=com.mysrc.MyPushSource$MySource1

前台页面test.html代码如下:

 

Html代码   收藏代码
  1. <html>  
  2.   <head>  
  3.   <script type="text/javascript" src="ajax-pushlet-client.js"></script>   
  4.   <script type="text/javascript">    
  5.          PL._init();    
  6.          PL.joinListen('myevent1');   
  7.          function onData(event) {   
  8.             alert(event.get("key1"));    
  9.          }  
  10.   </script>   
  11.   </head>  
  12.   <body>  
  13.     This is pushlet test page....<br>  
  14.   </body>  
  15. </html>  

 PL是在ajax-pushlet-client.js中定义的。好了,将工程部署到Tomcat,启动,请求test.hmtl,就能看到my_value1的alert的显示了。

需要说明的是,也可以将test.html和ajax-pushlet-client.js放在本地,不用请求服务器上的,因为这儿的关键是触发服务器上的pushlet那个servlet,之后能进行心跳同步。打开ajax-pushlet-client.js,找到PL.pushletURL = PL._getWebRoot() + 'pushlet.srv';这一行,这儿PL._getWebRoot() 是通过ajax-pushlet-client.js在服务器上的路径得到url的。这儿咋们自己换成服务器的地址就可以了。我的为:PL.pushletURL = "http://192.168.1.154:7087/PushletTest/" + 'pushlet.srv';

OK,然后用浏览器打开这个本地的test.html页面就可以


利用推送源周期性地向订阅了某一事件的所有网页端推送信息,但怎么实现向特定的某一个用户推送信息呢,想象一个网络聊天室,怎么向单独的一个好友私聊呢。问题的关键就是那个SessionID,Pushlet默认是用java.rmi.server.UID参数的随机字符串作为会话标志,这就造成我们没法跟一个特点的用户对应上,也就是说客户必须在joinListen的时候提供一个他的ID,就像登陆qq时,输入用户名一样。

好了,这里就列出怎么修改相关代码,实现上述功能。

同样,首先用MyEclipse新建一个web工程,我这里命名为PushletTest2。不同的是,我们不引用pushlet.jar包了,因为我们要更改源码,在下载pushlet的时候里面就包含源代码了,最外层是nl包,加入我的工程的src里。好了,加进去之后会报错,将log4j.jar加入引用就好了。。之后,同样别忘了把pushlet.properties和sources.properties加入WebRoot/WEN-INF下。工程结构如下:

FirPush.java是自己写的一个触发推送动作的类,它是一个servlet,请求该servlet就触发向特定的用户推送信息的动作(当然,怎么触发推送动作还有很多种形式)。

web.xml代码如下:

Xml代码   收藏代码
  1. <span style="font-size: x-small;"><?xml version="1.0" encoding="UTF-8"?>  
  2. <web-app version="2.5"   
  3.     xmlns="http://java.sun.com/xml/ns/javaee"   
  4.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   
  5.     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee   
  6.     http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">  
  7.     <servlet>  
  8.        <servlet-name>pushlet</servlet-name>  
  9.        <servlet-class>nl.justobjects.pushlet.servlet.Pushlet</servlet-class>  
  10.        <load-on-startup>3</load-on-startup>  
  11.     </servlet>  
  12.     <servlet>   
  13.     <servlet-name>FirePush</servlet-name>  
  14.         <servlet-class>com.mysrc.FirePush</servlet-class>  
  15.     </servlet>      
  16.     <servlet-mapping>  
  17.        <servlet-name>pushlet</servlet-name>  
  18.        <url-pattern>/pushlet.srv</url-pattern>  
  19.     </servlet-mapping>      
  20.     <servlet-mapping>  
  21.        <servlet-name>FirePush</servlet-name>  
  22.        <url-pattern>/FirePush</url-pattern>  
  23.     </servlet-mapping>      
  24.   <welcome-file-list>  
  25.     <welcome-file>index.jsp</welcome-file>  
  26.   </welcome-file-list>  
  27. </web-app></span>  

 Ok,接下来就是要进行修改了,首先打开ajax-pushlet-client.js。PL对象,在它的最开始添加一个属性userId:'',  ,因为分析ajax-pushlet-client.js之后会发现,所有的请求都是get方式,也就是说是将请求参数添加到url里的,我们要做的是在进行join请求的时候将userId加到url上。找到PL的_doRequest,它是一个函数,所有的请求都是通过调用它发出的,找到var url = PL.pushletURL + '?p_event=' + anEvent;这一行,这儿就是在构造请求参数,在它的后面加入代码:

Js代码   收藏代码
  1. if (anEvent == 'join' || anEvent == 'join-listen') {    url = url + '&userId=' + PL.userId;   
  2.         }  

 好了,ajax-pushlet-client.js的修改就完成了。

接下来是test.html:

Html代码   收藏代码
  1. <html>  
  2.   <head>  
  3.   <script type="text/javascript" src="ajax-pushlet-client.js"></script>   
  4.   <script type="text/javascript">    
  5.          PL.userId='piero';  
  6.          PL._init();    
  7.          PL.joinListen('myevent1');   
  8.          function onData(event) {   
  9.             alert(event.get("key1"));    
  10.          }  
  11.   </script>   
  12.   </head>  
  13.   <body>  
  14.     This is pushlet test page....<br>  
  15.   </body>  
  16. </html>  

然后就是修改pushlet的java源代码,找到nl.justobjects.pushlet.core包下的SessionManager类,将它的createSession方法改成:

Java代码   收藏代码
  1. public Session createSession(Event anEvent) throws PushletException {  
  2.         // Trivial  
  3.         //return Session.create(createSessionId());  
  4.         return Session.create(anEvent.getField("userId""visitor"));  
  5.     }  

 这儿就使得建立的session的id是发送过来的userId,而不是一个随机字符串。getField的第二个参数是当得不到请求参数userId的值的时候设定的默认值。

好了,所有的准备工作都完成了,接下来就是通过userId给特点的用户推送信息了。

FirePush.java代码如下:

Java代码   收藏代码
  1. package com.mysrc;  
  2.   
  3. import java.io.IOException;  
  4.   
  5. import javax.servlet.ServletException;  
  6. import javax.servlet.http.HttpServlet;  
  7. import javax.servlet.http.HttpServletRequest;  
  8. import javax.servlet.http.HttpServletResponse;  
  9.   
  10. import nl.justobjects.pushlet.core.Dispatcher;  
  11. import nl.justobjects.pushlet.core.Event;  
  12. import nl.justobjects.pushlet.core.SessionManager;  
  13.   
  14. public class FirePush extends HttpServlet {  
  15.   
  16.     @Override  
  17.     protected void doGet(HttpServletRequest req, HttpServletResponse resp)  
  18.             throws ServletException, IOException {  
  19.         myUnicast();  
  20.         //myMulticast();  
  21.         //myBroadcast();  
  22.     }  
  23.     private void myUnicast()  
  24.     {  
  25.         if(SessionManager.getInstance().hasSession("piero")){  
  26.             Event  event = Event.createDataEvent("myevent1");   
  27.             event.setField("key1""houhou_yesttttt....");            
  28.             Dispatcher.getInstance().unicast(event,"piero"); //向ID为piero的用户推送  
  29.                 
  30.             System.out.println("success....");  
  31.         }  
  32.         else {  
  33.             System.out.println("piero do not login....%%%%%%%%%%%%");  
  34.         }  
  35.     }  
  36.     private void myMulticast()  
  37.     {  
  38.         Event  event = Event.createDataEvent("myevent1");   
  39.         event.setField("key1""houhou....");    
  40.         Dispatcher.getInstance().multicast(event);  //向所有和myevent1名称匹配的事件推送  
  41.           
  42.         System.out.println("wa success....");  
  43.     }  
  44.     private void myBroadcast()  
  45.     {  
  46.         Event  event = Event.createDataEvent("myevent1"); //向所有的事件推送,不要求和这儿的myevent1名称匹配  
  47.         event.setField("key1""dig hole....");      
  48.         Dispatcher.getInstance().broadcast(event);  
  49.           
  50.         System.out.println("asw success....");  
  51.     }  
  52. }  

 这儿主要利用了dispatcher的unicat/multicat/broadcast方法。

好了,值得一提的是在ajax-pushlet-client.js有publish方法,也就是上面提到的触发信息推送动作,其实完全可以在前端调用这个js的publish函数向订阅了某事件的所有网页推送信息。test2.html代码如下:

Html代码   收藏代码
  1. <html>  
  2.   <head>  
  3.   <script type="text/javascript" src="ajax-pushlet-client.js"></script>   
  4.   <script type="text/javascript">   
  5.          PL.userId='juvenh';  
  6.          PL._init();   
  7.                 
  8.          PL.joinListen('event223');   
  9.          function onData(event) {   
  10.                alert(event.get("eventVal"));    
  11.          }  
  12.            
  13.          function sendnews(){   
  14.             //PL.publish("myevent1","key1=dlut&ba=ls");   
  15.             p_publish('myevent1', 'key1', 'dlut', 'ba', 'ls');  
  16.         }  
  17.   </script>   
  18.   </head>  
  19.     
  20.   <body>  
  21.     This is my JSP page. <br>  
  22.     <input type = "button" value="发消息" onclick="sendnews()"/>   
  23.   </body>  
  24. </html>  

 上面代码中的PL.publish和p_publish完全等效,查看p_publish的代码,其实也是构造请求url。这儿的publish方法只能向订阅某一事件的所有网页推送消息,也即等同于multicast方法,无法向某一个特定的用户推送,解决方法还是向上面那样修改pushlet的java源代码,在nl.justobjects.pushlet.core包下的Controller.java中的protected void doPublish(Command aCommand);函数,看一下就会发现,这儿就是调用了dispacher的multicast函数,这儿改成unicast,前提是上面的js的publish里提供了userId


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值