JAVA GUI聊天室

JAVA GUI聊天室

涉及的知识点:Java网络编程、GUI、多线程、IO流

服务端:

  • 服务端界面设计
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.FileWriter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;

import javax.swing.*;

public class ServiceView extends JFrame implements ActionListener{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	private static final int port = 9090;

	private JButton openBtn, closeBtn;

	private JButton JBExport = new JButton("导出");


	//创建文本输入框, 参数分别为行数和列数
	public static JTextArea jtMessage = new JTextArea();
	//创建聊天消息框
	public static JTextArea jtMember = new JTextArea();

	JScrollPane JSMessage = new JScrollPane(jtMessage);

	JScrollPane JSMember = new JScrollPane(jtMember);

	private Service service = null;
	private static ServiceView view;

	public static ArrayList<ClientView> clientViews = new ArrayList<>();
	public static ArrayList<String> user = new ArrayList<String>();


	public static ServiceView getView() {
		return view;
	}

	public static void main(String[] args) {
		view = new ServiceView();
	}

	public ServiceView() {
		this.setTitle("服务端");
		this.setLayout(new BorderLayout());
		this.setSize(500, 500);
		this.setLocationRelativeTo(null);
		this.setDefaultCloseOperation(EXIT_ON_CLOSE);


		JPanel panel_north = new JPanel();   	
		panel_north.setLayout(null);
		panel_north.setPreferredSize(new Dimension(500, 50));
		panel_north.setBackground(Color.WHITE);

		JLabel label = new JLabel("端口:");
		JTextField JTPort = new JTextField(8);
		JTPort.setText("9090");
		openBtn = new JButton("打开服务端");
		closeBtn = new JButton("关闭服务端");

		label.setBounds(10, 10, 60, 30);
		JTPort.setBounds(60, 10, 100, 30);
		openBtn.setBounds(240, 10, 100, 30);
		closeBtn.setBounds(360, 10, 100, 30);

		closeBtn.setEnabled(false);

		openBtn.addActionListener(this);
		closeBtn.addActionListener(this);


		JPanel panel_south = new JPanel();   	
		panel_south.setLayout(null);
		panel_south.setPreferredSize(new Dimension(500, 450));


		JLabel log = new JLabel("日志");
		JLabel online = new JLabel("在线用户");


		log.setFont(new Font(null,9, 18));

		log.setBounds(10, 60, 60, 20);
		JBExport.setBounds(300, 80, 60, 20);
		online.setBounds(390, 60, 60, 20);
		
		JBExport.addActionListener(this);

		//设置文本输入框大小和位置
		JSMessage.setBounds(10, 80, 350, 300);
		//设置文本输入框字体
		jtMessage.setFont(new Font("楷体", Font.BOLD, 14));

		//聊天消息框自动换行
		jtMessage.setLineWrap(true);
		//聊天框不可编辑,只用来显示
		jtMessage.setEditable(false);

		JSMember.setBounds(370, 80, 100, 300);
		jtMember.setEditable(false);

		panel_north.add(label);
		panel_north.add(JTPort);
		panel_north.add(openBtn);
		panel_north.add(closeBtn);

		panel_south.add(log); 
		panel_south.add(JBExport);
		panel_south.add(online);
		panel_south.add(JSMessage);
		panel_south.add(JSMember);
		
		this.add(panel_north, BorderLayout.NORTH);
		this.add(panel_south, BorderLayout.SOUTH);

		this.setVisible(true);
	}


    //时间监听
	@Override
	public void actionPerformed(ActionEvent e) {
		if (e.getSource() == openBtn) {
			open();
		} 

		if (e.getSource() == closeBtn) {
			stop();
		}

		if (e.getSource() == JBExport) {
			String msg = jtMessage.getText();
			//得到实时时间
			Date date = new Date();
			SimpleDateFormat ft = new SimpleDateFormat ("yyyy-MM-dd-hh-mm-ss");
			System.out.println(ft.format(date));
			//日志写入txt文件(以时间命名)
			String fileName = "E:\\"+ft.format(date)+".txt";
			
			try {
				FileWriter writer = new FileWriter(fileName,true);
				//写入日志文件
				writer.write(msg);
				
				writer.close();
				
			} catch (IOException e1) {
				//e1.printStackTrace();
				
			}
			
		}

		
	}

	public void open() { //开启服务器
		service = new Service(port);
		Thread thread = new Thread(service);
		thread.start();

		JOptionPane.showMessageDialog(null, "服务器打开!");
		System.out.println("服务器打开");
		openBtn.setEnabled(false);
		closeBtn.setEnabled(true);
	}

