XMPP——Smack

转自:http://blog.csdn.net/wklken/article/details/6460075

[1]连接、登陆及账户操作

需求:

基于XMPP的IM工具,需实现和gtalk实现通信,需实现同spark的通信,需架设服务器,实现同自身客户端的通信,传文件,视频聊天

 

写完未实现需要改进的地方:离线消息,离线文件

一、XMPP

XMPP : The Extensible Messaging and Presence Protocol

中文全称:可扩展通讯和表示协议

简介:

可扩展通讯和表示协议 (XMPP) 可用于服务类实时通讯、表示和需求 - 响应服务中的 XML 数据元流式传输。XMPP 以 Jabber 协议为基础,而 Jabber 是即时通讯中常用的开放式协议。

 

二、Smack

    Smack是一个开源,易于使用的XMPP(jabber)客户端类库。

   Smack API, 是一个 Java 的XMPP Client Library,也是由Jive Software开发。 优点:编程简单。 缺点:API并非为大量并发用户设计,每个客户要1个线程,占用资源大,1台机器只能模拟有限(数千个)客户.

smack是一个用 java 写的XMPP客户端代码库, 是 spark 的核心.

 

二、连接及断开

基本方法

 XMPPConnection connection = new XMPPConnection("gmail.com");

        connection.connect();

实现的方法

 

[java] view plain copy print ?
  1. public static XMPPConnection getConnection(String domain) throws XMPPException {  
  2.       
  3.      XMPPConnection connection = new XMPPConnection(domain);  
  4.      connection.connect();  
  5.      return connection;  
  6. }  
  7.   
  8.   
  9. public static XMPPConnection getConnection(String domain,int port) throws XMPPException {  
  10.      ConnectionConfiguration config = new ConnectionConfiguration(domain,port);  
  11.      XMPPConnection connection = new XMPPConnection(config);  
  12.      connection.connect();  
  13.      return connection;  
  14. }  

断开  

     connection.disconnect();

     

四、登陆

connection.login("[email protected]", "*****");

 

五、账户操作

 

   可以对账户进行基本操作,包括注册,注销,修改密码

[c-sharp] view plain copy print ?
  1. /** 
  2.      * 注册用户 
  3.      * @param connection 
  4.      * @param regUserName 
  5.      * @param regUserPwd 
  6.      * @return 
  7.      */  
  8.     public static boolean createAccount(XMPPConnection connection,String regUserName,String regUserPwd)  
  9.     {  
  10.         try {  
  11.             connection.getAccountManager().createAccount(regUserName, regUserPwd);  
  12.             return true;  
  13.         } catch (Exception e) {  
  14.             return false;  
  15.         }  
  16.     }  
  17.       
  18.     /** 
  19.      * 删除当前用户 
  20.      * @param connection 
  21.      * @return 
  22.      */  
  23.     public static boolean deleteAccount(XMPPConnection connection)  
  24.     {  
  25.         try {  
  26.             connection.getAccountManager().deleteAccount();  
  27.           
  28.             return true;  
  29.         } catch (Exception e) {  
  30.             return false;  
  31.         }  
  32.     }  
  33.       
  34.     /** 
  35.      * 删除修改密码 
  36.      * @param connection 
  37.      * @return 
  38.      */  
  39.     public static boolean changePassword(XMPPConnection connection,String pwd)  
  40.     {  
  41.         try {  
  42.             connection.getAccountManager().changePassword(pwd);  
  43.           
  44.             return true;  
  45.         } catch (Exception e) {  
  46.             return false;  
  47.         }  
  48.     }  

 

[2]会话、消息监听、字体表情和聊天窗口控制

上一篇是连接,登陆登出和账户管理

继续

连接之后,拿到了connection,通过它可以搞定会话

 

 

1.       建立一个会话

[java] view plain copy print ?
  1. MessageListener msgListener  
  2.  = new MessageListener()  
  3.         {  
  4.             public void processMessage(Chat chat, Message message)  
  5.             {  
  6.   
  7.                 if (message != null && message.getBody() != null)  
  8.                 {  
  9.                     System.out.println("收到消息:" + message.getBody());  
  10.                     // 可以在这进行针对这个用户消息的处理,但是这里我没做操作,看后边聊天窗口的控制  
  11.                 }  
  12.   
  13.             }  
  14.         };  
  15. Chat chat = Client.getConnection().getChatManager()  
  16.                 .createChat(userName, msgListener);  

 

