`

仿QQ聊天第三版(头像设置、文件传输)

 
阅读更多

在这个版本已经实现了基本的聊天,群聊以及文件发送功能.

 

为了图简单,只要是在线的用户就都会出现在所有客户端列表中,没有单独为每个用户保存好友,群聊所有人都会收到消息.

注册的用户信息都保存在文件中,每次服务器启动就先读取数据.

客户端连接上之后,就给所有在线的其他客户端发送自己上线的消息,然后其他客户端就更新好友列表.

双击即可打开对话窗口进行聊天或者传文件.

 

界面演示图:



 

之前两个版本:

第一版:

http://479001499.iteye.com/blog/2100893

 

第二版:

 http://479001499.iteye.com/blog/2101491

 

 

 

这个版本在第二版之上改进的功能:

 

增加头像设置,文件传输.

 

在User类中增加一个属性,String 用来保存图片路径.设置头像实际为设置String的值.然后再生成ImageIcon.

if (source.equals("头像")) {
				System.out.println("点击了更换头像");
				JFileChooser jfc = new JFileChooser("images\\");
				int state = jfc.showOpenDialog(MyInfo.this);
				if (state == 0) {
					user.headIcon = jfc.getSelectedFile().getAbsolutePath();
					head.setIcon(new ImageIcon(user.headIcon));
					// 将这个消息传至服务器
					Message msg = new Message();
					msg.type = MessageUtil.ChangeInfo;
					msg.senderNum = user.num;
					msg.receiverNum = 2;// 所有人加上服务器都要接受并修改信息
					msg.content = user;
					try {
						MessageUtil.send(os, msg);
					} catch (Exception ee) {
						ee.printStackTrace();
					}
				}

			} 

 

修改之后,像所有客户端发送消息,让他们更新消息:

if (msg.type == MessageUtil.ChangeInfo) {
								System.out.println("接受到用户修改信息");
								// 标记修改了信息,当这个为true的时候.再打开对话窗口就需要更新其头像,否则再打开就只需要setVisible
								havaChanged = true;

								User us = (User) msg.content;
								String olaNik = map.get(msg.senderNum).name;

								// 将map<账号,昵称>中的元素进行修改
								mapN2N.remove(olaNik);
								ChatAllUI.dlm.removeElement(olaNik);
								// 将map<昵称,账号>中的元素进行修改
								mapN2N.put(us.name, msg.senderNum);
								ChatAllUI.dlm.addElement(us.name);
								map.put(msg.senderNum, us);

								// 更新各个地方的显示
								if (us.num == user.num) {
									nik.setText(user.name);
									textField_1.setText(user.qianming);
									dlm.set(0, user.name);
								} else {
									int temp = dlm.indexOf(olaNik);
									dlm.removeElement(olaNik);
									dlm.add(temp, us.name);
								}
							}

 

在原有基础上增加一个文件收发的工具类FileTransfer,用来从文件中读取数据和保存数据到文件.

 

package v140813;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class FileTransfer {

	/**
	 * 文件发送
	 * 
	 * @param os
	 *            输出流
	 * @param file
	 *            文件
	 */
	public static void fileSend(OutputStream os, File file) {

		try {
			FileInputStream fis = new FileInputStream(file);
			BufferedInputStream bis = new BufferedInputStream(fis);
			BufferedOutputStream bos = new BufferedOutputStream(os);

			int t = bis.read();
			while (t != -1) {
				bos.write(t);
				t = bis.read();
			}
			bos.flush();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	/**
	 * 收到了开始接收文件的消息里面的内容为文件名,保存在fileRec 目录下
	 * 
	 * @param is
	 *            输入流
	 * @param fileName
	 *            文件名
	 * @param size
	 *            文件大小
	 * @param num
	 *            接收者的num
	 */
	public static void fileReceive(InputStream is, String fileName, long size,
			int num) {
		File f = new File("fileRec\\" + num + "\\");
		if (!f.exists()) {
			f.mkdir();
		}
		File file = new File("fileRec\\" + num + "\\" + fileName);
		try {
			BufferedInputStream bis = new BufferedInputStream(is);
			FileOutputStream fos = new FileOutputStream(file);
			BufferedOutputStream bos = new BufferedOutputStream(fos);

			for (long i = 0; i < size; i++) {
				int t = bis.read();
				// System.out.println(t);
				bos.write(t);
			}
			bos.flush();
			System.out.println("接收完毕");
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

 

 

客户端这边,发送文件之前,首先向服务器发送一条消息,内容为文件名和文件大小.

服务器启动一个线程接收文件,在线程中需要将输入流锁起.

 

服务器收完文件之后,再向接收文件的客户端发送一条消息,内容为文件名和文件大小

同样,客户端开始接收文件.接收完毕之后,向发送者发出消息说已经接收了文件.

public class ReceiveFileThread extends Thread {
		String fileName;
		long size;

		public ReceiveFileThread(String content) {

			String contents[] = content.split("#");
			this.fileName = contents[0];
			size = Long.parseLong(contents[1]);
			System.out.println("准备接收  文件大小:" + size);
		}

		public void run() {
			try {
				synchronized (is) {
					FileTransfer.fileReceive(is, fileName, size);
				}
				System.out.println("接收完毕");
			} catch (Exception e) {
				e.printStackTrace();
			}

		}
	}

	/**
	 * 发送文件的线程
	 * 
	 * @author Huangbin
	 *
	 */
	class SendFileThread extends Thread {
		File file;
		OutputStream os;
		String content;
		int receiverNum;

		public SendFileThread(File file, int receiverNum, String content) {
			this.file = file;
			this.os = Server.slist.get(receiverNum).os;
			this.content = content;
			this.receiverNum = receiverNum;

		}

		public void run() {
			synchronized (os) {
				try {
					MessageUtil.send(os, new Message(8, num, receiverNum,
							content));
					System.out.println("准备发送");

					// 开始发送
					System.out.println("开始发送");
					FileTransfer.fileSend(os, file);
					System.out.println("发送完毕");
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}

 

(这里的接收文件线程和发送文件线程可有可无,因为流只有一个,传文件同时就不能传消息,有没有线程都一样的,初步预计的解决办法是传文件的时候再和服务器建立一个单独的连接,专门用来文件的传输,这样就不会因为只有一个流而不能同时工作了.)

 

接收客户端的处理:

if (msg.type == MessageUtil.FileTransfer) {
								String fileName = ((String) msg.content)
										.split("#")[0];
								if (pcMap.containsKey(msg.senderNum)) {
									// 消息中的发送者在我这边是待会儿的接收者
									pcMap.get(msg.senderNum).textArea
											.append(map.get(msg.senderNum).name
													+ "    给你发送了一个文件"
													+ msg.content + "\r\n");
								} else {
									ChatOneUI coui = new ChatOneUI(os, is, num,
											msg.senderNum, map);
									coui.textArea
											.append(map.get(msg.senderNum).name
													+ "    给你发送了一个文件:  "
													+ fileName + "\r\n");
									pcMap.put(msg.senderNum, coui);
								}
								System.out.println(msg.content);
								ReceiveFileThread rft = new ReceiveFileThread(
										(String) msg.content);
								rft.start();
								// 给线程缓冲时间,不然这个接收消息的线程又去读取消息去了
								while (rft.isAlive()) {
								}
								// 接收完毕了,发送消息给对方告诉他已经收到了
								pcMap.get(msg.senderNum).textArea
										.append("接收完毕。");
								MessageUtil.send(os, new Message(
										MessageUtil.ONEUSER, num,
										msg.senderNum, "已经接收了你发送的文件: "
												+ fileName + "\r\n"));
							}

 

 

附上所有的代码:(图片素材在第二版里面,将images文件夹放到ChatClient文件夹下)

客户端每个包下都有一个说明文件,里面说明了这个包在上一个包的基础上进行了一些什么修改

 

  • 大小: 207.1 KB
1
0
分享到:
评论
2 楼 紫梦飘逸 2014-09-15  
1 楼 人生难得糊涂 2014-08-19  
      

相关推荐

    Android 仿qq上传头像(一)

    以上就是实现"Android 仿qq上传头像(一)"所需的主要知识点,涵盖了从用户交互、图片处理到网络通信的整个流程。通过熟练掌握这些技能,开发者可以构建出类似QQ头像上传的功能,为用户提供流畅、便捷的体验。

    仿QQ聊天系统4.0源码(扩展韩顺平的简单的聊天程序的功能及界面)

    而"仿QQ聊天系统4.0所要用的外jar.zip"则可能包含了项目依赖的第三方库,如网络通信库、GUI框架等,这些都是实现聊天功能所必需的。 总的来说,仿QQ聊天系统4.0是一个综合性的项目,涵盖了网络编程、GUI设计、多...

    带qq昵称qq头像的qq帐号登录ecshop插件v3.0版

    在ECShop这个开源电子商务平台中,"带QQ昵称QQ头像的QQ帐号...然而,需要注意的是,与第三方平台的集成可能会涉及用户隐私保护和数据安全问题,所以在使用此类插件时,必须确保符合相关法律法规,保护用户数据的安全。

    如何设置2021QQ透明头像.docx

    设置 2021QQ 透明头像需要经过三个步骤:下载透明图片、登录网页版、上传头像并保存。通过按照这些步骤操作,可以成功设置透明头像。需要注意的是,下载的图片需要将后缀改为 JPG,以避免上传失败。 相关知识点 * ...

    JAVA版QQ聊天室的开发

    - 使用Java的Properties类或者第三方库如Apache Commons Configuration读取和解析配置文件。 8. **用户管理**: - 包括用户权限管理、账户激活、密码重置等操作,这需要设计合适的用户模型和数据库表结构。 - ...

    QQ的DLL文件修改大全

    ### QQ的DLL文件修改大全 #### 一、概述 在探讨QQ DLL文件修改之前,我们需要先了解DLL(Dynamic Link Library)的基本概念。DLL是Windows操作系统中的动态链接库,是一种共享库,可以被多个应用程序同时调用,...

    android完美高仿微信上传头像

    Android提供了`CropIntent`,但可能在部分设备上不兼容,因此建议使用第三方库如`android-image-cropper`。此外,图片可能因拍摄角度不同需要旋转,可以通过ExifInterface获取图片的旋转角度并使用Matrix进行旋转...

    C#仿QQ界面开发程序

    在实际项目中,开发者还可能使用到其他技术,如设计模式来组织代码结构,或者第三方库来增强功能,例如用于消息推送的第三方服务。然而,由于提供的信息有限,以上分析基于对C#桌面应用开发的一般理解。在开发过程中...

    qq第三方登录web版demo很简单

    在这个“qq第三方登录web版demo很简单”的项目中,我们将探讨如何使用Java Web技术实现QQ登录的集成。 首先,我们需要理解QQ开放平台(QQ Connect)的概念。QQ Connect是腾讯提供的一种服务,它允许开发者将QQ账号...

    xamarin Android 仿QQ 登陆界面

    在本文中,我们将深入探讨如何使用Xamarin.Android构建一个仿QQ登录界面,并实现记录头像登录功能。Xamarin是一个强大的跨平台开发工具,允许开发者使用C#语言来编写原生的Android、iOS和Windows应用程序。它提供了...

    QQ在线状态查看和即时会话.e.rar

    例如,聊天记录在传输过程中会被加密,防止被第三方截取。同时,QQ账号的安全性也得到了保障,用户可以通过设置登录验证、密保问题等方式增加账户的安全等级。 至于压缩包文件"QQ在线状态查看和即时会话.e.rar",...

    第三方登录qqweb版

    1. **OAuth2.0协议**:这是QQ第三方登录的核心协议,它定义了一种授权机制,使得应用可以安全地获取到用户在QQ平台上的部分信息,如用户ID、昵称、头像等,但无需知道用户的QQ密码。OAuth2.0提供了授权码、简化授权...

    2009超级彩虹qq显ip

    1. **彩虹QQ**:彩虹QQ是2000年代后期流行的一款针对腾讯QQ的第三方增强工具,它提供了诸如查看对方IP、在线状态提示、自定义头像等腾讯官方未提供的功能。 2. **IP显示功能**:在QQ聊天中,通常只能看到对方的地理...

    最新版第三方qq登录源码

    在本文中,我们将深入探讨如何使用最新版的第三方QQ登录源码,以及涉及的相关技术点。 1. **OAuth2.0授权协议**: QQ登录通常基于OAuth2.0协议,这是一种开放标准授权框架,允许用户让第三方应用在无需获取用户...

    java swt版本的qq可以实现的功能

    - 文件传输:考虑到后期功能扩展,聊天窗口还预留了文件及图片发送的功能。 ### 总结与协作建议 1. **任务分配**:根据各成员的能力和兴趣进行合理分工,以保证项目高效推进。已完成任务的成员应主动协助进度较慢...

    QQ2011登录.rar

    QQ2011登录是腾讯公司推出的一款即时通讯软件QQ的2011年版本,主要专注于提供在线聊天、文件传输、群组讨论等多种功能。在这个版本中,QQ进行了多项改进和优化,以提升用户体验和安全性。以下是关于QQ2011登录的相关...

    第三方登陆 qq 新浪微博

    QQ和新浪微博都是中国流行的社交媒体平台,它们提供了开放的API接口,允许开发者集成第三方登录功能。下面我们将深入探讨这个主题。 1. **QQ互联(QQ Open Platform)**:QQ互联是腾讯公司提供的一项服务,它允许...

    QQ2011登录界面

    QQ采用了加密技术,如SSL(Secure Socket Layer)或TLS(Transport Layer Security)协议,确保用户在输入账号和密码时的数据传输安全,防止被第三方截取。 此外,QQ2011可能还包含了其他登录方式,例如通过手机...

    qq 2008 压 缩 包

    QQ 2008是一款由腾讯公司推出的即时通讯软件,主要功能是提供在线聊天、文件传输、群组讨论等多元化沟通服务。在这个“qq 2008 压缩包”中,包含的主要文件是“QQ2008.exe”,这通常是软件的安装程序,用户可以通过...

Global site tag (gtag.js) - Google Analytics