一、什么是pushlet?

1.pushlet推送是一种将java后台数据推送到web页面的框架技术,实现了comet。

2.comet是一个用于描述客户端和服务器之间交互的术语,即使用长期保持的http连接来在连接保持畅通的情况下支持客户端和服务器间的事件驱动的通信

3.传统的web系统的工作流程是客户端发出请求,服务器端进行响应,而comet则是在现有技术的基础上,实现服务器数据、事件等快速push到客户端,所以会出现一个术语”服务器推“技术。

Ajax、Comet与Websocket

二、单机

1.项目采用技术

1).后端SSH框架

2).前端jsp

3).接口提供方c#

2.流程

对jsp列表页面的数据处理时调用c#端,当c#端处理完之后会调用java端接口,java端通过接口创建事件发布消息,jsp列表页面会做后端事件监听做数据更新操作。

3.项目结构

将pushlet.jar放到lib目录中,引入到工程,在resources资源目录下添加pushlet.properties和sources.properties配置文件,如下图:

pushlet.properties:pushlet初始化配置

source.properties:消息源配置

4.web.xml配置

    <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> 

5.pushlet.properties

#
# Pushlet configuration.
# Place this file in the CLASSPATH (e.g. WEB-INF/classes) or directly under WEB-INF.
#
# $Id: pushlet.properties,v 1.13 2007/12/07 12:57:40 justb Exp $
##
#
#
config.version=1.0.2#
# CLASS FACTORY SPECIFICATION
#
# Change these if you want to override any of the core classes
# within the Pushlet framework with your own custom classes.
#
# Examples:
# - custom SessionManager for authorisation
# - maintain lists of active subjects (topics)
# - send events on subscription
# - plug in custom logging like log4j
# Note that you must maintain the semantics of each class !
# Below are the default properties for the core classes.
controller.class=nl.justobjects.pushlet.core.Controller
dispatcher.class=nl.justobjects.pushlet.core.Dispatcher
logger.class=nl.justobjects.pushlet.util.Log4jLogger
# logger.class=nl.justobjects.pushlet.util.DefaultLogger
#sessionmanager.class=nl.justobjects.pushlet.core.SessionManager
sessionmanager.class=com.yudu.pushlet.WfSessionManager
session.class=nl.justobjects.pushlet.core.Session
subscriber.class=nl.justobjects.pushlet.core.Subscriber
subscription.class=nl.justobjects.pushlet.core.Subscription# sessionmanager.maxsessions=200#
# DISPATCHER
## TODO: allow properties to be maintained in
# a user dir
# config.redirect=/etc/pushlet.properties#
# LOGGING
## log level (trace(6) debug(5) info (4), warn(3), error(2), fatal(1))
# default is info(4)
log.level=4#
# LOCAL EVENT SOURCES
## should local sources be loaded ?
sources.activate=true#
# SESSION
## algoritm to generate session key:
# values: "randomstring" (default) or "uuid".
# session.id.generation=uuid
session.id.generation=randomstring# length of generated session key when using "randomstring" generation
session.id.size=10# Overall session lease time in minutes
# Mainly used for clients that do not perform
# listening, e.g. when publishing only.
session.timeout.mins=5#
# EVENT QUEUE
#
# Properties for per-client data event queue# Size for
queue.size=24
queue.read.timeout.millis=20000
queue.write.timeout.millis=20#
# LISTENING MODE
## You may force all clients to use pull mode
# for scalability
listen.force.pull.all=false#
# Comma-separated list of User Agent substrings.
# Force these browsers to use pull mode, since they
# don't support JS streaming, matching is done using
# String.indexOf() with lowercased agent strings
# use multiple criteria with &.
#
listen.force.pull.agents=safari#
# PULL MODE
## time server should wait on refresing pull client  45000
pull.refresh.timeout.millis=30000# minimum/maximum wait time client should wait before refreshing
# server provides a random time between these values
pull.refresh.wait.min.millis=2000
pull.refresh.wait.max.millis=3000#
# POLL MODE
## time server should wait on refresing poll client
poll.refresh.timeout.millis=6000# minimum/maximum wait time client should wait before refreshing
# server provides a random time between these values   6000~10000
poll.refresh.wait.min.millis=3000
poll.refresh.wait.max.millis=6000