通过会话发送消息

两个方法,一个直接发送一条文本,一个发送一个Message对象,可包含一些信息,一般使用后者,因为需要包装字体等信息

[java] view plain copy print ?
  1. public static void sendMessage(Chat chat,String message) throws XMPPException {  
  2.         chat.sendMessage(message);  
  3.     }  
  4.       
  5.     public static void sendMessage(Chat chat,Message message) throws XMPPException {  
  6.         chat.sendMessage(message);  
  7.     }  

 

 

2.       消息监听

每个connection的chatManager可以设置一个消息监听器,因为IM必须实现他人对你发起会话也会弹出窗口,即自己可以主动发起会话,也可以接收他人发起的会话

[java] view plain copy print ?
  1. ChatManager manager = Client.getConnection().getChatManager();  
  2.         manager.addChatListener(new ChatManagerListener() {  
  3.             public void chatCreated(Chat chat, boolean arg1) {  
  4.                 chat.addMessageListener(new MessageListener() {  
  5.                     public void processMessage(Chat arg0, Message message) {  
  6.                      //若是聊天窗口已存在,将消息转往目前窗口  
  7.                      //若是窗口不存在,开新的窗口并注册  
  8.   
  9.                     }     
  10.                 });  
  11.             }  
  12.         });  

   其实窗口的管理是使用线程的,来一个新的会话,起线程

3.  字体表情

在这里实现字体和表情是使用自身开发IM之间的实现。

 

字体实现思想:

在发送消息的同时,将字体内容作为附加信息发送,接收方接收到根据字体信息进行处理后显示

  

   实现:使用Message对消息进行封装

[java] view plain copy print ?
  1. Message msg = new Message();  
  2.         msg.setProperty("size", size);  
  3.         msg.setProperty("kind", kind);  
  4.         msg.setProperty("bold", bold);  
  5.         msg.setProperty("italic", italic);  
  6.         msg.setProperty("underline", underline);  
  7.         msg.setProperty("color", color);  
  8.         msg.setBody(getSendInfo());//真正的消息  
  9.         chat.sendMessage(msg);  

 

 

接收方先获取设置信息后展示

       展示的控件: JTextPane receiveText = new JTextPane();

[java] view plain copy print ?
  1. Style style = receiveText.addStyle("font", null);  
  2.         StyleConstants.setFontSize(style, size);  
  3.         StyleConstants.setFontFamily(style, kind);  
  4.         StyleConstants.setBold(style, bold);  
  5.         StyleConstants.setItalic(style, italic);  
  6.         StyleConstants.setUnderline(style, underline);  
  7.         StyleConstants.setForeground(style, color);  

 

  表情:

       实现机制是客户端本身存有一套表情图片,在选中时,将表情编号加入到消息中,实际发送出去的只是文本,拿到后解析字符串,将编号转为具体表情展示

      具体就不写了

 

 

1.  聊天窗口控制

所谓控制,主要是控制唯一性

无论是你发起一个会话开启一个窗口,还是对方给你发送会话开启,你与对方之间有且仅有一个窗口,之后任何消息都在这个窗口中处理

 

思想:单例类,持有一个

//现有的聊天窗口

    publicstatic TreeMap<String,TelFrame> currentChat = new TreeMap<String,TelFrame>();

 

其实应该用concurrentHashMap可能会更好,不顾我这边分派的主线程只有一个,不涉及多个线程并发的问题,所以用了Treemap,汗一个,貌似应该hashmap,当时考虑不同

 

然后,在接收消息的时候根据发消息的用户,判定窗口是否存在,存在,转发消息到该窗口,不存在,建立新的窗口

若是关闭窗口,注销之

 

