java聊天室程序—基于socket通信

(一)配置

(1)下载jar包

1.选择Platform Independent

9d5f743f7170988d1056a23184605d74.jpeg

2.点击第二个Download

8826644436ece6c5f23849be0867dc69.jpeg

3.点击红框部分

bc5b6df76feb4f204215ac3a8f239e72.jpeg

4.下载jar包进行解压

(2)将jar包导入Java项目

1. 打开eclipse创建一个新项目

2.右击 项目名在 New 下点击 Folder,创建 lib 文件夹

1af0e7cb7d36f9bb655b52ff93260246.jpeg

d5b92aa6e390966e664358b5d43f8a62.jpeg

3.将下载好的驱动包用鼠标左键拖入lib文件中

c54f0611b41dfcf9739b9a1c26d05fcd.jpeg

出现该选项框,点击 OK 即可

e8bb2cd8e1eaf18696b4eaf42e7389c8.jpeg

lib 目录下出现该驱动包

206eee59c5cd9b4cfa6b0bddb008012f.jpeg

4.右击该驱动包, Build Path —> Add to Build Path

960ac6878b6546b07a0d0fb19efe5d03.jpeg

项目目录下出现 Referenced Libraries 文件夹

fa4ef0c6685544fe9751207cbc549117.jpeg

5.右击 src 新建一个包 Package取名为 JavaJdbc,点击 Finish,然后将打包的项目中的Java文件放到包里。

6.将图片mount.jpg放入src文件夹下。

f5497f246ce41fc12d977a12846ebadc.png

(3)新建Java数据库导入sql文件

1.使用小P面板打开MYSQL数据库

25f098b99922e87b0f00e0bc74412a33.jpeg

2.右键localhost新建一个数据库

5aaff19a254ef5f643e354a61cf3319d.jpeg

3.名称改为java后点击确定

7574cdcf116c3485d2340ff76943ed3d.jpeg

4.右键新建的Java数据库,点击输入SQl文件(已上传资源)

f5b9d35a880d50e21c2550bde99b595b.jpeg

5.点击打包的项目里的java.sql,然后点击打开

e4a131f234012984c462533278ae7be5.jpeg

6.前置条件完成,可以进行项目功能验证

(二)效果展示

用户可以通过注册界面输入用户名、密码等信息进行注册,并保存到数据库中。。

1. 运行server.java文件

e342ad67c335dc4ff4724aef691f59b1.jpeg

弹出服务器界面

6aca609e276aceb6648e25abef988f58.jpeg

2. 运行login.java文件弹出登陆界面后点击注册

b5bf9606ec6ee339575c6a07143fafc9.jpeg

24f244bec2465e3164aae1159ca1cfea.png

输入完用户名、密码后回车或点击注册

1267ce6b96aaede84d40f93a980bced0.png

弹出注册成功界面则点击返回登陆回到登陆界面进行登录

748379a23d5d1517a7d97ec4f5b85982.jpeg

用户输入用户名和密码后,系统会验证其信息的正确性,如果验证通过,则用户可以登录到聊天室。

3.回到登陆界面,输入注册的用户名和密码点击登录

8da401a953217a63ef9b569ccc10de40.png

4. 用户名和密码正确,用户登陆到聊天室

61d70cbb4a7e213833cb28a67f178188.png

如果用户名或者密码错误,则会出现弹窗

a15c7598686ab292cd0a2bf418c33781.jpeg

5. 在线用户列表

在聊天室和服务器界面上,系统会实时显示当前在线用户的列表。

用户登录成功,服务器的列表会显示所有用户的用户名

77f50fd94568fa90c6739fe222a28353.png

用户登录成功,聊天室的用户列表会显示除自己以外的所有用户

2b8bc5eed2d4925aabc0ee5be0326631.png

6. 公聊

用户登录后可以在聊天室公聊板块中与其他用户进行交流,由于支持文本消息的发送和接收。

在文本框输入信息进行回车或者点击发送大厅消息

695abaa00bbecd9845fd89017c99c283.png

消息发送完毕,会显示在文本区域

d97ee467a4235a443625fe560ce3143f.png

对其他用户,消息发送方则会显示用户昵称

a0f63b04b2fbb450089c21805e91a4e4.png

7. 私聊

用户可以向其他用户发起私聊请求,并进入私聊界面进行一对一的交流,私聊内容只有双方可见。

选中聊天室界面的用户列表在线的用户,点击私发消息

402e405039b61c1f54a612e3af34f603.png

显示私聊界面,在输入框中输入消息后回车,或者点击发消息按钮发送消息

2618fc4fe7d2117168b51126b17c792c.png

接收方收到系统提示

335405f1ce37ec1eb9a7ec17ca674833.png

接收方弹出私聊界面

