java仿QQ通信项目四(客户信息和客户端获取好友列表) - Go语言中文社区

java仿QQ通信项目四(客户信息和客户端获取好友列表)


java仿QQ通信项目四

项目文件:JavaQQServer

我们在使用QQ时,都拥有自己的资料卡,我们还有自己的好友列表,还可以添加好友,删除好友,下面我们来一步步实现这些功能:

添加好友的流程:

  • 客户端1通过JKnum账号查找到好友(查找好友的方法)此时会发送好友查找信息给服务器

  • 服务器端在DaoTools信息库内查找对应JKnum账号的好友2并获得其昵称,发送好友查找应答消息给客户端1

  • 客户端1发送好友添加信息给客户端2,消息包内包含客户端1的昵称和对客户端2的分组名

  • 客户端2收到好友添加消息,适时回复,根据验证信息,客户端2发送好友申请应答消息给客户端1:
    ①若同意: 将客户端1添加到对应分组 ;在应答消息中提供提供对客户端1的分组名和客户端1对自己的分组名;
    ②若不同意: 回复拒绝应答消息给客户端1

  • 服务器在转发好友申请应答消息:
    ①若申请同意,则在客户端1的相应分组内增加好友2,在客户端2的相应分组内增加好友1,并转发申请应答消息
    ②若不同意申请,只转发好友申请回复消息给客户端1

  • 客户端1收到客户端2的申请应答:
    ①同意:将客户端2添加到对应分组内
    ②不同意:申请失败

①UserInfo内完善保存用户好友的功能

  • 好友列表信息存储:

★ 所有分组存储在一个以组名为键值的HashMap容器内,每个一分组用一个ArrayList来存储,队列里面存储该分组下的好友账号
★为了便于访问,组名另外用一个队列存储
private HashMap <String , ArrayList < Integer> > groups = new HashMap<String,ArrayList < Integer> > ();
private ArrayList < String > groupName = new ArrayList< String>();

	//好友账号列表
	private HashMap<String,ArrayList<Integer> > groups = new HashMap<String,ArrayList<Integer> >();//每一个分组下是一个队列
	//好友分组列表
	private ArrayList<String> groupName = new ArrayList<String>();
	
	public UserInfo(){
		//构造函数内建立默认分组
		addGroup("default");
	}
	
	//得到组数
	public int getListCount(){
		return groupName.size();
	}
	
	//第index组的名字
	public String getGroupName(int index){
		return groupName.get(index);
	}
	
	//name组的人数
	public int getFriendsNum(String name){
		return groups.get(name).size();
	}
	
	//name组的第index个好友的账号
	public int getFriendJKNum(String group, int index){
		return groups.get(group).get(index);
	}
	
	//增加分组
	public void addGroup(String GroupName){
		ArrayList<Integer> ng= new ArrayList<Integer>();
		groups.put(GroupName, ng);
	}
	
	//删除分组
	public void deleteGroup(String GroupName){
		groups.remove(GroupName);
	}

	//增加好友(在对应分组中增加好友)
	public void addFriend(int friend,String group){
		ArrayList<Integer> gr=groups.get(group);
		gr.add(friend);
	}
	
	//删除好友(找到对应分组的列表下JKnum账号的好友并删除)
	public void delFriend(int JKnum, String group){
		ArrayList<Integer> gr=groups.get(group);
		for(int i=0;i<gr.size();i++){
			if(gr.get(i)==JKnum){
				gr.remove(i);
				return;
			}
				
		}
	}

②DaoTools内完善好友的互加机制,和好友列表的增删功能:

  • 通过帐号得到用户信息
  • 在互加好友的双方列表中增加好友信息
	//通过账号查找好友昵称
	public static String getUserName(int JKnum){
		UserInfo user=userDB.get(JKnum);
		if(user==null) 
			return null;
		else
			return user.getnickName();
	}

	//互加好友
	public static void addFriend(int JKnum1, int JKnum2,String group1, String group2){
		//获得双方对象
		UserInfo user1=userDB.get(JKnum1);
		UserInfo user2=userDB.get(JKnum2);
		user1.addFriend(JKnum2, group1);
		user2.addFriend(JKnum1, group2);
	}

③用户登陆成功后应得到自己的资料及好友列表

  • 用户资料消息:0x03
    在这里插入图片描述
    (此处的listCount和budyCount改为int类型,另外在消息中添加上用户自己的昵称,用户登录成功后由服务器下发给客户端)
package MSGType;

import java.util.ArrayList;

public class ClientInfoMsg extends MSHead{
	public ClientInfoMsg(int len, byte type, int dest, int src) {
		super(len, type, dest, src);
	}

	private String MyNickName;//自身昵称
	//自身头像(待完善)
	
	private int listCount;//分组个数
	
	private ArrayList <String> listName= new ArrayList <String> ();//组名
	
	private ArrayList < ArrayList<friend> > list= new ArrayList < ArrayList<friend> >();//各个分组
	
