天天看點

基于xmpp openfire smack開發之smack類庫介紹和使用[2]

關于smack程式設計庫,前面我們提到,它是面向java端的api,主要在pc上使用,利用它我們可以向openfire伺服器注冊使用者,發送消息,并且可以通過監聽器獲得此使用者的應答消息,以及建構聊天室,分組,個人通訊錄等等。

基于xmpp openfire smack開發之smack類庫介紹和使用[2]

下面我們寫幾個程式小例子測試一下。

[java] view

plaincopy

ppconnection.debug_enabled = true;  

accountmanager accountmanager;  

final connectionconfiguration connectionconfig = new connectionconfiguration(  

        "192.168.1.78", integer.parseint("5222"), "csdn.shimiso.com");  

// 允許自動連接配接  

connectionconfig.setreconnectionallowed(true);  

connectionconfig.setsendpresence(true);  

connection connection = new xmppconnection(connectionconfig);  

try {  

    connection.connect();// 開啟連接配接  

    accountmanager = connection.getaccountmanager();// 擷取賬戶管理類  

} catch (xmppexception e) {  

    throw new illegalstateexception(e);  

}  

// 登入  

connection.login("admin", "admin","smacktest");  

system.out.println(connection.getuser());   

connection.getchatmanager().createchat("[email protected]",null).sendmessage("hello word!");  

運作結果:

基于xmpp openfire smack開發之smack類庫介紹和使用[2]

在login中一共有三個參數,登入名,密碼,資源名,可能有人不明白資源名到底是什麼意思,其實就是用戶端的來源,用戶端的名稱,如果不寫它預設就叫smack,如果你用相同的賬戶不同的資源名和同一個人發三條消息,那将會彈出三個視窗,而不是一個視窗。

同時smack還為我們提供了非常好的調試工具smack debug,利用該工具我們可以準确的捕獲詳細的往返封包資訊。

connection.login("admin", "admin","smacktest3");    

chatmanager chatmanager = connection.getchatmanager();  

chat newchat = chatmanager.createchat("[email protected]", new messagelistener() {  

    public void processmessage(chat chat, message message) {  

        if (message.getbody() != null) {  

            system.out.println("received from 【"  

                    + message.getfrom() + "】 message: "  

                    + message.getbody());  

        }  

    }  

});  

scanner input = new scanner(system.in);  

while (true) {  

    string message = input.nextline();   

    newchat.sendmessage(message);  

基于xmpp openfire smack開發之smack類庫介紹和使用[2]

這裡我們用scanner來捕捉使用者在控制台的鍵盤操作,将資訊發出,同時建立了一個messagelistener監聽,在其中強制實作processmessage方法即可捕獲發回的資訊,在初次使用上還是較為容易上手的,我們隻要細心檢視api即可逐漸深入下去。

需要給所有線上的使用者發送一個通知,或者給所有線上和離線的使用者全發送,我們先示範如何給線上使用者發送一個廣播:

ppconnection.debug_enabled = false;  

connection.login("admin", "admin","smacktest3");   

message newmsg = new message();   

newmsg.setto("[email protected]");  

newmsg.setsubject("重要通知");  

newmsg.setbody("今天下午2點60分有會!");  

newmsg.settype(message.type.headline);// normal支援離線   

connection.sendpacket(newmsg);  

connection.disconnect();  

基于xmpp openfire smack開發之smack類庫介紹和使用[2]

将參數設定為message.type.normal即可支援離線廣播,openfire系統會自動判斷該使用者是否線上,如果線上就直接發送出去,如果不線上則将資訊存入ofoffline表,現在我将shimiso使用者登出,再給它發消息,我們可以進入openfire庫的ofoffline表中,非常清楚看到裡面躺着一條離線消息記錄是發給shimiso這個使用者的

基于xmpp openfire smack開發之smack類庫介紹和使用[2]

請看如下代碼

connectionconfig.setsendpresence(false);//不要告訴伺服器自己的狀态  

}   

connection.login("shimiso", "123","smacktest");   