[java] view plain copy print ?
  1. //注册聊天室  
  2.     public static void registerChat(String userName,TelFrame chatroom)  
  3.     {  
  4.         //System.out.println("注册:"+userName);  
  5.         currentChat.put(userName, chatroom);  
  6.     }  
  7.     //注销注册  
  8.     public static void removeChat(String userName)  
  9.     {  
  10.         System.out.println("用户注销聊天室:"+userName);  
  11.         currentChat.remove(userName);  
  12.     }  
  13.     //查看是否已有  
  14.     public static boolean isChatExist(String userName)  
  15.     {  
  16.           
  17.         return currentChat.containsKey(userName);  
  18.     }  
  19.     //获取对象  
  20.     public static TelFrame getChatRoom(String userName)  
  21.     {  
  22.         return currentChat.get(userName);  
  23.     }  
  24.       
  25.  下一篇,主要是用户列表,头像,分组及管理的  

[3]用户列表,头像,组操作,用户操作

转载请注明出处:http://blog.csdn.net/wklken/archive/2011/06/01/6460112.aspx

上一篇主要是会话的管理

继续,这是显示用户列表方面的

 

1.       用户列表

Smack主要使用Roster进行列表管理的

connection.getRoster();

[java] view plain copy print ?
  1. /** 
  2.      * 返回所有组信息 <RosterGroup> 
  3.      *  
  4.      * @return List(RosterGroup) 
  5.      */  
  6.     public static List<RosterGroup> getGroups(Roster roster) {  
  7.         List<RosterGroup> groupsList = new ArrayList<RosterGroup>();  
  8.         Collection<RosterGroup> rosterGroup = roster.getGroups();  
  9.         Iterator<RosterGroup> i = rosterGroup.iterator();  
  10.         while (i.hasNext())  
  11.             groupsList.add(i.next());  
  12.         return groupsList;  
  13.     }  
  14.   
  15.     /** 
  16.      * 返回相应(groupName)组里的所有用户<RosterEntry> 
  17.      *  
  18.      * @return List(RosterEntry) 
  19.      */  
  20.     public static List<RosterEntry> getEntriesByGroup(Roster roster,  
  21.             String groupName) {  
  22.         List<RosterEntry> EntriesList = new ArrayList<RosterEntry>();  
  23.         RosterGroup rosterGroup = roster.getGroup(groupName);  
  24.         Collection<RosterEntry> rosterEntry = rosterGroup.getEntries();  
  25.         Iterator<RosterEntry> i = rosterEntry.iterator();  
  26.         while (i.hasNext())  
  27.             EntriesList.add(i.next());  
  28.         return EntriesList;  
  29.     }  
  30.   
  31.     /** 
  32.      * 返回所有用户信息 <RosterEntry> 
  33.      *  
  34.      * @return List(RosterEntry) 
  35.      */  
  36.     public static List<RosterEntry> getAllEntries(Roster roster) {  
  37.         List<RosterEntry> EntriesList = new ArrayList<RosterEntry>();  
  38.         Collection<RosterEntry> rosterEntry = roster.getEntries();  
  39.         Iterator<RosterEntry> i = rosterEntry.iterator();  
  40.         while (i.hasNext())  
  41.             EntriesList.add(i.next());  
  42.         return EntriesList;  
  43.     }  

 

这里注意下,与gtalk通讯,貌似gtalk是没有分组的,汗,所以使用第三个方法直接取

 

当然,还要处理,若是刚注册用户,一个组都没有的,需要默认两个组,我的好友及黑名单

黑名单的消息,一律杀掉,不会接受处理

2.       用户头像的获取

使用VCard,很强大,具体自己看API吧

可以看看VCard传回来XML的组成,含有很多信息的

 

[java] view plain copy print ?
  1. /** 
  2.      * 获取用户的vcard信息 
  3.      * @param connection 
  4.      * @param user 
  5.      * @return 
  6.      * @throws XMPPException 
  7.      */  
  8.     public static VCard getUserVCard(XMPPConnection connection, String user) throws XMPPException  
  9.     {  
  10.         VCard vcard = new VCard();  
  11.         vcard.load(connection, user);  
  12.           
  13.         return vcard;  
  14.     }  
  15.   
  16. 获取头像使用  
  17.     /** 
  18.      * 获取用户头像信息 
  19.      */  
  20.     public static ImageIcon getUserImage(XMPPConnection connection, String user) {  
  21.         ImageIcon ic = null;  
  22.         try {  
  23.             System.out.println("获取用户头像信息: "+user);  
  24.             VCard vcard = new VCard();  
  25.             vcard.load(connection, user);  
  26.               
  27.             if(vcard == null || vcard.getAvatar() == null)  
  28.             {  
  29.                 return null;  
  30.             }  
  31.             ByteArrayInputStream bais = new ByteArrayInputStream(  
  32.                     vcard.getAvatar());  
  33.             Image image = ImageIO.read(bais);  
  34.       
  35.               
  36.             ic = new ImageIcon(image);  
  37.             System.out.println("图片大小:"+ic.getIconHeight()+" "+ic.getIconWidth());  
  38.           
  39.         } catch (Exception e) {  
  40.             e.printStackTrace();  
  41.         }  
  42.         return ic;  
  43.     }  
  

 

