smack APIを用いたチャットシステムの開発

13041 ワード

昨日smackの関連コードとAPIを勉強したのは、プロジェクトでチャット機能を使うためで、今朝会社に着くとすぐに関連コードを書き始めました.ここでは私がコードを書いたときの感想を書きます.
チャット机能は人と人の间の情报の伝达にほかならないが、私はまずUserShipクラスを书いてチャットの状态とチャットのリストをカプセル化した.
 
private static final long serialVersionUID = 1L;
    boolean status = true;
    List<String> userShip = new ArrayList<String>();

    /**
     * @return the status
     */
    public boolean isStatus() {
        return status;
    }

    /**
     * @param status the status to set
     */
    public void setStatus(boolean status) {
        this.status = status;
    }

    /**
     * @return the userShip
     */
    public List<String> getUserShip() {
        return userShip;
    }

    /**
     * @param userShip the userShip to set
     */
    public void setUserShip(List<String> userShip) {
        this.userShip = userShip;
    }

チャットシステムでは複数のチャットが使用されるので,MultiUserChatというクラスを用いて実現した.チャット中に人が入ったり離れたりする場合、私たちは上に書いてあるUserShipクラスを使います.
final UserShip userShip = new UserShip();

    MultiUserChat mUserChat = null;

    public final void setChatMap(String key, List<String> value) {
        chatMap.put(key, value);
    }

    public final void addUser(String userName) {
        userShip.setStatus(true);
        if (userShip.getUserShip() == null) {
            userShip.setUserShip(new ArrayList<String>());
        }
        userShip.getUserShip().add(userName);
    }

    public final void removeUser(String userName) {
        userShip.setStatus(true);
        if (userShip.getUserShip() == null) {
            userShip.setUserShip(new ArrayList<String>());
        }
        userShip.getUserShip().remove(userName);
    }

私の前のいくつかの転載した文章を見たことがある学生はすべてチャットが接続する必要があることを知っていて、XPPConnection類を使うだけでいいです.接続を行う前にXMPPPConnectionを構築する必要があります.XMPPPConnectionの構築方法はたくさんあります.public XMPPPConnection(String serviceName,Callback Handler callbackHandler)、public XMPPPConnection(String serviceName)、public XMPPPConnection(ConnectionConfiguration config)、public XMPPPConnection(ConnectionConfiguration config,CallbackHandler callbackHandler)ここではpublic XMPPPConnection(ConnectionConfiguration config)を使用していますこれは、ConnectionConfigurationというクラスにhostとportという2つのフィールドがあることを考慮すると、ちょうど私たちがリモートに接続するホストアドレスとポートを表しているため、ConnectionConfigurationクラスにも多くの構造方法があります.public ConnectionConfiguration(String serviceName)、public ConnectionConfiguration(String serviceName、ProxyInfo proxy),public ConnectionConfiguration(String host, int port, String serviceName),public ConnectionConfiguration(String host, int port, String serviceName, ProxyInfo proxy),public ConnectionConfiguration(String host, int port),public ConnectionConfiguration(String host, int port, ProxyInfo proxy)ああ、私が使っているのは当然public ConnectionConfiguration(String host,int port)という構造方法ですが、他のserviceName、proxyのようなものはほとんど差がありません.主にサーバに接続しています.これらの構造方法では、最終的に次のinit方法が呼び出されます.
private void init(String host, int port, String serviceName, ProxyInfo proxy)
    {
        this.host = host;
        this.port = port;
        this.serviceName = serviceName;
        this.proxy = proxy;
        String javaHome = System.getProperty("java.home");
        StringBuilder buffer = new StringBuilder();
        buffer.append(javaHome).append(File.separator).append("lib");
        buffer.append(File.separator).append("security");
        buffer.append(File.separator).append("cacerts");
        truststorePath = buffer.toString();
        truststoreType = "jks";
        truststorePassword = "changeit";
        keystorePath = System.getProperty("javax.net.ssl.keyStore");
        keystoreType = "jks";
        pkcs11Library = "pkcs11.config";
        socketFactory = proxy.getSocketFactory();
    }

次に、具体的な接続コードです.簡単です.
private ConnectionConfiguration connectionConfig;
    private XMPPConnection connection;

    public ChatServiceImpl() {

    }

    /**
     *    IMServer(host,port)
     */
    public ChatServiceImpl(String host, int port) {
        connectionConfig = new ConnectionConfiguration(host, port);
        // connectionConfig.setSASLAuthenticationEnabled(false);
        connection = new XMPPConnection(connectionConfig);
        try {
            connection.connect();
            logger.info("    ,   :" + connection.getServiceName());
        } catch (XMPPException e) {
            e.printStackTrace();
        }
    }

これらの基本的な仕事があれば、私たちはお互いにチャットを始めることができます.具体的な機能は具体的なプロジェクトのニーズに応じて書きます.私のところでは多くの人がチャットする必要があります.それでは、部屋に入ることと部屋を離れることが発生します.私たちはこの2つの状況をリスニングする必要があります.このときに使用されるAPIはDefaultParticipantStatusListenerです.このようなリスニングができます.のチャット状態です.このクラスには状態に関する方法がたくさんあります.私たちはこれらの方法をすべて実現する必要はありません.だから、ここで私はD e f a u l t i c i p antStatusListenerというクラスを継承して特定の方法を実現しました.
private static class DefParticipantStatusListener extends DefaultParticipantStatusListener {
        private final ChatServiceImpl chatService;

        public DefParticipantStatusListener(ChatServiceImpl chatService) {
            this.chatService = chatService;
        }

