JavaSE写仿QQ聊天室

用到Java SE中的Socket进行连接

登陆Server

这是服务器端,需要首先启动且只能启动一次
这里写图片描述

登陆Client

1号登陆
这里写图片描述

2号登陆

这里写图片描述

屏幕下方托盘
这里登陆2个用户,鼠标放在上面会出现如图
这里写图片描述

鼠标右击这里写图片描述

托盘图标要放在 src 目录下,不然查找不到


代码

代码下载
http://download.csdn.net/download/xiao_ma_csdn/10269610

Server4

package com.qqText;

import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;
import java.util.Vector;

import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.border.TitledBorder;
import javax.swing.event.MouseInputListener;

public class Server4 extends Thread {

    static DataOutputStream dos;
    static DataInputStream dis;
    public JFrame frame;
    public JTextArea viewArea;
    public JTextField viewField;
    public JButton button1, buttonLogin, buttonExit;
    public JLabel jlable;
    public JTextField MyName;
    public static DefaultListModel listModel;
    public static JList userList; // 显示对象列表
    public JSplitPane centerSplit;
    public boolean isConnected = false;
    static Server4 Server4;
    static Socket s;

    public static HashMap<String,Socket> hash = new HashMap<String,Socket>();

    public static void main(String[] args) throws IOException {
        Server4 = new Server4();
        Server4.serverSurface("服务器");
        ServerSocket ss = new ServerSocket(8848);
        while (true) {
            Server4.viewArea.append("等待新客户连接......\n");
            s = ss.accept();
            Server4.viewArea.append("连接成功......" + s + "\n");
            new ServerThread(s).start();
        }
    }

    static class ServerThread extends Thread {
        Socket socket;
        public ServerThread(Socket socket) {
            this.socket = socket;
        }
        public void run() {
            String key = null;      
            try {
                ObjectInputStream ins = new ObjectInputStream(socket.getInputStream());
                while(true){
                    Vector v = null;
                    try {
                        v = (Vector)ins.readObject();                   
                    } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                    }
                    if(v!=null){
                        for(int i = 0;i<v.size();i++){
                            String info = (String) v.get(i);                            
                            if(info.startsWith("用户:")){
                                key = info.substring(3);
                                hash.put(key,socket);
                                Set<String> set = hash.keySet();// 获得集合中所有键的Set视图
                                Iterator<String> keyIt = set.iterator();// 获得所有键的迭代器,为每一个key发送所有key
                                while(keyIt.hasNext()){
                                    String receiveKey = keyIt.next();
                                    Socket s = hash.get(receiveKey);
                                    PrintWriter out = new PrintWriter(s.getOutputStream(),true);
                                    Iterator<String> keyIt1 = set.iterator();
                                    while(keyIt1.hasNext()){
                                        String receiveKey1 = keyIt1.next();
                                        out.println(receiveKey1);
                                        out.flush();
                                    }                                   
                                }
                                listModel.addElement(info);
                                }else if(info.startsWith("退出:")){
                                    key = info.substring(3);
                                    hash.remove(key);
                                    Set<String> set = hash.keySet();
                                    Iterator<String> it = set.iterator();
                                    while(it.hasNext()){
                                        String recivekey = it.next();
                                        Socket s = hash.get(recivekey);
                                        PrintWriter out = new PrintWriter(socket.getOutputStream(),true);
                                        out.println("退出:"+key);
                                        out.flush();
                                    }                                   
                                }else{
                                    key = info.substring(info.indexOf(":发送给:") + 5,info.indexOf(":的信息是:"));// 获得接收方的key值,即接收方的用户名
                                    String sendUser = info.substring(0,info.indexOf(":发送给:"));// 获得发送方的key值,即发送方的用户名
                                    Set<String> set = hash.keySet();
                                    Iterator<String> it = set.iterator();
                                    while(it.hasNext()){
                                        String receiveKey = it.next();
                                        if(receiveKey.equals(key) && !sendUser.equals(receiveKey)){
                                            Socket s = hash.get(key);
                                            PrintWriter out = new PrintWriter(s.getOutputStream(),true);
                                            out.println("MSG:"+info);   
                                            out.flush();                                        
                                        }
                                    }                                   
                                }
                            }
                        }                                                                           
                    }                                           
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public void serverSendMessage() {
        String message = "";
        PrintWriter out = null ;
        message = "服务器说:"+ viewField.getText();
        viewArea.setText(viewArea.getText() + message + "\n");
        Set<String> set = hash.keySet();
        Iterator<String> it = set.iterator();
        while(it.hasNext()){
            String receiveKey = it.next();
            Socket s = hash.get(receiveKey);
            try {
                out = new PrintWriter(s.getOutputStream());         
            } catch (IOException e) {
                e.printStackTrace();
            }finally{   
                String msg = "服务器"+ ":发送给:"+ s + ":的信息是: "+ viewField.getText();// 定义发送的信息
                out.println("MSG:"+msg);
                out.flush();
            }                   
        }
    }

    // 窗体
    public void serverSurface(String name) {
        frame = new JFrame("Chat Room");
        viewArea = new JTextArea(10, 40);
        jlable = new JLabel();
        jlable.setText("服务器开始工作");
        button1 = new JButton("发送");
        MyName = new JTextField();
        MyName.setColumns(9);
        MyName.setText(name);
        JPanel panel = new JPanel();
        panel.setLayout(new GridLayout(8, 1));
        panel.add(jlable);
        panel.add(MyName);
        panel.add(button1);

        JPanel jp_input = new JPanel();
        jp_input.setBorder(new TitledBorder("发送消息"));
        viewField = new JTextField(50);
        jp_input.add(viewField);

        listModel = new DefaultListModel();
        userList = new JList(listModel);
        JScrollPane sp = new JScrollPane(viewArea);
        sp.setBorder(new TitledBorder("消息显示区"));
        sp.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);// 水平滚动轴
        sp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);// 垂直滚动条
        JScrollPane spFriend = new JScrollPane(userList);
        spFriend.setBorder(new TitledBorder("在线人员"));
        spFriend.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);// 垂直滚动条
        centerSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, spFriend, sp);
        centerSplit.setDividerLocation(130);

        frame.add("Center", centerSplit);
        frame.add("East", panel);
        frame.add("South", jp_input);
        frame.setSize(700, 400);
        frame.setLocation(200, 100);
        frame.setVisible(true);

        // 文本框按回车键时事件
        viewField.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                serverSendMessage();
            }
        });
        // 发送按钮
        button1.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if (e.getSource() == button1) {
                    serverSendMessage();
                }
            }
        });
    }
}

