dwr消息推送

闲来无事,把自己关于对dwr消息推送的实现过程描述一番。

首先第一步,当然在工程中是加入dwr.jar了,接着在web.xml中配置以下代码

<servlet>
        <servlet-name>dwr-invoker</servlet-name>
        <servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
        <init-param>
            <param-name>config</param-name>
            <param-value>/WEB-INF/config/dwr.xml</param-value>
        </init-param>
        <init-param>
            <param-name>debug</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>
        <init-param>
            <param-name>classes</param-name>
            <param-value>java.lang.Object</param-value>
        </init-param>
        <init-param>
            <param-name>activeReverseAjaxEnabled</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>initApplicationScopeCreatorsAtStartup</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>maxWaitAfterWrite</param-name>
            <param-value>3000</param-value>
        </init-param>
        <init-param>
            <param-name>logLevel</param-name>
            <param-value>WARN</param-value>
        </init-param>
        <load-on-startup>2</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dwr-invoker</servlet-name>
        <url-pattern>/dwr/*</url-pattern>
    </servlet-mapping>

从配置中可以看出需要新建一个dwr配置文件,如下

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE dwr PUBLIC 
    "-//GetAhead Limited//DTD Direct Web Remoting 3.0//EN" 
    "http://getahead.org/dwr//dwr30.dtd">
<dwr>
    <allow>
        <!-- <create javascript="udao" creator="spring"> <param name="beanName" 
            value="udao" /> <include method="getUserPage"/> </create> <convert converter="bean" 
            match="com.cpsoft.app.web.domain.PageModel" /> -->
        
        <create javascript="MessagePush" creator="spring">
            <param name="beanName" value="messagePush" />
        </create>
        <convert converter="bean" match="java.lang.StackTraceElement" />
        <convert converter="exception" match="java.lang.Exception" />
    </allow>
</dwr>

那么大家可以看到,我配置了一个messagePush这个对象,那么我就来说说这个对象吧

@Component
public class MessagePush {

    final public static String SCRIPT_SESSION_USERID = "SCRIPT_SESSION_USERID";
    final public static String SCRIPT_SESSION_MSG = "showMessage"; //这是页面上当后台消息推送时,自动触发的js方法名称
    
    private Logger log = Logger.getLogger(this.getClass());
    private ScriptSessionListener listener;
    private boolean isInit = false;
    
    public boolean isInit(){
        return isInit;
    }
    /**
     * 获取scriptSession的监听对象,只需要实例化一次
     * @return
     */
    public ScriptSessionListener getListener() {
        if(listener == null){
            listener = new ScriptSessionListener() {
                public void sessionCreated(ScriptSessionEvent ev) {
                    HttpSession session = WebContextFactory.get().getSession();
                    Staff staff = SessionUtil.getStaff(session);
                    if(staff!=null){
                        ev.getSession().setAttribute(SCRIPT_SESSION_USERID, staff.getId()); //与当前登录用户相关联
                        log.info("a ScriptSession["+staff.getId()+"] is created!");
                        Map<String, Staff> onlineStaffMap = CacheUtil.getOnlineStaffMap(); //获取当前的在线用户
                        if(!onlineStaffMap.containsKey(staff.getId())) onlineStaffMap.put(staff.getId(), staff); //如果不存在,则将当前用户加入到缓存中
                    }
                    if(!isInit) isInit = true;
                }

                public void sessionDestroyed(ScriptSessionEvent ev) {
                    String userId = (String) ev.getSession().getAttribute(SCRIPT_SESSION_USERID);
                    log.info("a ScriptSession["+userId+"] is distroyed!");
                }
            };
        }
        return listener;
    }
    
    /**
     * 初始化dwr监听,只在程序中调用一次即可
     */
    public void init(){
        if(listener == null){
            Container container = ServerContextFactory.get().getContainer();
            ScriptSessionManager manager = container
                    .getBean(ScriptSessionManager.class);
            manager.addScriptSessionListener(getListener());
            log.info("the dwr client is inited!");
        }
    }
    
}

这个类的主要作用是初始化监听,接着如果有了监听,那现在就可以推送消息了,请看代码

/**
     * 采用dwr的方式向前台推送消息
     * @param userId 用户Id
     * @param autoMessage 消息内容
     */
    private static void sendMessageAuto(final String userId, final String autoMessage) {
        Browser.withAllSessionsFiltered(new ScriptSessionFilter() {
            public boolean match(ScriptSession session) {
                String id = (String) session.getAttribute(MessagePush.SCRIPT_SESSION_USERID);
                if (id == null || !userId.equals(id)) { //匹配接收人的Id
                    return false;
                }
                return true;
            }
        }, new Runnable() {
            private ScriptBuffer script = new ScriptBuffer();
            public void run() {
                script.appendCall(MessagePush.SCRIPT_SESSION_MSG, autoMessage); //推送消息(我在这里用的是json字符串)
                Collection<ScriptSession> sessions = Browser.getTargetSessions(); //获取当前的目标客户端对象
                for (ScriptSession scriptSession : sessions) {
                    scriptSession.addScript(script);
                }
            }
        });
    }

说到这里,后台工作就告一段落了,接着来说说前台,首先引入js吧

<!-- 消息推送 -->
<script type='text/javascript' src='${ctx}/dwr/engine.js'></script>
<script type='text/javascript' src='${ctx}/dwr/util.js'></script>
<script type="text/javascript" src="${ctx}/dwr/interface/MessagePush.js"></script>

在onload 加入

<body onload="dwr.engine.setActiveReverseAjax(true);dwr.engine.setNotifyServerOnPageUnload(true);">

那么现在大工告成了,只要后台调用上面的推送方法,前台就好自动触发

function showMessage(autoMessage){
    //alert(autoMessage);
    if(!callCometShowMsg){
        eval("var json="+ autoMessage);
        g_showTip("消息类型:"+json.MESSAGE_TYPE+"<br />消息内容:"+json.MESSAGE_DATA);
    }else{
        callCometShowMsg(autoMessage);
    }
}

最后说说总结一下把,实测了一下,发现Ie8下反应慢一点,对于chrome,我用的这个版本会有问题, 火狐表现良好

有什么问题可以留言,看到第一时间回复

posted on 2014-05-29 16:57  somewhere!  阅读(1106)  评论(2编辑  收藏  举报

导航