3.       组操作和用户分组操作

主要是建立删除分组,用户添加到分组等操作

 

 

[c-sharp] view plain copy print ?
  1. /** 
  2.      * 添加一个组 
  3.      */  
  4.     public static boolean addGroup(Roster roster,String groupName)  
  5.     {  
  6.         try {  
  7.             roster.createGroup(groupName);  
  8.             return true;  
  9.         } catch (Exception e) {  
  10.             e.printStackTrace();  
  11.             return false;  
  12.         }  
  13.     }  
  14.       
  15.     /** 
  16.      * 删除一个组 
  17.      */  
  18.     public static boolean removeGroup(Roster roster,String groupName)  
  19.     {  
  20.         return false;  
  21.     }  
  22.       
  23.     /** 
  24.      * 添加一个好友  无分组 
  25.      */  
  26.     public static boolean addUser(Roster roster,String userName,String name)  
  27.     {  
  28.         try {  
  29.             roster.createEntry(userName, name, null);  
  30.             return true;  
  31.         } catch (Exception e) {  
  32.             e.printStackTrace();  
  33.             return false;  
  34.         }  
  35.     }  
  36.     /** 
  37.      * 添加一个好友到分组 
  38.      * @param roster 
  39.      * @param userName 
  40.      * @param name 
  41.      * @return 
  42.      */  
  43.     public static boolean addUser(Roster roster,String userName,String name,String groupName)  
  44.     {  
  45.         try {  
  46.             roster.createEntry(userName, name,new String[]{ groupName});  
  47.             return true;  
  48.         } catch (Exception e) {  
  49.             e.printStackTrace();  
  50.             return false;  
  51.         }  
  52.     }  
  53.       
  54.     /** 
  55.      * 删除一个好友 
  56.      * @param roster 
  57.      * @param userName 
  58.      * @return 
  59.      */  
  60.     public static boolean removeUser(Roster roster,String userName)  
  61.     {  
  62.         try {  
  63.               
  64.             if(userName.contains("@"))  
  65.             {  
  66.                 userName = userName.split("@")[0];  
  67.             }  
  68.             RosterEntry entry = roster.getEntry(userName);  
  69.             System.out.println("删除好友:"+userName);  
  70.             System.out.println("User: "+(roster.getEntry(userName) == null));  
  71.             roster.removeEntry(entry);  
  72.               
  73.             return true;  
  74.         } catch (Exception e) {  
  75.             e.printStackTrace();  
  76.             return false;  
  77.         }  
  78.           
  79.     }  
  

 

4.     用户查询

本来是用户操作的,分组和增删在3里讲了,这里主要是查询操作

查询用户

[java] view plain copy print ?
  1. public static List<UserBean> searchUsers(XMPPConnection connection,String serverDomain,String userName) throws XMPPException  
  2.     {  
  3.         List<UserBean> results = new ArrayList<UserBean>();  
  4.         System.out.println("查询开始..............."+connection.getHost()+connection.getServiceName());  
  5.           
  6.         UserSearchManager usm = new UserSearchManager(connection);  
  7.           
  8.           
  9.         Form searchForm = usm.getSearchForm(serverDomain);  
  10.         Form answerForm = searchForm.createAnswerForm();  
  11.         answerForm.setAnswer("Username", true);  
  12.         answerForm.setAnswer("search", userName);  
  13.         ReportedData data = usm.getSearchResults(answerForm, serverDomain);  
  14.            
  15.          Iterator<Row> it = data.getRows();  
  16.          Row row = null;  
  17.          UserBean user = null;  
  18.          while(it.hasNext())  
  19.          {  
  20.              user = new UserBean();  
  21.              row = it.next();  
  22.              user.setUserName(row.getValues("Username").next().toString());  
  23.              user.setName(row.getValues("Name").next().toString());  
  24.              user.setEmail(row.getValues("Email").next().toString());  
  25.              System.out.println(row.getValues("Username").next());  
  26.              System.out.println(row.getValues("Name").next());  
  27.              System.out.println(row.getValues("Email").next());  
  28.              results.add(user);  
  29.              //若存在,则有返回,UserName一定非空,其他两个若是有设,一定非空  
  30.          }  
  31.            
  32.          return results;  
  33.     }  

 

