转:http://blog.csdn.net/huwenfeng_2011/article/details/43413651

Group

在openfire中的gorop——组,也可以理解为共享组。什么叫共享组呢。当有一个组名字为“学习组”,当其他用户加入这个组的时候,那么他们会自动成为相互的好友。实际上

在openfire内,用户的好友不仅仅只是花名册,还包括共同在一个组的成员。当然这个组有很多好处。比如,那我们公司做的一个项目为例。我们做学校老师与家里沟通的的APP,需要预先将老师和家长做成好友,这个就不要重新让用户手动去添加了,可以直接生成放在用一个组内。当然,还有很多其他的用户。大家随意发挥吧,呵呵。。。

Group通讯

这里所讲的group通讯主要是将客户端与服务端之间基于group之上的操作通讯。

比如服务端的CRUD操作,如何知会给客户端。目前据本人了解,openfire提供的客户端版本中都没让用户自己操作gruop的功能,我想在客户端也并不需要这些功能。下面几个小节就主要讲讲服务端的操作。

终端查询

客户端发送查询的命令如下:

  1. <iq id="9Fzzk-5" type="get">
  2. <sharedgroup xmlns="http://www.jivesoftware.org/protocol/sharedgroup">
  3. </sharedgroup>
  4. </iq>

服务端怎么处理呢?

IQSharedGroupHandler,就是在针对客户端的查询命令处理。该类位于org.jivesoftware.openfire.handler下。

源码如下:

  1. @Override
  2. public IQ handleIQ(IQ packet) throws UnauthorizedException {
  3. IQ result = IQ.createResultIQ(packet);
  4. String username = packet.getFrom().getNode();
  5. <span style="white-space:pre">    </span>//以下是一些校验。。。 此处省略....
  6. <span style="white-space:pre">    </span>//这里才开始处理。
  7. Collection<Group> groups = rosterManager.getSharedGroups(username);
  8. Element sharedGroups = result.setChildElement("sharedgroup",
  9. "http://www.jivesoftware.org/protocol/sharedgroup");
  10. for (Group sharedGroup : groups) {
  11. String displayName = sharedGroup.getProperties().get("sharedRoster.displayName");
  12. if (displayName != null) {
  13. sharedGroups.addElement("group").setText(displayName);
  14. }
  15. }
  16. return result;
  17. }

从源码中,可以看书,groups集合从用户的花名册中得到。RosterManager。

那么就一起看看源码吧

  1. public Collection<Group> getSharedGroups(String username) {
  2. Collection<Group> answer = new HashSet<Group>();
  3. Collection<Group> groups = GroupManager.getInstance().getSharedGroups(username);
  4. for (Group group : groups) {
  5. String showInRoster = group.getProperties().get("sharedRoster.showInRoster");
  6. if ("onlyGroup".equals(showInRoster)) {
  7. if (group.isUser(username)) {
  8. // The user belongs to the group so add the group to the answer
  9. answer.add(group);
  10. }
  11. else {
  12. // Check if the user belongs to a group that may see this group
  13. Collection<Group> groupList = parseGroups(group.getProperties().get("sharedRoster.groupList"));
  14. for (Group groupInList : groupList) {
  15. if (groupInList.isUser(username)) {
  16. answer.add(group);
  17. }
  18. }
  19. }
  20. }
  21. else if ("everybody".equals(showInRoster)) {
  22. // Anyone can see this group so add the group to the answer
  23. answer.add(group);
  24. }
  25. }
  26. return answer;
  27. }

那么这里比较重要的方法:

Collection<Group> groups =

GroupManager.getInstance().getSharedGroups(username);

这里调用了DAO,首先会从缓存列表中根据用户名获取所拥有的组。如果缓存中不存在则,查询数据库

缓存Cache<String, Object> groupMetaCache;

那么group设计到了那些表呢。主要有3张表:

ofGroup、ofGroupProp、ofGroupUser

ofGroup该表就是grouo的信息内容:

ofGroupProp是group的权值属性表:

Name是权值名称,propValue是值,在上面源码中看到的onlyGroup、everybody就是值了。比如onlyGroup就是该组只对该组成员有效,everybody则是针对所有成员,所有人都能加入这个组当中去。

ofGroupUser这个是用户与组关系表。里面有三个值

组名+用户+用户所在该组的权限。

关于组的信息就说到这,解下继续源码for里面很简单了,就是封装组。

