該插件主要處理當(dāng)接收方處于離線狀態(tài)時(shí),服務(wù)器端發(fā)送回執(zhí)給客戶端。工作原理是首先對消息進(jìn)行攔截,判斷消息類型為chat時(shí),查詢接收方是否在線,如果在線直接忽略,如果是離線狀態(tài),則將消息存放到離線消息列表,再對發(fā)送方進(jìn)行回執(zhí)。另一方面,在網(wǎng)絡(luò)不穩(wěn)定時(shí),openfire容易出現(xiàn)掉包情況,原因是在客戶端掉線,openfire并不能馬上知道客戶端已經(jīng)斷線。 為解決掉包問題,需要在客戶端發(fā)消息時(shí)設(shè)置要求回執(zhí)就行,然后在在服務(wù)器端發(fā)送回執(zhí)給客戶端,告訴客戶端已經(jīng)收到消息。
插件源碼如下:
/** * 消息回執(zhí)插件 * @author zjn */public class MessageReceiptPlugIn implements Plugin, PacketInterceptor { private static final Logger log = LoggerFactory.getLogger(MessageReceiptPlugIn.class); private InterceptorManager interceptoerManager; public MessageReceiptPlugIn() { interceptoerManager = InterceptorManager.getInstance(); } @Override //初始化插件 public void initializePlugin(PluginManager manager, File pluginDirectory) { interceptoerManager.addInterceptor(this); System.out.println("初始化......加載插件成功!"); } @Override //服務(wù)器斷開時(shí)銷毀插件 public void destroyPlugin() { interceptoerManager.removeInterceptor(this); System.out.println("服務(wù)器斷開......銷毀插件成功!"); } @SuppressWarnings("deprecation") @Override //消息攔截器 public void interceptPacket(Packet packet, Session session, boolean incoming, boolean processed) throws PacketRejectedException { System.out.println("接收到的消息內(nèi)容:" + packet.toXML()); Packet copyPacket = packet.createCopy(); if (packet instanceof Message) { Message message = (Message) copyPacket; // 一對一聊天,單人模式,判斷所攔截消息的類型為chat if (message.getType() == Message.Type.chat) { // 程序執(zhí)行中;是否為結(jié)束或返回狀態(tài)(是否是當(dāng)前session用戶發(fā)送消息) if (processed || !incoming) { return; } // 判斷接受者是否在線,2代表離線狀態(tài),1代表在線狀態(tài),0代表用戶不存在 if (IsOnLineUtils.IsUserOnLine(message.getTo()) == 2) { // 離線時(shí),向offline表寫數(shù)據(jù) OfflineMessageStore offlineMessageStore = new OfflineMessageStore(); offlineMessageStore.addMessage(message); // 向客戶端發(fā)回執(zhí) Message receiptMessage = new Message(); receiptMessage.setTo(message.getFrom()); receiptMessage.setType(Message.Type.normal); Element received = receiptMessage.addChildElement("received", "urn:xmpp:receipts"); received.setAttributeValue("id", message.getID()); System.out.println("0000000000回執(zhí)內(nèi)容" + receiptMessage); try { XMPPServer.getInstance().getPacketDeliverer().deliver(receiptMessage); System.out.println("服務(wù)端回執(zhí)成功!"); } catch (Exception e) { e.printStackTrace(); } } } } }}
以下是判斷用戶是否在線的方法:
public class IsOnLineUtils { /** * 判斷openfire用戶的狀態(tài) strUrl : url格式 - * http://my.openfire.com:9090/plugins/presence/status?jid=user1@my.openfire * .com&type=xml 返回值 : 0 - 用戶不存在; 1 - 用戶在線; 2 - 用戶離線 說明 :必須要求 openfire加載 * presence 插件,同時(shí)設(shè)置任何人都可以訪問 */ public final static String URL = "http://192.168.0.54:9090/plugins/presence/status?jid="; public static short IsUserOnLine(JID jid) { String strUrl = URL + jid + "&type=xml"; short shOnLineState = 0; // -不存在- try { URL oUrl = new URL(strUrl); URLConnection oConn = oUrl.openConnection(); if (oConn != null) { BufferedReader oIn = new BufferedReader(new InputStreamReader(oConn.getInputStream())); if (null != oIn) { String strFlag = oIn.readLine(); oIn.close(); if (strFlag.indexOf("type=\"unavailable\"") >= 0) { shOnLineState = 2; } if (strFlag.indexOf("type=\"error\"") >= 0) { shOnLineState = 0; } else if (strFlag.indexOf("priority") >= 0 || strFlag.indexOf("id=\"") >= 0) { shOnLineState = 1; } } } } catch (Exception e) { } return shOnLineState; }}