以上查询貌似是多字段查询,即用户多个属性中某一个符合即作为查询结果

实际是可以实现根据某一特定字段查询的,如用户名,或昵称,这里笼统了,若需扩展去查看下API重写下

 

 

下一篇,状态,心情和头像修改

[4]状态,心情,头像更改

这里写完,最基本的IM功能也就完了,

还剩下个发送接收文件,离线消息扩展等等

 

呵呵,三天时间,看的不是很深入,欢迎大家补充呀

 

1.       修改自身状态

包括上线,隐身,对某人隐身,对某人上线

[java] view plain copy print ?
  1. public static void updateStateToAvailable(XMPPConnection connection)  
  2.     {  
  3.         Presence presence = new Presence(Presence.Type.available);  
  4.         connection.sendPacket(presence);  
  5.      }  
  6.       
  7.     public static void updateStateToUnAvailable(XMPPConnection connection)  
  8.     {  
  9.         Presence presence = new Presence(Presence.Type.unavailable);  
  10.         connection.sendPacket(presence);  
  11.         }  
  12.       
  13.     public static void updateStateToUnAvailableToSomeone(XMPPConnection connection,String userName)  
  14.     {  
  15.         Presence presence = new Presence(Presence.Type.unavailable);  
  16.         presence.setTo(userName);  
  17.         connection.sendPacket(presence);  
  18.     }  
  19.     public static void updateStateToAvailableToSomeone(XMPPConnection connection,String userName)  
  20.     {  
  21.         Presence presence = new Presence(Presence.Type.available);  
  22.         presence.setTo(userName);  
  23.         connection.sendPacket(presence);  
  24.   
  25.     }  

2.       心情修改

  

[java] view plain copy print ?
  1. /** 
  2.      * 修改心情 
  3.      * @param connection 
  4.      * @param status 
  5.      */  
  6.     public static void changeStateMessage(XMPPConnection connection,String status)  
  7.     {  
  8.         Presence presence = new Presence(Presence.Type.available);  
  9.         presence.setStatus(status);  
  10.         connection.sendPacket(presence);  
  11.       
  12.     }  

3.       修改用户头像

有点麻烦,主要是读入图片文件,编码,传输之

[java] view plain copy print ?
  1. public static void changeImage(XMPPConnection connection,File f) throws XMPPException, IOException  
  2.     {  
  3.       
  4.         VCard vcard = new VCard();  
  5.         vcard.load(connection);  
  6.           
  7.             byte[] bytes;  
  8.             
  9.                 bytes = getFileBytes(f);  
  10.                 String encodedImage = StringUtils.encodeBase64(bytes);  
  11.                 vcard.setAvatar(bytes, encodedImage);  
  12.                 vcard.setEncodedImage(encodedImage);  
  13.                 vcard.setField("PHOTO", "<TYPE>image/jpg</TYPE><BINVAL>"  
  14.                         + encodedImage + "</BINVAL>", true);  
  15.                   
  16.                   
  17.                 ByteArrayInputStream bais = new ByteArrayInputStream(  
  18.                         vcard.getAvatar());  
  19.                 Image image = ImageIO.read(bais);  
  20.                 ImageIcon ic = new ImageIcon(image);  
  21.                    
  22.              
  23.             
  24.             vcard.save(connection);  
  25.              
  26.     }  
  27.       
  28.     private static byte[] getFileBytes(File file) throws IOException {  
  29.         BufferedInputStream bis = null;  
  30.         try {  
  31.             bis = new BufferedInputStream(new FileInputStream(file));  
  32.             int bytes = (int) file.length();  
  33.             byte[] buffer = new byte[bytes];  
  34.             int readBytes = bis.read(buffer);  
  35.             if (readBytes != buffer.length) {  
  36.                 throw new IOException("Entire file not read");  
  37.             }  
  38.             return buffer;  
  39.         } finally {  
  40.             if (bis != null) {  
  41.                 bis.close();  
  42.             }  
  43.         }  
  44. }  

