超详细带你用Java实现QQ的聊天功能

简介: 超详细带你用Java实现QQ的聊天功能

第一步:完成界面搭建🐓



要求:


创建两个窗口:一个客户端,一个服务端,完成代码书写

步骤:


1.定义JFrame窗体中的组件:文本域,滚动条,面板,文本框,按钮


//属性
    //文本域
    private JTextArea jta;
    //滚动条
    private JScrollPane jsp;
    //面板
    private JPanel jp;
    //文本框
    private JTextField jtf;
    //按钮
    private JButton jb;


2.在构造方法中初始化窗口的组件:


 //构造方法
    public ServerChatMain(){
        //初始化组件
        jta = new JTextArea();
        //设置文本域默认不可编辑
        jta.setEditable(false);
        //注意:需要将文本域添加到滚动条中,实现滚动效果
        jsp =new JScrollPane(jta);
        //初始化面板
        jp = new JPanel();
        jtf = new JTextField(10);
        jb=new JButton("发送");
        //注意:需要将文本框与按钮添加到面板中
        jp.add(jtf);
        jp.add(jb);


注意:需要将滚动条与面板全部添加到窗体中,继承了窗体的属性,这里this就是窗体

this.add(jsp, BorderLayout.CENTER);//BorderLayout--边框布局

       this.add(jp,BorderLayout.SOUTH);


4.设置设置”标题“,大小,位置,关闭,是否可见


 

//注意:需要设置”标题“,大小,位置,关闭,是否可见
        this.setTitle("QQ聊天服务端");
        this.setSize(400,300);
        this.setLocation(700,300);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//窗体关闭,程序就退出
        this.setVisible(true);//设置窗体可见
    }

这样我们就完成了服务端的QQ聊天界面窗口搭建:


注意:JTextArea文本域是不可以书写的



客户端与服务端代码类似,这里就不一一展示了


书写完毕代码,运行效果如下图:




第二步:TPC通信的思路与步骤🐻‍❄️


使用网络编程完成数据点的传输(TCP,UDP协议)


TCP协议🐶

TCP 是面向连接的运输层协议。应用程序在使用 TCP 协议之前,必须先建立 TCP 连接。在传送数据完毕后,必须释放已经建立的 TCP 连接

每一条 TCP 连接只能有两个端点,每一条 TCP 连接只能是点对点的(一对一)

TCP 提供可靠交付的服务。通过 TCP 连接传送的数据,无差错、不丢失、不重复,并且按序到达

TCP 提供全双工通信。TCP 允许通信双方的应用进程在任何时候都能发送数据。TCP 连接的两端都设有发送缓存和接受缓存,用来临时存放双向通信的数据

面向字节流。TCP 中的“流”指的是流入到进程或从进程流出的字节序列




TCP 服务端 具体步骤(客户端类似)🐮

具体步骤:


  1.创建一个服务端的套接字


   2.等待客户端连接


  3.获取socket通道的输入流(输入六是实现读取数据的,一行一行读取)BufferedReader->readLine();


   4.获取socket 通道的输出流(输出流实现写出数据,也是写一行换一行,刷新)BufferedWriter->newLine();


   5.关闭socket 通道


TCP通信步骤代码实现:🐸


try {
            //1.创建一个服务端的套接字
            ServerSocket serverSocket = new ServerSocket(8888);
            //2.等待客户端连接
           Socket socket = serverSocket.accept();
            //3.获取socket通道的输入流(输入六是实现读取数据的,一行一行读取)BufferedReader->readLine();
            //InputStream in = socket.getInputStream();
           BufferedReader br=new BufferedReader(new InputStreamReader(socket.getInputStream()));
            //4.获取socket 通道的输出流(输出流实现写出数据,也是写一行换一行,刷新)BufferedWriter->newLine();
            //当用户点击发送按钮的时候写出数据
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            //循环读取数据并拼接到文本域
            String line = null;
           while((line = br.readLine())!=null){
               //将读取的数据拼接到文本域中显示
               jta.append(line+System.lineSeparator());
           }
            //5.关闭socket 通道
            serverSocket.close();
        }catch (IOException e) {
            e.printStackTrace();
        }


点击发送按钮实现数据的传输🐺


@Override
    public void actionPerformed(ActionEvent actionEvent) {
        System.out.println("发送按钮被点击了");
    }


步骤:


1.获取文本框中发送的内容

