本周的主要任务依旧是围绕着原开发平台添加一些新功能。
本周完成的功能如下:
①在用户管理中添加“清空登录用户”按钮并实现清空在线用户的session功能;
②增加用户登陆冲突检测功能;
③增加广播模块;
④增加消息弹窗提示功能,并与广播模块关联;
⑤进一步完善上周的用户管理模块,增加判断用户在线状态的功能。
技术关卡:
①获取session。servlet2.1之后便无原生的通过sessionid取得session的方法,研究了很久,迫不得已添加了针对session的监听器,用于获得session的创建和销毁等信息。
②模拟用户冲突。模拟用户各种冲突的情况,多重判断。
③添加广播模块。借鉴了一些消息模块的代码,基本完成模块功能。目前是通过在数据库中的广播表中添加用户字段来做提醒判断的,仅发送给在线用户时系统负荷不是很大,若不按照逻辑全员发送广播则系统开销较大。本功能应该有改进的余地。
④弹窗提示功能。碰巧找到了一个实现好的第三方弹窗组件——Ext.ux.Notification,大大缩短了开发时间,否则此功能可能拖延到下周。组件的发声代码与系统代码有冲突,所以当前功能只有弹窗无警示音。
读书:
DOM Scripting: Web Design with JavaScript and the Document Object Model .2nd Edition [Jeremy Keith] p160-p252.
代码:
①:根据sessionid获得session的两个类
MySessionContext.java
package com.alaahong.listener; import javax.servlet.http.HttpSession; import java.util.HashMap; public class MySessionContext { private static MySessionContext instance; private HashMap mymap; private MySessionContext() { mymap = new HashMap(); } public static MySessionContext getInstance() { if (instance == null) { instance = new MySessionContext(); } return instance; } public synchronized void AddSession(HttpSession session) { if (session != null) { mymap.put(session.getId(), session); } } public synchronized void DelSession(HttpSession session) { if (session != null) { mymap.remove(session.getId()); } } public synchronized HttpSession getSession(String session_id) { if (session_id == null) return null; return (HttpSession) mymap.get(session_id); } }
SessionListener.java
package bc.sf.user.listener; import javax.servlet.http.HttpSessionListener; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSession; import java.util.HashMap; import java.util.Map; public class SessionListener implements HttpSessionListener { public static Map userMap = new HashMap(); private MySessionContext myc=MySessionContext.getInstance(); public void sessionCreated(HttpSessionEvent httpSessionEvent) { myc.AddSession(httpSessionEvent.getSession()); } public void sessionDestroyed(HttpSessionEvent httpSessionEvent) { HttpSession session = httpSessionEvent.getSession(); myc.DelSession(session); } }
②:Ext.ux.Notification.js
Ext.namespace("Ext.ux"); Ext.ux.NotificationMgr = { positions :new Ext.util.MixedCollection() } Ext.ux.Notification = Ext.extend(Ext.Window, { initComponent: function(){ Ext.apply(this, { iconCls: this.iconCls || 'x-icon-information', cls: 'x-notification', width: 200, height: 100, autoHeight: true, plain: false, draggable: false, autoHide : this.autoHide && true, //是否自动隐藏窗口 hideDelay: this.hideDelay || 3000 ,//如果自动隐藏,n毫秒后隐藏窗口。autoHide为true,hideDelay起作用 minimizable:true, // constrain:true, bodyStyle: 'text-align:left' }); if(this.autoHide) { this.task = new Ext.util.DelayedTask(this.hideWin, this); } Ext.ux.Notification.superclass.initComponent.call(this); }, hideWin:function(){ this.hide(); this.close();//关闭当前窗口 }, setMessage: function(msg){ this.body.update(msg); }, setTitle: function(title, iconCls){ Ext.ux.Notification.superclass.setTitle.call(this, title, iconCls||this.iconCls); }, onRender:function(ct, position) { Ext.ux.Notification.superclass.onRender.call(this, ct, position); }, minimize:function(){ if(this.minimizable){ this.hideWin(); } }, onDestroy: function(){ Ext.ux.NotificationMgr.positions.get(this.xpos).remove(this.ypos); Ext.ux.Notification.superclass.onDestroy.call(this); }, cancelHiding: function(){ this.addClass('fixed'); if(this.autoHide) { this.task.cancel(); } }, afterShow: function(){ Ext.ux.Notification.superclass.afterShow.call(this); Ext.fly(this.body.dom).on('click', this.cancelHiding, this); if(this.autoHide) { this.task.delay(this.hideDelay || 3000); } }, animShow: function(x,y){ this.ypos = x||0; this.xpos = y||0; do{ //获取当前x轴的定位数据 if(Ext.ux.NotificationMgr.positions.get(this.xpos) == null){ Ext.ux.NotificationMgr.positions.add(this.xpos,[]); } //获取y轴定位数据,如果定位数据为-1,说明当前定位数据可用 while(Ext.ux.NotificationMgr.positions.get(this.xpos).indexOf(this.ypos)>-1) this.ypos++; //this.setSize(this.width,this.height); this.totalHeight = -20-((this.getSize().height+10)*this.ypos); //如果当前x轴上的y轴数据是第一次显示,不检测高度(如果检测高度,会导致死循环) if(this.ypos == 0 || Ext.getBody().getHeight() - this.height+this.totalHeight > 0){ this.totalWidth = -20-((this.getSize().width+10)*this.xpos); Ext.ux.NotificationMgr.positions.get(this.xpos).push(this.ypos); this.el.alignTo(document, "br-br", [ this.totalWidth, this.totalHeight]); this.el.slideIn('b', { duration: 1, callback: this.afterShow, scope: this }); break; } else{//如果y轴的高度大于当前窗口的高度,开始进入新的x轴定位数据 this.xpos++; // this.totalWidth = -20-((this.getSize().width+10)*this.xpos); this.ypos=0; } }while(true) }, animHide: function(){ if(typeof(Ext.ux.NotificationMgr.positions.get(this.xpos)) != 'undefined'){ Ext.ux.NotificationMgr.positions.get(this.xpos).remove(this.ypos); if(Ext.ux.NotificationMgr.positions.get(this.xpos).length == 0){//当前x轴上的y轴定位数据为0 Ext.ux.NotificationMgr.positions.removeKey(this.xpos); } } this.el.ghost("b", { duration: 1, remove: true }); }, /** * 调用方法:操作成功,显示成功的信息 * @param {} title * @param {} msg */ showSuccess:function(title,msg){ this.iconCls= 'x-icon-information', this.title = title||'success'; this.html = msg||'process successfully!'; this.show(document); }, /** * 调用方法:操作失败,显示失败的信息 * @param {} title * @param {} msg */ showFailure:function(title,msg){ this.iconCls= 'x-icon-error', this.title = title||'success'; this.html = msg||'process successfully!'; this.show(document); }, /** * 调用方法:显示操作结果的信息 * @param {} title * @param {} msg * @param {} success 操作是否成功 */ showMessage:function(title,msg,success){ if(success){ this.iconCls= 'x-icon-information'; this.autoHide=true;//自动隐藏窗口 this.task = new Ext.util.DelayedTask(this.hideWin, this); } else{ this.iconCls= 'x-icon-error'; } this.title = title; this.html = msg; this.show(document); }, focus: Ext.emptyFn }); Ext.EventManager.onWindowResize(function(){ Ext.ux.NotificationMgr.positions.clear(); });
下面是一些流程,只是简单示意,没有标注判断跳转等动作。