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

实现的方法

 

  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("javatest2011@gmail.com", "*****");

 

五、账户操作

 

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

[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.       建立一个会话

  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对象,可包含一些信息,一般使用后者,因为需要包装字体等信息

  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必须实现他人对你发起会话也会弹出窗口,即自己可以主动发起会话,也可以接收他人发起的会话

  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对消息进行封装

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

  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,当时考虑不同

 

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

若是关闭窗口,注销之

 

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

  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的组成,含有很多信息的

 

  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里讲了,这里主要是查询操作

查询用户

  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.       修改自身状态

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

  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.       心情修改

  

  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.       修改用户头像

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

  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实现的监听器

 

 

 

 

  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.       文件的发送

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

 

  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.       文件接收,必须使用监听

 

  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.

 

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

 

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

 

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

 

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

 

接着,拿离线消息

 

  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文档都没找到,晕死

 

就这些



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值