6.source.properties以及消息源类

#
# 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$TemperatureEventPullSource
#source2=nl.justobjects.pushlet.test.TestEventPullSources$SystemStatusEventPullSource
#source3=nl.justobjects.pushlet.test.TestEventPullSources$PushletStatusEventPullSource
#source4=nl.justobjects.pushlet.test.TestEventPullSources$AEXStocksEventPullSource
#source5=nl.justobjects.pushlet.test.TestEventPullSources$WebPresentationEventPullSource
#source6=nl.justobjects.pushlet.test.TestEventPullSources$PingEventPullSource# $前是消息源类,$后是消息源类的内部类
source1=com.yudu.pushlet.YuduBpmEventPullSources$BpmEventSource# TO BE DONE IN NEXT VERSION
# define Push Sources here. These must implement the interface
# nl.justobjects.pushlet.core.EventSource

YuduBpmEventPullSources.java

package com.yudu.pushlet;import java.io.Serializable;import nl.justobjects.pushlet.core.Event;
import nl.justobjects.pushlet.core.EventPullSource;public class YuduBpmEventPullSources   implements Serializable {  private static final long serialVersionUID = 4677762094577114268L;public static class BpmEventSource extends EventPullSource {   @Override   protected long getSleepTime() {   return 3000;     }   @Override   protected Event pullEvent() {   Event event =Event.createDataEvent("/yudu/ydbpm"); event.setField("ydbpm","ping");   return event;    }   }
} 

7.session管理类