然后服务端返回客户端组消息,内容如下:

  1. <iq type="result" id="9Fzzk-5" to="zhangf@8ntmorv1ep4wgcy/Spark 2.6.3#android">
  2. <sharedgroup xmlns="http://www.jivesoftware.org/protocol/sharedgroup">
  3. <group>testg </group>
  4. </sharedgroup>
  5. </iq>

从这段消息中可以知道,服务返回是以人(用户)为基础单位,告诉客户端,这个用户(也就是你的好友)所跟您在一起的组。本人认为这样并不是很好。个人认为服务端的返回应该是这样:

  1. <group name=’testgroup’>
  2. <username>u1</username>
  3. <username>u2</username>
  4. ......
  5. </group>

当然openfire并没有这么做,至少在3.8.1的版本没能这么做。这也为了迎合用户的花名册了。

Ok,查询就都这里。

控制台上的操作

当管理将一个用户添加到group中时:

1、向客户端发送新的iq,告诉它你有新的好友了,你和这个组了的一个人的好友关系是

both(互为好友为什么互为好友呢,之前说过了,凡事群组的成员都是互为好友的,两个用户都加入对方是both,那么可以自动获取到对方的状态,相当于加了监听)。当然

这个组内有多少个成员,便会发送多少条消息。内容如下:

  1. <iq type="sgo" id="784-19" to="huwf@hytest240/Spark 2.6.3#10000141" from="hytest240">
  2. <query xmlns="jabber:iq:roster">
  3. <item jid="10530@hytest240" name="好友名称" subscription="both">
  4. <group>groupname#groupdesc</group>
  5. </item>
  6. </query>
  7. </iq>

注意<group>groupname#groupdesc</group>这里面有个“#”这个是本人自己加的。因为我们项目中把groupname作为了id,desc则为组的名称。实际上我们没有用到描述这个字段。

2、当管理台删除一个用户的时候,步骤个上面一样。发送的消息内容如下:

  1. <iq type="sgo" id="812-26" to="huwf@hytest240/Spark 2.6.3#10000141" from="hytest240">
  2. <query xmlns="jabber:iq:roster">
  3. <item jid="10015@hytest240" subscription="remove"/>
  4. </query>
  5. </iq>

它只是告诉你,你没这个好友了。当然这个消息是删除正在在线状态的用户。删除其他用户的消息,这里就不在啰嗦了。

Group事件

在控制台操作的group出发的事件由GroupManager控制。在GroupManager的构造函数中添加了监听事件。有7个监听事件。

1、groupCreated。创建group

1)添加gourp权值属性

2)加入group缓存

3)删除元缓存

2、groupDeleting 删除group

1)发送iq消息给组内成员“jabber:iq:group:delete”

2)从缓存中移除

3)从db中移除

......

花名册

处理流程

终端获取流程:

1、终端发送

  1. <iq id="Ho4CO-2" type="get">
  2. <query xmlns="jabber:iq:roster"></query>
  3. </iq>

2、系统返回

  1. <iq type="result" id="Ho4CO-2" to="zhangf@8ntmorv1ep4wgcy/Spark 2.6.3#android">
  2. <query xmlns="jabber:iq:roster">
  3. <item jid="guany@8ntmorv1ep4wgcy" name="关羽" subscription="both">
  4. <group>testg </group>
  5. </item>
  6. <item jid="liub@8ntmorv1ep4wgcy" name="liub" subscription="both">
  7. <group>我的兄弟</group>
  8. <group>testg </group>
  9. </item>
  10. <item jid="zhugl@8ntmorv1ep4wgcy" name="zhugl" subscription="from">
  11. <group>军机处</group>
  12. </item>
  13. </query>
  14. </iq>

走进源码看IQRosterHandler的处理。IQRosterHandler是服务端对用户花名册的处理。

IQRosterHandler位于org.jivesoftware.openfire.handler。

IQRosterHandler中的handleIQ方法,根据客户端的IQ请求中的to属性判别用户是查询还是删除。

查询:

  1. if (recipientJID == null || recipientJID.getNode() == null ||
  2. !UserManager.getInstance().isRegisteredUser(recipientJID.getNode())) {
  3. returnPacket = manageRoster(roster);
  4. }

manageRoster方法,有两个判断

1、if (IQ.Type.get == type) 这里从缓存中查找用户好友,并封装消息

2、else if (IQ.Type.set == type)由分为两种

1)removeItem移除列表

2)createRosterItem创建列表

removeRosterItem:删除用户列表。并广播整个列表好友删除消息。

组与花名册就先到这,以后还补充。这块还是比较简单。主要看handle这个包下的类。