8f29b8f4bd8fe7d215421779f4710332.png

8. 保存聊天记录

系统会将聊天室公聊和私聊的内容保存到文件中,方便用户查看历史记录。

用户登录后,右键javajdbc,点击Refresh

2d1caf3e894936f1f3d6f1bcb419aaa7.jpeg

在聊天记录文件夹下就能看到不同用户的聊天记录

5ff2feb80dba8bcb357462f8e27b2e2e.png

聊天记录有标记私聊和公聊

3668f88f50fc8dcd2098b61c7ee7e7c9.jpeg

9. 踢人

管理员可以通过后台管理界面选择将某个用户踢出聊天室,以维护聊天室的秩序。

选中服务器用户列表的用户,点击踢出聊天室

6f62144790e2bca3bc63dd23a2c2b345.png

该用户出现弹窗提示被移出聊天室

325066cbc483951cfd4f573b89a9624b.png

用户收到该用户下线信息,用户列表更新

1fd1b6f3d7c08409e254af51e852bfb4.png

(三)源代码

1.server.java

package javajdbc;

import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;

class server extends JFrame implements Runnable, ListSelectionListener, ActionListener {
    private Socket s = null;
    private ServerSocket ss = null;
    private ArrayList<ChatThread> users = new ArrayList<ChatThread>(); //容量能够动态增长的数组
    DefaultListModel<String> dl = new DefaultListModel<String>();
    private JList<String> userList = new JList<String>(dl);//显示对象列表并且允许用户选择一个或多个项的组件。单独的模型 ListModel 维护列表的内容。

    private JPanel jpl = new JPanel();
    private JButton jbt = new JButton("踢出聊天室");
    private JButton jbt1 = new JButton("群发消息");
    //群发消息输入栏
    JTextField jtf = new JTextField(20);
    
    JLabel input2 = new JLabel("请输入:");
    //private JAreaText jtx=new JAreaText();
    public server() throws Exception{
        this.setTitle("服务器端");

        SwingUtilities.invokeLater(new Runnable() { // 在事件分派线程中执行初始化操作和界面布局
        	public void run() {
                userList.setBackground(new Color(224,224,239)); // 设置列表背景色
                userList.repaint(); // 强制重新绘制界面,以显示新的背景色
                add(userList, BorderLayout.CENTER); // 添加到北面
                add(jpl, "South"); // 添加到南面
                jpl.setLayout(new FlowLayout(FlowLayout.LEFT, 10, 10)); // 设置布局为FlowLayout,并指定对齐方式
                jpl.add(input2); // 添加标签到jpl面板
                jpl.add(jtf); // 添加文本框到jpl面板
                // 创建一个新的面板,并设置其布局为FlowLayout
                JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 20, 0));
                // 将jbt1和jbt添加到这个新的面板中
                buttonPanel.add(jbt1);
                buttonPanel.add(jbt);
                // 将这个新的面板添加到原来的面板(即jpl)中,并设置其位置为BorderLayout.CENTER
                jpl.add(buttonPanel, BorderLayout.CENTER); 

                setVisible(true); // 设置窗口为可见状态
            }
        });
        

        //实现群发
        jbt1.addActionListener(this);
        //实现踢人
        jbt.addActionListener(this);


        this.setDefaultCloseOperation(EXIT_ON_CLOSE);
        this.setLocation(400,200);
        this.setSize(540, 400);
        this.setVisible(true);
        this.setAlwaysOnTop(true);
        ss = new ServerSocket(9999);
        new Thread(this).start();//监听用户端的加入
        // 添加滚动条
        JScrollPane scrollPane = new JScrollPane(userList);
        this.add(scrollPane, BorderLayout.CENTER); // 将滚动条添加到界面中心
        

    }
    @Override
    public void run() {
        while(true){
            try{
                s = ss.accept();
                ChatThread ct = new ChatThread(s); //新用户新线程
                users.add(ct); //将每个线程加入到users
                //发送Jlist里的用户登陆信息,为了防止后面登陆的用户无法更新有前面用户的好友列表
                ListModel<String> model = userList.getModel();//获取Jlist的数据内容
                for(int i = 0; i < model.getSize(); i++){
                    ct.ps.println("USERS#" + model.getElementAt(i));
                }
                ct.start();
            }catch (Exception ex){
                ex.printStackTrace();
                javax.swing.JOptionPane.showMessageDialog(this,"服务器异常!");
                System.exit(0);
            }
        }
    }

    //群发消息按钮点击事件监听
    @Override
    public void actionPerformed(ActionEvent e) {
        String label = e.getActionCommand();
        if(label.equals("群发消息")){
            handleAll();
        }else if(label.equals("踢出聊天室")){
            try {
                handleExpel();
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }
    }

    public void handleAll(){
        if(!jtf.getText().equals("")){
            sendMessage("ALL#" + jtf.getText());
            //发送完后,是输入框中内容为空
            jtf.setText("");
        }
    }//群发消息

    public void handleExpel() throws IOException {
        sendMessage("OFFLINE#" + userList.getSelectedValuesList().get(0));
        dl.removeElement(userList.getSelectedValuesList().get(0));//更新defaultModel
        userList.repaint();//更新Jlist
    }//踢人

    public class ChatThread extends Thread{
        Socket s = null;
        private BufferedReader br = null;
        private PrintStream ps = null;
        public boolean canRun = true;
        String nickName = "";
        public ChatThread(Socket s) throws Exception{
            this.s = s;
            br = new BufferedReader(new InputStreamReader(s.getInputStream()));
            ps = new PrintStream(s.getOutputStream());
        }
        public void run(){
            while(canRun){
                try{
                    String msg = br.readLine();//接收客户端发来的消息
                    String[] strs = msg.split("#");
                    if(strs[0].equals("LOGIN")){//收到来自客户端的上线消息
                        nickName = strs[1];
                        dl.addElement(nickName);
                        userList.repaint();
                        sendMessage(msg);
                    }else if(strs[0].equals("MSG") || strs[0].equals("SMSG") || strs[0].equals("FSMSG")){
                        sendMessage(msg);//发送消息
                    }else if(strs[0].equals("OFFLINE")){//收到来自客户端的下线消息
                        sendMessage(msg);
                        //System.out.println(msg);
                        dl.removeElement(strs[1]);
                        // 更新List列表
                        userList.repaint();
                    }
                }catch (Exception ex){}
            }
        }
    }

    public void sendMessage(String msg){  //服务器端发送给所有用户
        for(ChatThread ct : users){
            ct.ps.println(msg);
        }
    }

	@Override
	public void valueChanged(ListSelectionEvent e) {
		// TODO 自动生成的方法存根
		
	}
	
    public static void main(String[] args) throws Exception{
        new server();
    }
}

