DWR2.x的推技术

DWR2.x的推技术也叫DWR Reverse Ajax(逆向Ajax)主要是在BS架构中,从服务器端向多个浏览器主动推数据的一种技术。在DWR所开的线程中使用Reverse Ajax时,通过WebContextFactory.get()获取WebContext对象,进而获取脚本Session。在DWR之外使用Reverse Ajax时,就要用到ServerContext,在Spring环境中要得到ServerContext,就需要用到Spring的ServletContextAware接口。

一、Reverse Ajax的实现有3种方式:

      DWR的逆向Ajax主要包括两种模式:主动模式和被动模式。其中主动模式包括polling和comet两种,被动模式只有piggyback这一种。

     1、piggyback方式

           这是默认的方式。

           如果后台有什么内容需要推送到前台,是要等到那个页面进行下一次ajax请求的时候,将需要推送的内容附加在该次请求之后,传回到页面。只有等到下次请求页面主动发起了,中间的变化内容才传递回页面。

      2、comet方式

           当服务端建立和浏览器的连接,将页面内容发送到浏览器之后,对应的连接并不关闭,只是暂时挂起。如果后面有什么新的内容需要推送到客户端的时候直接通过前面挂起的连接再次传送数据。服务器所能提供的连接数目是一定的,在大量的挂起的连接没有关闭的情况下,可能造成新的连接请求不能接入,从而影响到服务质量。

      3、polling方式

           由浏览器定时向服务端发送ajax请求,询问后台是否有什么内容需要推送,有的话就会由服务端返回推送内容。这种方式和我们直接在页面通过定时器发送ajax请求,然后查询后台是否有变化内容的实现是类似的。只不过用了dwr之后这部分工作由框架帮我们完成了。

二、使用DWR的推技术的步骤

     1、在web.xml文件中增加以下配置信息

Xml代码  

 

<!-- 开始DWR配置 -->
  <servlet>
         <servlet-name>dwr-invoker</servlet-name>
         <!--
         <servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>
         -->
         <servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
         <init-param>
             <param-name>debug</param-name>
             <param-value>true</param-value>
         </init-param>
         <!-- dwr反转 -->
         <!-- 1、piggyback方式


         这是默认的方式。  
         如果后台有什么内容需要推送到前台,是要等到那个页面进行下一次ajax请求的时候,将需要推送的内容附加在该次请求之后,传回到页面。  
         只有等到下次请求页面主动发起了,中间的变化内容才传递回页面。  
         2、comet方式  
         当服务端建立和浏览器的连接,将页面内容发送到浏览器之后,对应的连接并不关闭,只是暂时挂起。如果后面有什么新的内容需要推送到客户端的时候直接通过前面挂起的连接再次传送数据。  
         服务器所能提供的连接数目是一定的,在大量的挂起的连接没有关闭的情况下,可能造成新的连接请求不能接入,从而影响到服务质量。  
         3、polling方式  
         由浏览器定时向服务端发送ajax请求,询问后台是否有什么内容需要推送,有的话就会由服务端返回推送内容。这种方式和我们直接在页面通过定时器发送ajax请求,然后查询后台是否有变化内容的实现是类似的。只不过用了dwr之后这部分工作由框架帮我们完成了。  
    

-->
         <!-- DWR默认采用piggyback方式 -->
         <!-- 使用polling和comet的方式 -->
         <init-param>
          <param-name>pollAndCometEnabled</param-name>
          <param-value>true</param-value>
         </init-param>
         <!-- comet方式 -->
         <!--       
          <init-param>     
          <param-name>activeReverseAjaxEnabled</param-name>     
          <param-value>true</param-value>     
          </init-param>     
         -->
         <!-- polling方式:在comet方式的基础之上,再配置以下参数 -->
         <!--       
          <init-param>     
          <param-name>org.directwebremoting.extend.ServerLoadMonitor</param-name>     
          <param-value>org.directwebremoting.impl.PollingServerLoadMonitor</param-value>     
          </init-param>     
         -->
         <!-- 毫秒数。页面默认的请求间隔时间是5秒 -->
         <!--       
          <init-param>     
          <param-name>disconnectedTime</param-name>     
          <param-value>60000</param-value>       
          </init-param>     
         -->
         <init-param>
          <param-name>crossDomainSessionSecurity</param-name>
          <param-value>false</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>
  <listener>
   <listener-class>
    org.directwebremoting.servlet.EfficientShutdownServletContextAttributeListener
   </listener-class>
  </listener>
  <listener>
   <listener-class>
    org.directwebremoting.servlet.EfficientShutdownServletContextListener
   </listener-class>
  </listener>
  <!-- 结束DWR配置 -->

2、在dwr.xml中增加以下配置信息

Xml代码

 

<?xml version="1.0" encoding="UTF-8"?>  
 <!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 2.0//EN" "http://getahead.org/dwr//dwr20.dtd">
 <dwr>  
     <allow>  
      <create creator="new" javascript="DWRAction">
      <param name="class" value="com.tcps.action.DwrActionTest"/>
      <include method="DwrTest"/>
      <include method="sessionDestory"/>
   </create>
         
         <create creator="new" javascript="DWRReverse">
         <param name="class" value="com.tcps.action.DWRReverse" />
         </create>
         
         <convert converter="bean" match="com.tcps.model.User"> 
             <param name="include" value="username,password" />
         </convert>
     </allow>
 </dwr>

 

3、pojo类User的源码

Java代码

 

public class User implements java.io.Serializable {

