DWR通过后台服务端直接精确推送信息给前台
需求:我们一个微信客户端收集到用户采集的信息之后,调用接口保存数据库的同时通知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接收不到:
c页面效果图:
通过页面a推送到页面b:
页面a推送到页面b效果图,c页面自然接收不到:
上一篇: 前端不经过后端直接上传图片到oss
下一篇: Android中的视图属性