当前位置: 首页 > news >正文

仿QQ聊天室项目

仿QQ聊天室项目

完整代码见

       https://github.com/skyerhxx/QQ-Project

 

完整项目结构

QQ_Client

QQ_Server

 

二者之间的连接简图

 

一些界面的程序的对应关系

QqClientLogin   

QqFriendList     

QqChat        

 

MyServerFrame   

 

开发过程

 

登录界面

创建普通Java项目

并创建model、view、tools、common 四个包

在view下创建QqClientLogin.java

 

/**
 * 功能: qq客户端登录界面
 */

package com.qq.client.view;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class QqClientLogin extends JFrame {

    //定义界面上部需要的组件
    JLabel jbl1;

    //定义界面中部需要的组件

    //定义界面下部需要的组件
    JPanel jp1;
    JButton jp1_jb1,jp1_jb2,jp1_jb3;

    public static void main(String[] args){
        QqClientLogin qqClientLogin = new QqClientLogin();

    }
    public QqClientLogin(){
        //处理界面上部
        jbl1 = new JLabel(new ImageIcon("./src/resources/tou.gif"));
        this.add(jbl1,"North");
        this.setSize(350,240);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true); //设置让它可见

    }
}

/**
 * 功能: qq客户端登录界面
 */

package com.qq.client.view;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class QqClientLogin extends JFrame {

    //定义界面上部需要的组件
    JLabel jbl1;

    //定义界面中部需要的组件

    //定义界面下部需要的组件
    JPanel jp1;
    JButton jp1_jb1,jp1_jb2,jp1_jb3;

    public static void main(String[] args){
        QqClientLogin qqClientLogin = new QqClientLogin();

    }
    public QqClientLogin(){
        //处理界面上部
        jbl1 = new JLabel(new ImageIcon("./src/resources/tou.gif"));

        //处理界面下部
        jp1 = new JPanel();
        jp1_jb1 = new JButton(new ImageIcon("./src/resources/denglu.gif"));
        jp1_jb2 = new JButton(new ImageIcon("./src/resources/quxiao.gif"));
        jp1_jb3 = new JButton(new ImageIcon("./src/resources/xiangdao.gif"));
        //把3个按钮放入到jp1
        jp1.add(jp1_jb1);
        jp1.add(jp1_jb2);
        jp1.add(jp1_jb3);


        this.add(jbl1,"North");
        //把jp1放在页面下部
        this.add(jp1,"South");
        this.setSize(350,240);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true); //设置让它可见

    }
}

/**
 * 功能: qq客户端登录界面
 */

package com.qq.client.view;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class QqClientLogin extends JFrame {

    //定义界面上部需要的组件
    JLabel jbl1;

    //定义界面中部需要的组件
        //中部有3个JPanel, 由一个选项卡窗口管理
    JTabbedPane jtp;
    JPanel jp2,jp3,jp4;
    JLabel jp2_jbl1,jp2_jbl2,jp2_jbl3,jp2_jbl4;
    JButton jp2_jb1;
    JTextField jp2_jtf;
    JPasswordField jp2_jpf;
    JCheckBox jp2_jcb1,jp2_jcb2;


    //定义界面下部需要的组件
    JPanel jp1;
    JButton jp1_jb1,jp1_jb2,jp1_jb3;

    public static void main(String[] args){
        QqClientLogin qqClientLogin = new QqClientLogin();

    }
    public QqClientLogin(){
        //处理界面上部
        jbl1 = new JLabel(new ImageIcon("./src/resources/tou.gif"));
        //处理界面中部
        jp2 = new JPanel(new GridLayout(3,3));

        jp2_jbl1 = new JLabel("QQ号码",JLabel.CENTER);
        jp2_jbl2 = new JLabel("QQ密码",JLabel.CENTER);
        jp2_jbl3 = new JLabel("忘记密码",JLabel.CENTER);
        jp2_jbl3.setForeground(Color.blue);
        jp2_jbl4 = new JLabel("申请密码保护",JLabel.CENTER);
        jp2_jb1 = new JButton(new ImageIcon("./src/resources/clear.gif"));
        jp2_jtf = new JTextField();
        jp2_jpf = new JPasswordField();
        jp2_jcb1 = new JCheckBox("隐身登录");
        jp2_jcb2 = new JCheckBox("记住密码");
        //把控件按照顺序加入到jp2
        jp2.add(jp2_jbl1);
        jp2.add(jp2_jtf);
        jp2.add(jp2_jb1);
        jp2.add(jp2_jbl2);
        jp2.add(jp2_jpf);
        jp2.add(jp2_jbl3);
        jp2.add(jp2_jcb1);
        jp2.add(jp2_jcb2);
        jp2.add(jp2_jbl4);
        //创建选项卡窗口
        jtp = new JTabbedPane();
        jtp.add("QQ号码",jp2);
        jp3 = new JPanel();
        jtp.add("手机号码",jp3);
        jp4 = new JPanel();
        jtp.add("电子邮件",jp4);


        //处理界面下部
        jp1 = new JPanel();
        jp1_jb1 = new JButton(new ImageIcon("./src/resources/denglu.gif"));
        jp1_jb2 = new JButton(new ImageIcon("./src/resources/quxiao.gif"));
        jp1_jb3 = new JButton(new ImageIcon("./src/resources/xiangdao.gif"));
        //把3个按钮放入到jp1
        jp1.add(jp1_jb1);
        jp1.add(jp1_jb2);
        jp1.add(jp1_jb3);


        this.add(jbl1,"North");
        this.add(jtp,"Center");
        //把jp1放在页面下部
        this.add(jp1,"South");
        this.setSize(350,240);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true); //设置让它可见

    }
}

 