	public void stop() { 
		//关闭服务器

		openBtn.setEnabled(true);
		closeBtn.setEnabled(false);
		try {
			synchronized (Service.sockets) { 

				//关闭各个连接
				for (ChatSocket socket : Service.sockets) {
					socket.getInputStream().close();
					socket.getOutputStream().close();
				}
				Service.sockets.removeAllElements();

			}


			for (ClientView view : clientViews) {
				view.getInputStream().close();
				view.getOutputStream().close();
			}

			service.getServerSocket().close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}
  • 服务端多线程循环等待连接
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Vector;

import javax.swing.JOptionPane;

/**
 *  服务端,使用线程达到循环等待连接的目的
 * @author Administrator
 *
 */
public class Service implements Runnable{

    private ServerSocket serverSocket = null;
    private int port = 9090;
    //客户端集合
    public static Vector<ChatSocket> sockets = new Vector<ChatSocket>();
    
    
    
    public Service(int port){
    	this.port = port;
    }
    
    
    @Override
    public void run() {
        try {
            serverSocket = new ServerSocket(port); 
            while (true) { 
            	
            	//循地接收客户端的连接
                Socket socket = serverSocket.accept();
                                
                //新客户端连接,创建ChatSocket对象(包含InputStream和OutputStream)
                ChatSocket chatSocket = new ChatSocket(socket); 
                
                //往客户端管理器里添加客户
                sockets.add(chatSocket); 
                
                //启用线程使服务器开始不断接收客户端信息
                Thread thread = new Thread(chatSocket); 
                thread.start();

            }
        } catch (IOException e) {
            //e.printStackTrace();
        	JOptionPane.showMessageDialog(null, "服务器关闭!");
        }
    }
    
    public ServerSocket getServerSocket() {
        return serverSocket;
    }
    

}
  • 服务端功能
import java.io.*;
import java.net.*;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.Vector;


/**
 * 功能:使用传入的socket获得数据流,达到传输数据的目的
 * @author Administrator
 *
 */
@SuppressWarnings("unused")
public class ChatSocket implements Runnable{


	private Socket socket = null;
	private DataInputStream inputStream = null;
	private DataOutputStream outputStream = null;
	

	public ChatSocket(Socket socket) {
		this.socket = socket;
		try {
			this.inputStream = new DataInputStream(socket.getInputStream());
			this.outputStream = new DataOutputStream(socket.getOutputStream());
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	//get方法
	public DataInputStream getInputStream() {
		return inputStream;
	}

	public DataOutputStream getOutputStream() {
		return outputStream;
	}


	//向客户端发送数据
	public void send(String message) { 
		try {
			outputStream.writeUTF(message);
			outputStream.flush();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}


	@Override
	public void run() { 

		String message = null;

		//循环读取客户端发来的数据
		while (true) {
			try {

				//读取到的数据
				message = inputStream.readUTF();

				String[] s = message.split("#");

				String name = s[0];
				String msg = s[1];
				String state = s[2];

				Date date = new Date();
				SimpleDateFormat ft = new SimpleDateFormat ("HH:MM:ss"); 
				String time = ft.format(date);

				if(state.equals("1")) {

					//清空列表
					ServiceView.jtMember.setText(null);
					//添加用户到用户列表
					ServiceView.user.add(name);
					//添加用户上线通知
					ServiceView.jtMessage.append(time+"  "+name+msg+"\n");

					//列表更新
					Iterator<String> it = ServiceView.user.iterator();

					while(it.hasNext()) {
						String u = it.next();
						ServiceView.jtMember.append(u+"\n");
					}

				}
				else if(state.equals("2")){
					//发送给其他客户端(完整的输入的信息包含:用户名#信息#状态)
					//添加聊天信息
					ServiceView.jtMessage.append(time+"  "+name+":"+msg+"\n");
					
					
					
					for (ChatSocket socket : Service.sockets) {

						if (!this.equals(socket)) {
							socket.send(message);
						}else {
							continue;
						}
					}
				}else if(state.equals("3")) {
					//清空列表
					ServiceView.jtMember.setText(null);
					//移除下线用户
					ServiceView.user.remove(name);
					//添加下线信息
					ServiceView.jtMessage.append(time+"  "+s[0]+s[1]+"\n");

					//列表更新
					Iterator<String> it = ServiceView.user.iterator();

					while(it.hasNext()) {
						String u = it.next();
						ServiceView.jtMember.append("    "+u+"\n");
					}
				}

			} catch (IOException e) {
				//客户端已退出,将其移出客户端集合
				Service.sockets.remove(this);
			}
		}
	}
}

客户端:

import java.applet.Applet;
import java.applet.AudioClip;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.*;
import java.net.*;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.swing.*;

public class ClientView extends JFrame implements ActionListener, Runnable, KeyListener {
	/**
	 * 聊天室测试
	 */
	private static final long serialVersionUID = 1L;

	private JTextArea textArea;
	private JTextField textField, Name;
	private JButton btnSend;
	private JLabel label;
	private JPanel panel_north, panel_south;

	private Socket socket = null;
	private DataInputStream inputStream = null;
	private DataOutputStream outputStream = null;
	private JScrollPane scrollPane;

	private Date date = new Date();
	int state = 1;
	private static String name = null;

	public JTextArea getTextArea() {
		return textArea;
	}

	public DataInputStream getInputStream() {
		return inputStream;
	}
	public DataOutputStream getOutputStream() {
		return outputStream;
	}


	public static void main(String[] args) {
		
		
		name = JOptionPane.showInputDialog(null, "昵称:");
		if(name == null) {
			return;
		}
		
		ClientView view = new ClientView();

		Thread thread = new Thread(view);
		thread.start();
	}



	public ClientView() {

		try {
			//连接服务器,建立TCP服务
			socket = new Socket("127.0.0.1", 9090);
			UserView();

			state = 1;
			String s = "上线";
			
			File file = new File("music/01.wav");
			URI uri = file.toURI();
			URL url = uri.toURL();
			AudioClip ac = Applet.newAudioClip(url);
			ac.play();
			
			sendMessage(s);

		} catch (UnknownHostException e) {
			JOptionPane.showMessageDialog(null, "未知的服务器地址!");
			e.printStackTrace();
		} catch (IOException e) {
			JOptionPane.showMessageDialog(null, "服务器未开启!");
			System.exit(0);
		}

	}


	private void UserView() {
		textArea = new JTextArea(20, 20);
		textArea.setEditable(false);
		scrollPane = new JScrollPane(textArea);
		textField = new JTextField(15);
		textField.addKeyListener(this);
		btnSend = new JButton("发送");
		btnSend.addActionListener(this);
		label = new JLabel("昵称:");
		Name = new JTextField(name);
		panel_north = new JPanel();
		panel_south = new JPanel();
		panel_north.add(label);
		panel_north.add(Name);
		panel_north.setLayout(new FlowLayout(FlowLayout.LEFT));

		panel_south.add(textField);
		panel_south.add(btnSend);
		panel_south.setLayout(new FlowLayout(FlowLayout.CENTER));

		add(panel_north, BorderLayout.NORTH);
		add(scrollPane, BorderLayout.CENTER);
		add(panel_south, BorderLayout.SOUTH);

		setTitle("聊天室测试——2.0");
		setSize(500, 500);
		setLocation(450, 150);
		setVisible(true);
		setDefaultCloseOperation(EXIT_ON_CLOSE);


		addWindowListener(new WindowAdapter() { //窗口关闭后断开连接
			@Override
			public void windowClosing(WindowEvent e) {
				try {
					state = 3;
					sendMessage("下线");
					
					if (socket != null)
						socket.close();
					if (inputStream!= null)
						inputStream.close();
					if (outputStream != null)
						outputStream.close();

				} catch (IOException e1) {
					e1.printStackTrace();
				}
			}
		});
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		if (e.getSource() == btnSend) {
			String s = textField.getText();
			state = 2;
			sendMessage(s);
		}
	}


	//回车键监听
	public void keyPressed(KeyEvent arg0) {
		if (arg0.getKeyCode() == KeyEvent.VK_ENTER) {
			String s = textField.getText();
			state = 2;
			sendMessage(s);
		}
	}

	@Override
	public void keyTyped(KeyEvent e) {}

	@Override
	public void keyReleased(KeyEvent e) {}



	/**
	 * 循环接收服务端发送的消息
	 */
	@Override
	public void run() {
		try {
						
			inputStream = new DataInputStream(socket.getInputStream());

			while (true) {

				String[] s = inputStream.readUTF().split("#");

				SimpleDateFormat ft = new SimpleDateFormat ("HH:MM:ss"); 
				String time = ft.format(date);
				if(s[2].equals("2")) {
					
					File file = new File("music/02.wav");
					URI uri = file.toURI();
					URL url = uri.toURL();
					AudioClip ac = Applet.newAudioClip(url);
					ac.play();
					
					//解析出信息内容:s[0] 该用户名  s[1]  信息
					textArea.append(time+"    "+s[0] + ":\n"+ s[1] + "\n\n");
					//手动设置光标的位置未最后一行
					textArea.setCaretPosition(textArea.getDocument().getLength());
				}

			}
		} catch (IOException e) {

		}

	}

	/**
	 * 发送信息给服务端
	 */
	private void sendMessage(String s) {
		try {

			if (!s.equals("")) { 

				
				SimpleDateFormat ft = new SimpleDateFormat ("HH:MM:ss"); 
				String time = ft.format(date);

				if(state == 2) {
					textField.setText("");
					textArea.append(time+"    我【" + Name.getText() +  "】:\n" + s + "\r\n\n");
				}
				
				
				outputStream = new DataOutputStream(socket.getOutputStream());

				//发送的格式:用户名#消息
				outputStream.writeUTF(Name.getText() + "#" + s+"#"+state); 
				
				outputStream.flush();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

}

运行结果:
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_40270579/article/details/84104515