欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

DWR通过后台服务端直接精确推送信息给前台

程序员文章站 2024-03-24 11:33:34
...

需求:我们一个微信客户端收集到用户采集的信息之后,调用接口保存数据库的同时通知pc端指定用户有新信息进来了
决定使用DWR做这个推的功能,我在查询资料之初都是大都是模仿某一位同学的代码给出大概思路,要不缺类,要不缺配置文件,连一个完整的代码都没有,即使按照他们的步骤配出来,总会因为边边角角的错误失败,真的很磨耐心,最后参考了很多同学的资料以及官方文档,实现了我的需求,但痛定思痛,我将这个过程记录下来,希望以后的同学学习DWR能看到我这一篇文章便不再需要再看其它的了,我参考了很多文章和github的代码,就不一一道谢了,日后有人参考我的也是如此,将我们程序员的开源精神发扬光大!
首先我直接把项目地址放出来:
https://github.com/lightTrace/DWR
这是一个动态的web项目,解压后,放到TOMCAT的webapp目录下直接可以运行,在eclipse的话直接import-Existing Projects into workspace 解压的项目,然后再放到tomcat下跑就可以了。
先吃一颗定心丸,如果觉得好,给我一个star哦!

1.首先是web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    id="WebApp_ID" version="2.5">
    <servlet>
        <!-- 指定DWR核心Servlet的名字 -->
        <servlet-name>dwr</servlet-name>
        <servlet-class>
            <!-- 指定DWR核心Servlet的实现类 -->
            org.directwebremoting.servlet.DwrServlet
        </servlet-class>
        <!-- 指定DWR核心Servlet处于调试状态 -->
        <init-param>
            <param-name>debug</param-name>
            <param-value>true</param-value>
        </init-param>
        <!-- 设置使用反向Ajax技术 -->
        <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>60</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

<!-- 下面是我在后文将要提到的一个servlet的设置,注意根据自己程序设置servlet-class和servlet-name区域的值 -->  
    <servlet>  
        <servlet-name>MySevlet</servlet-name>  
        <servlet-class>com.test.DWRServlet</servlet-class>  
    </servlet>  
<!-- 下面是我在后文将要提到的一个servlet的设置,注意根据自己程序设置url-pattern区域的值 -->      
    <servlet-mapping>  
        <servlet-name>MySevlet</servlet-name>  
        <url-pattern>/server/push</url-pattern>  
    </servlet-mapping> 

    <!-- 指定核心Servlet的URL映射 -->
    <servlet-mapping>
        <servlet-name>dwr</servlet-name>
        <url-pattern>/dwr/*</url-pattern>
    </servlet-mapping>
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
</web-app>

就是配置好与DWR相关的文件,其中MySevlet是我直接用来做推送的servlet,放在这里大家记住就好,稍后再说。
2.做一个推送消息的类

package com.test;

import java.util.Collection;
import java.util.LinkedList;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpSession;

import org.directwebremoting.Browser;
import org.directwebremoting.ScriptBuffer;
import org.directwebremoting.ScriptSession;
import org.directwebremoting.ScriptSessionFilter;
import org.directwebremoting.ScriptSessions;
import org.directwebremoting.WebContextFactory;

public class Message {

    public void addMessage(String userid, String message) {
        final String userId = userid;
        final String autoMessage = message;
        System.out.println("To:" + userid + ",Msg:" + message);
        Browser.withAllSessionsFiltered(new ScriptSessionFilter() {
            public boolean match(ScriptSession session) {
                if (session.getAttribute("name") == null)
                    return false;
                else
                    return (session.getAttribute("name")).equals(userId);
                }
            }, new Runnable() {
                private ScriptBuffer script = new ScriptBuffer();

                public void run() {
                    script.appendCall("receiveMessages", autoMessage);
                    Collection<ScriptSession> sessions = Browser
                            .getTargetSessions();
                    for (ScriptSession scriptSession : sessions) {
                        if(scriptSession.getAttribute("name").equals(userId)){
                            scriptSession.addScript(script);
                            break;
                        }
                    }
                }
            });
    }

    public void onPageLoad(String name) {
        HttpSession session = WebContextFactory.get()
                .getSession();
        session.setAttribute("name", name);
        WebContextFactory.get().getScriptSession().setAttribute("name", name);

    }

}

里面有两个方法,addMessage()中userid指的是要推送的标识符,message是推送的信息。
至于onPageLoad方法,是让被推送页面一加载的时候就加载这个方法,将用户标识符通过 WebContextFactory.get().getScriptSession().setAttribute(“name”, name);存入ScriptSession中,然后在addMessage()中就推送到含有标识符的ScriptSession中,而不是推送到所有的ScriptSession中,这就实现了精确推送

3.然后和web.xml同一目录级别配置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 javascript="Message" creator="new" scope="application"><!-- application -->  
        <param name="class" value="com.test.Message"></param>  
    </create> 
</allow>
</dwr>

简单介绍下dwr.xml:
allow段落里面定义的试DWR可以创建和转换的类;
creator属性 是必须的 - 它用来指定使用那种创造器,new: 用Java的new关键字创造对象。
这里需要注意的就是value值是Message的路径不能放错了。
至于DWRScriptSessionListener是用来监听ScriptSession的创建及销毁事件,是为了更好的管理ScriptSession,是个工具类,知道即可。
4.DWRServlet

package com.test;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class DWRServlet
 */
