概述
最近项目需要一个主动推送的功能,果断百度、google发现网上主要有两种实现方式:
一种是使用HTML5的webSockect,这个需要Tomcat7以上才支持,而且需要客户端的IE浏览器都支持HTML5。所以被我们果断的放弃的了。
另一种是使用dwr实现,dwr是一个JS与服务端Java类交互的Ajax框架。可以做到后台调用Java类方法的同时前台JS方法执行,前台JS方法执行的同时后台Java类的对应方法被执行。
最后使用了DWR来实现后台向前台的数据推送。
基本实现思路:
既然涉及到推送,那么我们肯定要明确推送的发起点以及推送的目标点(每个用户都要有明确ID),并且保证当用户在不同页面跳转时,保证数据都能够推送到前台(会话状态)。在我们的系统中,主要发起点是用户A在前台点击某些操作触发的,推送的目标点是用户B。
Dwr推送的基本思想是将一个后台的Java类映射为一个前台的同名JS类,同时通过JS维持一个长连接,与每个页面产生一个scriptsession,该session保证了长连接的同时也保证了每个链接会话的不同状态。当前台调用java对应的JS类中的某个方法时,dwr调用后台的java类中的同名方法,后台java类的某个方法被调用的时候,前台的对应JS对象的方法也会被调用,也就实现了向前台推送。
实现方式:
1,引入DWR包
2,在web.xml文件中配置:
-
-
class> - org.directwebremoting.servlet.DwrListener
-
class> -
-
- dwr-invoker
-
class> - org.directwebremoting.servlet.DwrServlet
-
class> -
- crossDomainSessionSecuri
ty -
false -
-
-
allowScriptTagRemoting -
true -
-
-
classes -
java.lang.Object -
-
-
activeReverseAjaxEnabled -
true -
-
-
initApplicationScopeCrea torsAtStartup -
true -
-
-
maxWaitAfterWrite -
3000 -
-
-
logLevel -
WARN -
-
-
debug -
true -
-
-
- dwr-invoker
-
/dwr - public
class PushUtil { -
-
-
public void onPageLoad(String userId) { -
//ScriptSession,DWR中提供的脚本会话对象,这个会话是储存在本地线程中的 -
ScriptSession scriptSession = WebContextFactory.get().getScriptSession(); -
//给每个脚本会话赋值一个属性,一般作为脚本会话的区别属性 -
scriptSession.setAttribute("userId", userId); -
//初始化信息 -
initInfo(); -
} -
-
//初始化方法 -
private void initInfo() { -
//得到当前服务端的dwr容器 -
Container container = ServerContextFactory.get().getContainer(); -
//从dwr容器中得到脚本会话管理类 -
ScriptSessionManager manager = container.getBean(ScriptSessionManager.class); -
//从脚本会话管理类中得到目前所有的脚本会话对象 -
Collection sessions = manager.getAllScriptSessions(); -
//得到当前访问用户的HttpSession -
HttpSession httpSession = WebContextFactory.get().getSession(); -
//判断当前Http会话中是否已经有scriptSessionId属性 -
//如果有,则说明该HttpSession已经绑定了一个ScriptSession对象 -
//如果没有,则说明该HttpSession还没有绑定ScriptSession -
if(httpSession.getAttribute("scriptSessionId")!=null){ -
//得到当前HttpSession中存放的scriptSessionId属性 -
int id = (Integer)httpSession.getAttribute("scriptSessionId"); -
//遍历所有的ScirptSession对象,尝试将所有ScirptSession的id不是HttpSession中存放的scriptSessionId -
//的ScriptSession对象废止,注意:这里是废止不是立刻删除 -
for(ScriptSession session:sessions){ -
if(session.hashCode()!=id){ -
session.invalidate(); -
} -
} -
} - //
System.out.println("after invalidate sessionId:"+httpSession.getId()+",scriptSessionCount:"+manager.getScriptSessionsByHttpS essionId(httpSession.getId()).size()); -
//得到会话监听对象 -
ScriptSessionListener listener = PushListener.getInstance(); -
//将监听对象添加到ScriptSessionManager管理类上 -
manager.addScriptSessionListener (listener); -
} -
-
//这个方法用来推送,也就是当调用这个方法的时候,前台的JS对应函数就会被触发 -
public static void sendMessageAuto(String userid,String message) { -
//由于我们的推送是有目标的,所以需要目标ID以及要推送信息 -
Browser.withAllSessionsFiltered(new PushFilter(userid),new PushRunable(message)); -
} -
- }
- PushListener类
-
- public
class PushListener implements ScriptSessionListener{ -
-
private static PushListener listener; -
-
private PushListener() { -
-
} -
-
public static synchronized PushListener getInstance(){ -
if(listener==null){ -
listener = new PushListener(); -
} -
return listener; -
} -
-
-
public void sessionCreated(ScriptSessionEvent ev) { -
//得到当前的HttpSession类 -
HttpSession session = WebContextFactory.get().getSession(); -
//当前登录用户的用户ID -
String userId = ((Users) session.getAttribute("users")).getUserId() + ""; -
//向新创建的ScriptSession中添加属性userId,来标识该ScriptSession对应的用户 -
ev.getSession().setAttribute("userId", userId); -
//向HttpSession中设置新生成的ScriptSession对象的ID -
session.setAttribute("scriptSessionId", ev.getSession().hashCode()); -
} -
-
-
public void sessionDestroyed(ScriptSessionEvent ev) { -
//尝试废止该ScriptSession对象 -
ev.getSession().invalidate(); -
} -
- }
- PushFilter类
-
- public
class PushFilter implements ScriptSessionFilter { -
-
private static PushFilter filter; -
-
private String userId; -
-
public PushFilter() { -
-
} -
-
public PushFilter(String id){ -
this.userId = id; -
} -
-
-
@Override -
public boolean match(ScriptSession session) { -
//根据脚本中的userId属性来判断是否是要推送的目标脚本会话 -
if (session.getAttribute("userId") == null){ -
return false; -
}else{ -
return (session.getAttribute("userId")).equals(userId); -
} -
} -
- }
- PushRunnable
- 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() { -
//要推送到的前台目标的JS方法以及该方法的参数 -
script.appendCall("showMessage", message); -
//这里得到的ScriptSession的集合是通过PushFilter过滤过的 -
Collection sessions = Browser.getTargetSessions(); -
for (ScriptSession scriptSession : sessions) { - //
System.out.println(scriptSession.getAttribute("userId")); -
scriptSession.addScript(script); -
} -
} - }