	//内部类
	class friend{
		String nickName;
		int JKnum;
		friend(String nickName,int JKnum){
			this.nickName=nickName;
			this.JKnum=JKnum;
		}
	}
	//设置昵称
	public void setMyNickName(String name){
		this.MyNickName=name;
	}
	
	//得到自身昵称
	public String getMyName(){
		return MyNickName;
	}
	
	//设置分组个数
	public void setListCount(int num){
		this.listCount=num;
	}
	//得到分组个数
	public int getListCount(){
		return listCount;
	}
	
	//添加分组
	public void addList(String name){
		listName.add(name);
		ArrayList<friend> al= new ArrayList<friend>();
		list.add(al);
	}
	
	//在第Index组内添加好友
	public void addFriend(int index, String name, int JKnum){
		friend f= new friend(name,JKnum);
		list.get(index).add(f);
	}
	
	
	//得到第Index组的组名
	public String getListName(int index){
		return listName.get(index);
	}
	//得到第index组内好友个数
	public int getFriendsNum(int index){
		return list.get(index).size();
	}
	
	//得到第i组第j个好友昵称
	public String getName(int i,int j){
		return list.get(i).get(j).nickName;
	}
	
	//得到第i组第j个好友的账号
	public int getJKnum(int i,int j){
		return list.get(i).get(j).JKnum;
	}
	
}

④完善好友申请消息,好友申请应答消息

  • 查找好友消息:0x08
    消息头(消息总长int+消息类型byte+消息发送对象int=0(服务器)+消息发送源int):13 bytes
    消息体:查询对象int: 4 bytes
package MSGType;

public class searchFriendMsg extends MSHead{

	int friendInSearch;
	public searchFriendMsg(int len, byte type, int dest, int src, int friendInSearch) {
		super(len, type, dest, src);
		this.friendInSearch=friendInSearch;
	}
	