        /**
         * @see org.jivesoftware.smackx.muc.DefaultParticipantStatusListener#joined(java.lang.String)
         */
        @Override
        public void joined(String participant) {
            chatService.addUser(participant);
            chatService.userShip.setStatus(true);
            logger.info(participant + " -      ");
        }

        /**
         * @see org.jivesoftware.smackx.muc.DefaultParticipantStatusListener#left(java.lang.String)
         */
        @Override
        public void left(String participant) {
            chatService.removeUser(participant);
            chatService.userShip.setStatus(true);
            logger.info(participant + " -      ");
        }

    }

次に具体的な誰かのチャット記録を記憶する必要があります.私はPacketListenerという傍受クラスを実現して実現しました.この傍受クラスはprocessPacketというメッセージパケットを処理するクラスしかありません.パラメータは自然にメッセージパケットPacketですが、私たちがメッセージを処理するのはメッセージ体を処理することです.Packetにはメッセージ体の関連属性が見つかりません.だから私はPacketにサブクラスがあるかどうかを見て、Messageクラスにbodyに関する操作があることを発見しました.
final Map<String, List<String>> chatMap = new HashMap<String, List<String>>();//chatMap                      
private static class DefaultPacketListener implements PacketListener {

        private final ChatServiceImpl chatService;
        private final String userName;

        public DefaultPacketListener(ChatServiceImpl chatService, String userName) {
            this.userName = userName;
            this.chatService = chatService;
        }

        @Override
        public void processPacket(Packet packet) {
            List<String> list = null;
            Message message = (Message) packet;
            Iterator<Body> it = message.getBodies().iterator();
            if (it != null) {
                while (it.hasNext()) {
                    Body body = it.next();
                    logger.info(body.getMessage());

                    if (chatService.chatMap.containsKey(userName)) {
                        logger.info("     - " + userName);
                        list = chatService.chatMap.get(userName);
                    } else {
                        logger.info("    - " + userName);
                        list = new ArrayList<String>();
                    }
                    String msg = body.getMessage();

                    list.add(message.getFrom() + "  : " + msg);
                    chatService.setChatMap(userName, list);
                }
            }
        }
    }

上の2つのlistenerがあれば、部屋に入ってチャットができます.ここではMultiUserChatのpublic synchronized void join(String nickname,String password,DiscussionHistory history,long timeout)という方法で実現されています.この方法は同じステップで、スレッドの安全を保証しています.
public boolean JoinRoom(final String userName, String password, String group, DiscussionHistory history, Long timeout, ChatServiceImpl chatService) {
        MultiUserChat mChat = null;
        try {
            // SASLAuthentication.supportSASLMechanism("bfmp", 0);
            connection.login(userName, password);
            loginState = true;
            mChat = new MultiUserChat(connection, group);
            mUserChat = mChat;
            mChat.join(userName, password, history, SmackConfiguration.getPacketReplyTimeout());
            mChat.addMessageListener(new DefaultPacketListener(chatService, userName));
            mChat.addParticipantStatusListener(new DefParticipantStatusListener(this));

        } catch (XMPPException e) {
            e.printStackTrace();
            logger.error(e.fillInStackTrace());
        }
        return loginState;
    }

次に、具体的なメッセージの送信、メッセージの受信、友人リストの表示を実現します.これらのコードは簡単で、詳しくは説明しません.
public void sendGroupMessage(String content) {
        try {
            mUserChat.sendMessage(content);//  MultiUserChat  sendMessage         
        } catch (XMPPException e) {
            e.printStackTrace();
        }
    }

    /**
     * @see com.dasongame.chat.ChatService#receiveGroupMessage(java.lang.String)
     */
    @Override
    public List<String> receiveGroupMessage(String userName, ChatServiceImpl chatService) {
        List<String> list = null;
        if (chatMap.containsKey(userName)) {
            list = chatMap.get(userName);
            setChatMap(userName, new ArrayList<String>());
        }
        return list;
    }

    /**
     * @see com.dasongame.chat.ChatService#getUserShip()
     */
    @Override
    public List<String> getOccupants(ChatServiceImpl chatSerivce) {
        List<String> list = new ArrayList<String>();
        Iterator<String> it = null;
        it = chatSerivce.mUserChat.getOccupants();//            
        while (it != null && it.hasNext()) {
            list.add(it.next());
        }
        userShip.setStatus(false);
        return list;
    }

    /**
     * @see com.dasongame.chat.ChatService#getUserShipStatus()
     */
    @Override
    public boolean isOccupantsChange(ChatServiceImpl chatSerivce) {
        return chatSerivce.userShip.isStatus();
    }

    /**
     * @see com.dasongame.chat.ChatService#sendMessage(java.lang.String, java.lang.String)
     */
    @Override
    public void sendMessage(String message, String to) {
        Chat chat = connection.getChatManager().createChat(to, new MessageListener() {
            @Override
            public void processMessage(Chat chat, Message message) {
                System.out.println(message.getFrom() + " - " + message.getBody() + " - " + new Date().getTime());
            }
        });
        try {
            chat.sendMessage(message);//         
        } catch (XMPPException e) {
            System.out.println("      ");
            e.printStackTrace();
        }
    }

    /**
     * @see com.dasongame.chat.ChatService#displayBuddyList()
     */
    @Override
    public void displayBuddyList() {
        roster = connection.getRoster();
        if (roster != null) {
            roster.setSubscriptionMode(Roster.SubscriptionMode.accept_all);
            Collection<RosterEntry> entries = roster.getEntries();

            System.out.println("    :" + roster.getEntryCount());
            System.out.println("    :");
            for (RosterEntry r : entries) {
                System.out.println("\t" + r.getUser());
            }
        }
    }

また、接続を切断する方法もあります.
public void disconnect() {
        connection.disconnect();
    }

これで基本的にチャットの基本的なニーズが実現されました.