4.  补充,用户状态的监听

 

即对方改变头像,状态,心情时,更新自己用户列表,其实这里已经有smack实现的监听器

 

 

 

 

[java] view plain copy print ?
  1. final Roster roster = Client.getRoster();  
  2.           
  3.         roster.addRosterListener(  
  4.                 new RosterListener() {  
  5.   
  6.                     @Override  
  7.                     public void entriesAdded(Collection<String> arg0) {  
  8.                         // TODO Auto-generated method stub  
  9.                         System.out.println("--------EE:"+"entriesAdded");  
  10.                     }  
  11.   
  12.                     @Override  
  13.                     public void entriesDeleted(Collection<String> arg0) {  
  14.                         // TODO Auto-generated method stub  
  15.                         System.out.println("--------EE:"+"entriesDeleted");  
  16.                     }  
  17.   
  18.                     @Override  
  19.                     public void entriesUpdated(Collection<String> arg0) {  
  20.                         // TODO Auto-generated method stub  
  21.                         System.out.println("--------EE:"+"entriesUpdated");  
  22.                     }  
  23.   
  24.                     @Override  
  25.                     public void presenceChanged(Presence arg0) {  
  26.                         // TODO Auto-generated method stub  
  27.                         System.out.println("--------EE:"+"presenceChanged");  
  28.                     }     
  29.                       
  30.                 });  
  31.               

 

下一篇主要是文件传输和接收

[5]文件传输及离线消息的获取

三天时间,赶在最后一下午实现了文件的传输,本来需要实现离线文件的发送的,一直没想好怎么弄,找openfire的离线文件插件没找到,后来想出一种方法,起服务器时起了一个系统用户,一直在线,当用户发送离线文件,检测到对方不存在,先发给系统用户,存到服务器路径,并在数据库中保存信息,当对方上线时,系统用户查表,拿文件发送

 

想是这么想的,问题是时间太紧,没有实现,囧。

下一篇写离线消息和离线文件

1.       文件的发送

开一个文件选择框,选中文件后再调用下面的方法

 

[java] view plain copy print ?
  1. public static void sendFile(XMPPConnection connection,  
  2.             String user, File file) throws XMPPException, InterruptedException {  
  3.           
  4.         System.out.println("发送文件开始"+file.getName());  
  5.         FileTransferManager transfer = new FileTransferManager(Client.getConnection());  
  6.         System.out.println("发送文件给: "+user+Client.getServiceNameWithPre());  
  7.         OutgoingFileTransfer out = transfer.createOutgoingFileTransfer(user+Client.getServiceNameWithPre()+"/Smack");//  
  8.           
  9.         out.sendFile(file, file.getName());  
  10.           
  11.         System.out.println("//////////");  
  12.         System.out.println(out.getStatus());  
  13.         System.out.println(out.getProgress());  
  14.         System.out.println(out.isDone());  
  15.           
  16.         System.out.println("//////////");  
  17.           
  18.         System.out.println("发送文件结束");  
  19.     }  

 

 

2.       文件接收,必须使用监听

 