public class DWRServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#HttpServlet()
     */
    public DWRServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doPost(request, response);  
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        Message mg = new Message();
        mg.addMessage(request.getParameter("id"), request.getParameter("message"));//注意这里就是可以进行数据库的查询操作,可以将查询需要推送的信息放到第二个参数,第一个参数自然是我们要指定推送的表示用户
        }
}

DWRServlet是我用来给微信调用的接口,进行数据库的查询后,将所需信息推送给指定用户,当然写完这个类,就要在前面的web.xml配一下,前面说过已经配好了
5.index.jsp
这里我将推送和被推送页面放在一块,如果你使用DWRServlet进行推送,那么这个页面就单独作为一个被推送页面

<%@ page language="java" contentType="text/html; charset=UTF-8"  
    pageEncoding="UTF-8"%>  
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">  
<html>
<head>
<title>starting page</title>
<script type="text/javascript" src="./dwr/engine.js"></script>
<script type="text/javascript" src="./dwr/util.js"></script>
<script type="text/javascript" src="./dwr/interface/Message.js"></script>
<script type="text/javascript" src="js/jquery-1.4.2.js"></script>
<script type="text/javascript">
    var chatlog = "";
    //发送信息
    function sendMessage() {
        var message = $("#message").val();
        var user = $("#user").val();
        Message.addMessage(user, message);
    }
    //接收信息
    function receiveMessages(messages) {
        var lastMessage =  messages;
        chatlog = "<div>" + lastMessage + "</div>" + chatlog;

        dwr.util.setValue("list", chatlog, {
            escapeHtml : false
        });
    }

    //读取name值作为推送的唯一标示
    function onPageLoad(){
        var userId = getQueryString("name");
        $("#myName").html(userId);
        Message.onPageLoad(userId);
     }

    //获取url中的参数
    function getQueryString(name) {
        var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
        var r = window.location.search.substr(1).match(reg);
        if (r != null) return unescape(r[2]); return null;
    }
    //一上来就加载onPageLoad()方法,将读取的name作为唯一标识,这里不一定要从url中取出name作为标识符,只要是该页面唯一的数据都可以是标识符
    $(document).ready(function(){
        dwr.engine.setActiveReverseAjax(true);
        dwr.engine.setNotifyServerOnPageUnload(true);
        onPageLoad();
        }); 

</script>
</head>
<body>
         我是<span id="myName" style="color:red"></span><br/>
         推送给下面这位user<br/>    
    user:<br/>
    <input id="user" type="text" /><br/>
    推送信息为:<br/>
    <input id="message" type="text" value="hey" />
    <input type="button" value="send" onclick="sendMessage()" />
    <br>
    <div id="list"></div>
</body>
</html>

index.jsp就是这么点东西,都有详细注释,大家看看.

首先直接打开参数为a、b、c的三个页面效果图:
通过servlet接口模拟后台直接推送给c,这里a和b接收不到:
DWR通过后台服务端直接精确推送信息给前台
c页面效果图:
DWR通过后台服务端直接精确推送信息给前台

通过页面a推送到页面b:
DWR通过后台服务端直接精确推送信息给前台
页面a推送到页面b效果图,c页面自然接收不到:
DWR通过后台服务端直接精确推送信息给前台