2.login.java

package javajdbc;

import java.awt.Container;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.LayoutManager;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.JPasswordField;
import javax.swing.JButton;
import javax.swing.JDialog;

import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.ActionEvent;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;



public class login {
	private JFrame frame;
	private JTextField textField;
	private JPasswordField passwordField;
	private JButton quitBt;
	

	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					login window = new login();
					window.frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Create the application.
	 */
	public login() {
		initialize();
	}

	/**
	 * Initialize the contents of the frame.
	 */
	private void initialize() {

		
		frame = new JFrame();
		frame.setBounds(400, 200, 450, 300);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setVisible(true);
		frame.setResizable(false);
		frame.getContentPane().setLayout(null);

		
		 JLabel j1=new JLabel("**********欢迎登陆**********");
		 j1.setBounds(75, 30, 330,20);
		 j1.setFont(new Font("宋体", Font.PLAIN,20));
		 frame.getContentPane().add(j1);
         

		JLabel lblNewLabel = new JLabel("用户名:");
		lblNewLabel.setBounds(105, 90, 54, 15);
		frame.getContentPane().add(lblNewLabel);

		JLabel lblNewLabel_1 = new JLabel("密    码:");
		lblNewLabel_1.setBounds(105, 140, 54, 15);
		frame.getContentPane().add(lblNewLabel_1);

		textField = new JTextField();
		textField.setBounds(201, 85, 100, 21);
		frame.getContentPane().add(textField);
		textField.setColumns(10);

		passwordField = new JPasswordField();
		passwordField.setBounds(201, 135,100, 21);
		frame.getContentPane().add(passwordField);
		

		JButton btnNewButton = new JButton("登录");
		btnNewButton.setBounds(30, 205, 93, 23);
		frame.getContentPane().add(btnNewButton);

		JButton btnNewButton_1 = new JButton("注册");
		btnNewButton_1.setBounds(175, 205, 93, 23);
		frame.getContentPane().add(btnNewButton_1);
		
		btnNewButton_1.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {

				new add();
				frame.removeNotify();

			}
		});

		
		JButton j2 = new JButton("退出");
		j2.setBounds(320, 205, 93, 23);
        frame.getContentPane().add(j2);
        
      //添加背景图片
      		JLabel background = new JLabel(new ImageIcon("src/mount.jpg")); 
      		background.setBounds(0, 0, 450, 300);
      		frame.getContentPane().add(background);
      		
      		
		textField.addActionListener(new ActionListener() {
	            @Override
	            public void actionPerformed(ActionEvent e) {
	            	passwordField.requestFocusInWindow(); // 请求焦点移动到下一个输入框
	            }
	        });
		
		passwordField.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                if(e.getKeyCode() == KeyEvent.VK_ENTER) {
                	connectionlain c = new connectionlain();

    				Connection conn = c.getConnect();

    				PreparedStatement ps = null;
    				ResultSet rs = null;

    				try {
    					ps = conn
    							.prepareStatement("select *from user where name=? and passwd=?");
    					
    					ps.setString(1, textField.getText());
    					ps.setString(2, passwordField.getText());
    					String name=textField.getText();
    					rs = ps.executeQuery();
    					if (rs.next()) {
    						//new login();
    						client1 cli=new client1(name);
    						frame.removeNotify();
    						

    					} else {
    						JOptionPane pane = new JOptionPane("用户或密码错误");
    	                     JDialog dialog  = pane.createDialog("警告");
    	                     dialog.show();
    					}

    				} catch (SQLException e1) {
    					// TODO Auto-generated catch block
    					e1.printStackTrace();
    				} catch (Exception e1) {
    					// TODO Auto-generated catch block
    					e1.printStackTrace();
    				}
                    
                }
            }
        });
		
		btnNewButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {

				connectionlain c = new connectionlain();

				Connection conn = c.getConnect();

				PreparedStatement ps = null;
				ResultSet rs = null;

				try {
					ps = conn
							.prepareStatement("select *from user where name=? and passwd=?");
					
					ps.setString(1, textField.getText());
					ps.setString(2, passwordField.getText());
					String name=textField.getText();
					rs = ps.executeQuery();
					if (rs.next()) {
						//new login();
						client1 cli=new client1(name);
						frame.removeNotify();
						

					} else {
						JOptionPane pane = new JOptionPane("用户或密码错误");
	                     JDialog dialog  = pane.createDialog("警告");
	                     dialog.show();
					}

				} catch (SQLException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				} catch (Exception e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}

			}

			

			
		});
		
        j2.addActionListener(new ActionListener() {
            
            @Override
            public void actionPerformed(ActionEvent e) {
                // TODO 自动生成的方法存根
                if(e.getActionCommand().equals("退出")){
                    System.exit(0);
                }
            }
        });
        
		
		
	}

	private void add(JButton quitBt2) {
		// TODO Auto-generated method stub
		
	}

	private Container getContentPane() {
		// TODO Auto-generated method stub
		return null;
	}


}

