原文: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 是怎么存离线消息的更多相关文章

  1. XMPP——Smack[6]离线消息和离线文件的实现

    终篇,三天所学所用,也就这些,如果需要大家要自己去查资料研究研究,功能其实可以很强大的 可惜界面做得不好,一大短处,从大一迄今没整好,主要是个人审美不行,哎 毕业季呀毕业季,明天摆摊卖书,再半月就可能 ...

  2. openfire接收离线消息

    先接收离线消息后再通知openfire上线 //获取离线消息 OfflineMessageManager offlineMessageManager=new OfflineMessageManager ...

  3. xmpp和OpenFire示例,即时聊天室,支持离线消息

    让我说说为什么写这个博客,这是因为我在上周末的研究XMPP和OpenFire,从互联网上下载Demo,但跑不起来.它花了很长的时间.它被改造.抬高.篇博文也是希望后边学习XMPP和OpenFire的同 ...

  4. XMPP——Smack[5]文件传输及离线消息的获取

    三天时间,赶在最后一下午实现了文件的传输,本来需要实现离线文件的发送的,一直没想好怎么弄,找openfire的离线文件插件没找到,后来想出一种方法,起服务器时起了一个系统用户,一直在线,当用户发送离线 ...

  5. Xmpp获取离线消息

    文章只是选取了其中一段,无XMPP基础的人可能看起来有点复杂; 假设我们注册了一个用户,用户名叫shimiso,那么我们如何让shimiso这个用户一登陆就取到离线消息呢? PPConnection. ...

  6. IM消息送达保证机制实现(二):保证离线消息的可靠投递

    1.前言 本文的上篇<IM消息送达保证机制实现(一):保证在线实时消息的可靠投递>中,我们讨论了在线实时消息的投递可以通过应用层的确认.发送方的超时重传.接收方的去重等手段来保证业务层面消 ...

  7. 可在广域网部署运行的QQ高仿版 -- GG叽叽V3.2,增加离线消息、离线文件功能(源码)

    (几句题外话:虽然就如何将GG发展为一个有商业价值的产品,我还没有很清晰明确的思路,但是从GG发布以来,通过GG认识了一些朋友,也接了一些小单子,赚了一点小钱.有了一点甜头,目前和2.3个好朋友一起做 ...

  8. Asmack离线消息时间获取

    DelayInformation info = (DelayInformation)message.getExtension("x","jabber:x:delay&qu ...

  9. 离线消息如何实现?-- ESFramework 4.0 快速上手(02)

    在ESFramework 4.0 快速上手一文中,主要介绍了如何使用ESPlus.Rapid命名空间中的引擎来快速地构建基于TCP的网络通信系统,即使是使用ESPlus.Rapid来进行ESFrame ...

随机推荐

  1. YTU 3006: 迷宫问题(栈与队列)

    3006: 迷宫问题(栈与队列) 时间限制: 1 Sec  内存限制: 128 MB 提交: 3  解决: 1 题目描述 编写一个求解迷宫问题的程序,要求输出迷宫的所有路径,并求最短路径长度及最短路径 ...

  2. SQL-字符串合并

    create table tb(id int, value varchar(10))  insert into tb values(1, 'aa')  insert into tb values(1, ...

  3. asp.net 父窗体获取子窗体的返回值,可用来对父窗体局部更新

    今天在项目上遇到了这个问题,其实只是window.returnValue的简单应用,不是asp.net的专属内容.作为积累,记录一个简单的实现模型. 图1  用到的文件 从图1中我们可以看到,只用到了 ...

  4. Adam 演示demo内容整理

    在这个6个多G的演示demo中,还是发现了不少东西. 这篇文章八卦向的东西比较多,不过支持abc格式的话,做Cutscene一下子多了很多可以用的东西. 1.在插件目录下发现了ABC格式的导入dll. ...

  5. 软件密码和https协议

    密码安全问题,一直是程序员最痛疼的问题,这一章主要的来说一下密码的安全,和怎么提高密码的安全,还有Tomcat的https协议. 密码对于一个程序的安全有多重要就不多说了,如果你做过银行系统的话,那么 ...

  6. spring,mybatis事务管理配置与@Transactional注解使用[转]

    spring,mybatis事务管理配置与@Transactional注解使用[转] spring,mybatis事务管理配置与@Transactional注解使用 概述事务管理对于企业应用来说是至关 ...

  7. 一、spring——helloWorld

    1.添加jar包,如下图所示: 2.建立spring项目,如下图所示: 3.验证,如下图所示:

  8. Statement和PreparedStatement批量更新

    优势:1.节省传递时间. 2.并发处理. PreparedStatement: 1) addBatch()将一组参数添加到PreparedStatement对象内部. 2) executeBatch( ...

  9. JAVA的文件创建

    package com.xia; import java.io.*; public class test2 { public static void main(String[] args) { //输 ...

  10. c++ 动态分配二维数组 new 二维数组

    #include "stdafx.h" #include <iostream> using namespace std; int _tmain(int argc, _T ...