1、新建立永久房间,同时保证房间中的成员存储到“ofmucmember”表当中。
2、新建一个用户登陆监听的插件,这个插件监听用户的登陆行为,同时在用户登陆时查询“ofmucmember”表,查询用户所在的房间。
3、将房间信息封装到自定义的IQ包中,发送到客户端。
4、不管使用Android客户端,还是对Spark进行二次开发,对Openfire发送过来的自定义IQ包进行解析。
5、显示群信息。
private static final String ADD_MEMBER =
"INSERT INTO ofMucMember (roomID,jid,nickname) VALUES (?,?,?)";
向ofmucmember插入数据的代码,同时顺藤摸瓜,你也可以找到一些列的调用函数。但是真正在运行的时候,我并没有找到什么时候能够调用这段代码实现向ofmucmember插入数据的操作。于是,解决对于持久room当中用户的持久化问题,就是解决整个改造问题的关键。
SELECT * FROM `openfire`.`ofmucroom`
结果如下:
public static void saveMember(LocalMUCRoom localMUCRoom, JID bareJID,
String resource) {
Connection con = null;
PreparedStatement pstmt = null;
try {
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(ADD_MEMBER);
pstmt.setLong(1, localMUCRoom.getID());
pstmt.setString(2, bareJID.toBareJID());
pstmt.setString(3, resource);
pstmt.executeUpdate();
}
catch (SQLException sqle) {
Log.error(sqle.getMessage(), sqle);
}
finally {
DbConnectionManager.closeConnection(pstmt, con);
}
}
在org.jivesoftware.openfire.muc.spi.LocalMUCRoom类下的public LocalMUCRole joinRoom(String nickname, String password.......)方法中增加如下代码:
}
finally {
lock.writeLock().unlock();
}
lock锁结束之前,也就是说在lock锁内部加入以下代码:
try {
if (isPersistent()) {
MUCPersistenceManager.saveMember(this, bareJID,
bareJID.getNode());
}
} catch (Exception e) {
e.printStackTrace();
}
也就说,如果这个room是Persistent room,那么,每个用户过来,我都让其保存到ofMucMember表中,如果这个用户已经在这个表中,会报主键冲突的错误,如果不想看到这个错误,可以再插入用户之前先进行查询操作,查找用户是否在表中。如果不在的话,就直接插入。
CREATE TABLE `ofmucmember` (
`roomID` BIGINT(20) NOT NULL,
`jid` TEXT NOT NULL,
`nickname` VARCHAR(255) NULL DEFAULT NULL,
`firstName` VARCHAR(100) NULL DEFAULT NULL,
`lastName` VARCHAR(100) NULL DEFAULT NULL,
`url` VARCHAR(100) NULL DEFAULT NULL,
`email` VARCHAR(100) NULL DEFAULT NULL,
`faqentry` VARCHAR(100) NULL DEFAULT NULL,
PRIMARY KEY (`roomID`, `jid`(70))
)
通过定义可以知道ofmucmember表的定义中roomID和jid为联合主键,不会产生每次SQL查询都只是用一个主键的效率问题。
com.yang.plugin.MUCPersistencePlugin
SimplePlugin
This is the Yang sample plugin.
YangZhilong
1.0
15/11/2014
http://localhost:9090/openfire/plugins.jsp
3.4.1
gpl
package com.yang.plugin.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.jivesoftware.database.DbConnectionManager;
/**
* @Title: MUCDao.java
* @Package com.yang.plugin.dao
* @Description: 根据用户名查询出用户所在群组的信息
* @author Yang
* @blog http://blog.csdn.net/yangzl2008
* @date 2013年11月27日 下午7:16:22
* @version V1.0
*/
public class MUCDao {
public static List
这个代码的主要作用就是,根据用户名查询出用户所在群组的信息。
package com.yang.plugin;
import java.io.File;
import java.util.List;
import java.util.Map;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Namespace;
import org.jivesoftware.openfire.IQRouter;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.container.Plugin;
import org.jivesoftware.openfire.container.PluginManager;
import org.jivesoftware.openfire.event.SessionEventDispatcher;
import org.jivesoftware.openfire.event.SessionEventListener;
import org.jivesoftware.openfire.handler.IQHandler;
import org.jivesoftware.openfire.muc.spi.LocalMUCRoom;
import org.jivesoftware.openfire.muc.spi.MultiUserChatServiceImpl;
import org.jivesoftware.openfire.session.Session;
import org.xmpp.packet.IQ;
import org.xmpp.packet.JID;
import com.yang.plugin.dao.MUCDao;
/**
*
* @Title: MUCPersistencePlugin.java
* @Package com.yang.plugin
* @Description: 监听用户登录信息,用户登录之后,查询用户所在room的信息,将room信息发送到客户端。
* @author Yang
* @blog http://blog.csdn.net/yangzl2008
* @date 2013年11月27日 上午9:32:21
* @version V1.0
*/
public class MUCPersistencePlugin implements Plugin, SessionEventListener {
private XMPPServer server;
private MultiUserChatServiceImpl mucService;
private IQRouter router;
@Override
public void sessionCreated(Session session) {
JID userJid = session.getAddress();
joinRooms(userJid);
}
@Override
public void sessionDestroyed(Session session) {
}
@Override
public void resourceBound(Session session) {
}
@Override
public void anonymousSessionCreated(Session session) {
}
@Override
public void anonymousSessionDestroyed(Session session) {
}
@Override
public void initializePlugin(PluginManager manager, File pluginDirectory) {
server = XMPPServer.getInstance();
SessionEventDispatcher.addListener(this);
System.out.println("Join room plugin is running!");
IQHandler myHandler = new MyIQHander();
IQRouter iqRouter = XMPPServer.getInstance().getIQRouter();
iqRouter.addHandler(myHandler);
router = XMPPServer.getInstance().getIQRouter();
}
public void joinRooms(JID userJid) {
List> data = MUCDao.getMUCInfo(userJid.toBareJID());
if (data == null || data.isEmpty()) {
return;
}
Map map = null;
/**
* 构建iq的扩展包,用于发送用户所在房间的名称。
*/
Document document = DocumentHelper.createDocument();
Element iqe = document.addElement("iq");
iqe.addAttribute("type", "result");
iqe.addAttribute("to", userJid.toFullJID());
iqe.addAttribute("id", "YANG");
Namespace namespace = new Namespace("""YANG");
Element muc = iqe.addElement("muc");
muc.add(namespace);
for (int i = 0, len = data.size(); i < len; i++) {
map = data.get(i);
String serviceID = map.get("serviceID");
mucService = (MultiUserChatServiceImpl) server
.getMultiUserChatManager().getMultiUserChatService(
Long.parseLong(serviceID));
String roomName = map.get("name");
LocalMUCRoom room = (LocalMUCRoom) mucService.getChatRoom(roomName);
//增加room和account信息
Element roome = muc.addElement("room");
roome.setText(room.getJID().toBareJID());
roome.addAttribute("account", userJid.toFullJID());
}
//最后发送出去!
IQ iq = new IQ(iqe);
System.out.println("iq " + iq.toXML());
router.route(iq);
}
@Override
public void destroyPlugin() {
SessionEventDispatcher.removeListener(this);
server = null;
mucService = null;
}
}
辅助打印Openfire出入数据类MyIQHander如下:
package com.yang.plugin;
import org.jivesoftware.openfire.IQHandlerInfo;
import org.jivesoftware.openfire.auth.UnauthorizedException;
import org.jivesoftware.openfire.handler.IQHandler;
import org.xmpp.packet.IQ;
/**
* @Title: MyIQHander.java
* @Package com.yang.plugin
* @Description: TODO
* @author Yang
* @blog http://blog.csdn.net/yangzl2008
* @date 2013年11月27日 下午9:56:27
* @version V1.0
*/
public class MyIQHander extends IQHandler {
private static final String MODULE_NAME = "group tree handler";
private static final String NAME_SPACE = "com:im:group";
private IQHandlerInfo info;
public MyIQHander() {
super(MODULE_NAME);
info = new IQHandlerInfo("gruops", NAME_SPACE);
}
@Override
public IQHandlerInfo getInfo() {
return info;
}
@Override
public IQ handleIQ(IQ packet) throws UnauthorizedException {
IQ reply = IQ.createResultIQ(packet);
System.out.println("XML " + reply.toXML());
return reply;
}
}
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.provider.IQProvider;
import org.xmlpull.v1.XmlPullParser;
import ouc.sei.suxin.android.data.Application;
import ouc.sei.suxin.android.data.entity.MUCInfo;
import ouc.sei.suxin.android.utils.Logger;
public class MUCPacketExtensionProvider implements IQProvider {
@Override
public IQ parseIQ(XmlPullParser parser) throws Exception {
int eventType = parser.getEventType();
MUCInfo info = null;
while (true) {
if (eventType == XmlPullParser.START_TAG) {
if ("room".equals(parser.getName())) {
String account = parser.getAttributeValue("", "account");
String room = parser.nextText();
info = new MUCInfo();
info.setAccount(account);
info.setRoom(room);
info.setNickname(account);
Logger.d("account is " + account + " and room is " + room);
Application.getInstance().addMUCInfo(info);
}
} else if (eventType == XmlPullParser.END_TAG) {
if ("muc".equals(parser.getName())) {
break;
}
}
eventType = parser.next();
}
return null;
}
}
ProviderManager.getInstance().addIQProvider("muc", "YANG", new MUCPacketExtensionProvider());
以上这段代码的意思是每当遇到标签为muc同时命名空间为YANG的IQ包时,交由MUCPacketExtensionProvider处理。
以上代码建议添加在Application的onCreate方法中。
/**
* @Title: MUCInfo.java
* @Package ouc.sei.suxin.android.data.entity
* @Description: 用于传输从Server端传输过来的MUC的信息
* @author Yang Zhilong
* @blog http://blog.csdn.net/yangzl2008
* @date 2013年11月27日 上午9:27:25
* @version V1.0
*/
public class MUCInfo {
private String account;
private String room;
private String nickname;
public String getAccount() {
return account;
}
public void setAccount(String account) {
this.account = account;
}
public String getRoom() {
return room;
}
public void setRoom(String room) {
this.room = room;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
if (nickname.contains("@")) {
this.nickname = nickname.substring(0, account.indexOf("@"));
return;
}
this.nickname = nickname;
}
@Override
public String toString() {
return "MUCInfo [account=" + account + ", room=" + room + ", nickname="
+ nickname + "]";
}
}