3.add.java

package javajdbc;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.ImageIcon;
import javax.swing.JButton;

import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class add {
	private JFrame frame;
	private JTextField textField;
	private JTextField textField_1;

	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					add window = new add();
					window.frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Create the application.
	 */
	public add() {
		initialize();
	}	

	/**
	 * Initialize the contents of the frame.
	 */
	private void initialize() {
		frame = new JFrame();
		frame.setBounds(400, 200, 450, 300);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setVisible(true);
		frame.setResizable(false);
		frame.getContentPane().setLayout(null);

		JLabel lblNewLabel = new JLabel("用户名:");
		lblNewLabel.setBounds(135, 60, 54, 15);
		frame.getContentPane().add(lblNewLabel);

		JLabel lblNewLabel_1 = new JLabel("密    码:");
		lblNewLabel_1.setBounds(135, 120, 54, 15);
		frame.getContentPane().add(lblNewLabel_1);

		textField = new JTextField();
		textField.setBounds(215, 60, 100, 21);
		frame.getContentPane().add(textField);
		textField.setColumns(10);

		textField_1 = new JTextField();
		textField_1.setBounds(215,120,100, 21);
		frame.getContentPane().add(textField_1);
		textField_1.setColumns(10);

		JButton btnNewButton = new JButton("注 册");
		btnNewButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				connectionlain c = new connectionlain();

				Connection conn = c.getConnect();

				PreparedStatement ps = null;
				try {
					ps = conn
							.prepareStatement("insert into user values(?,?)");

					ps.setString(1, textField.getText());
					ps.setString(2, textField_1.getText());
					ps.execute();

					new prompt();
					frame.removeNotify();
				//  System.out.println("成功");

				} catch (SQLException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}

			}
		});
		btnNewButton.setBounds(80, 205, 93, 23);
		frame.getContentPane().add(btnNewButton);
		
		JButton returnButton = new JButton("返 回");
		returnButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {

				new login();
				frame.removeNotify();

			}
		});
		returnButton.setBounds(270, 205, 93, 23);
		frame.getContentPane().add(returnButton);
		
		textField_1.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                if(e.getKeyCode() == KeyEvent.VK_ENTER) {
                	connectionlain c = new connectionlain();

    				Connection conn = c.getConnect();

    				PreparedStatement ps = null;
    				try {
    					ps = conn
    							.prepareStatement("insert into user values(?,?)");

    					ps.setString(1, textField.getText());
    					ps.setString(2, textField_1.getText());
    					ps.execute();

    					new prompt();
    					frame.removeNotify();
    				//  System.out.println("成功");

    				} catch (SQLException e1) {
    					// TODO Auto-generated catch block
    					e1.printStackTrace();
    				}
                }
            }
		});
		
		//移动光标
		textField.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
            	textField_1.requestFocusInWindow(); // 请求焦点移动到下一个输入框
            }
        });
		
		
		//添加背景图片
		JLabel background = new JLabel(new ImageIcon("src/mount.jpg")); 
  		background.setBounds(0, 0, 450, 300);
  		frame.getContentPane().add(background);

	}

}