好友列表界面

新建QqFriendList.java

/*
    我的好友列表,也包括陌生人和黑名单
 */
package com.qq.client.view;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class QqFriendList extends JFrame{

    //处理第一张卡片
    JPanel jphy1,jphy2,jphy3;
    JButton jphy_jb1,jphy_jb2,jphy_jb3;
    JScrollPane jsp1;

    public static void main(String[] args) {
        QqFriendList qqFriendList = new QqFriendList();
    }

    public QqFriendList(){
        //处理第一张卡片
        jphy_jb1 = new JButton("我的好友");
        jphy_jb2 = new JButton("陌生人");
        jphy_jb3 = new JButton("黑名单");
        jphy1 = new JPanel(new BorderLayout());
        //假定有50个好友
        jphy2 = new JPanel(new GridLayout(50,1,4,4));
        //给jphy2初始化50个好友
        JLabel []jbls = new JLabel[50];
        for (int i = 0; i < jbls.length; i++) {
            jbls[i] = new JLabel(i+1+"", new ImageIcon("./src/resources/mm.jpg"),JLabel.LEFT);
            jphy2.add(jbls[i]);
        }


        jphy3 = new JPanel(new GridLayout(2,1));
        //把两个按钮加入到jphy3
        jphy3.add(jphy_jb2);
        jphy3.add(jphy_jb3);



        jsp1 = new JScrollPane(jphy2);

        //对jphy1初始化
        jphy1.add(jphy_jb1,"North");
        jphy1.add(jsp1,"Center");
        jphy1.add(jphy3,"South");

        this.add(jphy1,"Center");
        this.setSize(140,400);
        this.setVisible(true);
    }
}

 

/*
    我的好友列表,也包括陌生人和黑名单
 */