2.拼接需要发送的数据内容

3.自己也要显示

4.发送

5.清空文本框内容


@Override
    public void actionPerformed(ActionEvent actionEvent) {
        //System.out.println("发送按钮被点击了");
        //1.获取文本框中发送的内容
        String text = jtf.getText();
        //2.拼接需要发送的数据内容
        text = "服务端对客户端说:"+text;
        //3.自己也要显示
        jta.append(text);
        //4.发送
        try {
            bw.write(text);
            bw.newLine();//换行刷新
            bw.flush();
            //5.清空文本框内容
            jtf.setText("");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }



第三步:实现回车键发送数据(客户端类似)🐳


首先要实现一个接口


public class ClientChatMain extends JFrame implements ActionListener, KeyListener {
@Override
    public void keyPressed(KeyEvent e) {
        //回车键
        // System.out.println(e);
        //发送数据到socket 同道中
        if(e.getKeyCode()==KeyEvent.VK_ENTER) {
        sendDataToSocket();
    }



全部代码:🐲


服务端:


package com.ithmm.chat;
import javax.swing.*;
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.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Properties;
//说明:如果一个类,需要有界面的显示,那么这个类就需要继承JFrame,此时,该类可以被成为一个窗体类
/*步骤:
     1.定义JFrame窗体中的组件
     2.在构造方法中初始化窗口的组件
     3.使用网络编程完成数据的链接(TPC,UDP  协议)
     4.实现"发送”按钮的监听点击事件
     5.实现“回车键”发送数据
 */
public class ServerChatMain extends JFrame implements ActionListener, KeyListener {
    public static void main(String[] args) {
        //调用构造方法
        new ServerChatMain();
    }
    //属性
    //文本域
    private JTextArea jta;
    //滚动条
    private JScrollPane jsp;
    //面板
    private JPanel jp;
    //文本框
    private JTextField jtf;
    //按钮
    private JButton jb;
    //输出流(成员变量)
    private BufferedWriter bw = null;
    //服务端的端口号
    //private static int serverPort;
    //使用static静态方法读取外部京台文件
    //static代码块特点:1.在类加载的时候自动执行
    //特点2:一个类会被加载一次,因此静态代码块在程序中仅会被执行一次
    /*static{
        Properties prop = new Properties();
        try {
            //加载
            prop.load(new FileReader("chat.properties"));
            //给属性赋值
            Integer.parseInt(prop.getProperty("serverPort"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }*/
    //构造方法
    public ServerChatMain(){
        //初始化组件
        jta = new JTextArea();
        //设置文本域默认不可编辑
        jta.setEditable(false);
        //注意:需要将文本域添加到滚动条中,实现滚动效果
        jsp =new JScrollPane(jta);
        //初始化面板
        jp = new JPanel();
        jtf = new JTextField(10);
        jb=new JButton("发送");
        //注意:需要将文本框与按钮添加到面板中
        jp.add(jtf);
        jp.add(jb);
        //注意:需要将滚动条与面板全部添加到窗体中,继承了窗体的属性,这里this就是窗体
        this.add(jsp, BorderLayout.CENTER);//BorderLayout--边框布局
        this.add(jp,BorderLayout.SOUTH);
        //注意:需要设置”标题“,大小,位置,关闭,是否可见
        this.setTitle("QQ聊天服务端");
        this.setSize(400,300);
        this.setLocation(700,300);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//窗体关闭,程序就退出
        this.setVisible(true);//设置窗体可见
        /**************** TCP   服务端    Start *********************/
        //给发送按钮绑定一个监听点击事件
        jb.addActionListener(this);
        //给文本框绑定一个键盘点击事件
        jtf.addKeyListener(this);
        try {
            //1.创建一个服务端的套接字
            ServerSocket serverSocket = new ServerSocket(8888);
            //2.等待客户端连接
           Socket socket = serverSocket.accept();
            //3.获取socket通道的输入流(输入六是实现读取数据的,一行一行读取)BufferedReader->readLine();
            //InputStream in = socket.getInputStream();
           BufferedReader br=new BufferedReader(new InputStreamReader(socket.getInputStream()));
            //4.获取socket 通道的输出流(输出流实现写出数据,也是写一行换一行,刷新)BufferedWriter->newLine();
            //当用户点击发送按钮的时候写出数据
            bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            //循环读取数据并拼接到文本域
            String line = null;
           while((line = br.readLine())!=null){
               //将读取的数据拼接到文本域中显示
               jta.append(line+System.lineSeparator());
           }
            //5.关闭socket 通道
            serverSocket.close();
        }catch (IOException e) {
            e.printStackTrace();
        }
        /**************** TCP   服务端    end  *********************/
    }
    @Override
    public void actionPerformed(ActionEvent actionEvent) {
        //System.out.println("发送按钮被点击了");
       sendDataToSocket();
    }
    //行为
    @Override
    public void keyPressed(KeyEvent e) {
        //回车键
        // System.out.println(e);
        //发送数据到socket 同道中
        if(e.getKeyCode()==KeyEvent.VK_ENTER) {
            sendDataToSocket();
        }
    }
    //定义一个方法,实现将数据发送到socket通道中
    private void sendDataToSocket(){
        //1.获取文本框中发送的内容
        String text = jtf.getText();
        //2.拼接需要发送的数据内容
        text = "服务端对客户端说:"+text;
        //3.自己也要显示
        jta.append(text+System.lineSeparator());
        //4.发送
        try {
            bw.write(text);
            bw.newLine();//换行刷新
            bw.flush();
            //5.清空文本框内容
            jtf.setText("");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    @Override
    public void keyTyped(KeyEvent keyEvent) {
    }
    @Override
    public void keyReleased(KeyEvent keyEvent) {
    }
}


客户端:


import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.Properties;
//说明:如果一个类,需要有界面的显示,那么这个类就需要继承JFrame,此时,该类可以被成为一个窗体类
/*步骤:
     1.定义JFrame窗体中的组件
     2.在构造方法中初始化窗口的组件
 */
public class ClientChatMain extends JFrame implements ActionListener, KeyListener {
    public static void main(String[] args) {
        //调用构造方法
        new ClientChatMain();
    }
    //属性
    //文本域
    private JTextArea jta;
    //滚动条
    private JScrollPane jsp;
    //面板
    private JPanel jp;
    //文本框
    private JTextField jtf;
    //按钮
    private JButton jb;
    //s输出流
    private BufferedWriter bw =null;
    //客户端的IP地址
   // private static String clientIp;
    //客户端的port端口号
   // private static int clientPort;
    //静态代码块加载外部配置文件
   /* static{
      Properties prop = new Properties();
        try {
            prop.load(new FileReader("chat.properties"));
            clientIp = prop.getProperty("clientIp");
            clientPort =Integer.parseInt( prop.getProperty("clientPort"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }*/
    //构造方法
    public ClientChatMain(){
        //初始化组件
        jta = new JTextArea();
        //设置文本域默认不可编辑
        jta.setEditable(false);
        //注意:需要将文本域添加到滚动条中,实现滚动效果
        jsp =new JScrollPane(jta);
        //初始化面板
        jp = new JPanel();
        jtf = new JTextField(10);
        jb=new JButton("发送");
        //注意:需要将文本框与按钮添加到面板中
        jp.add(jtf);
        jp.add(jb);
        //注意:需要将滚动条与面板全部添加到窗体中,继承了窗体的属性,这里this就是窗体
        this.add(jsp, BorderLayout.CENTER);//BorderLayout--边框布局
        this.add(jp,BorderLayout.SOUTH);
        //注意:需要设置”标题“,大小,位置,关闭,是否可见
        this.setTitle("QQ聊天客户端");
        this.setSize(400,300);
        this.setLocation(700,300);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//窗体关闭,程序就退出
        this.setVisible(true);//设置窗体可见
        /**************** TCP   客户端    Start *********************/
        //给发送按钮绑定一个监听点击事件
        jb.addActionListener(this);
        //给文本框绑定一个键盘键
        jtf.addKeyListener(this);
        try {
            //1.创建一个客户端的套接字(尝试连接)
            Socket socket = new Socket("127.0.0.1",8888);
            //2.获取socket通道的输入流
           BufferedReader br =  new BufferedReader(new InputStreamReader(socket.getInputStream()));
            //3.获取socket 通道的输出流
          bw =  new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            //循环读取数据,并拼接到文本域
           String line = null;
           while((line = br.readLine())!=null){
               jta.append(line + System.lineSeparator());
           }
            //4.关闭socket 通道
            socket.close();
        }catch (Exception e){
            e.printStackTrace();
        }
        /**************** TCP   客户端    end  *********************/
    }
    @Override
    public void actionPerformed(ActionEvent e) {
       sendDataToSocket();
    }
    //行为
    @Override
    public void keyPressed(KeyEvent e) {
        //回车键
        if(e.getKeyCode() == KeyEvent.VK_ENTER){
            //发送数据
            sendDataToSocket();
        }
    }
    private void sendDataToSocket(){
        //1.获取文本框需要发送内容
        String text = jtf.getText();
        //2.拼接内容
        text = "客户端对服务端说"+text;
        //3.自己显示
        jta.append(text+System.lineSeparator());
        try {
            //4.发送
            bw.write(text);
            bw.newLine();//换行加刷新
            bw.flush();
            bw.write(text);
            //5.清空
            jtf.setText("");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    @Override
    public void keyTyped(KeyEvent e) {
    }
    @Override
    public void keyReleased(KeyEvent e) {
    }
}


接口类:


public interface addActistener {
}


public interface addActionListener {
}
目录
相关文章
|
3月前
|
安全 Java API
Java中的Lambda表达式:简洁与功能的结合
Java中的Lambda表达式:简洁与功能的结合
402 211
|
3月前
|
JavaScript Java 微服务
现代化 Java Web 在线商城项目技术方案与实战开发流程及核心功能实现详解
本项目基于Spring Boot 3与Vue 3构建现代化在线商城系统,采用微服务架构,整合Spring Cloud、Redis、MySQL等技术,涵盖用户认证、商品管理、购物车功能,并支持Docker容器化部署与Kubernetes编排。提供完整CI/CD流程,助力高效开发与扩展。
454 64
|
2月前
|
存储 数据可视化 Java
Java Stream API 的强大功能
Java Stream API 是 Java 8 引入的重要特性,它改变了集合数据的处理方式。通过声明式语法,开发者可以更简洁地进行过滤、映射、聚合等操作。Stream API 支持惰性求值和并行处理,提升了代码效率和可读性,是现代 Java 开发不可或缺的工具。
Java Stream API 的强大功能
|
3月前
|
前端开发 JavaScript Java
Java 项目实战城市公园信息管理系统开发流程与实用功能实现指南
本系统基于Java开发,采用Spring Boot后端框架与Vue.js前端框架,结合MySQL数据库,构建了一个高效的城市公园信息管理系统。系统包含管理员、用户和保洁人员三大模块,涵盖用户管理、园区信息查询、订票预约、服务管理等功能,提升公园管理效率与服务质量。
134 6
|
3月前
|
安全 Java 数据库
Java 项目实战病人挂号系统网站设计开发步骤及核心功能实现指南
本文介绍了基于Java的病人挂号系统网站的技术方案与应用实例,涵盖SSM与Spring Boot框架选型、数据库设计、功能模块划分及安全机制实现。系统支持患者在线注册、登录、挂号与预约,管理员可进行医院信息与排班管理。通过实际案例展示系统开发流程与核心代码实现,为Java Web医疗项目开发提供参考。
185 2
|
3月前
|
机器学习/深度学习 算法 Java
Java 大视界 -- Java 大数据机器学习模型在生物信息学基因功能预测中的优化与应用(223)
本文探讨了Java大数据与机器学习模型在生物信息学中基因功能预测的优化与应用。通过高效的数据处理能力和智能算法,提升基因功能预测的准确性与效率,助力医学与农业发展。
|
4月前
|
Java API
Java API中Math类功能全景扫描
在实际使用时,这些方法的精确度和性能得到了良好的优化。当处理复杂数学运算或高精度计算时,`Math`类通常是足够的。然而,对于非常精细或特殊的数学运算,可能需要考虑使用 `java.math`包中的 `BigDecimal`类或其他专业的数学库。
127 11
|
4月前
|
Java API
深入解析Java API中Object类的功能
了解和合理运用 Object类的这些方法,对于编写可靠和高效的Java应用程序至关重要。它们构成了Java对象行为的基础,影响着对象的创建、识别、表达和并发控制。
82 0
|
4月前
|
消息中间件 监控 Java
借助最新技术构建 Java 邮件发送功能的详细流程与核心要点分享 Java 邮件发送功能
本文介绍了如何使用Spring Boot 3、Jakarta Mail、MailHog及响应式编程技术构建高效的Java邮件发送系统,涵盖环境搭建、异步发送、模板渲染、测试与生产配置,以及性能优化方案,助你实现现代化邮件功能。
195 0