• 基于JAVA的TCP网络QQ聊天工具系统


    目 录
    1 功能设计 1
    1.1功能概述 1
    1.2功能模块图 1
    2 逻辑设计 2
    3 界面设计 4
    3.1注册界面: 4
    3.2登录界面 5
    3.3好友列表页面 5
    3.4好友聊天页面 6
    3.5服务器界面 7
    4 各模块详细设计 7
    4.1登录模块 7
    4.2注册模块 9
    4.3聊天模块 10
    4.4数据库工具类 12
    4.5封装的数据交换类 12
    5 系统测试 13
    6 主要问题解决过程 15
    7 作品总结 16
    1.1功能概述
    该系统是基于JAVA语言开发的一款网络聊天工具,通过Socket实现TCP编程,使用多线程实现了多客户端的连接。模仿腾讯QQ的界面,功能较为简单,但是使用了最基本的网络编程技术,如socket、tcp、I/O阻塞、多线程、MySQL数据库等。
    该系统实现了用户的注册、登录以及与好友聊天的功能。
    用户注册:系统随机生成账号,用户按照要求填入相应的信息。
    用户登录:用户根据自己的账号和密码进行登录。
    好友聊天:登录成功后,点击好友列表中的好友进行聊天。
    6 主要问题解决过程
    1)如何判断该好友是否在线?
    最后一节课的课程分享,5班的同学在他的课程设计中使用了数组对登录的用户进行了记载,0代码不在线,1代表在线。在这里,我使用了相同的处理方式,将所以已经成功登录的用户SocketThread加入到HashMap集合中,SocketThread中记录了所有成功连接的socket实体类。
    2)消息只能接收一次
    使用while循环,时刻监听socket发送的数据,I/O阻塞接受客户端的消息。
    3)验证登录和验证注册的逻辑使用了同一个。
    一开始写好了登录的验证,后来实现注册时,在想注册和登录不就是返回结果相反吗?登录时是通过服务器查询数据库中存在该账号才允许登录,而注册验证是查询数据库后没有该用户才允许注册,所以直接调用了同一个方法。后来注册时有时可以,有时出现问题,当时没有仔细想,后来才发现,本文转载自http://www.biyezuopin.vip/onews.asp?id=14869返回结果是相反,但是验证注册不需要密码啊,只需要查询数据库中是否有该用户即可,如果使用登录的验证进行注册验证,那用户账号一样,密码不一样,同样可以允许注册了。
    将注册的验证和注册的完成操作单独拿出,bug解决。
    4)如何将不同的请求进行集中操作?
    Java中的泛型可以处理不同数据的传入,但是由于平时使用的不多,对于泛型并不能彻底为我所用。最后封装了一个CommandTranser对象,实例化客户端时,通过sendData(CommandTranser msg)方法向服务器发送数据,然后通过getData()方法获得数据库返回的结果。
    5)如果好友不在线,发送的消息怎么处理?
    一开始自己想,只要好友不在线,弹出系统提示就足够了,不需要再将消息进行处理,可以在运行时出现了问题。没有想到好的解决办法,自己的处理方式是当好友不在线时,将该消息的发送方和接收方都设置为了自己。其实后来想想,如果实现了在线好友列表,在未发送消息之前,就可以知道好友是否在线,该问题就迎道而解。

    package cn.edu.ldu.ui;
    
    import java.awt.BorderLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.event.WindowAdapter;
    import java.awt.event.WindowEvent;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.JScrollBar;
    import javax.swing.JTextArea;
    import javax.swing.JTextField;
    
    import cn.edu.ldu.socket.Client;
    import cn.edu.ldu.socket.ClientThread;
    import cn.edu.ldu.util.CommandTranser;
    
    /**
     * 聊天对话框
     */
    public class ChatUI extends JFrame implements ActionListener {
    
    	private static final long serialVersionUID = 1L;
    	private JTextArea chat_txt;
    	private JTextField message_txt;
    	private JButton send_btn;
    	private JPanel panel;
    	private String owner;
    	private String friend;
    	private Client client;
    	private ClientThread thread;// 接收信息线程
    
    	public ChatUI(String owner, String friend, Client client) {
    		this.owner = owner;
    		this.friend = friend;
    		this.client = client;
    		init();
    		setTitle("与" + friend + "聊天中");
    		setSize(350, 350);
    		setLocationRelativeTo(null);
    		setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    		setVisible(true);
    		// 开启客户端接收信息线程
    		thread = new ClientThread(client, chat_txt);
    		thread.start();
    	}
    
    	private void init() {
    		// TODO Auto-generated method stub
    		setLayout(new BorderLayout());
    		panel = new JPanel();
    		message_txt = new JTextField(20);
    		send_btn = new JButton("发送");
    		panel.add(message_txt);
    		panel.add(send_btn);
    		chat_txt = new JTextArea();
    		chat_txt.setEditable(false);
    		chat_txt.add(new JScrollBar(JScrollBar.VERTICAL));
    		add(chat_txt, BorderLayout.CENTER);
    		add(panel, BorderLayout.SOUTH);
    		send_btn.addActionListener(this);
    		// 添加窗口关闭事件
    		addWindowListener(new WindowAdapter() {
    			@Override
    			public void windowClosing(WindowEvent e) {
    				// TODO Auto-generated method stub
    				thread.setOnline(false);
    			}
    
    			@Override
    			public void windowClosed(WindowEvent e) {
    				// TODO Auto-generated method stub
    				thread.setOnline(false);
    			}
    		});
    	}
    
    	@Override
    	public void actionPerformed(ActionEvent e) {
    		// TODO Auto-generated method stub
    		// 如果点击了发送按钮
    		if (e.getSource() == send_btn) {
    			Date date = new Date();
    			SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:ss a");
    
    			String message = "你说:" + message_txt.getText() + "\t"
    					+ sdf.format(date) + "\n";
    			// 在本地文本区追加发送的信息
    			chat_txt.append(message);
    			// msg为客户端向服务器发送的数据
    			CommandTranser msg = new CommandTranser();
    			msg.setCmd("message");
    			msg.setSender(owner);
    			msg.setReceiver(friend);
    			msg.setData(message_txt.getText());
    
    			client.sendData(msg);
    			// 发送信息完毕 写信息的文本框设空
    			message_txt.setText(null);
    		}
    	}
    
    }
    

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • 相关阅读:
    Spring Bean 生命周期 (核心)(荣耀典藏版)
    将输入对象转换为数组数组的维度大于等于1numpy.atleast_1d()
    ESP32-CAM——内网穿透教程
    【halcon】踩坑unin2
    决策树算法、随机森林算法
    【python】pycharm导入anaconda环境
    计算机组成原理知识总结(一)计算机概论
    【经典小练习】JavaSE—拷贝文件夹
    计算机毕业设计springboot+vue基本微信小程序的校园跑腿平台 uniapp
    Ubuntu20.04 通过nmcli命令查看网卡状态为unmanaged
  • 原文地址:https://blog.csdn.net/sheziqiong/article/details/127066266