4.prompt

package javajdbc;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;

public class prompt {
	private JFrame frame;

	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					prompt window = new prompt();
					window.frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Create the application.
	 */
	public prompt() {
		initialize();
	}

	/**
	 * Initialize the contents of the frame.
	 */
	private void initialize() {
		frame = new JFrame();
		frame.setBounds(400, 200, 450, 300);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setVisible(true);

		frame.getContentPane().setLayout(null);
		
		JLabel lblNewLabel = new JLabel("注册成功!");
		lblNewLabel.setFont(new Font("宋体", Font.PLAIN, 35));
		lblNewLabel.setBounds(140, 51, 215, 46);
		frame.getContentPane().add(lblNewLabel);
		
		JButton btnNewButton = new JButton("返回登录");
		btnNewButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				new login();
				frame.removeNotify();
				
				
			}
		});
		
		btnNewButton.setBounds(170, 160, 103, 33);
		frame.getContentPane().add(btnNewButton);
		
		//添加背景图片
		JLabel background = new JLabel(new ImageIcon("src/mount.jpg")); 
		background.setBounds(0, 0, 450, 300);
		frame.getContentPane().add(background);
	}



}

5.connectionlain.java

package javajdbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class connectionlain {
	
	public Connection getConnect() {
		Connection conn=null;
		String url="jdbc:mysql://127.0.0.1:3306/java";
		String user="root";
		String password="root";
		try{
			Class.forName("com.mysql.cj.jdbc.Driver");
			conn=DriverManager.getConnection(url, user, password);
			return conn;
		}catch(ClassNotFoundException e){
		    System.out.println("错误");
		    e.printStackTrace();
		    return null;
		}catch(Exception e){
			e.printStackTrace();
			return null;
		}
		
	}
	

}

6.client1.java

package javajdbc;

import javax.swing.*;


//import com.sun.org.apache.bcel.internal.generic.NEW;
import java.awt.*;
import java.awt.event.*;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.util.Date;

public class client1 extends JFrame implements Runnable,ActionListener {
	
	
    private static final Graphics Graphics = null;
	//north
    private JMenuBar bar = new JMenuBar();
    private JMenu menu = new JMenu("点击菜单");
    private JMenuItem about = new JMenuItem("软件介绍");
    private JMenuItem exit = new JMenuItem("退出");//退出
    JPanel north = new JPanel();
    //west
    JPanel west = new JPanel();
    DefaultListModel<String> dl = new DefaultListModel<String>();//用来修改JList
    private JList<String> userList = new JList<String>(dl);//用来展示和选择
    JScrollPane listPane = new JScrollPane(userList);
    JLabel list = new JLabel("用户列表");
    //center
    JLabel show = new JLabel("公共频道");
    JPanel center = new JPanel();
    

    
    JTextArea jta = new JTextArea(10,20);
    JScrollPane js = new JScrollPane(jta);
    JPanel operPane = new JPanel();//发送消息的操作面板
    JLabel input = new JLabel("请输入:");
    JTextField jtf = new JTextField(40);
    
    JButton jButton = new JButton("发消息");//私聊

    private JButton jbt = new JButton("发送大厅消息");//大厅发送
    private JButton jbt1 = new JButton("私发消息");
    private BufferedReader br = null;
    private PrintStream ps = null;
    
    
    
    
    //私聊面板
    JTextArea jTextArea = new JTextArea(11,45);
    JScrollPane js1 = new JScrollPane(jTextArea);
    JTextField jTextField = new JTextField(25);
    String suser = new String();
    JLabel input2 = new JLabel("请输入:");
    double MAIN_FRAME_LOC_X;//父窗口x坐标
    double MAIN_FRAME_LOC_Y;//父窗口y坐标
    
