openfire的MUC改造类似QQ永久群
2017-11-17 10:52
218 查看
openfire的MUC改造类似QQ永久群
在此非常感谢CSDN的博文:http://blog.csdn.net/yangzl2008/article/details/16991175,因为是这篇文章能够更快的解决问题。我的解决方案类似上面博文的方案,但是没有修改openfire的源码,并且解决了上面博文中出现的两个问题:
1.数据是插入到数据库ofmucmember中了,可是openfire管理后台查看群成员还是没有,必须重启openfire
2.解决掉插入ofmucmember可能会发生的主键冲突和异常
下面进入正题: 先说明下openfire的muc房间,房间里面的member是分几个角色的,分别为拥有着、管理员、成员、被排除者。如果你用spark 创建的群,默认自己的角色是拥有着。您会看见在ofmucaffiliation表中有一条对应记录。如下图:
图片的详情页面
要实现muc成员持久有两个方案:
第一,可以在openfire管理后台直接把用户添加到成员角色里面;(实现方式很简单,但是不便于实际使用)
第二,在客户端用户进入房间后把用户 存入ofmucmember表中。(下面讲解的就是这种实现)
如果想在客户端join的同时把这个用户持久化,让下次登录后可以自动返回成员加入的群列表。我们想象一下:如果这个地方有一个监听器是否很好,监听到有成员join的时候就进行数据库操作。答案是肯定的,openfire提供了这个类,类名是:org.jivesoftware.openfire.muc.MUCEventListener,类源码如下:
[code] /** * $RCSfile$ * $Revision: $ * $Date: $ * * Copyright (C) 2005-2008 Jive Software. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jivesoftware.openfire.muc; import org.xmpp.packet.JID; import org.xmpp.packet.Message; /** * Interface to listen for MUC events. Use the {@link MUCEventDispatcher#addListener(MUCEventListener)} * method to register for events. * * @author Gaston Dombiak */ public interface MUCEventListener { /** * Event triggered when a new room was created. * * @param roomJID JID of the room that was created. */ void roomCreated(JID roomJID); /** * Event triggered when a room was destroyed. * * @param roomJID JID of the room that was destroyed. */ void roomDestroyed(JID roomJID); /** * Event triggered when a new occupant joins a room. * * @param roomJID the JID of the room where the occupant has joined. * @param user the JID of the user joining the room. * @param nickname nickname of the user in the room. */ void occupantJoined(JID roomJID, JID user, String nickname); /** * Event triggered when an occupant left a room. * * @param roomJID the JID of the room where the occupant has left. * @param user the JID of the user leaving the room. */ void occupantLeft(JID roomJID, JID user); /** * Event triggered when an occupant changed his nickname in a room. * * @param roomJID the JID of the room where the user changed his nickname. * @param user the JID of the user that changed his nickname. * @param oldNickname old nickname of the user in the room. * @param newNickname new nickname of the user in the room. */ void nicknameChanged(JID roomJID, JID user, String oldNickname, String newNickname); /** * Event triggered when a room occupant sent a message to a room. * * @param roomJID the JID of the room that received the message. * @param user the JID of the user that sent the message. * @param nickname nickname used by the user when sending the message. * @param message the message sent by the room occupant. */ void messageReceived(JID roomJID, JID user, String nickname, Message message); /** * Event triggered when a room occupant sent a private message to another room user * * @param toJID the JID of who the message is to. * @param fromJID the JID of who the message came from. * @param message the message sent to user. */ void privateMessageRecieved(JID toJID, JID fromJID, Message message); /** * Event triggered when the subject of a room is changed. * * @param roomJID the JID of the room that had its subject changed. * @param user the JID of the user that changed the subject. * @param newSubject new room subject. */ void roomSubjectChanged(JID roomJID, JID user, String newSubject); }
[/code]
OK,我们已经知道利用这个类的
occupantJoined方法来持久化这个加入成员的用户数据,这个时候有个问题来了,我们知道openfire的群可以设置仅成员可以加入,或者是任何人可以加入,如图:
现在把你创建的群设置为只有群成员可以加入,然后我们用spark客户端测试是否可以加入,结果提示如下:
怎么办呢,有的业务就是只能管理员把成员批量拉入然后持久化数据库,不能随便加入;其中原因是由于openfire的MUC群成员默认都是放缓存里面的,一旦离线就从缓存把数据清理掉。细心的会发现,我们在openfire管理后台加入的用户在客户端就能够使用,那么我们看下openfire管理后台的那个界面是如何实现的哈:muc-room-affiliations.jsp 里面有一段代码如下:
[code] IQ iq = new IQ(IQ.Type.set); if ("owner".equals(affiliation) || "admin".equals(affiliation)) { Element frag = iq.setChildElement("query", "http://jabber.org/protocol/muc#owner"); Element item = frag.addElement("item"); item.addAttribute("affiliation", affiliation); item.addAttribute("jid", userJID); // Send the IQ packet that will modify the room's configuration room.getIQOwnerHandler().handleIQ(iq, room.getRole()); } else if ("member".equals(affiliation) || "outcast".equals(affiliation)) { Element frag = iq.setChildElement("query", "http://jabber.org/protocol/muc#admin"); Element item = frag.addElement("item"); item.addAttribute("affiliation", affiliation); item.addAttribute("jid", userJID); // Send the IQ packet that will modify the room's configuration room.getIQAdminHandler().handleIQ(iq, room.getRole()); }
[/code]
看了上面代码后,你是否已经知道如何去实现了呢;其实我们可以在成员join的时候模拟后台操作加入成员还是管理者等,也就是
occupantJoined方法实现如下:
[code] @Override public void occupantJoined(JID roomJID, JID user, String nickname) { String mjid = user.toBareJID(); if(MUCDao.exists(mjid, roomJID.getNode())) //如果成员存在 return ; else if( !MUCDao.existsMember(roomJID.getNode()) ){ //如果muc房间里面一个用户都还不存在 return ; } log.warn("occupantJoined:"+roomJID+">"+user+":"+nickname); MUCRoom mucroom =XMPPServer.getInstance().getMultiUserChatManager().getMultiUserChatService(roomJID).getChatRoom(roomJID.getNode()); IQ iq = new IQ(IQ.Type.set); Element frag = iq.setChildElement("query", "http://jabber.org/protocol/muc#member"); Element item = frag.addElement("item"); item.addAttribute("affiliation", "member"); item.addAttribute("jid", mjid); item.addAttribute("nick",nickname); // Send the IQ packet that will modify the room's configuration try { mucroom.getIQAdminHandler().handleIQ(iq, mucroom.getRole()); if(nickname != null && !"".equals(nickname)) MUCDao.updateNick(mucroom.getID(), mjid, nickname); } catch (Exception e) { e.printStackTrace(); log.error(e.getMessage()); } }
[/code]
其中
MUCDao类是自己定义的一个DAO类
好了,自此持久化和缓存问题已经解决。如果有什么疑问请加群:307245354
如有些疑问也可以看第二篇:见点击查看
相关文章推荐
- 将Openfire中的MUC改造成类似QQ群一样的永久群
- 将Openfire中的MUC改造成类似QQ群一样的永久群
- 将Openfire中的MUC改造成类似QQ群一样的永久群
- openfire的MUC改造类似QQ永久群(二)
- 将Openfire中的MUC改造成类似QQ群一样的永久群
- Android 将Openfire中的MUC改造成类似QQ群一样的永久群
- 使用 electron 实现类似新版 QQ 的登录界面效果(阴影、背景动画、窗体3D翻转)
- 用qt实现类似qq截图的工具
- Visual C++开发类似QQ游戏大厅全过程
- 如何做一个类似QQ说说体系的表结构(一)
- 类似QQ的左侧切换
- 闪烁窗口,类似QQ聊天有消息任务栏标题会闪动
- Android实现类似QQ头像点击打开相册或者拍照,并获取裁剪后的图片
- iOS开发之在Xcode代码中插入类似QQ的表情
- 类似QQ贴边掩藏功能的实现(三)
- ScrollView实现类似QQ可拉动
- 转:【专题九】实现类似QQ的即时通信程序
- ndroid:使用百度地图SDK定位当前具体位置(类似QQ发表说说的选择地点功能)
- 获得类似QQ的Ctrl+Enter按键操作
- 一个类似QQ弹出窗口的JQUERY插件