package com.qq.client.view;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class QqFriendList extends JFrame implements ActionListener,MouseListener{

    //处理第一张卡片(好友)
    //hy = 好友
    JPanel jpmsr1,jpmsr2,jpmsr3;
    JButton jpmsr_jb1,jpmsr_jb2,jpmsr_jb3;
    JScrollPane jsp2;

    //处理第二张卡片(陌生人)
    //msr = 陌生人
    JPanel jphy1,jphy2,jphy3;
    JButton jphy_jb1,jphy_jb2,jphy_jb3;
    JScrollPane jsp1;

    //把整个JFrame设置成CardLayout布局
    CardLayout cl;
    public static void main(String[] args) {
        QqFriendList qqFriendList = new QqFriendList();
    }

    public QqFriendList(){
        //处理第一张卡片(显示好友列表)
        jphy_jb1 = new JButton("我的好友");
        jphy_jb2 = new JButton("陌生人");
        jphy_jb2.addActionListener(this);
        jphy_jb3 = new JButton("黑名单");
        jphy1 = new JPanel(new BorderLayout());
        //假定有50个好友
        jphy2 = new JPanel(new GridLayout(50,1,4,4));
        //给jphy2初始化50个好友
        JLabel []jbls = new JLabel[50];
        for (int i = 0; i < jbls.length; i++) {
            jbls[i] = new JLabel(i+1+"", new ImageIcon("./src/resources/mm.jpg"),JLabel.LEFT);
            jbls[i].addMouseListener(this);
            jphy2.add(jbls[i]);

        }


        jphy3 = new JPanel(new GridLayout(2,1));
        //把两个按钮加入到jphy3
        jphy3.add(jphy_jb2);
        jphy3.add(jphy_jb3);



        jsp1 = new JScrollPane(jphy2);

        //对jphy1初始化
        jphy1.add(jphy_jb1,"North");
        jphy1.add(jsp1,"Center");
        jphy1.add(jphy3,"South");

        //处理第二张卡片
        jpmsr_jb1 = new JButton("我的好友");
        jpmsr_jb1.addActionListener(this);
        jpmsr_jb2 = new JButton("陌生人");
        jpmsr_jb3 = new JButton("黑名单");
        jpmsr1 = new JPanel(new BorderLayout());
        //假定有20个陌生人
        jpmsr2 = new JPanel(new GridLayout(20,1,4,4));
        //给jphy2初始化50个陌生人
        JLabel []jbls2 = new JLabel[20];
        for (int i = 0; i < jbls2.length; i++) {
            jbls2[i] = new JLabel(i+1+"", new ImageIcon("./src/resources/mm.jpg"),JLabel.LEFT);
            jpmsr2.add(jbls2[i]);
        }


        jpmsr3 = new JPanel(new GridLayout(2,1));
        //把两个按钮加入到jpmsr3
        jpmsr3.add(jpmsr_jb1);
        jpmsr3.add(jpmsr_jb2);


        jsp2 = new JScrollPane(jpmsr2);

        //对jpmsr1初始化
        jpmsr1.add(jpmsr3,"North");
        jpmsr1.add(jsp2,"Center");
        jpmsr1.add(jpmsr_jb3,"South");


        cl = new CardLayout();
        this.setLayout(cl);
        this.add(jphy1,"1");
        this.add(jpmsr1,"2");

        this.setSize(140,400);
        this.setVisible(true);
    }

    @Override
    public void actionPerformed(ActionEvent arg0) {
        //如果用户点击了陌生人按钮,就显示第二张卡片
        if(arg0.getSource() == jphy_jb2){
            cl.show(this.getContentPane(),"2");
        }
        else if(arg0.getSource()==jpmsr_jb1){
            cl.show(this.getContentPane(),"1");
        }
    }

    @Override
    public void mouseClicked(MouseEvent arg0) {
        //响应用户双击的事件,并得到好友的编号
        if(arg0.getClickCount() == 2){
            //得到该好友的编号
            String friendNo = ((JLabel)arg0.getSource()).getText();
            System.out.println("你希望和 "+friendNo+" 聊天");
        }
    }

    @Override
    public void mousePressed(MouseEvent e) {

    }

    @Override
    public void mouseReleased(MouseEvent e) {

    }

    @Override
    public void mouseEntered(MouseEvent arg0) {
        JLabel jl = (JLabel)arg0.getSource();
        jl.setForeground(Color.red);
    }

    @Override
    public void mouseExited(MouseEvent arg0) {
        JLabel jl = (JLabel)arg0.getSource();
        jl.setForeground(Color.black);
    }
}

效果是鼠标放上变红,移开又变黑

双击会输出 你希望和谁聊天

 

聊天界面 对象流

Qqchat()

/*
    这是与好友聊天的界面
 */
package com.qq.client.view;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class QqChat extends JFrame {

    JTextArea jta;
    JTextField jtf;
    JButton jb;
    JPanel jp;

    public static void main(String[] args) {
        QqChat qqChat = new QqChat("1");
    }

    public QqChat(String friend){
        jta = new JTextArea();
        jtf = new JTextField(15);
        jb = new JButton("发送");
        jp = new JPanel();
        jp.add(jtf);
        jp.add(jb);

        this.add(jta,"Center");
        this.add(jp,"South");
        this.setTitle("你正在和 "+friend+" 聊天");
        this.setIconImage(new ImageIcon("./src/resources/qq.gif").getImage());
        this.setSize(300,200);
        this.setVisible(true);
    }
}

 

接下来是

由它到它

先写服务器,先不涉及数据库

 

/*
    这是服务器端的控制界面,可以完成启动服务器,关闭服务器
    可以管理和监控用户
 */
package com.qq.server.view;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class MyServerFrame extends JFrame {

    JPanel jp1;
    JButton jb1,jb2;

    public static void main(String[] args) {
        MyServerFrame mysf = new MyServerFrame();
    }

    public MyServerFrame(){
        jp1 = new JPanel();
        jb1 = new JButton("启动服务器");
        jb2 = new JButton("关闭服务器");
        jp1.add(jb1);
        jp1.add(jb2);

        this.add(jp1);
        this.setSize(500,400);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
    }

}

用对象流获取用户发送的消息

