1 JSON概念
1、JSON数据格式
- JSON(JavaScript Object Notation)一种简单的数据格式,比xml更轻巧。JSON是JavaScript原生格式,这意味着在JavaScript中处理JSON数据不需要任何特殊的API或工具包。
- JSON的规则很简单:对象是一个无序的“‘名称/值’对”集合。一个对象以“{”(左括号)开始,“}”(右括号)结束。每个“名称”后跟一个“:”(冒号);“‘名称/值’对”之间使用“,”(逗号)分隔。
规则如下:- 映射用冒号(“:”)表示。名称:值。
- 并列的数据之间用逗号(“,”)分隔。
- 映射的集合(对象)用大括号(“{}”)表示。
- 并列数据的集合(数组)用方括号(“[]”)表示。
- 元素值可具有的类型:string, number, object, array, true, false, null。
- 解析JSON
JSON 只是一种文本字符串。它被存储在responseText属性中
为了读取存储在responseText属性中的 JSON 数据,需要根据JavaScript的eval语句。
函数eval会把一个字符串当作它的参数。然后这个字符串会被当作JavaScript代码来执行。因为JSON的字符串就是由JavaScript代码构成的,所以它本身是可执行的。
Demo1
Demo2
Demo3
Demo4
Demo5
注:json的值可以是双引号括起来的字符串、数值、true、false、null、对象或者数组。这些结构可以嵌套。
2 JSON-lib
<1>JSON-lib 是一个java类库
- 转换javabeans,maps,collections,java arrays和XML成为json格式数据
转换json格式数据成为javabeans 对象 - 需要jar包
jakarta commons-lang 2.5
jakarta commons-beanutils 1.8.0
jakarta commons-collections 3.2.1
jakarta commons-logging 1.1.1
ezmorph 1.0.6
注:Google的GSON和JSON-lib的功能基本上是一致的。
json06.html
JsonServlet.java
public class JsonServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType( "text/html;charset=utf-8");
PrintWriter out = response.getWriter();
// String json = “[{‘province’:‘吉林省’},{‘province’:‘辽宁省’},{‘province’:‘山东省’}]”;
//模拟查询数据库
List<Province> list = new ArrayList<Province>();
Province p1 = new Province(1, "吉林省" );
Province p2 = new Province(1, "辽宁省" );
Province p3 = new Province(1, "山东省" );
list.add(p1);
list.add(p2);
list.add(p3);
JSONArray json = JSONArray. fromObject(list);
out.println(json.toString());
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType( "text/html");
PrintWriter out = response.getWriter();
doGet(request, response);
}
}
JsonUtil.java
public class JsonUtil {
/**
* 将数组转换成String类型的JSON数据格式
*
* @param objects
* @return
*/
public static String array2json(Object[] objects){
JSONArray jsonArray = JSONArray. fromObject(objects);
return jsonArray.toString();
}
/**
* 将list集合转换成String类型的JSON数据格式
*
* @param list
* @return
*/
public static String list2json(List list){
JSONArray jsonArray = JSONArray. fromObject(list);
return jsonArray.toString();
}
/**
* 将map集合转换成String类型的JSON数据格式
*
* @param map
* @return
*/
public static String map2json(Map map){
JSONObject jsonObject = JSONObject. fromObject(map);
return jsonObject.toString();
}
/**
* 将Object对象转换成String类型的JSON数据格式
*
* @param object
* @return
*/
public static String object2json(Object object){
JSONObject jsonObject = JSONObject. fromObject(object);
return jsonObject.toString();
}
/**
* 将XML数据格式转换成String类型的JSON数据格式
*
* @param xml
* @return
*/
public static String xml2json(String xml){
JSONArray jsonArray = (JSONArray) new XMLSerializer().read(xml);
return jsonArray.toString();
}
/**
* 除去不想生成的字段(特别适合去掉级联的对象)
*
* @param excludes
* @return
*/
public static JsonConfig configJson(String[] excludes) {
JsonConfig jsonConfig = new JsonConfig();
jsonConfig.setExcludes(excludes);
jsonConfig.setIgnoreDefaultExcludes( true);
jsonConfig.setCycleDetectionStrategy(CycleDetectionStrategy. LENIENT);
return jsonConfig;
}
}
1 反向Ajax基础知识
-
什么是反向ajax
反向Ajax(Reverse Ajax)本质上则是这样的一种概念:能够从服务器端向客户端发送数据。在一个标准的HTTP Ajax请求中,数据是发送给服务器端的,反向Ajax可以某些特定的方式来模拟发出一个Ajax请求,这些方式本文都会论及,这样的话,服务器就可以尽可能快地向客户端发送事件(低延迟通信)。
-
反向ajax的目的
反向Ajax的目的是允许服务器端向客户端推送信息。Ajax请求在缺省情况下是无状态的,且只能从客户端向服务器端发出请求。你可以通过使用技术模拟服务器端和客户端之间的响应式通信来绕过这一限制。
- 为什么使用反向ajax
web开发在过去的几年中有了很大的进展,我们已经远超了把静态网页链接在一起的做法,这种做法会引起浏览器的刷新,并且要等待页面的加载。现在需要的是能够通过web来访问的完全动态的应用,这些应用通常需要尽可能的快,提供近乎实时的组件。
2 模拟反向ajax
test.js
window.οnlοad=function(){
document.getElementById(“ok”).οnclick=function(){
//setInterval()中的第二个参数是周期。在第一次调用后,会自动按照周期来执行指定函数
t = setInterval(“revAjax()”,1000);
};
document.getElementById("cancel").onclick=function(){
// clearTimeout(t);
clearInterval(t);
}
}
var t;
function revAjax(){
var xmlHttp=ajaxFunction();
xmlHttp.onreadystatechange=function(){
if(xmlHttp.readyState==4){
if(xmlHttp.status==200||xmlHttp.status==304){
var data = xmlHttp.responseText;
document.getElementById("showtime").innerHTML = "<h1>"+data+"</h1>";
}
}
}
xmlHttp.open("get","timeServlet?timeStamp="+new Date().getTime(),true);
xmlHttp.send(null);
// t = setTimeout(revAjax,1000);
}
function ajaxFunction(){
var xmlHttp;
try{ // Firefox, Opera 8.0+, Safari
xmlHttp=new XMLHttpRequest();
}
catch (e){
try{// Internet Explorer
xmlHttp=new ActiveXObject(“Msxml2.XMLHTTP”);
}
catch (e){
try{
xmlHttp=new ActiveXObject(“Microsoft.XMLHTTP”);
}
catch (e){}
}
}
return xmlHttp;
}
testajax.jsp
<%@ page language =“java” pageEncoding=“utf-8” %>
TimeServlet.java
public class TimeServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType( "text/html;charset=utf-8");
PrintWriter out = response.getWriter();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 hh点mm分ss秒" );
String time = sdf.format( new Date());
out.println(time);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType( "text/html");
PrintWriter out = response.getWriter();
doGet(request, response);
}
}
3 实现反向ajax
1、轮询(polling)(主动式)
轮询(polling)涉及了从客户端向服务器端发出请求以获取一些数据,这显然就是一个纯粹的Ajax HTTP请求。为了尽快地获得服务器端事件,轮询的间隔(两次请求相隔的时间)必须尽可能地小。但有这样的一个缺点存在:如果间隔减小的话,客户端浏览器就会发出更多的请求,这些请求中的许多都不会返回任何有用的数据,而这将会白白地浪费掉带宽和处理资源。
<1>HTTP轮询和JSONP轮询
JSONP轮询基本上与HTTP轮询一样,不同之处则是JSONP可以发出跨域请求(不是在你的域内的请求)。清单1使用JSONP来通过邮政编码获取地名,JSONP请求通常可通过它的回调参数和返回内容识别出来,这些内容是可执行的JavaScript代码。
用JavaScript实现的轮询的优点和缺点:
1. 优点:很容易实现,不需要任何服务器端的特定功能,且在所有的浏览器上都能工作。
2. 缺点:这种方法很少被用到,因为它是完全不具伸缩性的。试想一下,在100个客户端每个都发出2秒钟的轮询请求的情况下,所损失的带宽和资源数量,在这种情况下30%的请求没有返回数据。
public final class PollingServlet extends HttpServlet {
private final Random random = new Random();
private final BlockingQueue<String> messages = new LinkedBlockingQueue<String>();
private final Thread generator = new Thread( "Event generator") {
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
Thread. sleep(random.nextInt(5000));
} catch (InterruptedException e) {
Thread. currentThread().interrupt();
}
messages.offer( "At " + new Date());
}
}
};
@Override
public void init() throws ServletException {
generator.start();
}
@Override
public void destroy() {
generator.interrupt();
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
List<String> messages = new LinkedList<String>();
this.messages.drainTo(messages);
resp.setStatus(HttpServletResponse. SC_OK);
resp.setContentType( "application/json");
resp.getWriter().write( new JSONArray(messages).toString());
resp.getWriter().flush();
}
}
<2>Piggyback(被动式)
捎带轮询(piggyback polling)是一种比轮询更加聪明的做法,因为它会删除掉所有非必需的请求(没有返回数据的那些)。不存在时间间隔,客户端在需要的时候向服务器端发送请求。不同之处在于响应的那部分上,响应被分成两个部分:对请求数据的响应和对服务器事件的响应,如果任何一部分有发生的话。
这种方法也有着一些优点和缺点:
- 优点:没有不返回数据的请求,因为客户端对何时发送请求做了控制,对资源的消耗较少。该方法也是可用在所有的浏览器上,不需要服务器端的特殊功能。
- 缺点:当累积在服务器端的事件需要传送给客户端时,你却一点都不知道,因为这需要一个客户端行为来请求它们。
public final class PiggybackServlet extends HttpServlet {
private final Random random = new Random();
private final BlockingQueue messages = new LinkedBlockingQueue();
private final Thread generator = new Thread( “Event generator”) {
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
Thread. sleep(random.nextInt(5000));
} catch (InterruptedException e) {
Thread. currentThread().interrupt();
}
messages.offer( "At " + new Date());
}
}
};
@Override
public void init() throws ServletException {
generator.start();
}
@Override
public void destroy() {generator .interrupt();}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System. out.println(“FORM POSTED !” );
List messages = new LinkedList();
this.messages.drainTo(messages);
resp.setStatus(HttpServletResponse. SC_OK);
resp.setContentType( “application/json”);
try {
resp.getWriter().write( new JSONObject().put(“events” , new JSONArray(messages)).put(“formValid” , true).toString());
} catch (JSONException e) {
throw new ServletException(e.getMessage(), e);
}
resp.getWriter().flush();
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
List messages = new LinkedList();
this.messages.drainTo(messages);
resp.setStatus(HttpServletResponse. SC_OK);
resp.setContentType( “application/json”);
resp.getWriter().write( new JSONArray(messages).toString());
resp.getWriter().flush();
}
}
<3>Comet
使用了轮询或是捎带的反向Ajax非常受限:其不具伸缩性,不提供低延迟通信(只要事件一到达服务器端,它们就以尽可能快的速度到达浏览器端)。Comet是一个web应用模型,在该模型中,请求被发送到服务器端并保持一个很长的存活期,直到超时或是有服务器端事件发生。在该请求完成后,另一个长生存期的Ajax请求就被送去等待另一个服务器端事件。使用Comet的话,web服务器就可以在无需显式请求的情况下向客户端发送数据。
Comet的一大优点是,每个客户端始终都有一个向服务器端打开的通信链路。服务器端可以通过在事件到来时立即提交(完成)响应来把事件推给客户端,或者它甚至可以累积再连续发送。因为请求长时间保持打开的状态,故服务器端需要特别的功能来处理所有的这些长生存期请求。
* 流(streaming)
在流(streaming)模式中,有一个持久连接会被打开。只会存在一个长生存期请求(图3中的#1),因为每个到达服务器端的事件都会通过这同一连接来发送。因此,客户端需要有一种方法来把通过这同一连接发送过来的不同响应分隔开来。从技术上来讲,两种常见的流技术包括Forever Iframe(隐藏的IFrame),或是被用来在JavaScript中创建Ajax请求的XMLHttpRequest对象的多部分(multi-part)特性。
* Forever Iframe
Forever Iframe(永存的Iframe)技术涉及了一个置于页面中的隐藏Iframe标签,该标签的src属性指向返回服务器端事件的servlet路径。每次在事件到达时,servlet写入并刷新一个新的script标签,该标签内部带有JavaScript代码,iframe的内容被附加上这一script标签,标签中的内容就会得到执行。
1. 优点:实现简单,在所有支持iframe的浏览器上都可用。
2. 缺点: 没有方法可用来实现可靠的错误处理或是跟踪连接的状态,因为所有的连接和数据都是由浏览器通过HTML标签来处理的,因此你没有办法知道连接何时在哪一端已被断开了。
* Multi-part XMLHttpRequest
第二种技术,更可靠一些,是XMLHttpRequest对象上使用某些浏览器(比如说Firefox)支持的multi-part标志。Ajax请求被发送给服务器端并保持打开状态,每次有事件到来时,一个多部分的响应就会通过这同一连接来写入。
1. 优点:只打开了一个持久连接,这就是节省了大部分带宽使用率的Comet技术。
2. 缺点:并非所有的浏览器都支持multi-part标志。某些被广泛使用的库,比如说用Java实现的CometD,被报告在缓冲方面有问题。例如,一些数据块(多个部分)可能被缓冲,然后只有在连接完成或是缓冲区已满时才被发送,而这有可能会带来比预期要高的延迟。
public final class ReverseAjaxServlet extends HttpServlet {
private final Queue asyncContexts = new ConcurrentLinkedQueue();
private final String boundary = “ABCDEFGHIJKLMNOPQRST”; // generated
private final Random random = new Random();
private final Thread generator = new Thread( “Event generator”) {
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
Thread. sleep(random.nextInt(5000));
for (AsyncContext asyncContext : asyncContexts) {
HttpServletResponse peer = (HttpServletResponse) asyncContext.getResponse();
peer.getOutputStream().println( “Content-Type: application/json”);
peer.getOutputStream().println();
peer.getOutputStream().println( new JSONArray().put(“At " + new Date()).toString());
peer.getOutputStream().println( “–” + boundary );
peer.flushBuffer();
}
} catch (InterruptedException e) {
Thread. currentThread().interrupt();
} catch (IOException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
}
};
@Override
public void init() throws ServletException {
generator.start();
}
@Override
public void destroy() {
generator.interrupt();
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
AsyncContext asyncContext = req.startAsync();
asyncContext.setTimeout(0);
resp.setContentType( “multipart/x-mixed-replace;boundary=”” + boundary + “”" );
resp.setHeader( “Connection”, “keep-alive” );
resp.getOutputStream().print( “–” + boundary );
resp.flushBuffer();
asyncContexts.offer(asyncContext);
}
}
- 长轮询(long polling)
长轮询(long polling)模式涉及了打开连接的技术。连接由服务器端保持着打开的状态,只要一有事件发生,响应就会被提交,然后连接关闭。接下来。一个新的长轮询连接就会被正在等待新事件到达的客户端重新打开。
- script标签
正如iframe一样,其目标是把script标签附加到页面上以让脚本执行。服务器端则会:挂起连接直到有事件发生,接着把脚本内容发送回浏览器,然后重新打开另一个script标签来获取下一个事件。
-
优点:因为是基于HTML标签的,所有这一技术非常容易实现,且可跨域工作(缺省情况下,XMLHttpRequest不允许向其他域或是子域发送请求)。
-
缺点:类似于iframe技术,错误处理缺失,你不能获得连接的状态或是有干涉连接的能力。
- XMLHttpRequest长轮询
也是一种推荐的实现Comet的做法是打开一个到服务器端的Ajax请求然后等待响应。服务器端需要一些特定的功能来允许请求被挂起,只要一有事件发生,服务器端就会在挂起的请求中送回响应并关闭该请求,完全就像是你关闭了servlet响应的输出流。然后客户端就会使用这一响应并打开一个新的到服务器端的长生存期的Ajax请求。
-
优点:客户端很容易实现良好的错误处理系统和超时管理。这一可靠的技术还允许在与服务器端的连接之间有一个往返,即使连接是非持久的(当你的应用有许多的客户端时,这是一件好事)。它可用在所有的浏览器上;你只需要确保所用的XMLHttpRequest对象发送到的简单的Ajax请求就可以了。
- 缺点:相比于其他技术来说,不存在什么重要的缺点,像所有我们已经讨论过的技术一样,该方法依然依赖于无状态的HTTP连接,其要求服务器端有特殊的功能来临时挂起连接。
public final class ReverseAjaxServlet extends HttpServlet {
private final Queue<AsyncContext> asyncContexts = new ConcurrentLinkedQueue<AsyncContext>();
private final Random random = new Random();
private final Thread generator = new Thread( "Event generator") {
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
Thread. sleep(random.nextInt(5000));
while (!asyncContexts.isEmpty()) {
AsyncContext asyncContext = asyncContexts.poll();
HttpServletResponse peer = (HttpServletResponse) asyncContext.getResponse();
peer.getWriter().write( new JSONArray().put("At " + new Date()).toString());
peer.setStatus(HttpServletResponse. SC_OK);
peer.setContentType( "application/json");
asyncContext.complete();
}
} catch (InterruptedException e) {
Thread. currentThread().interrupt();
} catch (IOException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
}
};
@Override
public void init() throws ServletException {
generator.start();
}
@Override
public void destroy() {
generator.interrupt();
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
AsyncContext asyncContext = req.startAsync();
asyncContext.setTimeout(0);
asyncContexts.offer(asyncContext);
}
}
4 pushlets框架(DWR框架)
Pushlets 是一个开源的 Comet 框架, Pushlets 使用了观察者模型:客户端发送请求,订阅感兴趣的事件;服务器端为每个客户端分配一个会话 ID 作为标记,事件源会把新产生的事件以多播的方式发送到订阅者的事件队列里。
下载pushlets,官方地址:http: //www.pushlets.com/
搭建pushlets开发环境,演示示例:
创建一个web工程
解压缩下载的压缩包
将lib/pushlet.jar包复制到工程中的WEB-INF目录下的lib下
将 webapps\pushlet\WEB-INF\classes目录下所有properties文件复制到工程中的 WEB-INF目录下
将 webapps\pushlet\WEB-INF\web.xml文件的配置信息复制到工程中的 web.xml文件中
复制 lib目录下的ajax-pushlet-client.js文件和assets目录下的util.js文件
复制 example 目录下 chat相关 四个文件
Pushlet工作流程
客户端PL._init(),获取XMLHttpRequest,设置URL、状态。
客户端PL.joinListen (subject),p_event=join-listen-ack,服务端加入、监听、订阅,返回p_event=refresh。
客户端执行refresh,服务器端读取事件,并推送至客户端。
客户端根据收到的事件类型,进行相关操作。
客户端代码示例:
服务器端代码示例:
//向 /money 主题添加事件
public class Money implements Serializable{
public static class MoneyTest extends EventPullSource {
private int i ;
@Override
protected long getSleepTime() {
return 60000; // 10秒
}
@Override
protected Event pullEvent() {
// 用来向主题添加事件
System. out.println("------- " +i );
// 创建/money 主题相关事件
Event event = Event.createDataEvent( "/money");
// 设置事件参数 name value ,客户端通过name 获得 value
event.setField( "testName", "testValue" +i ++);
return event;
}
}
}
向sources.properties文件中,增加自定义内容:
source7=app.pushlet.Money$MoneyTest
web.xml
<?xml version ="1.0" encoding="UTF-8" ?>
<servlet>
<servlet-name> pushlet</servlet-name >
<servlet-class> nl.justobjects.pushlet.servlet.Pushlet</servlet-class >
<load-on-startup> 1</ load-on-startup>
</servlet>
<!-- Define the Servlet Mappings. -->
<!-- The pushlet -->
<servlet-mapping>
<servlet-name> pushlet</servlet-name >
<url-pattern> /pushlet.srv</url-pattern >
</servlet-mapping>
This is the description of my J2EE component This is the display name of my J2EE component TimeServlet app.servlet.TimeServlet TimeServlet /timeServlet index.jsp
chat.html
<title>Pushlet Chat</title>
<link href="chat.css" rel= "stylesheet">
<style type="text/css">
</style>
<script type= "text/javascript" src="util.js" ></script>
<script type= "text/javascript" src="ajax-pushlet-client.js" ></script>
<script type= "text/javascript"><!--
var chatDoc;
var chatFrame;
var nick=getPageParameter( 'nick', 'anon' );
window.onload = chat_init;
function chat_init(){
if (window.frames && window.frames["chatContents"]) //IE 5 (Win/Mac), Konqueror, Safari
chatFrame = window.frames[ "chatContents"];
else if (document.getElementById("chatContents").contentWindow) //IE 5.5+, Mozilla 0.9+, Opera
chatFrame = document.getElementById("chatContents" ).contentWindow;
else //Moz < 0.9 (Netscape 6.0)
chatFrame = document.getElementById( "chatContents");
if(chatFrame.document) //Moz 0.9+, Konq, Safari, IE, Opera
chatDoc = chatFrame.document;
else //Moz < 0.9 (Netscape 6.0)
chatDoc = chatFrame.contentDocument;
enterChat();
document.forms[0].msg.focus();
}
// Event Callback for join
function onJoinAck(event) {
appendMessage( 'Listening to chat');
}
// Event Callback: display all events
function onData(event) {
p_debug( false, "pushlet-app" , 'event received event=' + event.getEvent() );
var action = event.get( 'action');
var content = 'none action=' + action;
if (action == 'send' ) {
content = '<b>' + event.get('nick' ) + '</b>: <i>' + event.get('msg') + '</i>';
} else if (action == 'enter') {
content = '<b><i>*** ' + event.get('nick' ) + ' joined chat ***</i></b>';
} else if (action == 'exit') {
content = '<b><i>*** ' + event.get('nick' ) + ' left chat ***</i></b>';
}
appendMessage(content);
}
// Event Callback: display all events
function onNack(event) {
alert( 'negative response from server: ' + event.getEvent() + ' reason: ' + event.get('p_reason'));
}
function appendMessage (content){
var newDiv = chatDoc.createElement( "DIV");
newDiv.innerHTML = content;
chatDoc.getElementById( "contents").appendChild(newDiv);
chatFrame.scrollTo(0, chatDoc.getElementById("contents" ).offsetHeight);
}
function enterChat(){
p_join_listen( '/chat');
p_publish( '/chat', 'action' , 'enter' , 'nick' , nick);
}
function sendMsg(){
p_publish( '/chat', 'action' , 'send' , 'nick' , nick, 'msg', document.getElementById("msg" ).value);
resetForm();
}
function leaveChat(){
// Send exit to chatters
p_publish( '/chat', 'action' , 'exit' , 'nick' , nick);
// Stop pushlet session
p_leave();
// Give some time to send the leave request to server
setTimeout( 'gotoEnter()', 500);
}
function gotoEnter() {
window.location.href= 'enter.html';
}
function resetForm(){
document.forms[0].msg.value = "";
document.forms[0].msg.focus();
}//-->
</script>
Pushlet Chat (AJAX Version)
[exit]Moeny.java
//向 /money 主题添加事件
public class Money implements Serializable{
public static class MoneyTest extends EventPullSource {
private int i ;
@Override
protected long getSleepTime() {
return 10000; // 10秒
}
@Override
protected Event pullEvent() {
// 用来向主题添加事件
System. out.println("------- " +i );
// 创建/money 主题相关事件
Event event = Event. createDataEvent("/money");
// 设置事件参数 name value ,客户端通过name 获得 value
event.setField( "testName", "testValue" +i ++);
return event;
}
}
}
demo.html
sources.properties
source1=nl.justobjects.pushlet.test.TestEventPullSources
T
e
m
p
e
r
a
t
u
r
e
E
v
e
n
t
P
u
l
l
S
o
u
r
c
e
s
o
u
r
c
e
2
=
n
l
.
j
u
s
t
o
b
j
e
c
t
s
.
p
u
s
h
l
e
t
.
t
e
s
t
.
T
e
s
t
E
v
e
n
t
P
u
l
l
S
o
u
r
c
e
s
TemperatureEventPullSource source2=nl.justobjects.pushlet.test.TestEventPullSources
TemperatureEventPullSourcesource2=nl.justobjects.pushlet.test.TestEventPullSourcesSystemStatusEventPullSource
source3=nl.justobjects.pushlet.test.TestEventPullSources
P
u
s
h
l
e
t
S
t
a
t
u
s
E
v
e
n
t
P
u
l
l
S
o
u
r
c
e
s
o
u
r
c
e
4
=
n
l
.
j
u
s
t
o
b
j
e
c
t
s
.
p
u
s
h
l
e
t
.
t
e
s
t
.
T
e
s
t
E
v
e
n
t
P
u
l
l
S
o
u
r
c
e
s
PushletStatusEventPullSource source4=nl.justobjects.pushlet.test.TestEventPullSources
PushletStatusEventPullSourcesource4=nl.justobjects.pushlet.test.TestEventPullSourcesAEXStocksEventPullSource
source5=nl.justobjects.pushlet.test.TestEventPullSources
W
e
b
P
r
e
s
e
n
t
a
t
i
o
n
E
v
e
n
t
P
u
l
l
S
o
u
r
c
e
s
o
u
r
c
e
6
=
n
l
.
j
u
s
t
o
b
j
e
c
t
s
.
p
u
s
h
l
e
t
.
t
e
s
t
.
T
e
s
t
E
v
e
n
t
P
u
l
l
S
o
u
r
c
e
s
WebPresentationEventPullSource source6=nl.justobjects.pushlet.test.TestEventPullSources
WebPresentationEventPullSourcesource6=nl.justobjects.pushlet.test.TestEventPullSourcesPingEventPullSource
source7=app.pushlet.Money$MoneyTest