offlinemessagemanager offlinemanager = new offlinemessagemanager(  

        connection);  

    iterator<org.jivesoftware.smack.packet.message> it = offlinemanager  

            .getmessages();  

    system.out.println(offlinemanager.supportsflexibleretrieval());  

    system.out.println("離線消息數量: " + offlinemanager.getmessagecount());  

    map<string, arraylist<message>> offlinemsgs = new hashmap<string, arraylist<message>>();  

    while (it.hasnext()) {  

        org.jivesoftware.smack.packet.message message = it.next();  

        system.out  

                .println("收到離線消息, received from 【" + message.getfrom()  

                        + "】 message: " + message.getbody());  

        string fromuser = message.getfrom().split("/")[0];  

        if (offlinemsgs.containskey(fromuser)) {  

            offlinemsgs.get(fromuser).add(message);  

        } else {  

            arraylist<message> temp = new arraylist<message>();  

            temp.add(message);  

            offlinemsgs.put(fromuser, temp);  

    // 在這裡進行處理離線消息集合......  

    set<string> keys = offlinemsgs.keyset();  

    iterator<string> offit = keys.iterator();  

    while (offit.hasnext()) {  

        string key = offit.next();  

        arraylist<message> ms = offlinemsgs.get(key);  

        for (int i = 0; i < ms.size(); i++) {  

            system.out.println("-->" + ms.get(i));  

    offlinemanager.deletemessages();  

} catch (exception e) {  

    e.printstacktrace();  

offlinemanager.deletemessages();//删除所有離線消息  

presence presence = new presence(presence.type.available);  

            nnection.sendpacket(presence);//上線了  

            nnection.disconnect();//關閉連接配接  

基于xmpp openfire smack開發之smack類庫介紹和使用[2]

這裡我們需要特别當心的是先不要告訴openfire伺服器你上線了,否則永遠也拿不到離線消息,用下面英文大概意思就是在你上線之前去擷取離線消息,這麼設計是很有道理的。

the offlinemessagemanager helps manage offline messages even before the user has sent an available presence. when a user asks for his offline messages before sending an available presence then the server will not

send a flood with all the offline messages when the user becomes online. the server will not send a flood with all the offline messages to the session that made the offline messages request or to any other session used by the user that becomes online.

拿到離線消息處理完畢之後删除離線消息offlinemanager.deletemessages() 接着通知伺服器上線了。

  connection.login("admin", "admin","rooyee");   

  presence pre = connection.getroster().getpresence("[email protected]");  

    system.out.println(pre);  

    if (pre.gettype() != presence.type.unavailable) {  

        // 建立檔案傳輸管理器  

        filetransfermanager manager = new filetransfermanager(connection);  

        // 建立輸出的檔案傳輸  

        outgoingfiletransfer transfer = manager  

                .createoutgoingfiletransfer(pre.getfrom());  

        // 發送檔案  

        transfer.sendfile(new file("e:\\chrysanthemum.jpg"), "圖檔");  

        while (!transfer.isdone()) {  

            if (transfer.getstatus() == filetransfer.status.in_progress) {  

                // 可以調用transfer.getprogress();獲得傳輸的進度   

                system.out.println(transfer.getstatus());  

                system.out.println(transfer.getprogress());  

                system.out.println(transfer.isdone());  

            }  

基于xmpp openfire smack開發之smack類庫介紹和使用[2]

在這裡我們需要特别注意的是,跨資源是無法發送檔案的,看connection.login("admin", "admin","rooyee");這個代碼就明白了,必須是“域名和資源名”完全相同的兩個使用者才可以互發檔案,否則永遠都沒反應,如果不清楚自己所用的用戶端的資源名,可以借助前面提到的smackdebug工具檢視往返資訊完整封包,在to和from中一定可以看到。

如果我們自己要寫檔案接收例子的話,參考代碼如下:

filetransfermanager transfer = new filetransfermanager(connection);  

transfer.addfiletransferlistener(new recfiletransferlistener());  

public class recfiletransferlistener implements filetransferlistener {  

    public string getfiletype(string filefullname) {  

        if (filefullname.contains(".")) {  

            return "." + filefullname.split("//.")[1];  

            return filefullname;  

    @override  

    public void filetransferrequest(filetransferrequest request) {  

        system.out.println("接收檔案開始.....");  

        final incomingfiletransfer intransfer = request.accept();  

        final string filename = request.getfilename();  

        long length = request.getfilesize();  

        final string fromuser = request.getrequestor().split("/")[0];  

        system.out.println("檔案大小:" + length + "  " + request.getrequestor());  

        system.out.println("" + request.getmimetype());  

        try {  

            jfilechooser chooser = new jfilechooser();  

            chooser.setcurrentdirectory(new file("."));  

            int result = chooser.showopendialog(null);  

            if (result == jfilechooser.approve_option) {  

                final file file = chooser.getselectedfile();  

                system.out.println(file.getabsolutepath());  

                new thread() {  

                    public void run() {  

                        try {  

                            system.out.println("接受檔案: " + filename);  

                            intransfer  

                                    .recievefile(new file(file  

                                            .getabsolutepath()  

                                            + getfiletype(filename)));  

                            message message = new message();  

                            message.setfrom(fromuser);  

                            message.setproperty("rec_sign", "success");  

                            message.setbody("[" + fromuser + "]發送檔案: "  

                                    + filename + "/r/n" + "存儲位置: "  

                                    + file.getabsolutepath()  

                                    + getfiletype(filename));  

                            if (client.ischatexist(fromuser)) {  

                                client.getchatroom(fromuser)  

                                        .messagereceivehandler(message);  

                            } else {  

                                chatframethread cft = new chatframethread(  

                                        fromuser, message);  

                                cft.start();  

                            }  

                        } catch (exception e2) {  

                            e2.printstacktrace();  

                        }  

                    }  

                }.start();  

            } else {  

                system.out.println("拒絕接受檔案: " + filename);  

                request.reject();  

                message message = new message();  

                message.setfrom(fromuser);  

                message.setbody("拒絕" + fromuser + "發送檔案: " + filename);  

                message.setproperty("rec_sign", "reject");  

                if (client.ischatexist(fromuser)) {  

                    client.getchatroom(fromuser).messagereceivehandler(message);  

                } else {  

                    chatframethread cft = new chatframethread(fromuser, message);  

                    cft.start();  

                }  

            /* 

             * inputstream in = intransfer.recievefile(); 

             *  

             * string filename = "r"+intransfer.getfilename(); 

             * outputstream out = new fileoutputstream(new 

             * file("d:/receive/"+filename)); byte[] b = new byte[512]; 

             * while(in.read(b) != -1) { out.write(b); out.flush(); } 

             * in.close(); out.close(); 

             */  

        } catch (exception e) {  

            e.printstacktrace();  

        system.out.println("接收檔案結束.....");  

**  

 * 傳回所有組資訊 <rostergroup>  

 *   

 * @return list(rostergroup)  

 */  

public static list<rostergroup> getgroups(roster roster) {  

    list<rostergroup> groupslist = new arraylist<rostergroup>();  

    collection<rostergroup> rostergroup = roster.getgroups();  

    iterator<rostergroup> i = rostergroup.iterator();  

    while (i.hasnext())  

        groupslist.add(i.next());  

    return groupslist;  

/** 

 * 傳回相應(groupname)組裡的所有使用者<rosterentry> 

 *  

 * @return list(rosterentry) 

public static list<rosterentry> getentriesbygroup(roster roster,  

        string groupname) {  

    list<rosterentry> entrieslist = new arraylist<rosterentry>();  

    rostergroup rostergroup = roster.getgroup(groupname);  

    collection<rosterentry> rosterentry = rostergroup.getentries();  

    iterator<rosterentry> i = rosterentry.iterator();  

        entrieslist.add(i.next());  

    return entrieslist;  

 * 傳回所有使用者資訊 <rosterentry> 

public static list<rosterentry> getallentries(roster roster) {  

    collection<rosterentry> rosterentry = roster.getentries();  

使用vcard,很強大,具體自己看api吧,可以看看vcard傳回來xml的組成,含有很多資訊的

 * 擷取使用者的vcard資訊  

 * @param connection  

 * @param user  

 * @return  

 * @throws xmppexception  

public static vcard getuservcard(xmppconnection connection, string user) throws xmppexception  

{  

    vcard vcard = new vcard();  

    vcard.load(connection, user);  

    return vcard;  

 * 擷取使用者頭像資訊 

public static imageicon getuserimage(xmppconnection connection, string user) {  

    imageicon ic = null;  

    try {  

        system.out.println("擷取使用者頭像資訊: "+user);  

        vcard vcard = new vcard();  

        vcard.load(connection, user);  

        if(vcard == null || vcard.getavatar() == null)  

        {  

            return null;  

        bytearrayinputstream bais = new bytearrayinputstream(  

                vcard.getavatar());  

        image image = imageio.read(bais);  

        ic = new imageicon(image);  

        system.out.println("圖檔大小:"+ic.geticonheight()+" "+ic.geticonwidth());  

    } catch (exception e) {  

        e.printstacktrace();  

    return ic;  

 * 添加一個組  

public static boolean addgroup(roster roster,string groupname)  

        roster.creategroup(groupname);  

        return true;  

        return false;  

 * 删除一個組 

public static boolean removegroup(roster roster,string groupname)  

    return false;  

 * 添加一個好友  無分組 

public static boolean adduser(roster roster,string username,string name)  

        roster.createentry(username, name, null);  

 * 添加一個好友到分組 

 * @param roster 

 * @param username 

 * @param name 

 * @return 

public static boolean adduser(roster roster,string username,string name,string groupname)  

        roster.createentry(username, name,new string[]{ groupname});  

 * 删除一個好友 

public static boolean removeuser(roster roster,string username)  

        if(username.contains("@"))  

            username = username.split("@")[0];  

        rosterentry entry = roster.getentry(username);  

        system.out.println("删除好友:"+username);  

        system.out.println("user: "+(roster.getentry(username) == null));  

        roster.removeentry(entry);  

public static list<userbean> searchusers(xmppconnection connection,string serverdomain,string username) throws xmppexception  

    {  

        list<userbean> results = new arraylist<userbean>();  

        system.out.println("查詢開始..............."+connection.gethost()+connection.getservicename());  

        usersearchmanager usm = new usersearchmanager(connection);  

        form searchform = usm.getsearchform(serverdomain);  

        form answerform = searchform.createanswerform();  

        answerform.setanswer("username", true);  

        answerform.setanswer("search", username);  

        reporteddata data = usm.getsearchresults(answerform, serverdomain);  

         iterator<row> it = data.getrows();  

         row row = null;  

         userbean user = null;  

         while(it.hasnext())  

         {  

             user = new userbean();  

             row = it.next();  

             user.setusername(row.getvalues("username").next().tostring());  

             user.setname(row.getvalues("name").next().tostring());  

             user.setemail(row.getvalues("email").next().tostring());  

             system.out.println(row.getvalues("username").next());  

             system.out.println(row.getvalues("name").next());  

             system.out.println(row.getvalues("email").next());  

             results.add(user);  

             //若存在,則有傳回,username一定非空,其他兩個若是有設,一定非空  

         }  

         return results;  

包括上線,隐身,對某人隐身,對某人上線

ublic static void updatestatetoavailable(xmppconnection connection)  

    presence presence = new presence(presence.type.available);  

            nnection.sendpacket(presence);  

public static void updatestatetounavailable(xmppconnection connection)  

    presence presence = new presence(presence.type.unavailable);  

public static void updatestatetounavailabletosomeone(xmppconnection connection,string username)  

    presence.setto(username);  

public static void updatestatetoavailabletosomeone(xmppconnection connection,string username)  

 * 修改心情  

 * @param status  

public static void changestatemessage(xmppconnection connection,string status)  

    presence.setstatus(status);  

    connection.sendpacket(presence);  

有點麻煩,主要是讀入圖檔檔案,編碼,傳輸之

public static void changeimage(xmppconnection connection,file f) throws xmppexception, ioexception{  

        vcard.load(connection);  

            byte[] bytes;  

                bytes = getfilebytes(f);  

                string encodedimage = stringutils.encodebase64(bytes);  

                vcard.setavatar(bytes, encodedimage);  

                vcard.setencodedimage(encodedimage);  

                vcard.setfield("photo", "<type>image/jpg</type><binval>"  

                        + encodedimage + "</binval>", true);  

                bytearrayinputstream bais = new bytearrayinputstream(  

                        vcard.getavatar());  

                image image = imageio.read(bais);  

                imageicon ic = new imageicon(image);  

            vcard.save(connection);  

      private static byte[] getfilebytes(file file) throws ioexception {  

                bufferedinputstream bis = null;  

            try {  

            bis = new bufferedinputstream(new fileinputstream(file));  

            int bytes = (int) file.length();  

            byte[] buffer = new byte[bytes];  

            int readbytes = bis.read(buffer);  

            if (readbytes != buffer.length) {  

                throw new ioexception("entire file not read");  

            return buffer;  

        } finally {  

            if (bis != null) {  

                bis.close();  

即對方改變頭像,狀态,心情時,更新自己使用者清單,其實這裡已經有smack實作的監聽器

nal roster roster = client.getroster();  

roster.addrosterlistener(  

    new rosterlistener() {  

            @override  

            public void entriesadded(collection<string> arg0) {  

                // todo auto-generated method stub  

                system.out.println("--------ee:"+"entriesadded");  

            public void entriesdeleted(collection<string> arg0) {  

                system.out.println("--------ee:"+"entriesdeleted");  

            public void entriesupdated(collection<string> arg0) {  

                system.out.println("--------ee:"+"entriesupdated");  

            public void presencechanged(presence arg0) {  

                system.out.println("--------ee:"+"presencechanged");  

            }     

smacktest例子下載下傳