如何在网络间传递对象:对象流

对象流还要将对象序列化,才能在网络上传输

 

登录验证

 

 

MyServerFrame是服务器

先启动QQ_Server中的MyServerFrame
 

启动QQ_Client中的QqClientLogin

输入正确的密码123456

 

一对一聊天

 

多对多的聊天

实现多人聊天

 

每一个用户登录都会开一个线程.  你有3个用户登录就有3个线程同时在处理这3个用户与服务器的交互
 

 

 

把接收到的消息,显示到该显示的聊天界面(这是第7集的内容)

 

好友在线提示

好友在线,头像就是彩色的,不在线就是灰色的

 

当用户一登录成功了之后,迅速发一个请求包,让服务器给返回有哪些人在线

所有在线的人都存在一个HashMap里面,遍历就可找到所有的

 

现在可以看到在线的好友头像点亮,不在线的头像是灰色

 

但是后面登录的人可以看到前面登录的人,前面登录的人看不到后面登录的人

 

下面是第8集

后面登录的人应该有责任去通知其他在线的人他上线了,然后去更改他们的好友在线情况

 

功能全部实现

至此,项目完结

 

参考视频:

https://www.bilibili.com/video/BV174411w7SY?p=1

相关文章:

  • 基于Python+Flask+Echarts的 COVID-19数据可视化项目
  • go语言相关知识
  • go语言相关库和函数
  • Windows内核文件
  • MyOS(三):软盘读写
  • Python函数式编程(二):map、 reduce、 filter、 sorted
  • OpenCV(一)——图片灰度转换(灰度图) 修改图片尺寸(cv2.resize) 读取视频
  • opencv人脸识别 (一):人脸检测 (Haar级联 静态图像中人脸检测 视频中的人脸检测 )
  • opencv人脸识别 (二):人脸识别 (基于 LBPH)
  • Caffe(一)——简介 优点 Caffe2 编译和安装
  • Pytorch之经典神经网络CNN(一) —— 全连接网络 / MLP (MNIST) (trainset和Dataloader batch training learning_rate)
  • 神经网络/深度学习 相关知识
  • pytorch搭建神经网络分类Fashion-MNIST数据集
  • Python函数式编程(三):匿名函数lambda
  • 编程范式—命令式编程与函数式编程
  • 【EOS】Cleos基础
  • 【JavaScript】通过闭包创建具有私有属性的实例对象
  • 【刷算法】求1+2+3+...+n
  • Intervention/image 图片处理扩展包的安装和使用
  • Invalidate和postInvalidate的区别
  • JavaScript 奇技淫巧
  • JS笔记四:作用域、变量(函数)提升
  • leetcode46 Permutation 排列组合
  • Mithril.js 入门介绍
  • nginx(二):进阶配置介绍--rewrite用法,压缩,https虚拟主机等
  • Node 版本管理
  • tweak 支持第三方库
  • Yeoman_Bower_Grunt
  • 百度地图API标注+时间轴组件
  • 理解 C# 泛型接口中的协变与逆变(抗变)
  • 前端攻城师
  • 移动互联网+智能运营体系搭建=你家有金矿啊!
  • 长三角G60科创走廊智能驾驶产业联盟揭牌成立,近80家企业助力智能驾驶行业发展 ...
  • ​Linux·i2c驱动架构​
  • # 数论-逆元
  • #pragma data_seg 共享数据区(转)
  • #QT(智能家居界面-界面切换)
  • #周末课堂# 【Linux + JVM + Mysql高级性能优化班】(火热报名中~~~)
  • (Arcgis)Python编程批量将HDF5文件转换为TIFF格式并应用地理转换和投影信息
  • (C++)八皇后问题
  • (Redis使用系列) Springboot 使用Redis+Session实现Session共享 ,简单的单点登录 五
  • (阿里云万网)-域名注册购买实名流程
  • (编程语言界的丐帮 C#).NET MD5 HASH 哈希 加密 与JAVA 互通
  • (非本人原创)我们工作到底是为了什么?​——HP大中华区总裁孙振耀退休感言(r4笔记第60天)...
  • (利用IDEA+Maven)定制属于自己的jar包
  • (入门自用)--C++--抽象类--多态原理--虚表--1020
  • (转)shell调试方法
  • (转)为C# Windows服务添加安装程序
  • (转)总结使用Unity 3D优化游戏运行性能的经验
  • .aanva
  • .axf 转化 .bin文件 的方法
  • .Net Core 中间件验签
  • .net FrameWork简介,数组,枚举
  • .NET 反射的使用
  • .net 后台导出excel ,word