【pushlet学习】具体实战
业务需求:
1. 前端界面需要实时显示空调、照明等设备的状态, 如:空调电压、空调电流、光照强度等,这些量每一个称作一个测点;
采用传统的“请求/响应”方式,很难达到前台界面实时显示最新数据,为达到实时显示最新数据,我们采用一种“服务器推”的技术comet,而pushlet是“服务器推”技术的一种实现,这里我们采用pushlet技术来实现上述业务需求。
1. 前台界面打开时,会将测点名称集合以及主题名传递到后台,格式形如:{[测点1,测点2,测点3,....],subject};并在前台开启对此主题的监听;(注:主题名是动态随机生成的,每个界面的主题名都保证不相同)


主要功能:
package com.guoguo;import java.io.BufferedInputStream;import java.io.IOException;import java.io.InputStream;import java.util.ArrayList;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.stringtree.json.JSONReader;import org.stringtree.json.JSONValidatingReader;public class TestServlet extends HttpServlet {private static final long serialVersionUID = 1L;public TestServlet() {super();}/*** get/post方法的处理函数*/protected void service(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {// 读取请求报文数据request.setCharacterEncoding("UTF-8");// 获取请求的数据StringBuffer reqData = new StringBuffer();InputStream in = request.getInputStream();BufferedInputStream buf = new BufferedInputStream(in);byte[] buffer = new byte[1024];int iRead;while ((iRead = buf.read(buffer)) != -1) {reqData.append(new String(buffer, 0, iRead, "UTF-8"));}// 获取请求的测点名称数组JSONReader r = new JSONValidatingReader();@SuppressWarnings("unchecked")ArrayList<Object> keyList = (ArrayList<Object>) r.read(reqData.toString());// 获取订阅主题名称String aSubject = request.getParameter("subject");System.out.println("请求的测点:" + reqData.toString() + " , 主题名:" + aSubject);// 启动一个线程,实现创建Pushlet事件、做业务、向前台推送数据等功能PushThread pushThread = new PushThread(aSubject, keyList);pushThread.start();}}
- 获取各测点的值;
- 将各测点的值组装成字符串;
- 将该字符串设置为事件源的属性。
package com.guoguo;import java.text.SimpleDateFormat;import java.util.ArrayList;import java.util.Date;import java.util.HashMap;import java.util.Random;import org.stringtree.json.JSONValidatingWriter;import nl.justobjects.pushlet.core.Dispatcher;import nl.justobjects.pushlet.core.Event;import nl.justobjects.pushlet.core.Session;import nl.justobjects.pushlet.core.SessionManager;public class PushThread extends Thread {// 主题public String aSubject; // 客户端传递过来// 关键字列表public ArrayList<Object> keyList; // 客户端传递过来/*** 构造函数** @param aSubject* @param keyList*/public PushThread(String aSubject, ArrayList<Object> keyList) {this.aSubject = aSubject;this.keyList = keyList;}@Overridepublic void run() {Event event = Event.createDataEvent(aSubject);int i = 0;while (true) {try {Thread.sleep(5000);} catch (InterruptedException e) {// 线程阻塞,结束线程System.out.println("=========>sleep异常 --->" + "线程"+ Thread.currentThread().getId() + "关闭");break;}System.out.println("\n-----Thread ID: "+ Thread.currentThread().getId());// 判断当前连接的会话个数,没有会话,则线程退出Session[] sessions = SessionManager.getInstance().getSessions();// 当前无会话,结束线程if (0 == sessions.length) {System.out.println("=========>无sessions --->" + "线程"+ Thread.currentThread().getId() + "关闭");break;}// 判断当前会话中是否存在订阅该主题的订阅者,不存在则结束线程boolean if_exist_subscriber = true;// 遍历所有sessionfor (int j = 0; j < sessions.length; j++) {System.out.println(sessions[j].getSubscriber().match(event) == null ? "Session"+ j + ": 未订阅该事件 ": "Session" + j + ":订阅了该事件 ");if (null != sessions[j].getSubscriber().match(event)) {if_exist_subscriber = false;}}if (if_exist_subscriber) {System.out.println("=========>无"+aSubject+"订阅者 --->" + "线程" + Thread.currentThread().getId() + "关闭");break;}// 模拟业务处理:获取各测点的值HashMap<Object, Object> ret_value = new HashMap<Object, Object>();for (Object keyStr : keyList) {SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss");// 设置日期格式String currTm = df.format(new Date());ret_value.put(keyStr, currTm);// ret_value.put(keyStr, (10*(new Random().nextFloat())));}// 将返回值封装为json数据形式String ret_string = "[";ret_string += new JSONValidatingWriter().write(ret_value);ret_string += "]";event.setField("key1", ret_string);// 推送消息Dispatcher.getInstance().multicast(event); // 向所有和event名称匹配的事件推送}}}
## Properties file for EventSource objects to be instantiated.## Place this file in the CLASSPATH (e.g. WEB-INF/classes) or directly under WEB-INF.## $Id: sources.properties,v 1.2 2007/11/10 14:12:16 justb Exp $## Each EventSource is defined as <key>=<classname># 1. <key> should be unique within this file but may be any name# 2. <classname> is the full class name### Define Pull Sources here. These classes must be derived from# nl.justobjects.pushlet.core.EventPullSource# Inner classes are separated with a $ sign from the outer class.source1=nl.justobjects.pushlet.test.TestEventPullSources$TemperatureEventPullSourcesource2=nl.justobjects.pushlet.test.TestEventPullSources$SystemStatusEventPullSourcesource3=nl.justobjects.pushlet.test.TestEventPullSources$PushletStatusEventPullSourcesource4=nl.justobjects.pushlet.test.TestEventPullSources$AEXStocksEventPullSourcesource5=nl.justobjects.pushlet.test.TestEventPullSources$WebPresentationEventPullSourcesource6=nl.justobjects.pushlet.test.TestEventPullSources$PingEventPullSourcesource7=nl.justobjects.pushlet.test.TestEventPullSources$MyEventPullSourcesource8=nl.justobjects.pushlet.test.TestEventPullSources$SpEventPullSource# TO BE DONE IN NEXT VERSION# define Push Sources here. These must implement the interface# nl.justobjects.pushlet.core.EventSource
这里主要是配置servlet:TestServlet,其他servlet用不到
<?xml version="1.0" encoding="UTF-8"?><web-app><!-- Define the pushlet servlet --><servlet><servlet-name>pushlet</servlet-name><servlet-class>nl.justobjects.pushlet.servlet.Pushlet</servlet-class><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>pushlet</servlet-name><url-pattern>/pushlet.srv</url-pattern></servlet-mapping><servlet><display-name>ChatServlet</display-name><servlet-name>ChatServlet</servlet-name><servlet-class>com.guoguo.ChatServlet</servlet-class></servlet><servlet-mapping><servlet-name>ChatServlet</servlet-name><url-pattern>/ChatServlet</url-pattern></servlet-mapping><servlet><display-name>TestServlet</display-name><servlet-name>TestServlet</servlet-name><servlet-class>com.guoguo.TestServlet</servlet-class></servlet><servlet-mapping><servlet-name>TestServlet</servlet-name><url-pattern>/TestServlet</url-pattern></servlet-mapping></web-app>
前台界面,主要功能如下:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%String path = request.getContextPath();String basePath = request.getScheme() + "://"+ request.getServerName() + ":" + request.getServerPort()+ path + "/";%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><base href="<%=basePath%>"><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="<%=basePath%>js/pushlet_js/ajax-pushlet-client.js"></script><script type="text/javascript">var subscriptionId = null;window.onload = onInit;window.onbeforeunload = onUnsubscribe;// 监听后台返回的数据信息,更新页面function onData(event) {// 保存订阅编号,用于页面关闭时进行退订subscriptionId = event.get('p_sid');// 更新页面document.dataEventDisplay.event.value = event.get("key1");// ------实际案例处理(test)---------/* var respData = decodeURIComponent(event.get("key1"));var respObj = eval(respData);//var respActionNum = respObj.length;var obj = respObj[0];var str = "";for(var p in obj){if(typeof(obj[p]) != "function"){str += p + "=" + obj[p] + ", " ;}}alert(str); */}// 页面关闭时,取消订阅function onUnsubscribe() {if (subscriptionId != null) {PL.unsubscribe(subscriptionId);}}// 页面加载完,初始化请求、监听function onInit() {var aSubject = _getRandomString(6); //主题名var httpRequest = getXMLHttpRequest();if (httpRequest) {var reqData = getData();httpRequest.onreadystatechange = function() {if (httpRequest.readyState == 4) {if (httpRequest.status == 200) {// 请求成功,起pushlet监听PL._init();PL.joinListen(aSubject);} else {alert("实时请求失败!\n" + httpRequest.statusText);}}}url = '<%=request.getContextPath()%>' + '/TestServlet'+ '?subject=' + aSubject;httpRequest.open("POST", url, true);httpRequest.send(reqData);}}// 请求关键字function getData() {var reqData = "[30200000001010, 30200000001012, 30800000003009, 30800000006009]";return reqData;}// 获取http请求function getXMLHttpRequest() {req = false;//本地XMLHttpRequest对象if (window.XMLHttpRequest) {try {req = new XMLHttpRequest();} catch (e) {req = false;}//IE/Windows ActiveX版本} else if (window.ActiveXObject) {try {req = new ActiveXObject("Msxml2.XMLHTTP");} catch (e) {try {req = new ActiveXObject("Microsoft.XMLHTTP");} catch (e) {req = false;}}}return req;}// 获取长度为len的随机字符串function _getRandomString(len) {var len = len || 32;var chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz';var maxPos = chars.length;var pwd = '';for (i = 0; i < len; i++) {pwd += chars.charAt(Math.floor(Math.random() * maxPos));}return pwd;}</script></head><body><form name="dataEventDisplay"><table border="2" bordercolor="white" cellpadding="0" cellspacing="0"><tr><td><textarea cols="60" rows="10" name="event">没有消息 </textarea></td></tr></table></form><button onclick="onUnsubscribe()">取消订阅</button></body></html>

















附件列表
【pushlet学习】具体实战的更多相关文章
- NGUI 学习笔记实战之二——商城数据绑定(Ndata)
上次笔记实现了游戏商城的UI界面,没有实现动态数据绑定,所以是远远不够的.今天采用NData来做一个商城. 如果你之前没看过,可以参考上一篇博客 NGUI 学习笔记实战——制作商城UI界面 ht ...
- 深度学习入门实战(二)-用TensorFlow训练线性回归
欢迎大家关注腾讯云技术社区-博客园官方主页,我们将持续在博客园为大家推荐技术精品文章哦~ 作者 :董超 上一篇文章我们介绍了 MxNet 的安装,但 MxNet 有个缺点,那就是文档不太全,用起来可能 ...
- Android JNI学习(二)——实战JNI之“hello world”
本系列文章如下: Android JNI(一)——NDK与JNI基础 Android JNI学习(二)——实战JNI之“hello world” Android JNI学习(三)——Java与Nati ...
- Spring的学习与实战(续)
@ 目录 背景 JavaMailSender Spring集成邮件发送功能 1. 添加maven依赖 2. 添加Spring邮件配置 3. 创建邮件管理Bean并注入Spring应用上下文 4. 修改 ...
- Github点赞超多的Spring Boot学习教程+实战项目推荐!
Github点赞接近 100k 的Spring Boot学习教程+实战项目推荐! 很明显的一个现象,除了一些老项目,现在 Java 后端项目基本都是基于 Spring Boot 进行开发,毕竟它这 ...
- 深度学习入门实战(一):像Prisma一样算法生成梵高风格画像
本文由云+社区发表 作者:董超 导语:现在人工智能是个大热点,而人工智能离不开机器学习,机器学习中深度学习又是比较热门的方向,本系列文章就从实战出发,介绍下如何使用MXnet进行深度学习~ 既然是实战 ...
- Flask框架的学习与实战(一):开发环境搭建
Flask是一个使用 Python 编写的轻量级 Web 应用框架.其 WSGI 工具箱采用 Werkzeug ,模板引擎则使用 Jinja2.很多功能的实现都参考了django框架.由于项目需要,在 ...
- 1 如何使用pb文件保存和恢复模型进行迁移学习(学习Tensorflow 实战google深度学习框架)
学习过程是Tensorflow 实战google深度学习框架一书的第六章的迁移学习环节. 具体见我提出的问题:https://www.tensorflowers.cn/t/5314 参考https:/ ...
- Shiro入门学习与实战(一)
一.概述 1.Shiro是什么? Apache Shiro是java 的一个安全框架,主要提供:认证.授权.加密.会话管理.与Web集成.缓存等功能,其不依赖于Spring即可使用: Spring S ...
随机推荐
- Taffy自动化测试框架Web开发,Python Flask实践详解
1. 前言 最近为Taffy自动化测试框架写了个页面,主要实现了用例管理.执行,测试报告查看管理.发送邮件及配置等功能. 本页面适用所有基于taffy/nose框架编写的自动化测试脚本,或基于un ...
- noip2007-4
首先预处理f[i][j]表示i到j的路径 然后枚举i,j,如果f[i][j]<=s,那么 寻找最大的k,计算路径距离 计算最短的 代码: #include<bits/stdc++.h> ...
- Python & PyCharm & Django 搭建web开发环境(续)
由于Django自带轻量级的server,因此在前篇博文中,默认使用该server,但实际生产中是不允许这么干的,生产环境中通常使用Apache Httpd Server结合mod_wsgi.so来做 ...
- 为何 Delphi的 Local Variables 突然没有值显示了
可能是上次编译后 code未再修改过. 试试 随便 输入一个空格,然后F9
- express学习-express搭建后台
前言:本文是纯用node express做一个后端服务的教程,并不等同于express官网的入门教程,本文也并不涉及任何高级的Node服务端性能优化等知识. 本文是在已经看过express官方入门指南 ...
- Apache 子项目 概述
apache HTTP Server--------Web服务器(多用于静态网页,有负载均衡效果,可承受每天数百万人访问).apache Abdera>>>>>>& ...
- DevExpress v17.2新版亮点——CodeRush篇(一)
用户界面套包DevExpress v17.2日前终于正式发布,本站将以连载的形式为大家介绍各版本新增内容.本文将介绍了CodeRush v17.2 的新功能,快来下载试用新版本! Unit Test ...
- C语言基础:枚举.宏 分类: iOS学习 c语言基础 2015-06-10 22:01 20人阅读 评论(0) 收藏
枚举:一组有符号的整型常量,一 一列举所有的状态 枚举常和switch连用 enum week{ monday=1, tuesday, wednesday, thursday, friday, sat ...
- react 部分ES6写法
react+react-router+antd 栗子:https://github.com/Aquarius1993/reactApp 模块: 1. 引入模块 import React from 'r ...
- Eclipse之NDK编译-- Type 'jint' could not be resolved, and JNIEnv, jclass错误解决办法
最近在研究面部识别美白相关的功能.使用的是opencv,就去研究了.今天正好有空就把安装了ndk,安装完成之后就试图去编译demo程序,hellow-jni c代码,一开始编辑就报错了3个错误信息: ...