可以通过Pushlet来实现服务器对多个在线页面的时时提醒。Pushlet 是一个开源的 Comet 框架,Pushlet 使用了观察者模式:客户端发送请求,订阅感兴趣的事件;服务器端为每个客户端分配一个会话 ID 作为标记,事件源会把新产生的事件以多播的方式发送到订阅者的事件队列里。观察者模式的基本概念是:观察者模式完美的将观察者和被观察的对象分离开。举个例子,用户界面可以作为一个观察者,业务数据是被观察者,用户界面观察业务数据的变化,发现数据变化后,就显示在界面上。面向对象设计的一个原则是:系统中的每个类将重点放在某一个功能上,而不是其他方面。一个对象只做一件事情,并且将他做好。观察者模式在模块之间划定了清晰的界限,提高了应用程序的可维护性和重用性。观察者设计模式定义了对象间的一种一对多的依赖关系,以便一个对象的状态发生变化时,所有依赖于它的对象都得到通知并自动刷新。
下面我们介绍一个在具有审批和调查的系统中,当审批人回退到调查时,如果该调查人在线,那么就在他的页面提示带有超链接的信息。难点有两个,一是每间隔一段时间比如5分钟去提示一遍;二是要根据不同的登录用户去提示不同的信息。第一个问题通过Pushlet可以很好的实现,第二个问题是后台如何能根据不同用户登录的ID去发送各自的信息呢,其实这个问题很简单,不需要考虑那么复杂,我在后台代码中把所要提示的所有的ID的信息全部都push到一个集合map中,那么是不是就可以更具用户登录时的ID对比map中的key值,一样即发送与之对应的信息呢,这样难点就全部有了思路,具体我们看代码。
下载最新版本的Pushlet。MyEclipse下建立一个web工程,我这里叫PushletTest,将pushlet.jar加入引用路径,pushlet.properties和sources.properties放入WebRoot/WEB-INF下,sources.properties中配置后台java代码的入口一般是controller类。如图所示:
在web.xml中添加pushlet的servlet的声明,让这个servlet在服务器启动时就启动(load-on-startup为正数),web.xml代码如下:
<servlet>
<servlet-name>pushlet</servlet-name>
<servlet-class>nl.justobjects.pushlet.servlet.Pushlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>pushlet</servlet-name>
<url-pattern>/pushlet.srv</url-pattern>
</servlet-mapping>
然后controller类如下
@Controller
public class ReinvestigatingPushlet extends EventPullSource implements Serializable {
private static final long serialVersionUID = -4378845831200885879L;
private static ApplicationContext applicationContext;
private static PushletService pushletService;
/**
* 推送时间间隔
*/
protected long getSleepTime() {
return 300000;
}
public static void initApplicationContext(){
applicationContext=ContextLoaderListener.getCurrentWebApplicationContext();
}
/** 通过泛型方法取得bean实例 */
@SuppressWarnings("unchecked")
public static <T> T getBean(String name){
if(applicationContext==null){
initApplicationContext();
}
return (T) applicationContext.getBean(name);
}
/**
* 推送时所触发的方法
*/
protected Event pullEvent() {
//创建事件,并制定事件的主题
Event event = Event.createDataEvent("/ynb/helloworld"); //每一个观察者对应一个主题,也就是说你可以同时监视多个事件,在jsp中也会写入该主题的
String data = "";
try {
pushletService=(PushletService)getBean("pushletServiceImpl"); //此处,其实仅仅是想使用service,但是通过正常的注入是无法实现的,所以通过此方法注入service
List userList=pushletService.getExamenPersonId();
System.out.println("有重新调查进件的征信人员---------------:"+userList);
if(null!=userList&&userList.size()>0){
for (int i = 0; i < userList.size(); i++) {
List<ReinvestigatingApply> reinvestigatingApplyList = pushletService
.getReinvestigatingApply(userList.get(i)+"");
if(null!=reinvestigatingApplyList&&reinvestigatingApplyList.size()>0){
for (int j = 0; j < reinvestigatingApplyList.size(); j++) {
ReinvestigatingApply rgApply=reinvestigatingApplyList.get(j);
String bussinessContent="申请编号:"+rgApply.getApplicationId()+",打回重新调查的原因:"+rgApply.getBussinessContent()+"。<br/>是否立即处理?";
if(j==reinvestigatingApplyList.size()-1){
data=data+"<a οnclick='tanchu(\""+bussinessContent+"\","+rgApply.getApplicationId()+","+rgApply.getExamenId()+")'>申请编号<font color='red'>"+rgApply.getApplicationId()+"</font>于"+rgApply.getOptDate()+"被"+rgApply.getOperatorName()+"打回重新调查,请及时处理!</a>";
data=new String(data.getBytes("UTF-8"),"ISO-8859-1");
event.setField("message"+userList.get(i), data);
data="";
}else{
data=data+"<a οnclick='tanchu(\""+bussinessContent+"\","+rgApply.getApplicationId()+","+rgApply.getExamenId()+")'>申请编号<font color='red'>"+rgApply.getApplicationId()+"</font>于"+rgApply.getOptDate()+"被"+rgApply.getOperatorName()+"打回重新调查,请及时处理!</a><br/>";
}
}
}
}
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return event;
}
}
这样每隔5分钟此controller就会执行一遍
ajax-pushlet-client.js 这个是需要引入的js,找到PL.pushletURL = PL._getWebRoot() + 'pushlet.srv'; PL._getWebRoot()这个加不加具体看你自己项目的目录。
下面就是jsp页面了,如果你想要做提醒,那么最好这个页面就在主页面中写
在index.jsp中首先引入js <script type="text/javascript" src="<%=basePath%>scripts/ajax-pushlet-client.js"></script>
初始化dialog
$('#chongxindiaochaDialog').dialog( {
closed : true,
closable:false,
buttons : [{
text : '是',
iconCls : 'icon-undo',
handler : function() {
$('#chongxindiaochaDialog').dialog('close');
openBorrow();
}
} , {
text : '否',
iconCls : 'icon-no',
handler : function() {
$('#chongxindiaochaDialog').dialog('close');
}
} ]
});
//重新调查实时提醒
//PL._init(); 这个加上的话有些浏览器不支持,不加的话也可以使用的
//PL.setDebug(true);
PL.joinListen("/ynb/helloworld");//监听该主题的事件,如果发生该主题的事件,那么onData()方法会被调用
function onData(event){
var content=event.get("message"+<%=SpringSecurityUtils.getCurrentUser().getUserId()%>);
if(content!=""&&null!=content){
$.messager.show({
title:'注意啦',
width:300,
height:150,
msg:content,
timeout:60000,
showType:'slide'
});
}
}
网上大部分人说是要修改pushlet的java源代码,找到nl.justobjects.pushlet.core包下的SessionManager类,将它的createSession方法改成:
public Session createSession(Event anEvent) throws PushletException {// Trivial
//return Session.create(createSessionId());
return Session.create(anEvent.getField("userId", "visitor"));
}
但是我做的时候并没有去修改,具体的各位在做的时候可以测试调整,我这边主要就是给一个思路。