     // Fields    
     private Integer id;
      private String username;
      private String password;
      private String age;
      private String tel;
      private String sessionid;     // Constructors
    /** default constructor */
     public User() {
     } /** minimal constructor */
     public User(Integer id, String username, String password) {
         this.id = id;
         this.username = username;
         this.password = password;
     }
     
     /** full constructor */
     public User(Integer id, String username, String password, String age, String tel, String sessionid) {
         this.id = id;
         this.username = username;
         this.password = password;
         this.age = age;
         this.tel = tel;
         this.sessionid = sessionid;
     }
     @Override
     public String toString(){
        return this.username + this.password;
     }
     // Property accessors    public Integer getId() {
         return this.id;
     }
     
     public void setId(Integer id) {
         this.id = id;
     }    public String getUsername() {
         return this.username;
     }
     
     public void setUsername(String username) {
         this.username = username;
     }    public String getPassword() {
         return this.password;
     }
     
     public void setPassword(String password) {
         this.password = password;
     }    public String getAge() {
         return this.age;
     }
     
     public void setAge(String age) {
         this.age = age;
     }    public String getTel() {
         return this.tel;
     }
     
     public void setTel(String tel) {
         this.tel = tel;
     } public String getSessionid() {
   return sessionid;
  } public void setSessionid(String sessionid) {
   this.sessionid = sessionid;
  }

 

4、DWRReverse类源码

Java代码  

public class DWRReverse extends AbstractAction {
     public static WebContext wctx = null;    public static void sendMessage(User monitor) {
         if (wctx == null) {
             wctx = WebContextFactory.get();
         }
         ScriptBuffer script = new ScriptBuffer();
         //执行js 方法
         if (monitor != null) {
             StringBuffer sb = new StringBuffer();
             sb.append(monitor.getId()).append(",");
             sb.append(monitor.getUsername()).append(",");
             sb.append(monitor.getPassword()).append(",");
             sb.append(monitor.getAge()).append(",");
             sb.append(monitor.getTel());
             script.appendScript("receiveMessages('").appendData(sb.toString())
                     .appendScript("');");
         }
         ServerContext sctx = ServerContextFactory.get(wctx.getServletContext());
         Collection<ScriptSession> scriptSessions = sctx.getScriptSessionsByPage(wctx.getCurrentPage());
         Util util = new Util(scriptSessions);
         //可以设置样式等   
         // util.setStyle("test", "display", "none");   
         for (ScriptSession session : scriptSessions) {
             session.addScript(script);
         }
     }
 }

5、JSP页面源码

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
 <%
 String path = request.getContextPath();
 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
 %><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
   <head>
     <base href="<%=basePath%>">
     
     <title>My JSP 'dwrReverse.jsp' starting page</title>
     <script type='text/javascript' src='<%=basePath%>/dwr/interface/DWRReverse.js'></script>
     <script type='text/javascript' src='<%=basePath%>/dwr/engine.js'></script>
     <script type='text/javascript' src='<%=basePath%>/dwr/util.js'></script>
     
  <meta http-equiv="pragma" content="no-cache">
  <meta http-equiv="cache-control" content="no-cache">
  <meta http-equiv="expires" content="0">    
  <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
  <meta http-equiv="description" content="This is my page">
  <!--
  <link rel="stylesheet" type="text/css" href="styles.css">
  -->
  <script type="text/javascript">
   function getData(){   
          DWRReverse.sendMessage(null);   
         }     
         function receiveMessages(message) { 
          var msg = eval("("+message+")");
          var temp  = msg.split(",");
          var username = temp[1];
          var password = temp[2];
          var age = temp[3];
          var tel = temp[4];
          var newRow = document.getElementById('tableData').insertRow(2);
          var cell0 = newRow.insertCell(0);
          var cell1 = newRow.insertCell(1);
          var cell2 = newRow.insertCell(2);
          var cell3 = newRow.insertCell(3);
          cell0.innerHTML = username;
          cell1.innerHTML = password;
          cell2.innerHTML = age;
          cell3.innerHTML = tel;
         }
  </script>
   </head>
   <!-- 注:这个是要在使用reverse-ajax的页面必须的 -->
  <body οnlοad="dwr.engine.setActiveReverseAjax(true);getData();">
   <div align="center">
    <table title=用户表 class="list" align="center" id="tableData">
     <tr id="titleData">
      <td colspan="4">
       用户表
      </td>
      <td colspan="1" οnclick="getData()" style="size:10px">
       <a href="#"></a>
      </td>
     </tr>
     <tr id="headData" bgcolor="#fffce7" style="color:#968054">
      <td width="9%">
       用户名
      </td>
      <td width="20%">
       密码
      </td>
      <td width="33%">
       年龄
      </td>
      <td width="22%">
       电话
      </td>
     </tr>
    </table>
   </div>
  </body>
 </html>

 

最后,为了测试,后台实现定时器:

public class SampleTask extends TimerTask {
    private ServletContext context;
     private static boolean isRunning = false;    public SampleTask(ServletContext context) {
         this.context = context;
     }    @Override
     public void run() {
         // TODO Auto-generated method stub
         if (!isRunning) {
             isRunning = true;
             System.out.println("开始执行指定任务");
             if (DWRReverse.wctx != null) {
                 User user = new User(1, "tom", "123456", "10", "13909876543", "");
                 DWRReverse.sendMessage(user);
             }
             isRunning = false;
             // context.log("指定任务执行结束");
         } else {
             // context.log("上一次任务执行还未结束");
         }    }
}