Client4

package com.qqText;

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.MenuItem;
import java.awt.PopupMenu;
import java.awt.SystemTray;
import java.awt.TrayIcon;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.URL;
import java.net.UnknownHostException;
import java.text.DateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.Set;
import java.util.Vector;

import javax.swing.DefaultComboBoxModel;
import javax.swing.DefaultListModel;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JColorChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.JTextPane;
import javax.swing.border.TitledBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;

public class Client4 {

    public JFrame frame;
//  public JTextArea viewArea;
    public JTextPane textPane;
    public JTextField viewField,jt_login ;
    public JButton button1,buttonLogin,buttonExit;
    public JLabel jlable;
    public JTextField MyName;
    public DefaultListModel listModel;
    public static JList userList;       //显示对象列表
    public JSplitPane centerSplit;
    public static boolean isConnected = false;
    static Client4 objClient;
    static DefaultComboBoxModel model;
    static ObjectOutputStream out;
    boolean loginFlag = false;

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
        public void run() {
            objClient = new Client4();
            objClient.createClientSocket(objClient);
            }
        });     
    }
    public void createClientSocket(Client4 client) {
        try {
            Socket s = new Socket("localhost", 8848);
            out = new ObjectOutputStream(s.getOutputStream());
            client.clientSurface(); 
            new MyClientReader(s).start();                                                                                                  
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    static class MyClientReader extends Thread {
        Socket socket;

        public MyClientReader(Socket socket) {
            this.socket = socket;
        }
        public void run() {
            try {
                BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));             
                model = (DefaultComboBoxModel) userList.getModel();// 获得列表框的模型
                while(true){
                    String info = in.readLine().trim();// 读取信息
                    if (!info.startsWith("MSG:")) {// 接收到的不是消息
                        if (info.startsWith("退出:")) {// 接收到的是退出消息
                            model.removeElement(info.substring(3));// 从用户列表中移除用户
                        } else {// 接收到的是登录用户            
                            boolean itemFlag = false;// 标记是否为列表框添加列表项,为true不添加,为false添加
                            for (int i = 0; i < model.getSize(); i++) {// 对用户列表进行遍历
                                if (info.equals((String) model.getElementAt(i))) {// 如果用户列表中存在该用户名
                                    itemFlag = true;// 设置为true,表示不添加到用户列表
                                    break;// 结束for循环
                                }
                            }
                            if (!itemFlag) {            
                                model.addElement(info);// 将登录用户添加到用户列表
                            }
                    }
                    }else{              
                        DateFormat df = DateFormat.getDateInstance();// 获得DateFormat实例
                        String dateString = df.format(new Date()); // 格式化为日期
                        df = DateFormat.getTimeInstance(DateFormat.MEDIUM);// 获得DateFormat实例
                        String timeString = df.format(new Date()); // 格式化为时间
                        String id = info.substring(4,info.indexOf(":发送给:"));  //发送端的id
                        String message = info.substring(info.indexOf(":的信息是:")+6);
                        String text = new String("  " + id + "    " + dateString+ "  " + timeString + "\n  " + message+ "\n");

                        SimpleAttributeSet aSet = new SimpleAttributeSet();     
                        StyleConstants.setForeground(aSet, Color.red);    
                        StyleConstants.setBackground(aSet, Color.orange);    
                        StyleConstants.setFontFamily(aSet, "lucida bright italic");    
                        StyleConstants.setFontSize(aSet, 18);                       
                        //StyleConstants.setAlignment(aSet, StyleConstants.ALIGN_LEFT); 
                        objClient.textPane.setParagraphAttributes(aSet,false);                  
                        objClient.viewField.setText(null);// 清空文本框  
                        Document docs = objClient.textPane.getDocument();//获得文本对象
                            try {
                                docs.insertString(docs.getLength(), text,aSet);//对文本进行追加
                            } catch (BadLocationException e) {
                                e.printStackTrace();
                            }
                        }
                    }       
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public void sendMessage() {
        if (objClient.viewField.getText().equals("")) {
            return;// 如果没输入信息则返回,即不发送
        }
        Vector<String> v = new Vector<String>();// 创建向量对象,用于存储发送的消息
        Object[] receiveUserNames = userList.getSelectedValues();// 获得选择的用户数组
        if (receiveUserNames.length <= 0) {
            return;// 如果没选择用户则返回
        }
        for (int i = 0; i < receiveUserNames.length; i++) {
            String msg = objClient.jt_login.getText() + ":发送给:"+ (String) receiveUserNames[i] + ":的信息是: "+ objClient.viewField.getText();// 定义发送的信息
            v.add(msg);// 将信息添加到向量
        }
        try {
            out.writeObject(v);// 将向量写入输出流,完成信息的发送
            out.flush();// 刷新输出缓冲区

        } catch (IOException e) {
            e.printStackTrace();
        }
        DateFormat df = DateFormat.getDateInstance();// 获得DateFormat实例
        String dateString = df.format(new Date()); // 格式化为日期
        df = DateFormat.getTimeInstance(DateFormat.MEDIUM);// 获得DateFormat实例
        String timeString = df.format(new Date()); // 格式化为时间    
        String text = new String("   " + userList.getSelectedValue() + "    " + dateString+ "  " + timeString + "\n  " + viewField.getText()+ "\n");                        

        SimpleAttributeSet aSet=new SimpleAttributeSet();       //接受时只改变第一次接收到的方向
        StyleConstants.setForeground(aSet, Color.blue);        
        StyleConstants.setFontFamily(aSet, "lucida bright italic");    
        StyleConstants.setFontSize(aSet, 18);   
        StyleConstants.setAlignment(aSet, StyleConstants.ALIGN_RIGHT); 
        objClient.textPane.setParagraphAttributes(aSet,false);  
        Document docs = objClient.textPane.getDocument();//获得文本对象
        System.out.println(docs);
        try {
            docs.insertString(docs.getLength(), text,aSet);//对文本进行追加
        } catch (BadLocationException e) {
            e.printStackTrace();
        }
    }

    public void clientSurface() {
        frame = new JFrame("Chat Room");
//      viewArea = new JTextArea(10, 40);
        textPane = new JTextPane();
        jlable = new JLabel();
        jlable.setText("在线");
        button1 = new JButton("Send");
        MyName = new JTextField();      
        MyName.setColumns(9);
        JPanel panel = new JPanel(); 
        panel.setLayout(new GridLayout(8, 1));
        panel.add(jlable);
        panel.add(MyName);
        panel.add(button1);

        JPanel jp_input = new JPanel();
        jp_input.setBorder(new TitledBorder("发送消息")); 
        viewField = new JTextField(50);
        jp_input.add(viewField);

        buttonLogin = new JButton("登录");
        buttonExit = new JButton("退出");
        jt_login = new JTextField(20);
        JPanel panelLogin = new JPanel();
        panelLogin.setBorder(new TitledBorder("登录区")); 
        panelLogin.add(jt_login);
        panelLogin.add(buttonLogin);
        panelLogin.add(buttonExit);

        listModel = new DefaultListModel();  

        userList = new JList(listModel);  
        JScrollPane sp = new JScrollPane(textPane);
        sp.setBorder(new TitledBorder("消息显示区")); 
        sp.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);//水平滚动轴
        sp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);//垂直滚动条
        JScrollPane spFriend = new JScrollPane(userList);
        spFriend.setBorder(new TitledBorder("好友列表")); 
        userList.setModel(new DefaultComboBoxModel(new String[] { "" }));
        spFriend.setViewportView(userList);
        spFriend.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);//垂直滚动条      
        centerSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, spFriend, sp);  
        centerSplit.setDividerLocation(130);  

        frame.add("Center", centerSplit);
        frame.add("North", panelLogin);
        frame.add("East", panel);
        frame.add("South", jp_input);
        frame.setSize(700, 400);
        frame.setLocation(200,100);
        frame.setVisible(true);

        // 文本框按回车键时事件  
        viewField.addActionListener(new ActionListener() {  
            public void actionPerformed(ActionEvent e) {  
                sendMessage();  
            }  
        });  
        //发送按钮
        button1.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if (e.getSource() == button1) {
                    sendMessage();
                }
            }
        });
        //单击登录按钮
        buttonLogin.addActionListener(new ActionListener() {
            public void actionPerformed(final ActionEvent e) {
                if (loginFlag) {// 已登录标记为true
                    JOptionPane.showMessageDialog(null, "在同一窗口只能登录一次。");
                    return;
                }
                String userName = jt_login.getText().trim();// 获得登录用户名
                Vector v = new Vector();// 定义向量,用于存储登录用户
                v.add("用户:" + userName);// 添加登录用户
                try {
                    out.writeObject(v);// 将用户向量发送到服务器
                    out.flush();// 刷新输出缓冲区
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
                jt_login.setEnabled(false);// 禁用用户文本框
                buttonLogin.setEnabled(false);
                loginFlag = true;// 将已登录标记设置为true
                MyName.setText(userName);
            }
        });
        //退出按钮
        buttonExit.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                String exitUser = jt_login.getText().trim();
                Vector v = new Vector();
                v.add("退出:" + exitUser);
                try {
                    out.writeObject(v);
                    out.flush();// 刷新输出缓冲区
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
                System.exit(0); // 退出系统
            }
        });
