openfire的MUC改造类似QQ永久群

73 篇文章 0 订阅

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,类源码如下:

 
  /**
 * $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);
}


OK,我们已经知道利用这个类的 occupantJoined方法来持久化这个加入成员的用户数据,这个时候有个问题来了,我们知道openfire的群可以设置仅成员可以加入,或者是任何人可以加入,如图:

现在把你创建的群设置为只有群成员可以加入,然后我们用spark客户端测试是否可以加入,结果提示如下:

怎么办呢,有的业务就是只能管理员把成员批量拉入然后持久化数据库,不能随便加入;其中原因是由于openfire的MUC群成员默认都是放缓存里面的,一旦离线就从缓存把数据清理掉。细心的会发现,我们在openfire管理后台加入的用户在客户端就能够使用,那么我们看下openfire管理后台的那个界面是如何实现的哈:muc-room-affiliations.jsp 里面有一段代码如下:

  
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());
                }

看了上面代码后,你是否已经知道如何去实现了呢;其实我们可以在成员join的时候模拟后台操作加入成员还是管理者等,也就是 occupantJoined方法实现如下:

  
@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());
		}
	}
  
其中 MUCDao类是自己定义的一个DAO类

好了,自此持久化和缓存问题已经解决。如果有什么疑问请加群:307245354 

如有些疑问也可以看第二篇:见点击查看

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值