(转)OpenFire源码学习之七:组(用户群)与花名册(用户好友)的更多相关文章

  1. (转)OpenFire源码学习之六:用户注册

    转:http://blog.csdn.net/huwenfeng_2011/article/details/43413509 用户注册 注册流程: 1.客户端进行握手给服务端发送连接消息: <s ...

  2. (转)OpenFire源码学习之二十七:Smack源码解析

    转:http://blog.csdn.net/huwenfeng_2011/article/details/43484199 Smack Smack是一个用于和XMPP服务器通信的类库,由此可以实现即 ...

  3. (转)OpenFire源码学习之十八:IOS离线推送

    转:http://blog.csdn.net/huwenfeng_2011/article/details/43458213 IOS离线推送 场景: 如果您有iOS端的APP,在会话聊天的时候,用户登 ...

  4. (转)OpenFire源码学习之十:连接管理(上)

    转:http://blog.csdn.net/huwenfeng_2011/article/details/43415827 关于连接管理分为上下两部分 连接管理 在大并发环境下,连接资源 需要随着用 ...

  5. (转)OpenFire源码学习之四:openfire的启动流程

    转:http://blog.csdn.net/huwenfeng_2011/article/details/43413233 openfire启动 ServerStarter 启动流程图: 启动的总入 ...

  6. (转)即时通讯IM OpenFire源码学习之三:在Eclipse中构建源码

    转:http://blog.csdn.net/huwenfeng_2011/article/details/43412617 源码搭建 下载地址: 地址:http://www.igniterealti ...

  7. (转)OpenFire源码学习之十三:消息处理

    转:http://blog.csdn.net/huwenfeng_2011/article/details/43417817 消息处理流程总揽(该图来源于互联网,图片很大,不过类容还是挺清楚的.不方便 ...

  8. (转)OpenFire源码学习之八:MUC用户聊天室

    转:http://blog.csdn.net/huwenfeng_2011/article/details/43413817 MUC 房间属性设置 以上属性存储在MUCPersistenceManag ...

  9. (转)OpenFire源码学习之五:用户登录

    转:http://blog.csdn.net/huwenfeng_2011/article/details/43413377 登陆 登陆认证,客户端发送认SASL证消息: <auth mecha ...

随机推荐

  1. Network基础(二):数制转换

    一.数制转换 目标: 1)请将下列数字转换为十进制数: (110010011111)2 .(10110101110)2 2)请将下列十进制数转换为二进制: 156.2608.1043 方案: 使用按权 ...

  2. <自动化测试>之<Selenium API 的用法1>

    今天,简单,举例说一下在用python+selenium中元素定位的主要方法,第一部分是单个元素的操作,第二部分是一类元素的操作,实际操作中注意区分 #!/usr/bin/env python # - ...

  3. Selenium之Android使用学习

    20140507 Selenium一般用在web自动化上,为什么Android上也能用呢? 如图,手机端和DB联动:手机端的客户端给server发数据流,进行增删改查操作,这种写数据用update更新 ...

  4. 关于IDEA的一些问题

    关于IDEA的一些问题 快速创建SpringBoot项目传送门:参考网址 创建Maven Web项目(带有webapp文件夹目录的项目)传送门:参考网址

  5. 用 Flask 来写个轻博客 (14) — M(V)C_实现项目首页的模板

    Blog 项目源码:https://github.com/JmilkFan/JmilkFan-s-Blog 目录 目录 前文列表 实现所需要的视图函数 实现 home.html 模板 代码分析 实现效 ...

  6. idea Maven 一键 mvn clean package

    文章目录 方法一 方法二 方法一 方法二

  7. PHP 3DES 加解密(CBC模式,pkcs5padding填充)

    1.前言:项目中接入第三方支付遇到3DES加密,以前也没用过,搜了好多,都不适用,各种不对,后来自己结合搜到的终于弄正确了,检测地址:http://tool.chacuo.net/crypt3des. ...

  8. Java封装JDBC数据库增、删、改、查操作成JAR文件,以供Web工程调用,适用于多种数据库

    废话不多说,直接上源代码,最后有使用方法,当然,也可以作为普通公用类使用,只是封装成JAR更方便使用. package db.util; import java.io.BufferedReader; ...

  9. 微信小程序 Page构造函数重写

    //utils/utils.js const oldPage = Page; console.log(oldPage) Page = function (app) { //定义新函数 app.newS ...

  10. vue入门例子

    vue入门例子 1.声明示渲染        {{message}} 2.绑定事件 v-bind 3.控制切换一个程序是否显示        v-if 4.渲染循环                  ...