    boolean FirstSecret = true;//是否第一次私聊
    String sender=null;//私聊发送者的名字
    String receiver=null;//私聊接收者的名字
    private static  String nickName = null;
    public client1(String name) throws Exception{
        //north 菜单栏
        bar.add(menu);
        menu.add(about);
        menu.add(exit);
        about.addActionListener(this);
        exit.addActionListener(this);
        BorderLayout bl = new BorderLayout();
        north.setLayout(bl);
        north.add(bar,BorderLayout.NORTH);
        add(north,BorderLayout.NORTH);
        
        //east 好友列表
        Dimension dim = new Dimension(100,150);
       
        west.setPreferredSize(dim);//在使用了布局管理器后用setPreferredSize来设置窗口大小

        BorderLayout bl2 = new BorderLayout(1,1);
        west.setLayout(bl2);
        west.add(listPane,BorderLayout.CENTER);//显示好友列表
        add(west,BorderLayout.EAST);
        userList.setFont(new Font("隶书",Font.BOLD,18));
        //userList.setBackground(new Color(224,224,239));
        //center 聊天消息框  发送消息操作面板
        jta.setEditable(false);//消息显示框是不能编辑的
        jta.setBackground(new Color(218,218,241));
        
         
        jTextArea.setEditable(false);
        jta.setFont(new Font("宋体", Font.PLAIN,15));
        BorderLayout bl3 = new BorderLayout(10,5);
        center.setLayout(bl3);
        FlowLayout fl = new FlowLayout(FlowLayout.LEFT);
        operPane.setLayout(fl);
        operPane.add(input);
        operPane.add(jtf);
        operPane.add(jbt);//发送消息
        //operPane.add(jbt1);
        list.setBackground(new Color(224,224,239));
        west.add(list,BorderLayout.NORTH);//用户列表
        west.add(jbt1,BorderLayout.SOUTH);//私发消息
        west.setBackground(Color.LIGHT_GRAY);
        center.add(show,BorderLayout.NORTH);
        center.add(js,BorderLayout.CENTER);//js是消息展示框JScrollPane
        center.add(operPane,BorderLayout.SOUTH);
        add(center,BorderLayout.CENTER);
        center.setBackground(Color.LIGHT_GRAY);

        js.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);//需要时才显示滚动条
        //if(nickName!=null||(!nickName.equals(""))) {
        //鼠标事件,点击
        //jbt.addActionListener(this);
        jbt1.addActionListener(this);
        this.setDefaultCloseOperation(EXIT_ON_CLOSE);
        //this.setAlwaysOnTop(true);
    
        nickName=name;
        String path="聊天记录/" +nickName+"聊天记录.txt";
        if (!Files.exists(Paths.get(path))) {
            Files.createFile(Paths.get(path));
        }
        this.setTitle(nickName + "的聊天室");
        this.setSize(700,400);
        this.setVisible(true);

        Socket s = new Socket("127.0.0.1", 9999);
        br = new BufferedReader(new InputStreamReader(s.getInputStream()));
        ps = new PrintStream(s.getOutputStream());
        new Thread(this).start();//run()
        
        	ps.println("LOGIN#" + nickName);//发送登录信息,消息格式:LOGIN#nickName
        
        //}else {
        //	System.out.println("buxing");
        //}
        