package com.yudu.pushlet;import nl.justobjects.pushlet.core.Event;
import nl.justobjects.pushlet.core.Session;
import nl.justobjects.pushlet.core.SessionManager;
import nl.justobjects.pushlet.util.PushletException;public class WfSessionManager extends SessionManager {/** 创建session 将用户id或者用户登录的sessionid* by oklin 2016* */public Session createSession(Event anEvent) throws PushletException {// Trivial//return Session.create(createSessionId());String userId = anEvent.getField("uid", createSessionId());Session session = SessionManager.getInstance().getSession(userId);if(session != null){//System.out.print("存在session:"+userId);session.stop();//session = SessionManager.getInstance().getSession(userId);//return session;}return Session.create(userId);}}

8.todolist.jsp

<%@ include file="../common/include.jsp"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%><%@ page import="java.util.ResourceBundle" %><%String basePath = path+"/";ResourceBundle res = ResourceBundle.getBundle("ydbpm");%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link href="${path}/css/table.css" rel="stylesheet" type="text/css" />
<link href="${path}/css/base.css" rel="stylesheet" type="text/css" />
<link href="${path}/css/document/documentSearch.css" rel="stylesheet"type="text/css" />
<link href="${path}/tools/jquery-ui/css/smoothness/jquery-ui-1.10.3.custom.min.css" rel="stylesheet" type="text/css" />
<link href="${path}/tools/ztree/css/zTreeStyle/zTreeStyle.css"rel="stylesheet" type="text/css" />
<link href="${path}/css/meetingissues/draft.css" rel="stylesheet"type="text/css" />
<style type="text/css">
.t-main tbody tr:hover {background: #DCE8FA
}
.isFlowEnding {background: #B5CEF4;font-weight: bold;
}.isFlowEnding td {color: red;
}.isTaskEnding {font-weight: bold;
}
</style>
<script type="text/javascript" src="<%=path%>/js/pushlet/ajax-pushlet-client.js"></script>   <script type="text/javascript">    PL._init(); //对pushlet的初始化,触发web.xml中的servlet。   PL.userId='${userInfo.userInfoId}';  PL.joinListen('/yudu/ydbpm'); //这里的监听的主题,必须在sources.properties中配置的对象中声明这个主题。   function onData(event) {   if(event.get("YUDU_WF_MSG")){ switch(event.get("YUDU_WF_MSG")){case "WF_SUBMIT":case "WF_BACK":case "WF_QUIT":location.href=location.href;//location.reload();break;}}}  </script>
<title></title>
</head>
<body><script src="${path}/tools/jquery-ui/js/jquery-ui-1.10.3.custom.min.js" type="text/javascript" charset="UTF-8"></script><script src="${path}/js/document/todolist.js" type="text/javascript" charset="UTF-8"></script>
</body>
</html>

9.todolist.js核心代码

var restate=basePath+"yudu/submitdone.action";//调用java端,完成服务端消息推送
//在调用中间件url中嵌套了java端urlvar url = protocol+"/Viewer.axd?op=forms&uid=" + uid + "&bid=" + bid+"&id="+id+"&catalog=0&ext="+escape(restate)+"&extp="+escape("uid="+uid+"_3");

10.pushlet处理action

package com.yudu.pushlet;import org.apache.commons.lang.StringUtils;import com.ccc.base.action.BaseAction;
import com.ccc.system.model.UserInfo;
import com.yudu.pushlet.PushletUtil;;/** 发送消息* * by oklin 2016-4-22* */
public class SendMsgAction  extends BaseAction {/*** */private static final long serialVersionUID = 1930946576605702484L;public static final String WF_SUBMIT_MSG="WF_SUBMIT"; //提交 1public static final String WF_BACK_MSG="WF_BACK"; //回退 2public static final String WF_QUIT_MSG="WF_QUIT"; //退出 3public static final String WF_ERROR_MSG="WF_ERROR"; //发生错误 4public static final String WF_UNKNOWN_MSG="WF_UNKNOWN"; //未知错误/*** 无法获取session* 所有在一个参数的值中将多个参数的值拼接起来* @return*/public String submitDone() {try {String sessionId = this.getRequest().getParameter("uid").split("_")[0];String msgt = this.getRequest().getParameter("uid").split("_")[1];if(StringUtils.isNotBlank(msgt)){int msgType = Integer.parseInt( msgt);switch(msgType){case 1:PushletUtil.sendMessage(sessionId,WF_SUBMIT_MSG);break;case 2:PushletUtil.sendMessage(sessionId,WF_BACK_MSG);break;case 3:PushletUtil.sendMessage(sessionId,WF_QUIT_MSG);break;case 4:PushletUtil.sendMessage(sessionId,WF_ERROR_MSG);break;default:PushletUtil.sendMessage(sessionId,WF_UNKNOWN_MSG);break;}}} catch (Exception e) {e.printStackTrace();}return SUCCESS;}
}

10.pushlet工具类

package com.yudu.pushlet;import nl.justobjects.pushlet.core.Dispatcher;
import nl.justobjects.pushlet.core.Event;
import nl.justobjects.pushlet.core.SessionManager;import org.apache.commons.lang.StringUtils;public class PushletUtil {private static String PLATFORM_MESSAGE = "YUDU_WF_MSG";/** * 发送消息至客户端* @param sessionId* @param msg*/public static void sendMessage(String sessionId, String msg){if(StringUtils.isNotBlank(sessionId) && SessionManager.getInstance().hasSession(sessionId)){Event event = Event.createDataEvent("/yudu/ydbpm");event.setField(PLATFORM_MESSAGE, msg);Dispatcher.getInstance().unicast(event, sessionId);}}/*** 广播至所有在线客户端* @param msg*/public static void sendBroadcast(String msg){Event event = Event.createDataEvent("/yudu/ydbpm");event.setField(PLATFORM_MESSAGE, msg);Dispatcher.getInstance().broadcast(event);}
}

三、集群

nginx做负载均衡,反向代理两个服务,前端页面无需获取真实ip,后端亦如此。即可实现集群下服务端消息推送

pushlet实现单机-集群服务端消息推送相关推荐

  1. Asp.net SignalR 实现服务端消息推送到Web端

    参考博客https://www.cnblogs.com/wintersun/p/4148223.html ASP .NET SignalR是一个ASP .NET 下的类库,可以在ASP .NET 的W ...

  2. SSE 服务端消息推送

    SSE(Server-sent events) SSE 它是基于 HTTP 协议的,一般意义上的 HTTP 协议是无法做到服务端主动向客户端推送消息的.有一种变通方法,就是服务器向客户端声明,发送的是 ...

  3. [Eureka集群] 在linux上部署SpringCloudEureka的集群服务端(Dalston.SR5版本)

    搭配使用 logback日志配置: https://blog.csdn.net/a755199443/article/details/92208902 Eureka单机服务端配置: https://b ...

  4. flux服务器推消息,服务端主动推送数据,除了 WebSocket 你还能想到啥?

    原标题:服务端主动推送数据,除了 WebSocket 你还能想到啥? 来自公众号: 江南一点雨 在 上篇文章 中,松哥和大家分享了 WebFlux 的基本用法,小伙伴们已经了解到使用 WebFlux ...

  5. 服务端如何推送消息给客户端?

    大家好,我是前端西瓜哥,今天带大家了解一下服务端如何推送消息给客户端. 有时候,我们希望服务端能够主动推送一些信息给客户端.但 HTTP 协议只能让客户端发起请求然后服务端响应,而无法让服务端主动去发 ...

  6. web端消息推送的方式介绍

    1.goeasy  官方地址:http://www.goeasy.io/ 集成简单,自己可以在官网上去看官方文档,12个月免费!值得一试. 2.dwr推送:官方地址http://directwebre ...

  7. Android端消息推送总结:实现原理、心跳保活、遇到的问题等

    前言 最近研究Android推送的实现, 研究了两天一夜, 有了一点收获, 写下来既为了分享, 也为了吐槽. 需要说明的是有些东西偏底层硬件和通信行业, 我对这些一窍不通, 只能说说自己的理解. 为什 ...

  8. SSE:使用HTTP做服务端数据推送的技术及其他通信技术

    文章目录 一.SSE 使用场景 服务端响应示例 浏览器处理服务器返回数据 SSE使用注意事项 使用示例 二.轮询 三.WebSocket 什么是Socket?什么是WebSocket? 那么他是如何建 ...

  9. 即时通讯开发如何构建一套移动端消息推送系统

    消息推送作为移动端 APP 运营中的一项关键技术,已经被越来越广泛的运用. 本文追溯了推送技术的发展历史,剖析了其核心原理,并对推送服务的关键技术进行深入剖析,围绕消息推送时产生的服务不稳定性,消息丢 ...

最新文章

  1. lua 函数调用1 -- 闭包详解和C调用
  2. FPGA之道(12)FPGA芯片的配置方式
  3. vsphere服务器虚拟化流程,VMware vSphere服务器虚拟化实验
  4. Java线程池示例:任务窃取线程池WorkStealingPool
  5. 手把手教你Chrome浏览器安装Postman(含下载云盘链接)【转载】
  6. 获取指定长度的随机字符串
  7. oracle dbf 超大,oracle 数据库users01.dbf文件过大 转移方法
  8. N皇后问题(暴力法、回溯法)
  9. (三)使用预定义模型QDirModel的例子
  10. kmp算法next计算方法_【数据结构——串】KMP算法——next数组Python的实现方式
  11. 鸿蒙系统在哪里,“安卓系统”和“鸿蒙系统”区别在哪里?网友:根本就是一个天上一个地下...
  12. rfid 物流业务信息系统介绍
  13. 电解电容串联的均压电阻计算
  14. python怎么输入一个数-Python中实现输入一个整数的案例
  15. 行严格对角占优矩阵——一道矩阵代数作业题
  16. Hilditch细化算法
  17. 外包公司到底能不能选择
  18. 浏览器证书失效问题解决方法
  19. 京东技术三面 +HR 面,成功拿到 30K offer 就职京东
  20. 基于Java毕业设计影楼网站源码+系统+mysql+lw文档+部署软件

热门文章

  1. GTest学习笔记(一)
  2. java 打印byte数组内容_java中打印byte数组
  3. UpdatePanel的简单用法(非嵌套)
  4. 网络状态监控工具Smokeping 安装指南
  5. WriteProcessMemory函数说明
  6. log4j2的使用及配置详解
  7. JavaScript弹出对话框的三种方式-alert()-confirm()-prompt()
  8. HTML文件主体部分的标记对是,1.7 HTML的标记构成
  9. 泵体计算机仿真实训,ZJGKND01 1000MW火力发电机组仿真模拟教学实验平台
  10. CentOS 7 安装惠普打印机驱动