Openfire 是怎么存离线消息
原文:http://myopenfire.com/article/getarticle/26
1、openfire默认怎么存离线消息
在默认情况下,不添加任何插件的情况下,当用户不在线,对于发送给该用户的消息,会被openfire存放到数据库中的ofoffline表中。
为了更深入的了解离线消息的原理,我们来看一下ofoffline这个表,这个表的结构如下所示:
下面对这几个字段进行详细说明:
(1)Username:是用户名,如myopenfire1、myopenfire2。
(2)MessageID:是openfire产生的一个数字,openfire每处理一条消息到离线,这个值就会增1。
(3)CreateDate:表示这条消息被插入数据库的时间,注意插入数据库的时间不一定是这条消息到达服务器的时间。因为他们之间始终是有一点误差的。
(4)MessageSize:表示存储在stanza字段中的消息的字节数。
(5)Stanza:翻译为节的意思,这里指的就是数据包,存放的是message消息。
2、离线表中实际的数据是什么
Ok,我们来看看实际的存储,你就会更容易理解了,如下图是离线表中的数据:
注意stanza是存放的是xmpp协议表示的消息。
3、存放离线消息的类
在目录openfire_src\src\java\org\jivesoftware\openfire下,有一个OfflineMessageStore.java类,这个类就是用来存放离线消息的。
首先这个类是一个单例类,它的实例保存在XMPPServer中,代码如下:
- public static OfflineMessageStore getInstance() {
- return XMPPServer.getInstance().getOfflineMessageStore();
- }
我们可以通过getInstance来获得OfflineMessageStore的实例。
如果要向离线表中插入一条数据,那么可以调用addMessage方法,addMessage的源码分析如下:
- public void addMessage(Message message) {
- // 如果消息为null,直接返回
- if (message == null) {
- return;
- }
- // shouldStoreMessage判断哪些消息应该被存储,例如只有类型为chat的消息,才允许被存储。
- if(!shouldStoreMessage(message)) {
- return;
- }
- JID recipient = message.getTo();
- String username = recipient.getNode();
- // 如果没有接受者,那么就不必要存离线了。
- if (username == null || !UserManager.getInstance().isRegisteredUser(recipient)) {
- return;
- }
- else
- if (!XMPPServer.getInstance().getServerInfo().getXMPPDomain().equals(recipient.getDomain())) {
- // 如果这条消息的域名不对,是发送到其他服务器的,那么也不需要存了
- return;
- }
- // 产生下一条消息的一个序号
- long messageID = SequenceManager.nextID(JiveConstants.OFFLINE);
- // 获得xml格式的消息
- String msgXML = message.getElement().asXML();
- // 打开数据库连接,并且存储消息到数据库
- Connection con = null;
- PreparedStatement pstmt = null;
- try {
- con = DbConnectionManager.getConnection();
- pstmt = con.prepareStatement(INSERT_OFFLINE);
- pstmt.setString(1, username);
- pstmt.setLong(2, messageID);
- pstmt.setString(3, StringUtils.dateToMillis(new java.util.Date()));
- pstmt.setInt(4, msgXML.length());
- pstmt.setString(5, msgXML);
- pstmt.executeUpdate();
- }
- catch (Exception e) {
- Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
- }
- finally {
- DbConnectionManager.closeConnection(pstmt, con);
- }
- // 为存储离线的用户的缓存空间加上相应的字节数,如果设置了一个用户只能存储几M的数据,那么这个就是统计,这个用户已经存储了多少字节的离线消息
- if (sizeCache.containsKey(username)) {
- int size = sizeCache.get(username);
- size += msgXML.length();
- sizeCache.put(username, size);
- }
- }
如果要删除某条消息,可以使用deleteMessages这个函数,传入用户名作为参数,代码如下:
- public void deleteMessages(String username) {
- Connection con = null;
- PreparedStatement pstmt = null;
- try {
- // 打开数据库连接
- con = DbConnectionManager.getConnection();
- // DELETE_OFFLINE为 DELETE FROM ofOffline WHERE username=?
- pstmt = con.prepareStatement(DELETE_OFFLINE);
- pstmt.setString(1, username);
- pstmt.executeUpdate();
- // 将这个用户已经占用多少字节,重新置为0
- removeUsernameFromSizeCache(username);
- }
- catch (Exception e) {
- Log.error("Error deleting offline messages of username: " + username, e);
- }
- finally {
- // 关闭数据库连接
- DbConnectionManager.closeConnection(pstmt, con);
- }
- }
4、小结
本节讲解了离线消息的存储类OfflineMessageStore,这个类中有很多关于离线消息的处理函数,需要对openfire离线消息进行扩展的同学,不妨多看看这个类的实现。
Openfire 是怎么存离线消息的更多相关文章
- XMPP——Smack[6]离线消息和离线文件的实现
终篇,三天所学所用,也就这些,如果需要大家要自己去查资料研究研究,功能其实可以很强大的 可惜界面做得不好,一大短处,从大一迄今没整好,主要是个人审美不行,哎 毕业季呀毕业季,明天摆摊卖书,再半月就可能 ...
- openfire接收离线消息
先接收离线消息后再通知openfire上线 //获取离线消息 OfflineMessageManager offlineMessageManager=new OfflineMessageManager ...
- xmpp和OpenFire示例,即时聊天室,支持离线消息
让我说说为什么写这个博客,这是因为我在上周末的研究XMPP和OpenFire,从互联网上下载Demo,但跑不起来.它花了很长的时间.它被改造.抬高.篇博文也是希望后边学习XMPP和OpenFire的同 ...
- XMPP——Smack[5]文件传输及离线消息的获取
三天时间,赶在最后一下午实现了文件的传输,本来需要实现离线文件的发送的,一直没想好怎么弄,找openfire的离线文件插件没找到,后来想出一种方法,起服务器时起了一个系统用户,一直在线,当用户发送离线 ...
- Xmpp获取离线消息
文章只是选取了其中一段,无XMPP基础的人可能看起来有点复杂; 假设我们注册了一个用户,用户名叫shimiso,那么我们如何让shimiso这个用户一登陆就取到离线消息呢? PPConnection. ...
- IM消息送达保证机制实现(二):保证离线消息的可靠投递
1.前言 本文的上篇<IM消息送达保证机制实现(一):保证在线实时消息的可靠投递>中,我们讨论了在线实时消息的投递可以通过应用层的确认.发送方的超时重传.接收方的去重等手段来保证业务层面消 ...
- 可在广域网部署运行的QQ高仿版 -- GG叽叽V3.2,增加离线消息、离线文件功能(源码)
(几句题外话:虽然就如何将GG发展为一个有商业价值的产品,我还没有很清晰明确的思路,但是从GG发布以来,通过GG认识了一些朋友,也接了一些小单子,赚了一点小钱.有了一点甜头,目前和2.3个好朋友一起做 ...
- Asmack离线消息时间获取
DelayInformation info = (DelayInformation)message.getExtension("x","jabber:x:delay&qu ...
- 离线消息如何实现?-- ESFramework 4.0 快速上手(02)
在ESFramework 4.0 快速上手一文中,主要介绍了如何使用ESPlus.Rapid命名空间中的引擎来快速地构建基于TCP的网络通信系统,即使是使用ESPlus.Rapid来进行ESFrame ...
随机推荐
- 基于clahe的图像去雾
基于clahe的图像去雾 通过阅读一些资料,我了解到clahe算法对图像去雾有所价值,正好opencv中有了实现,拿过来看一看. 但是现在实现的效果还是有所差异 #); clahe] ...
- Android HandlerThread 完全解析
HandlerThread本质上是一个线程类,它继承了Thread: HandlerThread有自己的内部Looper对象,可以进行looper循环: 通过获取HandlerThread的loope ...
- 基于busybox和LFS的linux系统定制
自从在大学知道了Linux这玩意是可以定制的之后,一直想做出一版属于自己的Linux系统.最近工作比较闲,终于塌下心来好好学习了一下. 目前来说,我接触的定制Linux的方法主要有两种: 1. ...
- 初试 uTenux
申请的的开发套件到目前还没到手,看到网友们都开始动手干了,我也是按捺不住了,所以就先在悠龙公司的主页下载了uTenux_V1.5.00r160.zip,打算看看,先了解一下. 下面是文件目录表: └─ ...
- Java_JDK_HashMap
(二)HashMap 需要注意的无非几点: 是什么结构,如何存储的? 如何加入元素?既然是hashMap,那么是如何计算hashcode的呢?遇到冲突又是如何解决的呢? 如何删除元素? 当容量不够时是 ...
- spring加载hibernate映射文件的几种方式 (转)
在Spring的applicationContext.xml中配置映射文件,通常是在<sessionFactory>这个 Bean实例中进行的,若配置的映射文件较少时,可以用session ...
- CUBRID学习笔记 40 使用net修改数据
修改 connection.Open(); string queryString = "UPDATE nation set capital = 'X' where `code` = ...
- 函数(def)
一.为什么要使用函数: 面向过程的编程在代码里有很多代码是可以重复利用的,如果使用面向过程编程会使代码显得纷繁复杂,不利于他人和自己日后的阅读.而在函数式编程里,则可以把每个可重复利用的功能封装在一个 ...
- install Matlab2016b on Ubuntu 14.04
From Download Download the install file from Download MATLAB, Simulink, Stateflow, and Other MathWor ...
- 1----lua的环境搭建
本人使用的是LDT用来学习lua,原因是因为本人熟悉Eclipse的操作,并且安装方便 首先需要下载并配置JDK,也就是java的运行环境(以下为官网网址) http://www.oracle.com ...