java实现的聊天程序



//利用GUI和网络编程知识,建立一个简单的聊天程序。

package cn.itcast.udp.exercise;

import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Color;
import java.awt.Frame;
import java.awt.Panel;
import java.awt.TextArea;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.text.SimpleDateFormat;
import java.util.Date;

public class GUI_Chat extends Frame {
	
	private static final long serialVersionUID = 1L;
	
	private Button sendButton;
	private Button clearButton;
	private Button logButton;
	private Button shakeButton;
	private TextField textField;
	private TextArea viewTextArea;
	private TextArea sendTextArea;
	
	private DatagramSocket socket;
	private BufferedWriter writer;
	
	/*
	 * 构造函数
	 * 		初始化
	 * 		生成2个Panel, 以及界面组件
	 * 		处理事件
	 * 		显示窗体
	 * 		启动接收消息的线程 
	 */
	public GUI_Chat() {
		init();							// 设置标题, 大小, 位置, 处理关闭事件
		generateSouthPanel();			// 生成那边的Panel, 包含TextField和4个Button
		generateCenterPanel();			// 生成中间的Panel, 包含2个TextArea
		handleChatEvent();				// 各种事件的处理
		setVisible(true);				// 显示
		new ReceiveThread().start();	// 开启接收消息的线程
	}

	/*
	 * 初始化
	 * 		设置标题, 大小, 位置
	 * 		创建Socket和Writer
	 */
	private void init() {
		setTitle("GUI聊天室");
		setSize(400, 600);
		setLocation(600, 50);
		try {
			socket = new DatagramSocket();
			writer = new BufferedWriter(new FileWriter("msg.txt", true));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/*
	 * 创建南边的Panel
	 * 		其中包含用来输入IP的TextField和4个Button
	 */
	private void generateSouthPanel() {
		textField = new TextField(20);
		sendButton = new Button("发送");
		clearButton = new Button("清屏");
		logButton = new Button("记录");
		shakeButton = new Button("震动");
		
		Panel southPanel = new Panel();			// 用来布局的Panel, 默认流式布局. 文本框和按钮都放在Panel中
		southPanel.add(textField);			
		southPanel.add(sendButton);
		southPanel.add(clearButton);
		southPanel.add(logButton);
		southPanel.add(shakeButton);
		
		add(southPanel, BorderLayout.SOUTH);	// Panel放在Frame的南边
		
		textField.setText("127.0.0.1");
	}
	
	/*
	 * 创建中间的Panel
	 * 		其中包含2个TextView
	 */
	private void generateCenterPanel() {
		viewTextArea = new TextArea();
		sendTextArea = new TextArea(5, 1);					// 指定行数和列数, 列数由于是边界布局所以无效
		
		Panel centerPanel = new Panel();					// 把Panel改为边界布局, 1个TextArea在中间, 另一个在南边
		centerPanel.setLayout(new BorderLayout());			
		centerPanel.add(viewTextArea, BorderLayout.CENTER);
		centerPanel.add(sendTextArea, BorderLayout.SOUTH);
		
		add(centerPanel, BorderLayout.CENTER);				// Panel放在Frame的中间
		
		viewTextArea.setEditable(false);					// 用来显示的TextArea不能修改(会修改背景色为灰色)
		viewTextArea.setBackground(Color.WHITE);			// 背景色改回白色
	}
	
	/*
	 * 处理各种事件
	 * 		窗体关闭
	 * 		4个按钮
	 * 		发送快捷键
	 */
	private void handleChatEvent() {
		addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				try {
					socket.close();
					writer.close();
					System.exit(0);
				} catch (IOException e1) {
					e1.printStackTrace();
				}
			}
		});
		
		sendButton.addActionListener(new ActionListener() {		// 发送按钮被点击的时候, 执行send()方法
			public void actionPerformed(ActionEvent e) {
				send();
			}
		});
		
		clearButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				viewTextArea.setText("");
			}
		});
		
		sendTextArea.addKeyListener(new KeyAdapter() {
			public void keyPressed(KeyEvent e) {
				if (e.isControlDown() && e.getKeyCode() == KeyEvent.VK_ENTER || e.isAltDown() && e.getKeyCode() == KeyEvent.VK_S) {
					e.consume();	// 取消当前事件
					send();
				}
			}
		});
		
		logButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				showLog();
			}
		});
		
		shakeButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				sendData(new byte[] { -1 }, textField.getText());
			}
		});
	}
	
	/*
	 * 把指定的数据发送到指定的IP地址上
	 */
	private void sendData(byte[] data, String ip) {
		try {
			DatagramPacket packet = new DatagramPacket(data, data.length, InetAddress.getByName(ip), 6789);	// 创建Packet
			socket.send(packet);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/*
	 * 发送消息的方法
	 * 		发送之后会在TextView显示
	 * 		并且会保存聊天记录
	 */
	private void send() {
		String text = sendTextArea.getText();		// 获取文本框中的文本
		String ip = textField.getText();			// 获取IP地址
		ip = ip.trim().length() == 0 ? "255.255.255.255" : ip; 		// IP为空时, 群发
		try {
			String dateStr = getCurrentTime();		// 获取当前时间
			synchronized(this) {					// 为了让发送消息并显示之后才执行接收端的显示, 所以同步
				sendData(text.getBytes(), ip);
				String msg = dateStr + " 我对 " + (ip.equals("255.255.255.255") ? "所有人" : ip) + " 说:\r\n" + text + "\r\n\r\n";
				viewTextArea.append(msg);			// 在TextArea中显示发送的消息
				writer.write(msg);					// 保存聊天记录
			}
			sendTextArea.setText("");				// 清空TextArea
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/*
	 * 获取当前时间
	 */
	private String getCurrentTime() {
		Date date = new Date();
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		return sdf.format(date);
	}
	
	/*
	 * 用来接收数据的线程
	 * 		不停地接收数据, 显示到TextView, 并且保存聊天记录
	 */
	private class ReceiveThread extends Thread {	
		public void run() {
			try {
				DatagramSocket socket = new DatagramSocket(6789);							// 接收端Socket
				DatagramPacket packet = new DatagramPacket(new byte[1024000], 1024000);		// 接收端Packet
				while (true) {											// 循环接收
					socket.receive(packet);								// 收到数据
					byte[] data = packet.getData();						// 获取数据
					int len = packet.getLength();						// 获取长度
					if (len == 1 && data[0] == -1) {					// 收到特殊的消息, 震动
						shake();
						continue;
					}
					String ip = packet.getAddress().getHostAddress();	// 获取IP
					String text = new String(data, 0, len);				// 把收到的数据转为String
					String timeStr = getCurrentTime();					// 获取当前时间
					synchronized(GUI_Chat.this) {						// 为了确保在发送端显示之后再显示, 所以同步
						String msg = timeStr + " " + ip + " 对我说:\r\n" + text + "\r\n\r\n";
						viewTextArea.append(msg);						// 把收到的数据显示
						writer.write(msg);								// 保存聊天记录
					}
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	/*
	 * 震动
	 */
	private void shake() {
		int x = getLocation().x;	// 获取当前位置
		int y = getLocation().y;
		
		try {
			setLocation(x + 20, y + 20);
			Thread.sleep(20);
			setLocation(x - 20, y - 20);
			Thread.sleep(20);
			setLocation(x - 20, y + 20);
			Thread.sleep(20);
			setLocation(x + 20, y - 20);
			Thread.sleep(20);
			setLocation(x, y);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	/*
	 * 显示聊天记录
	 * 		从文件中读取数据, 显示到TextView
	 */
	private void showLog() {
		try {
			viewTextArea.setText("");	// 清空viewTextArea
			writer.flush();				// 刷出缓冲区中数据
			
			FileInputStream fis = new FileInputStream("msg.txt");		
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			byte[] buffer = new byte[1024];
			int len;
			while ((len = fis.read(buffer)) != -1)			// 从文件读取数据到内存
				baos.write(buffer, 0, len);
			fis.close();
			baos.close();
			
			String log = new String(baos.toByteArray());	// 把内存中数据转为String
			viewTextArea.setText(log);						// 显示到viewTextArea
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/*
	 * 测试方法, 创建聊天室对象
	 */
	public static void main(String[] args) {
		new GUI_Chat();		
	}
}


  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
java聊天程序源码 2 需求分析 2.1 业务需求 1. 与聊天室成员一起聊天。 2. 可以与聊天室成员私聊。 3. 可以改变聊天内容风格。 4. 用户注册(含头像)、登录。 5. 服务器监控聊天内容。 6. 服务器过滤非法内容。 7. 服务器发送通知。 8. 服务器踢人。 9. 保存服务器日志。 10.保存用户聊天信息。 2.2 系统功能模块 2.2.1 服务器端 1.处理用户注册 2.处理用户登录 3.处理用户发送信息 4.处理用户得到信息 5.处理用户退出 2.2.2 客户端 1.用户注册界面及结果 2.用户登录界面及结果 3.用户发送信息界面及结果 4.用户得到信息界面及结果 5.用户退出界面及结果 2.3 性能需求 运行环境:Windows 9x、2000、xp、2003,Linux 必要环境:JDK 1.5 以上 硬件环境:CPU 400MHz以上,内存64MB以上 3.1.2 客户端结构 ChatClient.java 为客户端程序启动类,负责客户端的启动和退出。 Login.java 为客户端程序登录界面,负责用户帐号信息的验证与反馈。 Register.java 为客户端程序注册界面,负责用户帐号信息的注册验证与反馈。 ChatRoom.java 为客户端程序聊天室主界面,负责接收、发送聊天内容与服务器端的Connection.java 亲密合作。 Windowclose 为ChatRoom.java的内部类,负责监听聊天室界面的操作,当用户退出时返回给服务器信息。 Clock.java 为客户端程序的一个小程序实现的一个石英钟功能。 3. 2 系统实现原理 当用户聊天时,将当前用户名、聊天对象、聊天内容、聊天语气和是否私聊进行封装,然后与服务器建立Socket连接,再用对象输出流包装Socket的输出流将聊天信息对象发送给服务器端 当用户发送聊天信息时,服务端将会收到客户端用Socket传输过来的聊天信息对象,然后将其强制转换为Chat对象,并将本次用户的聊天信息对象添加到聊天对象集Message中,以供所有聊天用户访问。 接收用户的聊天信息是由多线程技术实现的,因为客户端必须时时关注更新服务器上是否有最新消息,在本程序中设定的是3秒刷新服务器一次,如果间隔时间太短将会增加客户端与服务器端的通信负担,而间隔时间长就会让人感觉没有时效性,所以经过权衡后认为3秒最佳,因为每个用户都不可能在3秒内连续发送信息。 当每次用户接收到聊天信息后将会开始分析聊天信息然后将适合自己的信息人性化地显示在聊天信息界面上。 4.1.1 问题陈述 1.接受用户注册信息并保存在一个基于文件的对象型数据库。 2.能够允许注册过的用户登陆聊天界面并可以聊天。 3.能够接受私聊信息并发送给特定的用户。 4.服务器运行在自定义的端口上#1001。 5.服务器监控用户列表和用户聊天信息(私聊除外)。 6.服务器踢人,发送通知。 7.服务器保存日志。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值