//      创建托盘
         if (SystemTray.isSupported())
          {
             // 获取图片所在的URL
             URL url = Client4.class.getResource("qq.jpg");
             // 实例化图像对象
             ImageIcon icon = new ImageIcon(url);
             // 获得Image对象
             Image image = icon.getImage();
             // 创建托盘图标
             TrayIcon trayIcon = new TrayIcon(image);
             // 为托盘添加鼠标适配器
             trayIcon.addMouseListener(new MouseAdapter()
             {
                // 鼠标事件
                public void mouseClicked(MouseEvent e)
                {
                   if (e.getClickCount() == 2)
                   {
                      JOptionPane.showMessageDialog(null, "已登陆成功");
                   }
                }
             });
             // 添加工具提示文本
             trayIcon.setToolTip("QQ:本地连接\r\n速度:100.0 Mbps\r\n状态:已连接上");
             // 创建弹出菜单
             PopupMenu popupMenu = new PopupMenu();
             popupMenu.add(new MenuItem("我在线上"));
             popupMenu.add(new MenuItem("忙碌"));
             popupMenu.add(new MenuItem("隐身"));
             popupMenu.add(new MenuItem("离线"));
             popupMenu.addSeparator();
             popupMenu.add(new MenuItem("关闭所有声音"));
             popupMenu.add(new MenuItem("关闭头像闪动"));
             popupMenu.addSeparator();
             popupMenu.add(new MenuItem("退出"));

             // 为托盘图标加弹出菜弹
             trayIcon.setPopupMenu(popupMenu);
             // 获得系统托盘对象
             SystemTray systemTray = SystemTray.getSystemTray();
             try
             {
                // 为系统托盘加托盘图标
                systemTray.add(trayIcon);
             }
             catch (Exception e)
             {
                e.printStackTrace();
             }
          }
          else
          {
             JOptionPane.showMessageDialog(null, "not support");
          }
    }   
}

如果有误可以查看进行下载
http://download.csdn.net/download/xiao_ma_csdn/10269610
或者
https://github.com/mmaagithub/ChatRoom

猜你喜欢

转载自blog.csdn.net/xiao_ma_csdn/article/details/79444323