dwr学习总结

在DWR中,我们可以通过WebContextFactory.get()来取得一个WebContext对象,进而通过WebContext的getScriptSession()取得ScriptSession对象。

但是要注意,在我们自定义的Servlet中,我们也可以通过WebContextFactory.get()来取得一个WebContext,但是这种方法却不能取得ScriptSession对象。因为,此WebContext对象其实不是通过DWR的上下文环境得到的,所以,就根本没有创建ScriptSession对象。

假设这种方式也能得到ScriptSession的话,那么我们实现“推”也就可以不局限在DWR的上下文环境中了,那么其灵活性就会大很多了。所以,这就是我们不能在Servlet中实现推的原因。

 在我们需要推送的页面中,如果你刷新一下,那么就提交一个Http的request,此时,如果是第一次,那么就会创建一个httpSession对象,同时,请求由DwrServlet来处理后,就会创建一个ScriptSession.这个ScriptSession会和你的request请求的URI绑定放在一个由ScriptSessionManager维护的Map里面(这里面其实是一个URI对应的Set,在Set里面放置的是URI绑定的所有ScriptSession)。

当你刷新的时候,同样的一个HttpSession,却会创建一个新的ScriptSession,然后绑定到对应的URI上。

 向所有的页面访问者推送

当我们想向所有的页面访问者推送的时候,我们只需要,取得所有的页面访问者,就可以“推”了。
如何取得所有的页面访问者?

DWR3.0可以通过

//得到所有ScriptSession
Collection<ScriptSession> sessions = Browser.getTargetSessions();

DWR2.x可以通过

Collection pages = webContext.getScriptSessionsByPage("/yourPage.jsp");


通过此方法,就可以实现调用客户端的javascript函数,实现对客户端的操作。

在上面的推送中产生的问题

上面的方法已经可以实现向所有的访问者推送。但是问题是,在客户端,如果用户刷新一次或多次,那么,Collection里面可能就保存了很多的无用的ScriptSession,所以不仅仅会影响性能问题,更重要的是,可能就不能实现你想要的功能。

如何管理有效的ScriptSession

     由于上面的问题,我们就需要自己管理ScriptSession。其实,有效地HttpSession,就是那个和当前的HttpSession匹配的ScriptSession。

所以,我们就可以自己维护一个Map,在这个Map里面,我们定义key就是HttpSession的Id,其值就是ScriptSession对象。

在每一次页面载入的时候,都去注册此ScriptSession,那么就会把新的ScriptSession绑定到httpSession上面了。

在DWR3.0中推出了 ScriptSessionListener用来监听ScriptSession的创建及销毁事件。我们可以使用该监听器来维护我们自己的Map。

具体实现:

1.新建一个类实现ScriptSessionListener接口

public class PushListener implements ScriptSessionListener {
     
     //维护一个Map key为session的Id, value为ScriptSession对象
 public static final Map<String,ScriptSession> sessionMap = new HashMap<String,ScriptSession>();
 private static PushListener listener;
 
 private PushListener() {
}
 
 public static PushListener getInstance(){
 if(listener==null){
 listener = new PushListener();
 }
 return listener;
 }
 
 /**
 * 会话/长连接创建时调用的方法
 */
 public void sessionCreated(ScriptSessionEvent ev) {
 HttpSession httpSession = WebContextFactory.get().getSession();
//本系统登录时在HttpSession中放置系统用户
 if(httpSession.getAttribute("users")==null){
 return;
 }
 String userId = ((Users) httpSession.getAttribute("users")).getUserId() + "";
 // 每一个scriptsession对应唯一客户端
 ev.getSession().setAttribute("userId", userId);
 
 // 保证每一个httpSession在一个时间点只存在一个scriptsession
 sessionMap.put(httpSession.getId(), ev.getSession());
 }
 
 /**
 * 会话(长连接)关闭时调用的方法
 */
 public void sessionDestroyed(ScriptSessionEvent ev) {
 WebContext webContext = WebContextFactory. get();
 HttpSession httpSession = webContext.getSession();
 sessionMap.remove(httpSession.getId()); //移除scriptSession
 }
}
 




2.使用ScriptSessionFilter过滤

如果我们不想要给所有的客户端推送消息,只想给特定的客户端推送,那么我们可以使用
ScriptSessionFilter来实现。在filter中去判定session中的Attribute值是不是我们给定的。

 

我们需要一个ScriptSessionFilter对象

public class PushFilter implements ScriptSessionFilter {
private String userId;
 
 public PushFilter() {
}
 
 public PushFilter(String id){
 this.userId = id;
 }
/**
 * 匹配指定的客户端
 */
 @Override
 public boolean match(ScriptSession session) {
 if (session.getAttribute("userId") == null){
 return false;
 }else{
 return (session.getAttribute("userId")).equals(userId);
 }
 }}


3.实现run方法

public class PushRunable implements Runnable {

 private String message;
 private ScriptBuffer script = new ScriptBuffer();
 public PushRunable(){
 }
 public PushRunable(String msg){
 this.message = msg;
 }
 /**
 * 新启的线程,执行的业务
 */
 @Override
 public void run() {
 script.appendCall("showMessage", message);
 Collection<ScriptSession> sessions = Browser.getTargetSessions();
 for (ScriptSession scriptSession : sessions) {
//添加待执行的脚本到dwr excution池中
 scriptSession.addScript(script);
 }
 }
}


4.客户端注册

public class PushUtil {
 /**
 * 脚本接口(客户端注册接口),在页面调用
 * 
 * @param userId
 */
 public void onPageLoad(String userId) {
 ScriptSession scriptSession = WebContextFactory.get()
 .getScriptSession();
 scriptSession.setAttribute("userId", userId);
 initInfo();
 }
// 管理scriptsession
 private void initInfo() {
 Container container = ServerContextFactory.get().getContainer();
 ScriptSessionManager manager = container
 .getBean(ScriptSessionManager.class);
 Collection<ScriptSession> sessions = manager.getAllScriptSessions();
 Collection<ScriptSession> myManagerSessions = PushListener.sessionMap
 .values();
 // 未过滤dwr容器中的scriptsession
 System.out.println("before...");
 for (ScriptSession scriptSession : sessions) {
 if (!scriptSession.isInvalidated()) {
 System.out.print(scriptSession);
 }
 }
 // 根据自定义的session管理器过滤掉dwr容器中无效的scriptsession
 for (ScriptSession scriptSession : sessions) {
 if (!myManagerSessions.contains(scriptSession)) {
 scriptSession.invalidate();
 }
 }
 // 过滤后dwr容器中的scriptsession
 System.out.println();
 System.out.println("after...");
 for (ScriptSession scriptSession : sessions) {
 if (!scriptSession.isInvalidated()) {
 System.out.print(scriptSession);
 }
 }
// 给dwr的scriptsession管理器植入监听器,监听器中有自己的业务逻辑和对scriptsession的管理逻辑
 ScriptSessionListener listener = PushListener.getInstance();
 manager.addScriptSessionListener(listener);
 }
 
/**
 * 发送方法,供外部模块调用
 * 
 * @param userid
 * @param message
 */
 public static void sendMessageAuto(String userid, String message) {
 Browser.withAllSessionsFiltered(new PushFilter(userid),
 new PushRunable(message));
 }
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值