`
san586
  • 浏览: 132687 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

dwr3 Reverse Ajax学习小结

阅读更多
按照官网的例子,自己搭建了Clock等实例,回个头来总结下其中遇到的问题:
1、piggyback方式
    dwr默认采用的是piggyback这种被动模式,如果需要采用这种模式的话不需要任何额外的配置就能完成。所谓的Piggyback指的是如果后台有什么内容需要推送到前台(即调用页面的js方法),是要等到那个页面进行下一次ajax请求的时候,将需要推送的内容附加在该次请求之后,传回到页面。该方式可以替代我以前用的Jquery等的ajax方式。
2、polling方式
    由浏览器定时向服务端发送ajax请求,询问后台是否有什么内容需要推送,有的话就会由服务端返回推送内容。这种方式和我们直接在页面通过定时器发送ajax请求,然后查询后台是否有变化内容的实现是类似的。类似于Ajax的轮询方式,只不过用了dwr之后这部分工作由框架帮我们完成了。
3、comet模式
    指的的当服务端建立和浏览器的连接,将页面内容发送到浏览器之后,对应的连接并不关闭,只是暂时挂起。如果后面有什么新的内容需要推送到客户端的时候直接通过前面挂起的连接再次传送数据。既然有了comet模式,那么我就基本不用考虑polling方式了
重点的说下comet模式,即推模式。在官网的例子中用到了3种,分别如下:
Clock实例中
public void setClockDisplay(final String output) {
		String page = ServerContextFactory.get().getContextPath()+ "/clock.html";
		Browser.withPage(page, new Runnable() {
			public void run() {
				Util.setValue("clockDisplay", output);
			}
		});
}
,对于这里的page,起先我设置的是一个ACTION,测试了好长时间没有成功,后来查看了源代码,发现了问题,因为Clock.java中用到了
public Clock() {
		ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);
		executor.scheduleAtFixedRate(this, 1, 1, TimeUnit.SECONDS);
	}
ScheduledThreadPoolExecutor多线程,固实现的工厂类必须要是ServerContextFactory,而不能是WebContextFactory,在官网的例子中找到了依据(ServerContextFactory is a lot like WebContextFactory, however it will work outside a DWR thread. Since we're using the ScheduledThreadPoolExecutor thread here, we need to use ServerContext and not WebContext.),进一步说明由于用了多线程,所以page 处是不能用action的,因为不能是WebContextFactory。
查看了源代码,发现了Browser中还有一个方法,里面也是用的ServerContextFactory,而且还能简化这个例子:
Browser.withAllSessions(new Runnable() {
		    public void run() {
		    	Util.setValue("clockDisplay", output);
		    }
		});
经过测试,确实如此好用
JavascriptChat 实例中
Browser.withCurrentPage(new Runnable() {
            public void run() {
                ScriptSessions.addFunctionCall("receiveMessages", messages);
            }
        });
调用页面上的JS方法,这就是所谓的Reverse Ajax的经典展现。
JavaChat 中
Browser.withCurrentPage(new Runnable() {
            public void run() {
                // Clear the list and add in the new set of messages
                Util.removeAllOptions("chatlog");
                Util.addOptions("chatlog", messages, "text");
            }
        });

我认为JavaChat中的用法比JavascriptChat中的要简单。
再总结下关于“全推”和“半推”的使用方法,所谓全推是指上面的所有例子,客户端能看到服务端推的全部内容,半推就是客户端中只有部分能看到,或者说根据客户的权限不同,客户看到的服务端推的内容是不一样的。
全推的实现不用说了,半推的2种实现:
1、参照网上的一篇DWR聊天代码,用的是DWR2.0,我改成了3.0,大体是一样的,核心思路为:每创建一个 ScriptSession,就用户id和页面脚本session绑定
// 这里取会话(HttpSession)的id为用户id 
			user = new User(request.getSession().getId(), username);
			//保存用户到列表
			users.add(user);	
			//将用户id和页面脚本session绑定
			this.setScriptSessionFlag(user.getUserid());
/**
	 * 将用户id和页面脚本session绑定
	 * @param userid
	 */
	public void setScriptSessionFlag(String userid) {
		WebContextFactory.get().getScriptSession().setAttribute("userid", userid);
	}


然后根据用户id获得指定用户的页面脚本session
/**
	 * 根据用户id获得指定用户的页面脚本session
	 * @param userid
	 * @param request
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public ScriptSession getScriptSession(String userid, HttpServletRequest request) {
		ScriptSession scriptSessions = null;
		Collection<ScriptSession> sessions = new HashSet<ScriptSession>();
		sessions.addAll(ServerContextFactory.get().getScriptSessionsByPage("/index.jsp"));
		for (ScriptSession session : sessions) {
			String xuserid = (String) session.getAttribute("userid");
			if (xuserid != null && xuserid.equals(userid)) {
				scriptSessions = session;
			}
		}
		return scriptSessions;
	}

推送消息时,只推送指定ScriptSession的用户
/**
	 * 发送消息
	 * @param sender 发送者
	 * @param receiverid 接收者id
	 * @param msg 消息内容
	 * @param request
	 */
	public void send(String sender,String receiverid,String msg,HttpServletRequest request){
		ScriptSession session = this.getScriptSession(receiverid, request);
		Util util = new Util(session);
		util.setStyle("showMessage", "display", "");
		util.setValue("sender", sender);
		util.setValue("msg", msg);
	}

2、直接在页面中设置好用户的权限组DIV等标签,SS3EX中页面是动态的,根据用户登陆的标记,设置好标签,如:<security:authorize ifNotGranted="ROLE_ANONYMOUS"><div id="admin"></div>"></security:authorize>,服务端推送消息时采取JavaChat 中的方法,选择相应的标签ID推送消息,
Util.setValue("admin", "");

备注:半推的第一个例子中,服务器是推向指定的ScriptSession用户,这里有个BUG,就是当用户刷新页面时,HttpSession不变,但是ScriptSession每刷新一次就增加一个,虽然最终也能把全部适合的ScriptSession找到,但是我还是觉得不是很好。
分享到:
评论
5 楼 ping2010 2012-11-12  
“备注:半推的第一个例子中,服务器是推向指定的ScriptSession用户,这里有个BUG,就是当用户刷新页面时,HttpSession不变,但是ScriptSession每刷新一次就增加一个,虽然最终也能把全部适合的ScriptSession找到,但是我还是觉得不是很好。 ”实现ScriptSessionListener,用ScriptSessionManager进行管理,可以做到刷新页面的Remove掉以前之前的scriptSessionId
4 楼 skying8603 2011-02-22  
Util util = new Util(session);  dwr3里没这个方法把??
3 楼 马晨辉 2010-08-07  
能不能给个例子看看
2 楼 deepsea0001 2009-07-10  
Browser 类中有filter方法,是否可以用来实现半推,这样比较优雅。
1 楼 crabboy 2009-06-09  
commet方式比较耗资源吧?还是觉得polling方式好啊

相关推荐

Global site tag (gtag.js) - Google Analytics