[java] view plain copy print ?
  1. FileTransferManager transfer = new FileTransferManager(connection);  
  2. transfer.addFileTransferListener(new RecFileTransferListener());  
  3.   
  4. public class RecFileTransferListener implements FileTransferListener {  
  5.   
  6.     public String getFileType(String fileFullName)  
  7.     {  
  8.         if(fileFullName.contains("."))  
  9.         {  
  10.             return "."+fileFullName.split("//.")[1];  
  11.         }else{  
  12.             return fileFullName;  
  13.         }  
  14.           
  15.     }  
  16.       
  17.     @Override  
  18.     public void fileTransferRequest(FileTransferRequest request) {  
  19.         System.out.println("接收文件开始.....");  
  20.         final IncomingFileTransfer inTransfer = request.accept();  
  21.         final String fileName = request.getFileName();  
  22.         long length = request.getFileSize();   
  23.         final String fromUser = request.getRequestor().split("/")[0];  
  24.         System.out.println("文件大小:"+length + "  "+request.getRequestor());  
  25.         System.out.println(""+request.getMimeType());  
  26.         try {   
  27.               
  28.             JFileChooser chooser = new JFileChooser();   
  29.             chooser.setCurrentDirectory(new File("."));   
  30.               
  31.             int result = chooser.showOpenDialog(null);  
  32.               
  33.             if(result==JFileChooser.APPROVE_OPTION)  
  34.             {  
  35.                 final File file = chooser.getSelectedFile();  
  36.                 System.out.println(file.getAbsolutePath());  
  37.                     new Thread(){  
  38.                         public void run()  
  39.                         {  
  40.                         try {  
  41.   
  42.                             System.out.println("接受文件: " + fileName);  
  43.                             inTransfer  
  44.                                     .recieveFile(new File(file  
  45.                                             .getAbsolutePath()  
  46.                                             + getFileType(fileName)));  
  47.   
  48.                             Message message = new Message();  
  49.                             message.setFrom(fromUser);  
  50.                             message.setProperty("REC_SIGN", "SUCCESS");  
  51.                             message.setBody("["+fromUser+"]发送文件: "+fileName+"/r/n"+"存储位置: "+file.getAbsolutePath()+ getFileType(fileName));  
  52.                             if (Client.isChatExist(fromUser)) {  
  53.                                 Client.getChatRoom(fromUser).messageReceiveHandler(  
  54.                                         message);  
  55.                             } else {  
  56.                                 ChatFrameThread cft = new ChatFrameThread(  
  57.                                         fromUser, message);  
  58.                                 cft.start();  
  59.                                   
  60.                             }  
  61.                         } catch (Exception e2) {  
  62.                             e2.printStackTrace();  
  63.                         }  
  64.                         }  
  65.                     }.start();  
  66.             }else{  
  67.                   
  68.                 System.out.println("拒绝接受文件: "+fileName);  
  69.                   
  70.                 request.reject();  
  71.                 Message message = new Message();  
  72.                 message.setFrom(fromUser);  
  73.                 message.setBody("拒绝"+fromUser+"发送文件: "+fileName);  
  74.                 message.setProperty("REC_SIGN", "REJECT");  
  75.                 if (Client.isChatExist(fromUser)) {  
  76.                     Client.getChatRoom(fromUser)  
  77.                             .messageReceiveHandler(message);  
  78.                 } else {  
  79.                     ChatFrameThread cft = new ChatFrameThread(  
  80.                             fromUser, message);  
  81.                     cft.start();  
  82.                 }  
  83.             }  
  84.               
  85.               
  86.               
  87.               
  88.                
  89.             /* InputStream in = inTransfer.recieveFile(); 
  90.               
  91.              String fileName = "r"+inTransfer.getFileName(); 
  92.               
  93.              OutputStream out = new FileOutputStream(new File("d:/receive/"+fileName)); 
  94.              byte[] b = new byte[512]; 
  95.              while(in.read(b) != -1) 
  96.              { 
  97.                  out.write(b); 
  98.                  out.flush(); 
  99.              } 
  100.               
  101.              in.close(); 
  102.              out.close();*/  
  103.         } catch (Exception e) {  
  104.             e.printStackTrace();  
  105.         }  
  106.           
  107.         System.out.println("接收文件结束.....");  
  108.   
  109.     }  
  110.   
  111. }  

 

 

 

 

晕死,在演示的时候竟然发送文件崩盘了。。。。。实在无语

对了,在发送文件的createOutgoing那边有问题,貌似/Smack,哎,对spark发送就不成功

 

短短三天,查资料差得头晕,中文的信息貌似少之又少,哎,匆匆完成,只能算是个半成品,大家自己完善吧。

 

呵呵,下一篇最后一篇了,谢谢离线消息和离线文件吧

[6]离线消息和离线文件的实现

终篇,三天所学所用,也就这些,如果需要大家要自己去查资料研究研究,功能其实可以很强大的

可惜界面做得不好,一大短处,从大一迄今没整好,主要是个人审美不行,哎

 

毕业季呀毕业季,明天摆摊卖书,再半月就可能和生活四年的兄弟姐妹说再见,考研考公务员工作的,各奔东西了,我也将南下杭州

