DWR(Direct Web Remoting)是一个用于改善web页面与Java类交互的远程服务器端Ajax开源框架,可以帮助开发人员开发包含AJAX技术的网站。它可以允许在浏览器里的代码使用运行在WEB服务器上的JAVA方法,就像它就在浏览器里一样。
DWR采取了一个类似AJAX的新方法来动态生成基于JAVA类的JavaScript代码。这样WEB开发人员就可以在JavaScript里使用Java代码,就像它们是浏览器的本地代码(客户端代码)一样;但是Java代码运行在WEB服务器端而且可以自由访问WEB 服务器的资源。出于安全的理由,WEB开发者必须适当地配置哪些Java类可以安全的被外部使用。
DWR Reverse Ajax(逆向Ajax)主要是在BS架构中,从服务器端向多个浏览器主动推数据的一种技术。
项目使用的maven搭建,以下写具体搭建dwr框架步骤:
1、pom.xml加入配置:
org.directwebremoting
dwr
3.0.2-RELEASE
2、web.xml加入配置信息:
dwrServlet
org.directwebremoting.servlet.DwrServlet
debug
false
activeReverseAjaxEnabled
true
pollAndCometEnabled
true
crossDomainSessionSecurity
false
allowScriptTagRemoting
true
1
dwrServlet
/dwr/*
3、增加dwr.xml文件,这里与web.xml同级,内容如下:
include指定了只能调用该类中的哪个方法,MessageService为前面页面引用时的名称
4、新建DwrMessageService类如下:
public class DwrMessageService {
public void onPageLoad(String userId) {
// TODO Auto-generated method stub
ScriptSession scriptSession = WebContextFactory.get().getScriptSession();
scriptSession.setAttribute("userId", userId);
DwrScriptSessionManager dwrScriptSessionManagerUtil = new DwrScriptSessionManager();
try {
dwrScriptSessionManagerUtil.init();
} catch (ServletException e) {
e.printStackTrace();
}
}
private class DwrScriptSessionManager extends DwrServlet{
/**
*
*/
private static final long serialVersionUID = 1L;
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");
ev.getSession().setAttribute("userId", userId);
}
public void sessionDestroyed(ScriptSessionEvent ev) {
// System.out.println(">>>>>>>>a ScriptSession is distroyed");
}
};
manager.addScriptSessionListener(listener);
}
}
}
5、建立消息发送类SendDwrMsg,这里使用了静态内部内实现的单例模式,详细不说了,看代码 :
public class SendDwrMsg {
private static class SendDwrMsgHolder{
private static final SendDwrMsg instance=new SendDwrMsg();
}
public static SendDwrMsg getInstance() {
return SendDwrMsgHolder.instance;
}
public void sendMessageAuto(String userid, String message){
final String userId = userid;
final String autoMessage = message;
Browser.withAllSessionsFiltered(new ScriptSessionFilter() {
public boolean match(ScriptSession session){
if (session.getAttribute("userId") == null)
return false;
else
return (session.getAttribute("userId")).equals(userId);
}
}, new Runnable(){
private ScriptBuffer script = new ScriptBuffer();
public void run(){
//这里showMessage为前端接收消息的js方法名
script.appendCall("showMessage", autoMessage);
Collection sessions = Browser
.getTargetSessions();
for (ScriptSession scriptSession : sessions){
scriptSession.addScript(script);
}
}
});
}
}
到此dwr相关配置完成,下面说实际使用。
jsp页面中引入dwr的engine.js 、util.js 以及新建的初始化类的js,详细如下
调用MessageService中的onPageLoad方法:
dwr.engine._errorHandler = function(message, ex) {
dwr.engine._debug("Error: " + ex.name + ", " + ex.message, true);
};
//设置engine的errorHandler是为了防止浏览器弹出incomplete reply from server 错误
var initFlag=false;
function onPageLoad(){
if(!initFlag){
MessageService.onPageLoad(${initId});
dwr.engine.setActiveReverseAjax(true);dwr.engine.setNotifyServerOnPageUnload(true);
flag=true;
}
}
//推送信息
function showMessage(autoMessage){
console.log(autoMessage);
}
由于本测试为同一个页面推送及接收消息。为了防止重复初始化,加入initFlag标记,为使用能够达到精确推送的目的,而实际应用时用户可以多次登录,为此在后端以一定 的规则生成 了initId,每次访问这个页面时,后端都将生成一个initId用于唯一标识页面。
必须设置: dwr.engine.setActiveReverseAjax(true);dwr.engine.setNotifyServerOnPageUnload(true); 启动该页面的Reverse Ajax功能否则无法接收到消息
到此配置完成 。。
由于实际使用中应用使用了nginx做负载均衡,当把此项目部署后发现消息推送总是会出现延迟的情况,直接访问当前应用服务器又正常,推断应该是由nginx造成。在nginx配置文件中增加proxy_buffering off; 推送正常