springMVC+dwr3 实现消息精确推送(注解方式+文件方式)
本文假定以完成springMVC配置,并且涉及配置都是在springMVC配置之上添加。由于现在对其中的一些原理还不是很理解,所以对于每一个的配置的不会解释为什么这样做
dwr3是从dwr官网上下载最新的。http://directwebremoting.org/dwr/index.html
方法 1:(此方法可能在第一个打开页面是不能推送消息,原因不明)
文件方式:
1A、在web.xml里面加入dwr配置,如下:
<servlet>
<servlet-name>dwr-invoker</servlet-name>
<servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>activeReverseAjaxEnabled</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>pollAndCometEnabled</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>crossDomainSessionSecurity</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>allowScriptTagRemoting</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dwr-invoker</servlet-name>
<url-pattern>/dwr/*</url-pattern>
</servlet-mapping>
1B、在web.xml同级目录下建立dwr.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE dwr PUBLIC
"-//GetAhead Limited//DTD Direct Web Remoting 3.0//EN"
"http://directwebremoting.org/schema/dwr30.dtd">
<dwr>
<allow>
<create javascript="MessagePush" creator="new">
<param name="class" value="com.arch.web.dwr.MessagePush"></param>
</create>
</allow>
</dwr>
其中
com.arch.web.dwr.MessagePush,就是我的消息推送注册类。
1C、建立MessgePush类,具体类内容如下
public class MessagePush {
public void onPageLoad(String userId) {
ScriptSession scriptSession = WebContextFactory.get().getScriptSession();
scriptSession.setAttribute(userId, userId);
DwrScriptSessionManagerUtil dwrScriptSessionManagerUtil = new DwrScriptSessionManagerUtil();
try {
dwrScriptSessionManagerUtil.init();
} catch (ServletException e) {
e.printStackTrace();
}
}
}
开放onPageLoad方法供前段页面注册调用
1D、MessagePush需要DwrScriptSessionManagerUtil,建立DwrScriptSessionManagerUtil 内容如下:
public class DwrScriptSessionManagerUtil extends DwrServlet {
public void init() throws ServletException {
Container container = ServerContextFactory.get().getContainer();
ScriptSessionManager manager = container .getBean(ScriptSessionManager.class);
ScriptSessionListener listener = new ScriptSessionListener() {
public void sessionCreated(ScriptSessionEvent ev) {
HttpSession session = WebContextFactory.get().getSession();
String userId = (String) session.getAttribute("userId");
System.out.println("a ScriptSession is created!");
ev.getSession().setAttribute("userId", userId);
}
public void sessionDestroyed(ScriptSessionEvent ev) {
System.out.println("a ScriptSession is distroyed");
}
};
manager.addScriptSessionListener(listener);
}
}
1E、前段页面
引入dwr核心js
<script type="text/javascript" src="<%=basePath%>dwr/engine.js"></script> <!-- basePath:网站基本路基-->
<script type="text/javascript" src="<%=basePath%>dwr/util.js"></script>
引入消息注册js
<script type="text/javascript" src="<%=basePath%>dwr/interface/callTest.js"></script>
建立注册js和接受消息js
function onPageLoad(){
var userId = '${userId}';
MessagePush.onPageLoad(userId);
}
function showMessage(msg) {
alert(dwr.util.toDescriptiveString(data));
}
在页面body标签中加入onload属性信息
<body οnlοad="dwr.engine.setActiveReverseAjax(true);dwr.engine.setNotifyServerOnPageUnload(true);onPageLoad();">
1F、现在需要一个推送消息方法来向特定用户发送我们的推送消息(随便放入一个类中都可以)
public static void sendMessageAuto(String userid, String message) {
final String userId = userid;
final String autoMessage = message;
final String OP_ID = "userId";
Browser.withAllSessionsFiltered(new ScriptSessionFilter() {
public boolean match(ScriptSession session) {
if (session.getAttribute(OP_ID) == null)
return false;
else {
boolean f = session.getAttribute(OP_ID).equals(userId);
return f;
}
}
}, new Runnable() {
private ScriptBuffer script = new ScriptBuffer();
public void run() {
script.appendCall("showMessage", autoMessage);
Collection<ScriptSession> sessions = Browser.getTargetSessions();
for (ScriptSession scriptSession : sessions) {
scriptSession.addScript(script);
}
}
});
}
以上是全部配置,现在就可以使用sendMessageAuto向指定用户推送消息
注解方式:
注解方式其实和文件方式类似;需要修改的地方如下:
1、在(1A)步中,不再web.xml里面配置dwr,而是在springMVC文件中配置dwr,具体配置如下
<!-- DWR配置 -->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
<dwr:annotation-scan base-package="com.cb" scanDataTransferObject="true"/>
<dwr:configuration />
<dwr:annotation-config id="dwr"/>
<dwr:url-mapping />
<dwr:controller id="dwrController" debug="true">
<dwr:config-param name="allowScriptTagRemoting"
value="true" />
<dwr:config-param name="crossDomainSessionSecurity"
value="false" />
<dwr:config-param name="activeReverseAjaxEnabled"
value="true" />
<dwr:config-param name="pollAndCometEnabled"
value="true" />
<dwr:config-param name="allowScriptTagRemoting"
value="true" />
</dwr:controller>
<bean
class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="order" value="1" />
</bean>
<bean
class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">
<property name="order" value="2" />
</bean>
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="order" value="3" />
<property value="true" name="alwaysUseFullPath"></property>
<property name="mappings">
<props>
<prop key="/dwr/**">dwrController</prop>
</props>
</property>
</bean>
2、不需要dwr.xml配置文件,省略(
1B)步
3、在(1D)步中,向MessagePush类中加入注解
@RemoteProxy(name="MessagePush")
public class MessagePush {
@RemoteMethod
public void onPageLoad(String userId) {
ScriptSession scriptSession = WebContextFactory.get().getScriptSession();
scriptSession.setAttribute(userId, userId);
DwrScriptSessionManagerUtil dwrScriptSessionManagerUtil = new DwrScriptSessionManagerUtil();
try {
dwrScriptSessionManagerUtil.init();
} catch (ServletException e) {
e.printStackTrace();
}
}
}
其他不变。
注:此种方法有可能在首次打开页面的时候不能创建session,导致不能推送消息,但是页面刷新一下就好了。(为什么会这样具体原因还没有找到)
方法2:
为了解决方法1中出现的首次打开可能不能推送问题,这里的做法是在每次用户打开需要推送的页面时自动创建scriptSession,并且只要假定只要使用了dwr页面都需要推送(当然这个是可以根据自己的业务修改规则,实现特定页面精确推送)
文件方式:
2A、首先需要创建自己的session管理类,这里的名称为:com.toolbox.util.DwrScriptSessionManagerUtil
public class DwrScriptSessionManagerUtil extends DefaultScriptSessionManager{
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private static final String SS_ID = "DWR_ScriptSession_Id";
private static final String OP_ID = "userId";
public DwrScriptSessionManagerUtil(){
addScriptSessionListener(new ScriptSessionListener() {
public void sessionCreated(ScriptSessionEvent ev) {
logger.info(" script session in.....");
HttpSession httpSession = WebContextFactory.get().getSession();
ScriptSession scriptSession = ev.getSession();
String userId = (String)httpSession.getAttribute("userId");
if (userId == null) {
logger.info(" script session invalidate");
scriptSession.invalidate();
httpSession.invalidate();
return;
}
//已经存在旧的scriptSession 注销这个旧的scriptSession
DefaultScriptSession old = sessionMap.get(userId);
if (old != null){
DwrScriptSessionManagerUtil.this.invalidate(old);
}
httpSession.setAttribute(SS_ID, scriptSession.getId());
scriptSession.setAttribute(OP_ID, userId);
scriptSession.setAttribute("SESSIONID", httpSession.getId());
logger.info(" script session created: " + userId);
}
public void sessionDestroyed(ScriptSessionEvent ev) {
ScriptSession ss = ev.getSession();
if (ss.getAttribute(OP_ID) != null){
logger.info(" script session destroyed: " + ss.getAttribute(OP_ID));
}
}
});
//this.setScriptSessionTimeout(150000L);
}
2B、将我们的session管理类加入dwr控制器中
<servlet>
<servlet-name>dwr-invoker</servlet-name>
<servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
<init-param>
<param-name>org.directwebremoting.extend.ScriptSessionManager</param-name>
<param-value>com.toolbox.util.DwrScriptSessionManagerUtil</param-value>
</init-param>
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>activeReverseAjaxEnabled</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>pollAndCometEnabled</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>crossDomainSessionSecurity</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>allowScriptTagRemoting</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dwr-invoker</servlet-name>
<url-pattern>/dwr/*</url-pattern>
</servlet-mapping>
2C、在web.xnl同目录下建立一个空的dwr.xnl文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE dwr PUBLIC
"-//GetAhead Limited//DTD Direct Web Remoting 3.0//EN"
"http://directwebremoting.org/schema/dwr30.dtd">
<dwr>
<allow>
</allow>
</dwr>
2D、前端页面
<script type="text/javascript" src="<%=basePath%>dwr/engine.js"></script> <!-- basePath:网站基本路基-->
<script type="text/javascript" src="<%=basePath%>dwr/util.js"></script>
function showMessage(msg) { alert(dwr.util.toDescriptiveString(data)); }
<body οnlοad="dwr.engine.setActiveReverseAjax(true);dwr.engine.setNotifyServerOnPageUnload(true);">
这里因为后端假定只要使用了dwr就会需要推送消息,所以钱端不需要调用消息注册操作
2E、消息发送方法
public static void sendMessageAuto(String userid, String message) {
final String userId = userid;
final String autoMessage = message;
final String OP_ID = "userId";
Browser.withAllSessionsFiltered(new ScriptSessionFilter() {
public boolean match(ScriptSession session) {
if (session.getAttribute(OP_ID) == null)
return false;
else {
boolean f = session.getAttribute(OP_ID).equals(userId);
return f;
}
}
}, new Runnable() {
private ScriptBuffer script = new ScriptBuffer();
public void run() {
script.appendCall("showMessage", autoMessage);
Collection<ScriptSession> sessions = Browser.getTargetSessions();
for (ScriptSession scriptSession : sessions) {
scriptSession.addScript(script);
}
}
});
}
到这里全部都完了。现在前段能正常接收到推送消息
注解方式:
这里的注解方式就方便很多了,和《方法1》中类似需要改变的步骤有:
· 1、(2B) 中不需要在web.xml中配置dwr,dwr配置在springMVC中
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
<dwr:annotation-scan base-package="com.cb" scanDataTransferObject="true"/>
<dwr:configuration />
<dwr:annotation-config id="dwr"/>
<dwr:url-mapping />
<dwr:controller id="dwrController" debug="true">
<dwr:config-param name="allowScriptTagRemoting"
value="true" />
<dwr:config-param name="crossDomainSessionSecurity"
value="false" />
<dwr:config-param name="activeReverseAjaxEnabled"
value="true" />
<dwr:config-param name="org.directwebremoting.extend.ScriptSessionManager"
value="com.toolbox.util.DwrScriptSessionManagerUtil" />
<dwr:config-param name="pollAndCometEnabled"
value="true" />
<dwr:config-param name="allowScriptTagRemoting"
value="true" />
</dwr:controller>
<bean
class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="interceptors">
<list>
<bean class="com.arch.interceptor.AclInterceptorAdapter" />
</list>
</property>
<property name="order" value="1" />
</bean>
<bean
class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">
<property name="order" value="2" />
</bean>
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="order" value="3" />
<property value="true" name="alwaysUseFullPath"></property>
<property name="mappings">
<props>
<prop key="/dwr/**">dwrController</prop>
</props>
</property>
</bean>
2、不要dwr.xml配置文件,所以跳过 (2C)
其他步骤不变。
这样dwr3消息推送搭建完成。