【DWR系列02】-DWR逆向Ajax即服务器推送
一、简单例子直观认识
1.1 模拟场景
假定项目中需要新增一个功能,管理员发布某些信息,这些信息需要推送到所有已经登录的普通用户页面。
1.2 创建Web项目
简单起见,复用上一篇博客的项目例子,【DWR系列】-DWR简介及入门例子。即在原项目上直接新增测试。项目结构图如下:
1.3 修改web.xml
修改web.xml
,使DWR
支持逆向Ajax
,为接收DWR
请求的servlet
简单的增加一个参数即可:
<init-param>
<param-name>activeReverseAjaxEnabled</param-name>
<param-value>true</param-value>
</init-param>
最终web.xml
如下:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
id="WebApp_ID" version="3.1">
<display-name>testweb</display-name>
<servlet>
<servlet-name>dwr-invoker</servlet-name>
<!-- 接收js的Ajax请求的servlet -->
<servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
<!-- 启用逆向Ajax -->
<init-param>
<param-name>activeReverseAjaxEnabled</param-name>
<param-value>true</param-value>
</init-param>
</servlet> <servlet-mapping>
<servlet-name>dwr-invoker</servlet-name>
<!-- 拦截指定的URL -->
<url-pattern>/dwr/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
org.directwebremoting.servlet.DwrServlet
可以设置为随服务器启动而加载。
1.4 新增被推送页面
新增被推送页面normal.jsp
:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head> <title>My JSP 'index.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<script type='text/javascript' src='dwr/engine.js'></script>
<script type='text/javascript' src='dwr/util.js'></script>
</head> <body>
<h2>逆向Ajax页面,服务器推送</h2>
<span>推送信息:</span><span id="push"></span>
</body>
<script type="text/javascript">
window.onload = function(){
dwr.engine.setActiveReverseAjax(true);
}
</script>
</html>
注意需要引入两个js文件,engine.js
和util.js
,并在页面加载完后声明启用逆向Ajax。
1.5 服务端推送代码
复用上一篇博客的HelloWorld
,在有参无返回值方法内,将传递给后台的信息,推送给登录的页面,这也符合开始的需求:
/**
* 有参无返回值
*/
public void helloYN(final String name){
System.out.println(new Date().toLocaleString() + " js访问helloYN方法,name=" + name); //将接收到的内容推送到所有的浏览器
Browser.withAllSessions(new Runnable(){
@Override
public void run(){
Util.setValue("push",name);
}
});
}
这样,就可以用第一篇博客的例子进行测试了。
1.6 测试
首先启动项目,然后访问index.jsp
模拟管理员登录,再开两个浏览器或者标签页,登录normal.jsp
模拟普通用户登录,登录如下:
第一个为上一个篇博客的js调用Java方法页面,下面两个模拟普通用户登录,然后在有参无返回值输入框输入文本,点击按钮发送观察下面了个页面,发现内容几乎立即显示出来:
二、逆向Ajax简介
2.1 简介
逆向Ajax
俗称服务端推送
,但是实际意义上的服务端推送在现有条件下是实现不了的,可以设想一下,若服务端可以主动推送内容到客户端,那么当访问恶意网站的时候,会有可能被推送病毒或者木马。所以一般所谓的服务器端推送都是通过其它方式来实现的,比如说轮询或者长连接。
DWR的逆向Ajax(Reverse Ajax)有三种模式:
- Polling:轮询模式,DWR会以一个固定时间为周期去服务器获取数据,这种方式和自己编写循环执行Ajax一样。
- Comet:长连接模式,就是服务端持有请求,并不断的发送数据信息。上面的例子即是Comet模式。
- Piggyback:捎带模式,即当有推送需求时,等待下一次Ajax请求一并把数据发送过去。
2.2 各种模式选择
实现简单的对这三种模式进行比较:
- 响应速度:
Comet
(几乎瞬时)>Polling
(可自由设置轮询时间)>Piggyback
(因其不确定性) - 对服务器压力(连接数较高时):
Comet
>Polling
>Piggyback
通过比较可以发现,高性能等价于高消耗,当系统的主要功能需要用推送来完成且实时性要求高连接数不大的情况下可以使用Comet,连接数较大且对实时性没有较高要求(一分钟或以上)可以使用Polling,不建议使用Piggyback。
三、逆向推送进阶
不管使用哪种逆向推送都会面临一个问题,那就是被推送客户端的选择问题,大多数情况消息需要被推送到指定的客户端或指定角色的一系列客户端。首先通过下面一个例子进行直观认识。
3.1 创建Web项目
依然为了简便起见,复用原有项目。在上面进行简单修改。
3.2 设置不同属性值
既然要选择不同的客户端进行推送,就要有选择的依据,Web项目中常用的选择依据就是根据用户不同,进行区分。但是要有用户就要有登录模块,再次通过其它方式进行模拟。
3.2.1 通过URL将用户传入
在访问被推送页面的时候,将用户ID通过参数传递给JSP,例如:
http://localhost:8080/dwr/normal.jsp?userId=yiwangzhibujian
3.2.2 设置到session中
再将获取到的userId
放到session
,至此就模拟完登录过程:
String userId=request.getParameter("userId");
session.setAttribute("userId",userId);
正常系统的登录操作一般都会讲用户ID放到session中,此处进行简单模拟。
3.3 新增js
之前已经在normal.jsp
中开启了逆向Ajax功能,现在则需要开启关闭页面提醒服务器功能:
dwr.engine.setNotifyServerOnPageUnload(true);
然后将此进行注册(注册说法有些不妥当,先这么理解,后续会对功能进行详细解释):
HelloWorld.regist();
注册复用了HelloWorld
类,在里面新增了一个方法。
最终normal.jsp
如下:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head> <title>My JSP 'index.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<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/HelloWorld.js'></script>
<%
//模拟登录
//获取登录用户
String userId=request.getParameter("userId");
//将登录用户放到session中
session.setAttribute("userId",userId);
%>
</head> <body>
<h2>逆向Ajax页面,服务器推送,当前用户:${userId }</h2>
<span>推送信息:</span><span id="push"></span>
</body>
<script type="text/javascript">
window.onload = function(){
//开启逆向Ajax功能
dwr.engine.setActiveReverseAjax(true);
//开启关闭页面提醒服务器功能
dwr.engine.setNotifyServerOnPageUnload(true);
//对当前用户进行注册
HelloWorld.regist();
}
</script>
</html>
后续将对注释内容进行详解。
3.4 修改服务端类
依然复用HelloWorld
类,实际项目中最好不这么做:
3.4.1 新增注册方法
/**
* 当页面开启时注册用户
*/
public void regist(){
// 获取当前的scriptSession
ScriptSession scriptSession=WebContextFactory.get().getScriptSession();
//获取HttpSession 并获得其中的userId
HttpSession session=WebContextFactory.get().getSession();
String userId=(String) session.getAttribute("userId");
// 对当前scriptSession的key设置指定的值
scriptSession.setAttribute("key",userId);
}
这个方法实际工作是将不同的属性值放置到ScriptSession
中供过滤器使用,实际工作中可以使用监听器ScriptSessionListener
来完成这个工作。
3.4.2 新增推送方法
推送方法我们复用HelloWorld
的有参有返回值方法,这样可以将传入的参数进行推送,传入参数限定格式为,推送用户 推送内容(忽略校验,请按格式输入):
/**
* 有参有返回值
*/
public String helloYY(final String name){
//获得传入的值进行分解,推送用户 推送内容
final String[] param=name.split("[ ]{1,}");
System.out.println(new Date().toLocaleString() + " js访问helloYY方法,name=" + name);
//对符合条件的用户进行推送
Browser.withAllSessionsFiltered(new ScriptSessionFilter(){ @Override
public boolean match(ScriptSession session){
boolean isYou=param[0].equals(session.getAttribute("key"));
return isYou;
}
},new Runnable(){ @Override
public void run(){
Util.setValue("push",param[1]);
}
});
return "给" + param[0] + "成功推送一条消息";
}
最终的HelloWorld类内容如下:
package yiwangzhibujian; import javax.servlet.http.HttpSession; import org.directwebremoting.*;
import org.directwebremoting.ui.dwr.Util; import java.util.Date; /**
* @author yiwangzhibujian
*/
@SuppressWarnings("deprecation")
public class HelloWorld{ /**
* 无参无返回值
*/
public void helloNN(){
System.out.println(new Date().toLocaleString() + " js访问helloNN方法");
} /**
* 有参无返回值
*/
public void helloYN(final String name){
System.out.println(new Date().toLocaleString() + " js访问helloYN方法,name=" + name); // 将接收到的内容推送到所有的浏览器
Browser.withAllSessions(new Runnable(){
@Override
public void run(){
Util.setValue("push",name);
}
}); } /**
* 无参有返回值
*/
public String helloNY(){
System.out.println(new Date().toLocaleString() + " js访问helloNY方法");
return "Hello World!";
} /**
* 有参有返回值
*/
public String helloYY(final String name){
// 获得传入的值进行分解,推送用户 推送内容
final String[] param=name.split("[ ]{1,}");
System.out.println(new Date().toLocaleString() + " js访问helloYY方法,name=" + name);
// 对符合条件的用户进行推送
Browser.withAllSessionsFiltered(new ScriptSessionFilter(){ @Override
public boolean match(ScriptSession session){
boolean isYou=param[0].equals(session.getAttribute("key"));
return isYou;
}
},new Runnable(){ @Override
public void run(){
Util.setValue("push",param[1]);
}
});
return "给" + param[0] + "成功推送一条消息";
} /**
* 当页面开启时注册用户
*/
public void regist(){
// 获取当前的scriptSession
ScriptSession scriptSession=WebContextFactory.get().getScriptSession();
// 获取HttpSession 并获得其中的userId
HttpSession session=WebContextFactory.get().getSession();
String userId=(String) session.getAttribute("userId");
// 对当前scriptSession的key设置指定的值
scriptSession.setAttribute("key",userId);
}
}
3.5 测试
依然和上面的测试一样,登录三个页面,第一个为推送信息页面,后两个为用户页面,注意带上用户参数:
然后在第一个页面的有参有返回值框进行输入测试,测试结果如下:
测试结果通过,可以进行精准推送。
看这篇博客请先看,【DWR系列01】-DWR简介及入门例子:http://www.cnblogs.com/yiwangzhibujian/p/6145371.html
这一篇简单的介绍了DWR的逆向Ajax即服务端推送,并对服务端精准推送进行了简单的介绍。至此基本介绍完DWR的主要功能,更详细的介绍和源码分析会写在后续的博客中。
【DWR系列02】-DWR逆向Ajax即服务器推送的更多相关文章
- HTML5服务器推送消息的各种解决办法
摘要 在各种BS架构的应用程序中,往往都希望服务端能够主动地向客户端推送各种消息,以达到类似于邮件.消息.待办事项等通知. 往BS架构本身存在的问题就是,服务器一直采用的是一问一答的机制.这就意味着如 ...
- HTML5服务器推送消息的各种解决办法,html5服务器
HTML5服务器推送消息的各种解决办法,html5服务器 摘要 在各种BS架构的应用程序中,往往都希望服务端能够主动地向客户端推送各种消息,以达到类似于邮件.消息.待办事项等通知. 往BS架构本身存在 ...
- DWR第二篇之逆向Ajax
1. 本示例在第一篇架构基础上添加代码 2. 首先修改web.xml里dwr的servlet配置: <!-- 配置dwr请求的servlet --> <servlet> < ...
- DWR3.0框架入门(2) —— DWR的服务器推送
DWR3.0框架入门(2) —— DWR的服务器推送 DWR 在开始本节内容之前,先来了解一下什么是服务器推送技术和DWR的推送方式. 1.服务器推送技术和DWR的推送方式 传统模式的 Web ...
- Web端服务器推送技术原理分析及dwr框架简单的使用
1 背景 “服务器推送技术”(ServerPushing)是最近Web技术中最热门的一个流行术语.它是继“Ajax”之后又一个倍受追捧的Web技术.“服务器推送技术”最近的流行跟“Ajax ”有着密切 ...
- SSE技术详解:一种全新的HTML5服务器推送事件技术
前言 一般来说,Web端即时通讯技术因受限于浏览器的设计限制,一直以来实现起来并不容易,主流的Web端即时通讯方案大致有4种:传统Ajax短轮询.Comet技术.WebSocket技术.SSE(Ser ...
- web服务器推送技术
传统模式的 Web 系统以客户端发出请求.服务器端响应的方式工作.不能满足很多现实应用的需求,譬如: 监控系统:后台硬件温度.电压发生变化: 即时通信系统:其它用户登录.发送信息: 即时报价系统:后台 ...
- 前端通信:SSE设计方案(二)--- 服务器推送技术的实践以及一些应用场景的demo(包括在线及时聊天系统以及线上缓存更新,代码热修复案例)
距离上一篇博客,这篇文章的发布大概过了整整三个月.我也从饿了么度过了试用期,成为了正式员工.刚进来恰好遇到项目底层改造和迁移,将项目从angular全部迁移到vue上,所以适应这边的节奏和业务的开发任 ...
- 浅入浅出“服务器推送”之一:Comet简介
最近有个项目,其中有项需求要从服务器端主动向客户端推送数据,本以为很简单,但在实际做的过程中发现很棘手,并没有想象中的简单.从网上搜索学习,发现主流讲的还是Ajax的长轮询技术或者流技术,websoc ...
随机推荐
- 远程访问jupyter notebook
远程访问Jupyter Notebook Jupyter Notebook很好用,但是直接远程在服务器上用体验当然不如本地计算机好,那么如何远程访问呢? 首先需要在服务器上安装好ipython, ju ...
- 关于elasticsearch和kibana的时区和日期问题
elasticsearch原生支持date类型,json格式通过字符来表示date类型.所以在用json提交日期至elasticsearch的时候,es会隐式转换,把es认为是date类型的字符串直接 ...
- Sed、Awk单行脚本快速参考
文本间隔: # 在每一行后面增加一空行 sed G awk '{printf("%s\n\n",$0)}' # 将原来的所有空行删除并在每一行后面增加一空行. # 这样在输出的文本 ...
- MySQL安装与设置
下载zip,配置 1,系统变量添加:...\mysql-5.7.10-winx64,环境变量添加:%MYSQL_HOME%\bin 2,修改MySQL.ini basedir=(同系统变量路径) da ...
- PHP通过XML报文格式的POST请求方式,与第三方接口交互(发送xml,获取XML,并解析xml步骤)
开发者端:发送请求,并接收结果 <?php // 下面的demo,实现的功能如下: // 1-开发者需要判断一个用户是否存在,去请求第三方接口. // 2-与第三方接口的通信,是以xml格式传送 ...
- 推荐eclipse插件Properties Editor
需求:一般我们在做"国际化"功能时,我们需要properties中文表示方式用unicode表示.eclipse默认properties文件编辑器不方便查看,需要我们查看常常查找u ...
- java日期工具类
public class UtilDate { /** 年月日时分秒(无下划线) yyyyMMddHHmmss */ public static final String dtLong = " ...
- 读书笔记-JavaScript面向对象编程(一)
PDF下载链接: http://pan.baidu.com/s/1eSDSTVW 密码: 75jr 第1章 引言 1.1 回顾历史 1.2 变革之风 1.3 分析现状 1.4 展望未来 1.5 面向对 ...
- 异步select
server coding: #!/usr/bin/python # -*- coding: utf-8 -*- import select import socket import sys impo ...
- Ubuntu14.04安装配置web/ftp/tftp/dns服务器
目录: 1.安装ftp服务器vsftpd --基于tcp,需要帐号密码 2.安装tftp服务器tftpd-hpa,tftp-hpa --udp 3.web服务器--使用Apache2+Mysql+PH ...