感慨,天下无不散之筵席

在此祝所有刚毕业的,学业事业有成吧

 

不废话了,貌似最近太感性了,理科男,伤不起呀

 

1.离线消息

  openfire本身是支持离线消息的,不需要进行额外处理,可以用spark测试下

  使用smack,其实他提供了相应的方法

  Class OfflineMessageManager

 

  可以看下描述

 

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.

 

英文退化了点,汗,大意就是,必须在发送在线信息之前去获取离线消息 

 

刚开始没看这个,结果在上线之后,去取,结果。。。。离线消息数量总是为零,囧

 

首先,连接,状态要设为离线

 

[java] view plain copy print ?
  1. ConnectionConfiguration connConfig = new ConnectionConfiguration(serverDomain);  
  2.     
  3.   connConfig.setSendPresence(false); // where connConfig is object of .  
  4.   
  5.      connection = new XMPPConnection(connConfig);  
  6.      connection.connect();  

 

然后,登陆

  connection.login(userName, pwd);

 

接着,拿离线消息

 

[java] view plain copy print ?
  1. OfflineMessageManager offlineManager = new OfflineMessageManager(  
  2.                 Client.getConnection());  
  3.         try {  
  4.             Iterator<org.jivesoftware.smack.packet.Message> it = offlineManager  
  5.                     .getMessages();  
  6.   
  7.             System.out.println(offlineManager.supportsFlexibleRetrieval());  
  8.             System.out.println("离线消息数量: " + offlineManager.getMessageCount());  
  9.   
  10.               
  11.             Map<String,ArrayList<Message>> offlineMsgs = new HashMap<String,ArrayList<Message>>();  
  12.               
  13.             while (it.hasNext()) {  
  14.                 org.jivesoftware.smack.packet.Message message = it.next();  
  15.                 System.out  
  16.                         .println("收到离线消息, Received from 【" + message.getFrom()  
  17.                                 + "】 message: " + message.getBody());  
  18.                 String fromUser = message.getFrom().split("/")[0];  
  19.   
  20.                 if(offlineMsgs.containsKey(fromUser))  
  21.                 {  
  22.                     offlineMsgs.get(fromUser).add(message);  
  23.                 }else{  
  24.                     ArrayList<Message> temp = new ArrayList<Message>();  
  25.                     temp.add(message);  
  26.                     offlineMsgs.put(fromUser, temp);  
  27.                 }  
  28.             }  
  29.   
  30.             //在这里进行处理离线消息集合......  
  31.             Set<String> keys = offlineMsgs.keySet();  
  32.             Iterator<String> offIt = keys.iterator();  
  33.             while(offIt.hasNext())  
  34.             {  
  35.                 String key = offIt.next();  
  36.                 ArrayList<Message> ms = offlineMsgs.get(key);  
  37.                 TelFrame tel = new TelFrame(key);  
  38.                 ChatFrameThread cft = new ChatFrameThread(key, null);  
  39.                 cft.setTel(tel);  
  40.                 cft.start();  
  41.                 for (int i = 0; i < ms.size(); i++) {  
  42.                     tel.messageReceiveHandler(ms.get(i));  
  43.                 }  
  44.             }  
  45.               
  46.               
  47.             offlineManager.deleteMessages();  
  48.         } catch (Exception e) {  
  49.             e.printStackTrace();  
  50.         }  

 

记得最后要把离线消息删除,即通知服务器删除离线消息

offlineManager.deleteMessages();

否则,下次上了消息还存在

接着,上线

 Presence presence = new Presence(Presence.Type.available);
        connection.sendPacket(presence);

 

2.离线文件

 

这个我没实现,汗

主要思想:开发openfire插件,拦截离线文件,将文件存到服务器上,同时在数据库里开一张表,存储文件信息

               当用户上线时,查表,若是有,根据路径,拿了发送

当然,大家可以谷歌下是否有相应的插件,时间紧迫,我倒是没找着

 

 

 

到这里,大概就这些了,对了,还扩展了个视频音频聊天,不过使用的是JMF,点对点的,本来打算使用jingle的,结果连API文档都没找到,晕死

 

就这些



你可能感兴趣的:(smack,XMPP)