        jtf.setFocusable(true);//设置焦点
        //jbt.addActionListener(null);
        //键盘事件,实现当输完要发送的内容后,直接按回车键,实现发送
        //监听键盘相应的控件必须是获得焦点(focus)的情况下才能起作用
       jtf.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                if(e.getKeyCode() == KeyEvent.VK_ENTER) {
                	if(jtf.getText().equals("")||jtf.getText()=="") {
						  JOptionPane.showMessageDialog(null, "消息不能为空!");
						    
					}else {
						ps.println("MSG#" + nickName + "#" +  jtf.getText());//发送消息的格式:MSG#nickName#message
	                    //发送完后,是输入框中内容为空
	                    jtf.setText("");
					}
                    
                }
            }
        });
       jbt.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
					if(jtf.getText().equals("")||jtf.getText()=="") {
						  JOptionPane.showMessageDialog(null, "消息不能为空!");
						    
					}else {
						ps.println("MSG#" + nickName + "#" +  jtf.getText());//发送消息的格式:MSG#nickName#message
	                    //发送完后,是输入框中内容为空
	                    jtf.setText("");
					}
                    
                
			}
		});
       
       //私聊消息框按回车发送消息
        jTextField.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
            	
                if(e.getKeyCode() == KeyEvent.VK_ENTER) {
                	if(jTextField.getText()==""||jTextField.getText().equals("")) {
                		JOptionPane.showMessageDialog(null, "消息不能为空!");
                	}else {
                		handleSS();
                	}
                    
                }
            }
        });
        jButton.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
				if(jTextField.getText()==""||jTextField.getText().equals("")) {
            		JOptionPane.showMessageDialog(null, "消息不能为空!");
            	}else {
            		handleSS();
            	}   
			}
		});
        
        //监听系统关闭事件,退出时给服务器端发出指定消息
        this.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                ps.println("OFFLINE#" + nickName);//发送下线信息,消息格式:OFFLINE#nickName
            }
        });
        
        this.addComponentListener(new ComponentAdapter() {//监听父窗口大小的改变     
            public void componentMoved(ComponentEvent e) {
                Component comp = e.getComponent();							
                MAIN_FRAME_LOC_X = comp.getX();
                MAIN_FRAME_LOC_Y = comp.getY();			
            }
        }); 
    }
    
    public void run(){//客户端与服务器端发消息的线程
        while (true){
            try{
            	
                String msg = br.readLine();//读取服务器是否发送了消息给该客户端
                String[] strs = msg.split("#");
                Date date = new Date(); 
                SimpleDateFormat dateFormat= new
                SimpleDateFormat("yyyy-MM-dd:hh:mm:ss");
                String da1=dateFormat.format(date);
                //判断是否为服务器发来的登陆信息
                if(strs[0].equals("LOGIN")){
                    if(!strs[1].equals(nickName)){//不是本人的上线消息就显示,本人的不显示
                        jta.append(strs[1] + "上线啦!\n");
                        dl.addElement(strs[1]);//DefaultListModel来更改JList的内容
                        userList.repaint();
                    }
                }else if(strs[0].equals("MSG")){//接到服务器发送消息的信息
                    if(!strs[1].equals(nickName)){//别人说的
                        jta.append(strs[1] +  "说"+"("+da1+")"+":"+ strs[2] + "\n");
                        printToFile("公聊:"+strs[1] + "说" +"("+da1+")"+":" +strs[2]); // 将消息打印到文件
                    }else{
                        jta.append("我说"+"("+da1+")"+":" + strs[2] + "\n");
                        printToFile("公聊:我说" + "("+da1+")"+":"+strs[2]); // 将消息打印到文件
                    }
                }else if(strs[0].equals("USERS")){//USER消息,为新建立的客户端更新好友列表
                    dl.addElement(strs[1]);
                    userList.repaint();
                } else if(strs[0].equals("ALL")){
                    jta.append("系统消息:" + strs[1] + "\n");
                    printToFile("系统消息:" + strs[1]); // 将消息打印到文件
                }else if(strs[0].equals("OFFLINE")){
                	if(strs[1].equals(nickName)) {//如果是自己下线的消息,说明被服务器端踢出聊天室,强制下线
                        javax.swing.JOptionPane.showMessageDialog(this, "您已被系统请出聊天室!");
                        System.exit(0);
                	}
                    jta.append(strs[1] + "下线啦!\n");
                    dl.removeElement(strs[1]);
                    userList.repaint();
                }else if((strs[2].equals(nickName) || strs[1].equals(nickName)) && strs[0].equals("SMSG")){
                	if(!strs[1].equals(nickName)){
                    	jTextArea.append(strs[1] + "说"+"("+da1+")"+":" + strs[3] + "\n");
                    	 printToFile("私聊:"+strs[1] + "说" +"("+da1+")"+":" +strs[3]); // 将消息打印到文件
                        jta.append("系统提示:" + strs[1] + "私信了你" + "\n");
                    }else{
                        jTextArea.append("我说"+da1+":" + strs[3] + "\n");
                        printToFile("私聊:我说" +da1+":" +strs[3]); // 将消息打印到文件
                    }
                }else if((strs[2].equals(nickName) || strs[1].equals(nickName)) && strs[0].equals("FSMSG"))
                {
                	sender = strs[1];
                	receiver = strs[2];
                	//接收方第一次收到私聊消息,自动弹出私聊窗口
                	if(!strs[1].equals(nickName)) {
                		FirstSecret = false;
                		jTextArea.append(strs[1] + "说"+"("+da1+")"+":" + strs[3] + "\n");
                		printToFile("私聊:"+strs[1] + "说" +"("+da1+")"+":" +strs[3]); // 将消息打印到文件
                		jta.append("系统提示:" + strs[1] + "私信了你" + "\n");
                		handleSec(strs[1]);
                	}
                	else {
                		jTextArea.append("我说"+"("+da1+")"+":" + strs[3] + "\n");
                		printToFile("私聊:我说" +da1+":" +strs[3]); // 将消息打印到文件
                	}
                }
            }catch (Exception ex){//如果服务器端出现问题,则客户端强制下线
            	javax.swing.JOptionPane.showMessageDialog(this, "您已被系统请出聊天室!");
            	
                System.exit(0);
            }
        }
    }
    
    private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    
    //public static String path="聊天记录/" +nickName+"聊天记录.txt";
    //System.out.println(""+path);
    //将聊天记录写入"聊天记录.txt"
    private void printToFile(String msg) {
    	String path="聊天记录/" +nickName+"聊天记录.txt";
        try {
            
            
            try (PrintWriter writer = new PrintWriter(Files.newBufferedWriter(Paths.get(path), StandardOpenOption.APPEND))) {
                writer.println(msg);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    private static void deleteOldChatRecords(int months) {
    	String path="聊天记录/" +nickName+"聊天记录.txt";
        try {
            // 读取文件的创建日期
            Date fileCreationDate = getFileCreationDate(path);
            if (fileCreationDate == null) {
                System.out.println("No chat records found.");
                return;
            }
            LocalDate expirationDate = convertToLocalDate(fileCreationDate).plusMonths(months);
            if (LocalDate.now().isAfter(expirationDate)) {
                // 删除文件
                Files.deleteIfExists(Paths.get(path));
                System.out.println("Old chat records deleted successfully.");
            } else {
                System.out.println("No old chat records found.");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    private static LocalDate convertToLocalDate(Date fileCreationDate) {
		// TODO Auto-generated method stub
		return null;
	}

	//定时删除
    private static Date getFileCreationDate(String filePath) throws IOException {
        try (BufferedReader reader = Files.newBufferedReader(Paths.get(filePath))) {
            String line;
            while ((line = reader.readLine()) != null) {
                // 假设文件的创建日期是第一行,格式为 "Created on: yyyy-MM-dd HH:mm:ss"
                if (line.startsWith("Created on: ")) {
                    String dateStr = line.substring("Created on: ".length());
                    return DATE_FORMAT.parse(dateStr);
                }
            }
            return null; // 没有找到创建日期
        } catch (Exception e) {
            throw new IOException("Error reading file", e);
        }
    }
	

    
    @Override
    public void actionPerformed(ActionEvent e){//鼠标点击事件
        String label = e.getActionCommand();
        if(label.equals("发送消息")){//群发
            handleSend();
        }else if(label.equals("私发消息") && !userList.isSelectionEmpty()){//未点击用户不执行
            suser = userList.getSelectedValuesList().get(0);//获得被选择的用户
            handleSec(suser);//创建私聊窗口
            sender = nickName;
            receiver = suser;
        }else if(label.equals("发消息")){
            handleSS();//私发消息
        }else if(label.equals("软件介绍")){
            JOptionPane.showMessageDialog(this, "1.可以在聊天框中进行群聊\n\n2.可以点击选择用户进行私聊");
        }else if(label.equals("退出")){
            JOptionPane.showMessageDialog(this, "您已成功退出!");
            ps.println("OFFLINE#" + nickName);
            System.exit(0);
        } else{
            System.out.println("不识别的事件");
        }
    }

    public void handleSS(){//在私聊窗口中发消息
    	
    	String name=sender;
    	
    	if(sender.equals(nickName)) {
    		name = receiver;
    	}
    	if(FirstSecret) {
    		ps.println("FSMSG#" + nickName + "#" + name + "#" + jTextField.getText());
        	jTextField.setText(""); 
        	FirstSecret = false;
    	}
    	else {
    		ps.println("SMSG#" + nickName + "#" + name + "#" + jTextField.getText());
    		jTextField.setText("");
    	} 	     
    }

    public void handleSend(){//群发消息
        //发送信息时标识一下来源
        ps.println("MSG#" + nickName + "#" +  jtf.getText());
        //发送完后,是输入框中内容为空
        jtf.setText("");
    }

    public void handleSec(String name){ //建立私聊窗口
        JFrame jFrame = new JFrame();//新建了一个窗口      
        JPanel JPL = new JPanel();
        JPanel JPL2 = new JPanel();
        FlowLayout f2 = new FlowLayout(FlowLayout.LEFT);
        JPL.setLayout(f2);
        JPL.add(input2);
        JPL.add(jTextField);//文本
        JPL.add(jButton);
        JPL2.add(js1,BorderLayout.CENTER);
        JPL2.add(JPL,BorderLayout.SOUTH);
        jFrame.add(JPL2);
        
       
       // jButton.addActionListener(this);
        jTextArea.setFont(new Font("宋体", Font.PLAIN,15));
        jTextArea.setBackground(new Color(224,224,239)); // 设置文本区域的背景色
        jFrame.setSize(400,300);
        jFrame.setLocation((int)MAIN_FRAME_LOC_X+20,(int)MAIN_FRAME_LOC_Y+20);//将私聊窗口设置总是在父窗口的中间弹出
        jFrame.setTitle("与" + name + "私聊中");
        jFrame.setVisible(true);

        jTextField.setFocusable(true);//设置焦点
        
        jFrame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
            	jTextArea.setText("");
            	FirstSecret = true;
            }
        });
    }//私聊窗口
    
    public static void main(String[] args)throws Exception{
    	
    		deleteOldChatRecords(1);
            new client1(nickName);
    	
    	
    }
}

部分转载于这里这里

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值