美文网首页web后端程序员
使用DWR实现消息推送

使用DWR实现消息推送

作者: myfm289 | 来源:发表于2015-11-21 18:39 被阅读1170次

    dwr支持如下3种模式的消息推送:

    • Polling,浏览器每隔一段时间向服务器发出请求,查看是否有更新的内容;
    • Comet,
    • Piggyback,服务器等待浏览器下一次发出请求时,将更新的内容合并到响应一起返回。

    默认使用Piggyback模式,使用Polling/Comet模式需要额外的配置。

    DWR简单入门介绍了基于DWR构建项目。

    使用Maven构建项目,在pom.xml中添加如下配置

    <repositories>
        <repository>
            <!-- Please consider setting up your own on-site repository proxy such 
                as with Nexus and pointing the url element below at that instead -->
            <id>oss-sonatype-snapshots</id>
            <name>OSS Sonatype Snapshots Repository</name>
            <url>http://oss.sonatype.org/content/repositories/snapshots</url>
            <releases>
                <enabled>false</enabled>
            </releases>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </repository>
    </repositories>
    
    <dependencies>
    ...
        <dependency>
            <groupId>org.directwebremoting</groupId>
            <artifactId>dwr</artifactId>
            <version>3.0.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.2</version>
        </dependency>
        <!-- 使用Tomcat需要额外添加的依赖包 -->
        <dependency>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>catalina</artifactId>
            <version>6.0.44</version>
        </dependency>
    </dependencies>
    

    使用的容器是Tomcat(与使用Jetty的配置不同),在web.xml中添加如下配置

    <servlet>
        <servlet-name>dwr-invoker</servlet-name>
        <servlet-class>org.directwebremoting.server.tomcat.DwrCometProcessor</servlet-class>
        <init-param>
            <param-name>debug</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <!-- 2.0 RC3之前的参数名为pollAndCometEnabled -->
            <param-name>activeReverseAjaxEnabled</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>maxWaitAfterWrite</param-name>
            <param-value>1000</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>dwr-invoker</servlet-name>
        <url-pattern>/dwr/*</url-pattern>
    </servlet-mapping>
    

    dwr.xml中的配置

    <?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 creator="new" javascript="messagePush">
                <param name="class" value="me.util.MessagePushUtil" />
            </create>
        </allow>
    </dwr>
    

    采用的调试方式是,打开接收页面(receiver.jsp)和发送页面(sender.jsp),在发送页面将消息发送至服务端,由服务端将消息推送至接受页面。JSP文件中使用JQuery替代了dwr提供的<script type='text/javascript' src='/dwr/util.js'></script>

    接收页面(receiver.jsp)

    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
    <%@ page isELIgnored="false"%>
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <link rel="stylesheet" type="text/css" href="/css/easyui.css">
    <link rel="stylesheet" type="text/css" href="/css/demo.css">
    <script type="text/javascript" src="/js/jquery.js"></script>
    <script type="text/javascript" src="/js/jquery.easyui.min.js"></script>
    <script type='text/javascript' src='/dwr/engine.js'></script>
    <script type='text/javascript' src='/dwr/interface/messagePush.js'></script>
    <title>消息推送</title>
    </head>
    <body>
        <h2>接受消息推送</h2>
    </body>
    <script>
        $(function() {
            dwr.engine.setActiveReverseAjax(true);
            dwr.engine.setNotifyServerOnPageUnload(true);
            messagePush.onPageLoad('<%=session.getAttribute("uid")%>');
        });
    
        function showMessage(autoMessage) {
            $.messager.show({
                title : "消息推送",
                msg : autoMessage,
                showType : 'slide',
                timeout : 5000
            });
        }
    </script>
    </html>
    

    发送页面(sender.jsp)

    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
    <%@ page isELIgnored="false"%>
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <link rel="stylesheet" type="text/css" href="./css/easyui.css">
    <link rel="stylesheet" type="text/css" href="./css/demo.css">
    <script type="text/javascript" src="./js/jquery.js"></script>
    <script type="text/javascript" src="./js/jquery.easyui.min.js"></script>
    <script type='text/javascript' src='/dwr/engine.js'></script>
    <script type='text/javascript' src='/dwr/interface/messagePush.js'></script>
    <title>消息推送</title>
    </head>
    <body>
        <h2>发送消息推送</h2>
        <div id="p" class="easyui-panel"
            style="width: 400px; height: 100x; padding: 10px;">
            <div>
                ID:<input id="uid" style="width: 40%; height: 25px">消息:<input
                    id="msg" style="width: 40%; height: 25px"></br> </br> <a
                    href="javascript:void(0)" style="width: 30%; height: 25px"
                    onclick="sendMsg()">发送</a>
            </div>
        </div>
    </body>
    <script>
        function sendMsg() {
            messagePush.sendMessageAuto($('#uid').val(), $('#msg').val());
            $('#uid').val('');
            $('#msg').val('');
        }
    </script>
    </html>
    

    me/util/MessagePushUtil.java中的内容

    package me.util;
    
    import java.util.Collection;
    
    import javax.servlet.ServletException;
    
    import org.apache.log4j.Logger;
    import org.directwebremoting.Browser;
    import org.directwebremoting.ScriptBuffer;
    import org.directwebremoting.ScriptSession;
    import org.directwebremoting.ScriptSessionFilter;
    import org.directwebremoting.WebContextFactory;
    
    import me.message.MessagePushServlet;
    
    public class MessagePushUtil {
    
        private static final Logger LOGGER = Logger.getLogger(MessagePushUtil.class);
    
        public void onPageLoad(String userID) {
    
            ScriptSession scriptSession = WebContextFactory.get().getScriptSession();
            // 工厂方法get()返回WebContext实例,通过WebContext获取servlet参数
            // ScriptSession与HttpSession类似
            scriptSession.setAttribute("uid", userID);
    
            MessagePushServlet mpServlet = new MessagePushServlet();
            try {
                mpServlet.init();
                LOGGER.info(String.format("消息推送初始化成功,uid:%s", userID));
            } catch (ServletException e) {
                LOGGER.error(String.format("消息推送初始化错误,uid:%s", userID));
            }
    
        }
    
        /**
         * 根据userID向指定用户推送消息
         * 
         * @param userID
         * @param autoMessage
         */
        public void sendMessageAuto(String userID, String autoMessage) {
    
            final String uid = userID;
            final String message = autoMessage;
    
            Browser.withAllSessionsFiltered(new ScriptSessionFilter() {
                // 实现过滤器中的match()方法
                public boolean match(ScriptSession session) {
                    if (session.getAttribute("uid") == null)
                        return false;
                    else
                        return (session.getAttribute("uid")).equals(uid);
                }
            }, new Runnable() {
    
                private ScriptBuffer script = new ScriptBuffer();
    
                public void run() {
                    // 调用JSP中定义的showMessage()方法,实现消息的前端显示
                    script.appendCall("showMessage", message);
                    Collection<ScriptSession> sessions = Browser.getTargetSessions();
                    for (ScriptSession scriptSession : sessions) {
                        scriptSession.addScript(script);
                    }
                    LOGGER.info(String.format("向用户推送消息,uid:%s,message:%s", uid, message));
                }
            });
        }
    }
    

    me/message/MessagePushServlet.java中的内容,覆盖DwrServlet中的init()方法实现ScriptSession监听器,在页面中加入engine.js时,ScriptSession创建,默认由org.directwebremoting.impl.DefaultScriptSessionManager管理,当发生unload事件时,DefaultScriptSessionManager会被通知销毁ScriptSession。

    package me.message;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpSession;
    
    import org.apache.log4j.Logger;
    import org.directwebremoting.Container;
    import org.directwebremoting.ServerContextFactory;
    import org.directwebremoting.WebContextFactory;
    import org.directwebremoting.event.ScriptSessionEvent;
    import org.directwebremoting.event.ScriptSessionListener;
    import org.directwebremoting.extend.ScriptSessionManager;
    import org.directwebremoting.servlet.DwrServlet;
    
    public class MessagePushServlet extends DwrServlet {
    
        private static final long serialVersionUID = 4298890285665323894L;
        private static final Logger LOGGER = Logger.getLogger(MessagePushServlet.class);
    
        @Override
        public void init() throws ServletException {
    
            Container container = ServerContextFactory.get().getContainer();
            // 工厂方法get()返回ServerContext实例
            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("uid");
                    LOGGER.info("a ScriptSession is created");
                    ev.getSession().setAttribute("uid", userID);
                }
    
                public void sessionDestroyed(ScriptSessionEvent ev) {
                    LOGGER.info("a ScriptSession is distroyed");
                }
            };
            manager.addScriptSessionListener(listener);
        }
    }
    

    运行前还要修改Tomcat下的server.xml中的配置

    <!--
    <Connector connectionTimeout="20000" port="8080" 
    protocol="HTTP/1.1" redirectPort="8443"/>
    -->
    <Connector URIEncoding="UTF-8" connectionTimeout="20000" port="8080"
    protocol="org.apache.coyote.http11.Http11NioProtocol" redirectPort="8443"/>
    

    运行项目,打开http://localhost:8080/receiver.jsp,页面加载时,调用

    messagePush.onPageLoad('<%=session.getAttribute("uid")%>');

    调用服务端的me.util.MessagePushUtil.onPageLoad(String userID)方法,初始化成功(可以使用字符串,如"123456789",替换'<%=session.getAttribute("uid")%>')。打开http://localhost:8080/sender.jsp,填写刚才的uid(123456789)和消息内容,点击发送,调用

    messagePush.sendMessageAuto($('#uid').val(), $('#msg').val());

    调用服务端的me.util.MessagePushUtil.sendMessageAuto(String userID, String autoMessage)方法,调用receiver.jsp的showMessage(autoMessage)方法,可以在接收页面看到来自服务端推送的消息。

    页面预览如下,

    发送页面发送页面
    接收页面接收页面

    除此之外,在log4j.properties中添加类似的配置

    log4j.rootCategory=INFO, console
    log4j.category.org.directwebremoting.log=INFO, dwr, console
    
    log4j.appender.console=org.apache.log4j.ConsoleAppender
    log4j.appender.console.layout=org.apache.log4j.PatternLayout
    log4j.appender.console.layout.ConversionPattern=[%5p] %d{yyyy-MM-dd HH:mm:ss} %l - %m%n
    
    log4j.appender.dwr=org.apache.log4j.RollingFileAppender
    log4j.appender.dwr.File=../logs/dwr.log
    log4j.appender.dwr.MaxFileSize=100KB
    log4j.appender.dwr.MaxBackupIndex=1
    log4j.appender.dwr.layout=org.apache.log4j.PatternLayout
    log4j.appender.dwr.layout.ConversionPattern=[%5p] %d{yyyy-MM-dd HH:mm:ss} %l - %m%n
    

    参考资料

    DWR3实现服务器端向客户端精确推送消息
    DWR简单入门
    Reverse Ajax
    Logging

    相关文章

      网友评论

        本文标题:使用DWR实现消息推送

        本文链接:https://www.haomeiwen.com/subject/grjotttx.html