	public int getFriendInSearch()
	{
		return friendInSearch;
	}
	
}


  • 查找好友应答消息:0x18
    消息头:(消息总长int+消息类型byte+消息发送对象int+消息发送源int=0(服务器))(13 bytes)
    消息体:(查找结果byte(0成功1失败)(1 byte) + 查找对象昵称String (10 bytes)
package MSGType;

public class searchFriendResMsg extends MSHead {

	private byte result;
	private String findName;
	public searchFriendResMsg(int len, byte type, int dest, int src,byte result, String findName ) {
		super(len, type, dest, src);
		this.result=result;
		this.findName=findName;
	}
	public searchFriendResMsg(int len, byte type, int dest, int src,byte result){
		super(len, type, dest, src);
		this.result=result;
	}

	public byte getResult(){
		return result;
	}
	
	public String getFindName(){
		return findName;
	}

}

  • 好友申请消息:0x09
    消息头(消息总长int+消息类型byte+消息发送对象int+消息发送源int):13 bytes
    消息体(验证消息String(256 bytes)+发送方昵称String(10 bytes)+发送方分组String (10 bytes)
//添加好友申请0x09
package MSGType;

public class addFriendMsg extends MSHead{

	private	String checkMsg;//好友验证信息256
	private String senderName;//发送方昵称10
	private String group;//发送方对好友的分组10
	
	
	public addFriendMsg(int len, byte type, int dest, int src, String checkMsg, String senderName, String group) {
		super(len, type, dest, src);
		this.checkMsg=checkMsg;
		this.senderName=senderName;
		this.group=group;
	}
	
	public String getCheckMsg(){
		return checkMsg;
	}

	public String getGroup(){
		return group;
	}
	
	public String getSenderName(){
		return senderName;
	}
	
}

  • 好友申请应答消息:0x19
    消息头:(消息总长int+消息类型byte+消息发送对象int+消息发送源int)(13 bytes)
    消息体:(回复byte(0同意1拒绝)(1 byte) + 发送方分组String(10 bytes)+ 接收方分组String (10 bytes) )
//好友申请应答消息0x19
package MSGType;

public class addFriendResMsg extends MSHead{
	
	private byte Res;//为0同意,为1拒绝
	private String groupMe;//若同意为自己将好友分的组别名
	private String groupFriend;//若同意为好友将自己分的组别名
	
	
	//重载构造方法
	public addFriendResMsg(int len, byte type, int dest, int src, byte Res,
			String groupMe,String groupFriend ) {
		super(len, type, dest, src);
		this.Res=Res;
		this.groupMe=groupMe;
		this.groupFriend=groupFriend;
	}

	public addFriendResMsg(int len, byte type, int dest, int src, byte Res){
		super(len, type, dest, src);
		this.Res=Res;
	}
	
	public byte getRes(){
		return Res;
	}
	
	public String getMyGroup(){
		return groupMe;
	}
	
	public String getFriendGroup(){
		return groupFriend;
	}
}


②客户端:

  • 新增好友类:好友的账号JKnum和昵称
package javaQQclient1;

import java.awt.Image;

public class Friend {
	private int JKnum;
	private String nickName;
	
	
	public void setJKnum(int JKnum){
		this.JKnum=JKnum;
	}
	
	public int getJKnum(){
		return JKnum;
	}
	
	public void setNickName(String nickName){
		this.nickName=nickName;
	}
	
	public Image getNickName(){
		return nickName;
	}
}

  • 客户ChatClient类里面保存有自己的好友列表和添加了等待回复的好友列表:
  • private HashMap<String,ArrayList > friends= new HashMap<String,ArrayList >();//好友列表
  • private HashMap<Integer,Friend> addFriendList= new HashMap<Integer,Friend>();//添加好友列表

ⅰ.查找好友功能:
以下是错误示例:

//查找好友,得到好友
	public Friend findFriend(int JKnum) throws IOException{
		byte type=0x08;
		int len=13+4;
		int dest=0,src=this.JKnum;
		searchFriendMsg sfm= new searchFriendMsg(len,type,dest,src,JKnum);
		byte[]data=MSGTools.packMsg(sfm);
		dou.write(data);
		dou.flush();	
		//接收好友查找回复
		searchFriendResMsg sfrm= (searchFriendResMsg)MSGTools.readMsgHead(din);
		byte reply= sfrm.getResult();
		if(reply==0){//查找到
			System.out.println("查找到好友,昵称:"+sfrm.getFindName());
			Friend f= new Friend();
			f.setJKnum(JKnum);
			f.setNickName(sfrm.getFindName());
			return f;
		}
		else{
			System.out.println("未查找到好友:"+JKnum);
			return null;
		}
	}

此处对好友查找应答消息的处理是不可取的。
虽然我们期望在查找好友的操作之后能够立即收到来自服务器的应答,就像登录服务器的操作和注册操作一样,能够在同一个方法内获得操作的结果;
但是这两类操作前者是在已经启动线程的情况下进行的,而后者在线程启动前进行。
要注意在已经启动线程的情况下,客户端对所有来自服务器的消息,必须都放到线程当中处理。
正确写法:

	//发送查找好友消息
	public void findFriend(int JKnum) throws IOException{
		byte type=0x08;
		int len=13+4;
		int dest=0,src=this.JKnum;
		searchFriendMsg sfm= new searchFriendMsg(len,type,dest,src,JKnum);
		byte[]data=MSGTools.packMsg(sfm);
		dou.write(data);
		dou.flush();	
	}

ⅱ.添加好友功能:

	//发送添加好友消息
	public void addFriend(Friend friend, String group,String checkMsg) throws IOException{
		int dest=friend.getJKnum();
		int len=13+256+10+10;
		byte type=0x09;
		addFriendMsg afm= new addFriendMsg(len,type,dest,this.JKnum,checkMsg,this.nickName,group);
		byte[]data=MSGTools.packMsg(afm);
		dou.write(data);
		dou.flush();
		//添加到好友添加列表(待接收到好友申请应答消息再处理)
		addFriendList.put(dest, friend);
	}

这里我们在客户端保留有一个添加好友列表,因为我们的线程机制,再加上添加好友的操作并不一定能得到对方第一时间的回复,我们可以预先把查找到的需要添加的好友保存起来,等收到应答消息以后再删去记录。

ⅲ.处理好友申请功能

	//发送好友申请应答消息
	public void Reply2Add(byte reply,Friend friend,String MyGroup,String FriendGroup) throws IOException{
		byte type=0x19;
		int len,dest=friend.getJKnum();
		addFriendResMsg  afrm;
		if(reply==0){//添加好友到对应分组,发送给服务器自己和对方的分组
			ArrayList<Friend> al= this.friends.get(MyGroup);//得到对应的组
			al.add(friend);//在组中添加好友
			len=13+1+10+10;
		    afrm= new addFriendResMsg(len,type,dest,JKnum,reply,MyGroup,FriendGroup);
		}
		else{//不同意
			len=13+1;
			afrm= new addFriendResMsg(len,type,dest,JKnum,reply);
		}
		byte[]data=MSGTools.packMsg(afrm);
		dou.write(data);
		dou.flush();
	}

ⅳ.用户完善自己的资料和好友列表流程比较复杂,我们可以包装一个方法:

	//获取自身资料,好友列表
	public void getMyInfo() throws IOException{
		ClientInfoMsg cim= (ClientInfoMsg)MSGTools.readMsgHead(din);
		//我的昵称
		this.nickName=cim.getMyName();
		this.JKnum=cim.getDest();
		System.out.println("我的昵称:"+nickName);
		//组数
		int listCount=cim.getListCount();
		System.out.println("listCount:"+listCount);
		ArrayList<Friend> al;
		String groupName,friendName;
		int num,JKnum;
		
                        
                        
版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/qq_43496675/article/details/104251971
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2020-03-07 18:37:32
  • 阅读 ( 830 )
  • 分类:

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