使用 dwr 向客户端推送通知

来源:互联网 发布:淘宝英文店铺名字大全 编辑:程序博客网 时间:2024/05/16 15:28

 

主题:客户端在装载页面时调用 dwr 的方法连接服务端,服务端记录下WebContext 的特征,并启动一个永远run的线程,用以查看是否有新的通知,如果有新的通知就通过 dwr 调用所有停留在该页面的客户端的脚本,以达到推送通知的目的。

     

1, web.xml

<web-app>

   <listener>

      <listener-class>org.directwebremoting.servlet.DwrListener</listener-class>

   </listener>

   <servlet>

    <servlet-name>dwr-invoker</servlet-name>

    <display-name>DWRServlet</display-name>

    <description>Direct WebRemoter Servlet</description>

    <servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>

 

    <init-param>

      <param-name>activeReverseAjaxEnabled</param-name>

      <param-value>true</param-value>

    </init-param>

   

    <init-param>

     <param-name>pollAndCometEnabled</param-name>

     <param-value>true</param-value>

   </init-param>

    <init-param>

      <param-name>initApplicationScopeCreatorsAtStartup</param-name>

      <param-value>true</param-value>

    </init-param>

    <init-param>

      <param-name>jsonpEnabled</param-name>

      <param-value>true</param-value>

    </init-param>

   

    <load-on-startup>1</load-on-startup>

  </servlet>

  

  <servlet-mapping>

    <servlet-name>dwr-invoker</servlet-name>

    <url-pattern>/dwr/*</url-pattern>

  </servlet-mapping>

   ……

</web-app>

 

2,dwr.xml
<dwr>

  <allow>

    <createcreator="new"javascript="newNotification">

      <paramname="class"value="com.myself.NewNotification"/>

    </create>

  </allow>

</dwr>

 

3, com.myself.NewNotification

public class NewNotification{

   /**

    * 客户端刷新html 时将会在javascript中调用该方法。

    * 参考页面js->newNotification.execute();

    * @throwsInterruptedException

    */

   public void execute()throws InterruptedException {

      WebContext context = WebContextFactory.get();

      if (NewNotification.webContext ==null) {

         // 获得DWR上下文

         webContext =context;

      }

      HttpServletRequest request =context.getHttpServletRequest();

      String jid =(String)request.getSession().getAttribute(XMPPConstants.JID_ATTR_NAME);

      // 把接收者记录下来

      synchronized (receivers) {

         receivers.add(jid);

      }

      // 把接收者与客户端脚本 session对应

      context.getScriptSession().setAttribute(XMPPConstants.JID_ATTR_NAME, jid);

   }

  

   /**

    * DWR上下文

    */

   private static WebContext webContext;

   /**

    * 所有的用户,即通知的接收者,当用户进入到页面时,receivers就记录下用户的jid

    * 以便过后通过jid向用户所有的客户端推送通知。

    * 这里有一个弊端就是 receivers中的元素只会不断的增加,上限是xmpp服务端所注册的jid的总数。

    */

   private static Set<String> receivers =new HashSet<String>();

  

   /**

    * 推送通知的线程,会一直不停地跑。

    * 首先用 receivers中的jidxmpp服务器读取属于该jid的通知。

    * 然后将读取到的通知推送给客户端

    */

   private static Thread notification =new Thread() {

      MtReceiveAction action = new MtReceiveAction();

      @Override

        public void run() {

            while (!Thread.currentThread().isInterrupted()){

                try {

                Thread.sleep(XMPPConstants._MT_PERIOD);

                Map<String, String> jsonMap = newHashMap<String, String>();

               

                synchronized (receivers) {

                   Iterator<String> iter = receivers.iterator();

                   /*

                    * 让每个客户端都从xmpp服务器端去获取新的通知,如果获取到新的通知

                    */

                       while(iter.hasNext()) {

                       String receiver = iter.next();

                      

                       // xmpp读取新的通知

                        String jsonResult = action.receiveNotification(receiver);

                      

                       /*

                        * 如果读取到新的通知,那么把客户端标记及通知内容记录下来

                        */

                       if (jsonResult !=null) {

                           jsonMap.put(receiver, jsonResult);

                       }

                       }

                }

                // 获取当前页面URL,比如/ext3/test_tag.jsp

                String currentPage = webContext.getCurrentPage();

                // 所有浏览当前页面的脚本session

                Collection<ScriptSession>sessions = webContext.getScriptSessionsByPage(currentPage);

 

                /*

                 * 将通知推送给对应的接收者

                 */

                for(Iterator<String> jiter = jsonMap.keySet().iterator(); jiter.hasNext();){

                   // 接收者

                   String receiver = jiter.next();

                   // 通知内容

                   String jsonResult =jsonMap.get(receiver);

 

                   // 客户端脚本

                   ScriptBuffer script = new ScriptBuffer();

                   script.appendScript("pollingMsg(").appendData(jsonResult)

                         .appendScript(");");

 

                   for(ScriptSession session : sessions) {

                      /*

                       * 脚本session要与接收者对应

                       */

                      if(receiver.equals(session.getAttribute(XMPPConstants.JID_ATTR_NAME))) {

                         //执行客户端脚本

                         session.addScript(script);

                         break;

                      }

                   }

                }

                   

                } catch(InterruptedException e) {

                    Thread.currentThread().interrupt();

                } catch (MtReceiveExceptione) {

                e.printStackTrace();

                Log.error("推送通知失败:\n" +e.getMessage());

                }

            }

        }

   };

  

   static {

      notification.start();

   }

}

 

4,test.html

<scripttype="text/javascript" src="http://localhost:8080/asmack/dwr/engine.js"></script>

<scripttype="text/javascript" src="http://localhost:8080/asmack/dwr/util.js"></script>

<scripttype="text/javascript" src="http://localhost:8080/asmack/dwr/interface/newNotification.js"></script>

<!—注:此处的newNotification.js,其名字与 dwr.xml中的javascript值对应-->

题外话,如果作为客户端的test.html不在 asmack项目下,那么script的src属性就不能用相对路径,而必须用绝对的web路径,如上。

然后在该文件的onload中加入:

newNotification.execute();//com.myself.NewNotification中的方法

dwr.engine.setActiveReverseAjax(true);

 

当然还要定义一个function,即服务端的 dwr 将会调用的function:

function pollingMsg(jsonData){

   ……//省略处理通知的代码

}

 

以上就是具体步骤及代码。

这个方法的好处是,客户端不用去不停地使用ajax访问服务端,

只需要在装载页面时向服务端登记一下,然后由服务端不断地调用客户端的脚本以向客户端传递消息。

原创粉丝点击